diff --git a/onekey.sh b/onekey.sh index f1c5545..b7edf8c 100755 --- a/onekey.sh +++ b/onekey.sh @@ -9,7 +9,7 @@ export PATH # SPARK技术讨论与反馈QQ群:6646169 8346256 #================================================= -GAME_ENABLE="yes" +GAME_ENABLE="no" sh_ver="2.0" filepath=$(cd "$(dirname "$0")"; pwd) Green_font_prefix="\033[32m" && Red_font_prefix="\033[31m" && Green_background_prefix="\033[42;37m" && Red_background_prefix="\033[41;37m" && Yellow_background_prefix="\033[43;37m" && Font_color_suffix="\033[0m" && Yellow_font_prefix="\e[1;33m" && Blue_font_prefix="\e[0;34m" @@ -98,6 +98,21 @@ check_lidar(){ echo -e "${Error} 没有找到雷达,请确认雷达已正确连接!!" fi } + +check_camera_no_print(){ + #检查使用哪种设备 + if [ -n "$(lsusb -d 2bc5:0403)" ]; then + CAMERATYPE="astrapro" + fi + if [ -n "$(lsusb -d 2bc5:0401)" ]; then + CAMERATYPE="astra" + fi + if [ -n "$(lsusb -d 8086:0b07)" ]; then + CAMERATYPE="d435" + fi +} + + #检查摄像头设备 check_camera(){ @@ -752,14 +767,49 @@ spark_dock(){ } -#让SPARK夺宝奇兵比赛用示例程序 +#hsv范围值查找 +spark_hsv_detection(){ + echo -e "${Info}" + echo -e "${Info}hsv值自动查找" + ROSVER=`/usr/bin/rosversion -d` + PROJECTPATH=$(cd `dirname $0`; pwd) + source ${PROJECTPATH}/devel/setup.bash + + echo -e "${Info}" + echo -e "${Info}请确定:" + echo -e "${Info} A.摄像头已反向向下安装好。机械臂正常上电。" + echo -e "${Info} B.${Red_font_prefix}红色${Font_color_suffix}标定物已贴好在吸盘固定头正上方。" + echo -e "${Info} C.机械臂正常上电。" + echo -e "${Info}退出请输入:Ctrl + c " + echo -e "${Info}" + + echo -e "${Info}请选择比赛方式: + ${Green_font_prefix}1.${Font_color_suffix} 获取吸盘上方hsv值 + ${Green_font_prefix}2.${Font_color_suffix} 获取颜色块hsv值,需要将颜色块放在图像的矩形框中 + ${Green_font_prefix}3.${Font_color_suffix} 退出请输入:Ctrl + c" + echo && stty erase ^? && read -p "请输入数字 [1-2]:" armnum + case "$armnum" in + 1) + roslaunch spark_carry_object hsv_detection.launch camera_type_tel:=${CAMERATYPE} color:=${calibration} + ;; + 2) + roslaunch spark_carry_object hsv_detection.launch camera_type_tel:=${CAMERATYPE} color:=${color_block} + ;; + *) + echo -e "${Error} 错误,请填入正确的数字" + ;; + esac + +} + +#方块抓取示例程序 spark_carry_game(){ echo -e "${Info}" echo -e "${Info}夺宝奇兵比赛用示例程序" ROSVER=`/usr/bin/rosversion -d` PROJECTPATH=$(cd `dirname $0`; pwd) source ${PROJECTPATH}/devel/setup.bash - echo -e "${Info}请选择比赛方式: + echo -e "${Info}请选择方式: ${Green_font_prefix}1.${Font_color_suffix} 手动模式 ${Green_font_prefix}2.${Font_color_suffix} 自动模式 ${Green_font_prefix}3.${Font_color_suffix} 退出请输入:Ctrl + c" @@ -992,6 +1042,23 @@ coming_soon(){ } + +check_camera_game(){ + if [[ "${GAME_ENABLE}" == "yes" ]]; then + check_camera_no_print + if [[ "${CAMERATYPE}" == "d435" ]]; then + aa='a' + else + echo -e " + ${Green_font_prefix} 13.${Font_color_suffix} hsv值自动查找" + fi + echo -e " + ${Green_font_prefix} 20.${Font_color_suffix} 竞赛示例程序 + +————————————" + fi +} + #printf menu_status(){ echo -e "${Tip} 当前系统版本 ${OSDescription} !" @@ -1043,10 +1110,9 @@ echo -e " ${Green_font_prefix} 11.${Font_color_suffix} 语音控制SPARK移动 ${Green_font_prefix} 12.${Font_color_suffix} 给摄像头做标定 - ${Green_font_prefix} 20.${Font_color_suffix} 比赛程序 - -———————————— - +————————————" +check_camera_game +echo -e " ${Green_font_prefix}100.${Font_color_suffix} 问题反馈 ${Green_font_prefix}104.${Font_color_suffix} 文件传输 " @@ -1093,6 +1159,9 @@ case "$num" in 12) calibrate_camera ;; + 13) + spark_hsv_detection + ;; 20) spark_carry_game ;; diff --git a/src/3rd_app/move2grasp/launch/move2grasp.launch b/src/3rd_app/move2grasp/launch/move2grasp.launch index e7d4207..dcd279a 100755 --- a/src/3rd_app/move2grasp/launch/move2grasp.launch +++ b/src/3rd_app/move2grasp/launch/move2grasp.launch @@ -51,7 +51,7 @@ - + diff --git a/src/3rd_app/move2grasp/launch/teleop2grasp.launch b/src/3rd_app/move2grasp/launch/teleop2grasp.launch index 10234bf..8673fd8 100755 --- a/src/3rd_app/move2grasp/launch/teleop2grasp.launch +++ b/src/3rd_app/move2grasp/launch/teleop2grasp.launch @@ -15,6 +15,7 @@ + @@ -53,7 +54,7 @@ - + diff --git a/src/3rd_app/move2grasp/scripts/grasp_pro_new.py b/src/3rd_app/move2grasp/scripts/grasp_pro_new.py new file mode 100755 index 0000000..fd1db65 --- /dev/null +++ b/src/3rd_app/move2grasp/scripts/grasp_pro_new.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os +import time +import random +import ctypes +import roslib +import rospy +import smach +import smach_ros +import threading +import string +import math +import cv2 +import numpy as np +from geometry_msgs.msg import Twist +from std_msgs.msg import String +from geometry_msgs.msg import Pose, Point, Quaternion +from sensor_msgs.msg import Image +from cv_bridge import CvBridge, CvBridgeError +from spark_carry_object.msg import * + + +class GraspObject(): + ''' + 监听主控,用于物品抓取功能 + ''' + + def __init__(self): + ''' + 初始化 + ''' + + global xc, yc, xc_prev, yc_prev, found_count + xc = 0 + yc = 0 + xc_prev = xc + yc_prev = yc + found_count = 0 + self.is_found_object = False + # self.sub = rospy.Subscriber("/camera/rgb/image_raw", Image, self.image_cb, queue_size=1) + # 订阅机械臂抓取指令 + self.sub2 = rospy.Subscriber( + '/grasp', String, self.grasp_cp, queue_size=1) + # 发布机械臂位姿 + self.pub1 = rospy.Publisher( + 'position_write_topic', position, queue_size=10) + # 发布机械臂吸盘 + self.pub2 = rospy.Publisher('pump_topic', status, queue_size=1) + # 发布机械臂状态 + self.grasp_status_pub = rospy.Publisher( + 'grasp_status', String, queue_size=1) + # 发布TWist消息控制机器人底盘 + self.cmd_vel_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1) + pos = position() + pos.x = 120 + pos.y = 0 + pos.z = 35 + self.pub1.publish(pos) + + def grasp_cp(self, msg): + if msg.data == '1': + # 订阅摄像头话题,对图像信息进行处理 + self.sub = rospy.Subscriber("/camera/rgb/image_raw", Image, self.image_cb, queue_size=1) + self.is_found_object = False + rate = rospy.Rate(10) + times=0 + steps=0 + while not self.is_found_object: + rate.sleep() + times+=1 + # 转一圈没有发现可抓取物体,退出抓取 + if steps>=5: + self.sub.unregister() + print("stop grasp\n") + status=String() + status.data='-1' + self.grasp_status_pub.publish(status) + return + # 旋转一定角度扫描是否有可供抓取的物体 + if times>=30: + times=0 + steps+=1 + self.turn_body() + print("not found\n") + print("unregisting sub\n") + self.sub.unregister() + print("unregisted sub\n") + # 抓取检测到的物体 + self.grasp() + status=String() + status.data='1' + self.grasp_status_pub.publish(status) + if msg.data=='0': + # 放下物体 + self.is_found_object = False + self.release_object() + status=String() + status.data='0' + self.grasp_status_pub.publish(status) + + # 执行抓取 + def grasp(self): + print("start to grasp\n") + global xc, yc, found_count + # stop function + + filename = os.environ['HOME'] + "/thefile.txt" + file_pix = open(filename, 'r') + s = file_pix.read() + file_pix.close() + print(s) + arr=s.split() + a1=arr[0] + a2=arr[1] + a3=arr[2] + a4=arr[3] + a = [0]*2 + b = [0]*2 + a[0]=float(a1) + a[1]=float(a2) + b[0]=float(a3) + b[1]=float(a4) + print('k and b value:',a[0],a[1],b[0],b[1]) + r1 = rospy.Rate(0.095) + r2 = rospy.Rate(10) + pos = position() + # 物体所在坐标+标定误差 + pos.x = a[0] * yc + a[1] + pos.y = b[0] * xc + b[1] + pos.z = 20 + # pos.z = 20 + print("z = 20\n") + self.pub1.publish(pos) + r2.sleep() + # go down -100 + pos.z = -50 + self.pub1.publish(pos) + print("z = -83\n") + r2.sleep() + + # 开始吸取物体 + self.pub2.publish(1) + r2.sleep() + + # 提起物体 + pos.x = 250 #160 + pos.y = 0 + pos.z = 150 #55 + self.pub1.publish(pos) + r1.sleep() + # 使用CV检测物体 + def image_cb(self, data): + global xc, yc, xc_prev, yc_prev, found_count + # change to opencv + try: + cv_image1 = CvBridge().imgmsg_to_cv2(data, "bgr8") + except CvBridgeError as e: + print('error') + + # change rgb to hsv + cv_image2 = cv2.cvtColor(cv_image1, cv2.COLOR_BGR2HSV) + + # 蓝色物体颜色检测范围 + LowerBlue = np.array([95, 70, 60]) + UpperBlue = np.array([140, 255, 255]) + mask = cv2.inRange(cv_image2, LowerBlue, UpperBlue) + cv_image3 = cv2.bitwise_and(cv_image2, cv_image2, mask=mask) + + # gray process + cv_image4 = cv_image3[:, :, 0] + + # smooth and clean noise + blurred = cv2.blur(cv_image4, (9, 9)) + (_, thresh) = cv2.threshold(blurred, 90, 255, cv2.THRESH_BINARY) + kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25)) + cv_image5 = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) + cv_image5 = cv2.erode(cv_image5, None, iterations=4) + cv_image5 = cv2.dilate(cv_image5, None, iterations=4) + + # detect contour + # cv2.imshow("win1", cv_image3) + # cv2.imshow("win2", cv_image5) + cv2.waitKey(1) + contours, hier = cv2.findContours(cv_image5, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + + # if find contours, pick the biggest box + if len(contours) > 0: + size = [] + size_max = 0 + for i, c in enumerate(contours): + rect = cv2.minAreaRect(c) + box = cv2.boxPoints(rect) + box = np.int0(box) + x_mid = (box[0][0] + box[2][0] + box[1][0] + box[3][0]) / 4 + y_mid = (box[0][1] + box[2][1] + box[1][1] + box[3][1]) / 4 + w = math.sqrt((box[0][0] - box[1][0]) ** 2 + (box[0][1] - box[1][1]) ** 2) + h = math.sqrt((box[0][0] - box[3][0]) ** 2 + (box[0][1] - box[3][1]) ** 2) + size.append(w * h) + if size[i] > size_max: + size_max = size[i] + index = i + xc = x_mid + yc = y_mid + # if box is not moving for 20 times + # print found_count + if found_count >= 30: + self.is_found_object = True + cmd_vel = Twist() + self.cmd_vel_pub.publish(cmd_vel) + else: + # if box is not moving + if abs(xc - xc_prev) <= 2 and abs(yc - yc_prev) <= 2: + found_count = found_count + 1 + else: + found_count = 0 + else: + found_count = 0 + xc_prev = xc + yc_prev = yc + # 释放物体 + def release_object(self): + r1 = rospy.Rate(0.15) # 5s + r2 = rospy.Rate(1) # 1s + pos = position() + # go forward + pos.x = 200 + pos.y = 0 + pos.z = -40 #-80 + self.pub1.publish(pos) + r1.sleep() + + # stop pump + self.pub2.publish(0) + r2.sleep() + #r1.sleep() + pos.x = 120 + pos.y = 0 + pos.z = 35 + self.pub1.publish(pos) + r1.sleep() + return 'succeeded' + # 转动机器人到一定角度 + def turn_body(self): + cmd_vel = Twist() + cmd_vel.angular.z = 0.25 + rate = rospy.Rate(10) + for i in range(40): + self.cmd_vel_pub.publish(cmd_vel) + rate.sleep() + + + +if __name__ == '__main__': + try: + rospy.init_node('GraspObject', anonymous=False) + rospy.loginfo("Init GraspObject main") + GraspObject() + rospy.spin() + except rospy.ROSInterruptException: + rospy.loginfo("End spark GraspObject main") + diff --git a/src/3rd_app/move2grasp/scripts/teleop.py b/src/3rd_app/move2grasp/scripts/teleop.py index d3ea438..222ce46 100755 --- a/src/3rd_app/move2grasp/scripts/teleop.py +++ b/src/3rd_app/move2grasp/scripts/teleop.py @@ -33,7 +33,7 @@ def keyboardLoop(): #速度变量 # 慢速 - walk_vel_ = rospy.get_param('walk_vel', 0.3) + walk_vel_ = rospy.get_param('walk_vel', 0.2) # 快速 run_vel_ = rospy.get_param('run_vel', 1.0) yaw_rate_ = rospy.get_param('yaw_rate', 1.0) @@ -72,12 +72,16 @@ def keyboardLoop(): msg.data='1' grasp_pub.publish(msg) can_grasp=False + speed = 0 + turn = 0 elif ch == 'h': if can_release: msg=String() msg.data='0' grasp_pub.publish(msg) can_release=False + speed = 0 + turn = 0 elif ch == 'w': max_tv = walk_vel_ speed = 1 @@ -124,7 +128,7 @@ def keyboardLoop(): pub.publish(cmd) rate.sleep() #停止机器人 - stop_robot() + #stop_robot() def stop_robot(): cmd.linear.x = 0.0 diff --git a/src/spark_app/spark_carry/nodes/hsv_detection.py b/src/spark_app/spark_carry/nodes/hsv_detection.py new file mode 100755 index 0000000..86b5f49 --- /dev/null +++ b/src/spark_app/spark_carry/nodes/hsv_detection.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import cv2 +import numpy as np +import math +import os +import sys +import time +from PIL import Image, ImageDraw,ImageFont +import rospy +from spark_carry_object.msg import * + +def mean_hsv(img,HSV_value): + HSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + HSV_value[0]+=np.mean(HSV[:, :, 0]) + HSV_value[1]+=np.mean(HSV[:, :, 1]) + HSV_value[2]+=np.mean(HSV[:, :, 2]) + return HSV_value + + +def hsv_range(HSV_value): + # 设置HSV颜色值的范围 + H_range = 12 + S_range = 120 + V_range = 120 + + lower_H = int(HSV_value[0] - H_range) + upper_H = int(HSV_value[0] + H_range) + + lower_S = int(HSV_value[1] - S_range) + upper_S = int(HSV_value[1] + S_range) + + lower_V = int(HSV_value[2] - V_range) + upper_V = int(HSV_value[2] + V_range) + + if lower_H<0: + lower_H=0 + if upper_H>180: + upper_H=180 + + if lower_S<50: + lower_S=50 + if upper_S>255: + upper_S=255 + + if lower_V<50: + lower_V=50 + if upper_V>255: + upper_V=255 + + lower_HSV = np.array([lower_H, lower_S, lower_V]) + upper_HSV = np.array([upper_H, upper_S, upper_V]) + return lower_HSV, upper_HSV + + +def test(lower_HSV, upper_HSV, image): + hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) + mask = cv2.inRange(hsv, lower_HSV, upper_HSV) + mask = cv2.erode(mask, None, iterations=2) + mask = cv2.dilate(mask, None, iterations=2) + mask = cv2.GaussianBlur(mask, (3, 3), 0) + cv2.putText(mask, 'Done! Press q to exit!', (30, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.2, + (255, 255, 255), 2, cv2.LINE_AA) + cv2.imshow("HSV_img", mask) + +def arm_init(): + pub1 = rospy.Publisher('position_write_topic', position, queue_size=1) + + r1 = rospy.Rate(1) + r1.sleep() + pos = position() + pos.x = 120 + pos.y = 0 + pos.z = 35 + pub1.publish(pos) + r1.sleep() + +def save_hsv(name, lower_HSV, upper_HSV): + + content = str(lower_HSV[0]) + ',' +str(lower_HSV[1])+ ',' + str(lower_HSV[2]) \ + + ' ' + str(upper_HSV[0])+ ',' + str(upper_HSV[1])+ ',' + str(upper_HSV[2]) + '\n' + # 将HSV值写入文件,文件在spark目录下 + if name == 'color_block': + content = "block_HSV is :" + content + filename = os.environ['HOME'] + "/color_block_HSV.txt" + elif name == 'calibration': + content = "calibration_HSV is :" + content + filename = os.environ['HOME'] + "/calibration_HSV.txt" + + with open(filename, "w") as f: + f.write(content) + + print("HSV value has saved in" + filename) + print(content) + +def main(): + name = rospy.get_param("/spark_hsv_detection/color") + arm_init() + time.sleep(3) + HSV_value = [0,0,0] + count = 0 + capture = cv2.VideoCapture(0) + # 颜色块中心点上下左右扩大60个像素 + box_w = 60 + # 吸盘上方颜色像素范围 + cali_w = 20 + cali_h = 30 + # 收集300次取平均值 + collect_times = 300 + while True: + ret, img = capture.read() + if img is not None: + # 200次以内先做提醒,将颜色块放在矩形框中 + if count < 200: + cv2.putText(img, 'please put the color being', (30, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.2, + (0, 255, 0), 2, cv2.LINE_AA) + cv2.putText(img, 'tested in rectangle box!', (30, 80), cv2.FONT_HERSHEY_SIMPLEX, 1.2, + (0, 255, 0), 2, cv2.LINE_AA) + # 如果在200-500次以内开始收集hsv值,并求出平均值 + elif count > 200 and count < 200+collect_times: + cv2.putText(img, 'HSV_value is collecting!', (30, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.2, + (0, 255, 0), 2, cv2.LINE_AA) + if name == 'color_block': + frame = img[120:120 + box_w, 300:300 + box_w] + elif name == 'calibration': + frame = img[310:310 + cali_h, 355:355 + cali_w] + HSV_value = mean_hsv(frame, HSV_value) + # 500次以后开始检测,查看是否有提取到矩形框中颜色的HSV值 + elif count==200+collect_times: + for i in range(len(HSV_value)): + HSV_value[i] = HSV_value[i] / collect_times + lower_HSV, upper_HSV = hsv_range(HSV_value) + save_hsv(name, lower_HSV, upper_HSV) + + elif count > 200+collect_times: + test(lower_HSV, upper_HSV, img) + + count += 1 + if name == 'color_block': + cv2.rectangle(img, (300, 120), (300+box_w, 120+box_w), (0, 255, 0), 3) + elif name == 'calibration': + cv2.rectangle(img, (355, 310), (355 + cali_w, 310 + cali_h), (0, 255, 0), 3) + cv2.imshow("RGB_img", img) + cv2.waitKey(1) + if cv2.waitKey(10) == ord('q'): + break + cv2.destroyAllWindows() + return lower_HSV, upper_HSV + +if __name__ == '__main__': + rospy.init_node('hsv_detection', anonymous=True) + main() + rospy.spin()