ãããããäœæãããšãã«ROSã䜿çšããå Žåãããããã¹ãã¬ãªã«ã¡ã©ã§ã®äœæ¥ããµããŒãããŠããããšããåç¥ã§ãããã ããšãã°ã空éã®å¯èŠéšåãŸãã¯ç¹çŸ€ã®æ·±åºŠããããäœæã§ããŸãã ãããŠãROSã§ã©ãºããªãŒããŒã¹ã®StereoPiã¹ãã¬ãªã«ã¡ã©ã䜿çšããã®ã¯ã©ãã»ã©ç°¡åããšæããŸããã 以åã深床ãããã¯OpenCVã«ãã£ãŠå®å šã«æ§ç¯ããããšãã§ã«ç¢ºä¿¡ããŠããŸããããROSãæ±ã£ãããšã¯ãããŸããã ãããŠãç§ã¯ãããè©ŠããŠã¿ãããšã«ããŸããã 解決çãèŠã€ããããã®ç§ã®åéºã«ã€ããŠè©±ãããã§ãã
1. Raspberry Piã®ROSã¯ãŸã£ããçºçããŸããïŒ
æåã«ãRaspberry Piçšã«ROSãæ§ç¯ã§ãããã©ããã調ã¹ãããšã«ããŸããã Googleãæåã«ç§ã«èšã£ãã®ã¯ãç°ãªãããŒãžã§ã³ã®ROSãRaspberry Piã«ã€ã³ã¹ããŒã«ããããã®æé ã®ãªã¹ããã€ãŸããã®ROS wikiããŒãžã§ã
ããŠããã§ã«äœããå§ãŸããŸãïŒ Raspberryã§OpenCVãæ§ç¯ããã®ã«ããã£ãæéïŒçŽ8æéïŒãããèŠããŠããã®ã§ãæéãç¯çŽããããã«MicroSDã«ãŒãã®æ¢è£œã®ã€ã¡ãŒãžãæ¢ãããšã«ããŸããã
2. ROS for Raspberryã®æ¢è£œã®microSDã«ãŒãã€ã¡ãŒãžã¯ãããŸããïŒ
ãã®åé¡ã¯ãã§ã«ããã€ãã®éçºããŒã ã«ãã£ãŠè§£æ±ºãããŠããããšãå€æããŸããã æ奜家ã«ãã1åéãã®ã¢ã»ã³ããªãè¡ããªãå ŽåãOSãšROSã®æ°ããããŒãžã§ã³ã®ãªãªãŒã¹ã§çµ¶ããæŽæ°ãããããã€ãã®ã€ã¡ãŒãžãç®ç«ã¡ãŸããã
æåã®ãªãã·ã§ã³ã¯ãROSbotsããŒã ã®ãã€ãã£ãRaspbian OSã«ã€ã³ã¹ããŒã«ãããROSã§ããæŽæ°ãããç»åãªã³ã¯ã®ããããŒãžã¯æ¬¡ã®ãšããã§ãïŒ ready-to-use-image-raspbian-stretch-ros-opencv
2çªç®ã¯ã ubuntuã®Ubiquiti Roboticsããã®ç»åã§ãã
ãŸãã2çªç®ã®è³ªåãããã«çµãããŸããã ãã£ãšæ·±ãæœãæéã§ãã
3. ROSã¯Raspberry Piã«ã¡ã©ãšã©ã®ããã«é£æºããŸããïŒ
ãŸããROSã§ã¯äžè¬ã«ã©ã®ã¹ãã¬ãªã«ã¡ã©ããµããŒããããŠããŸããïŒ ç§ã¯ãROSçšã®æ¢è£œã®ãã©ã€ããŒã®å©çšå¯èœæ§ã宣èšãããŠããã¹ãã¬ãªã«ã¡ã©ã®ããããŒãžãèŠãŸããã
wiki.ros.org/Sensors
2ã€ã®ã»ã¯ã·ã§ã³ããããŸããã
2.3 3Dã»ã³ãµãŒïŒè·é¢èšãšRGB-Dã«ã¡ã©ïŒ
2.5ã«ã¡ã©
æåã®ã»ã¯ã·ã§ã³ã§ã¯ãã¹ãã¬ãªã«ã¡ã©ã ãã§ãªããTOFã»ã³ãµãŒãã¹ãã£ã³LIDARããªã¹ããããŠããããšãããããŸãããäžè¬ã«ã3Dã§ããã«æ å ±ãæäŸã§ãããã¹ãŠã®ãã®ã§ãã ãããŠã2çªç®ã«ã¯æ¢ã«ã¹ãã¬ãªã«ã¡ã©ããããŸãã ããã€ãã®ã¹ãã¬ãªã«ã¡ã©ã®ãã©ã€ããŒã衚瀺ããããšããŠããã³ãŒãã«çå£ã«æ²¡é ããããšã瀺åããŠããã®ã§ãç§ã®åã³ã¯å¢ããŸããã§ããã
ããŠãäžæ©æ»ããŸãã ROSã®åäžã®Raspberry Piã«ã¡ã©ã§ã©ã®ããã«æ©èœããŸããïŒ
ããã§ã¯ã3ã€ã®æ¥œããé©ããåŸ ã£ãŠããŸããã
- ROSã«ã¯ãRaspberry Piã«ã¡ã©ãæäœããããã®ç¹å¥ãªraspicam_nodeããŒããããããšãããããŸãã
- ããŒãã®çš®é¡ã¯githubã«ãããã³ãŒãã¯ç©æ¥µçã«ç¶æãããææžåãããŠããŸãïŒ github.com/UbiquityRobotics/raspicam_node
- Rohan AgrawalããŒãïŒ @Rohbotics ïŒã®èè ã¯ãRaspberry Piã®æ¢è£œã®ã€ã¡ãŒãžã®1ã€ãç©æ¥µçã«ãµããŒãããäŒç€Ÿã§åããŠããŸã
githubãªããžããªraspicam_nodeãèŠãŠãåé¡ã調ã¹ãŸããã ããã§ãã»ãŒ7ãæåã«ãçããã³ã¡ã³ããªãã§ããã¹ãã¬ãªã¢ãŒãããšããç¡åã®ååã®æªè§£æ±ºã®åé¡ãèŠã€ãããŸããã å®éããã¹ãŠã®ã€ãã³ãã¯ããã«çºå±ããŸããã
4.ããŒãã³ã¢ãã©ããïŒ
èè ã«åäŸã®è³ªåãããªãããã«ãç§ã¯ãœãŒã¹ã³ãŒããèŠãŠãã¹ãã¬ãªã¢ãŒãã®è¿œå ãè ãããã®ãè©äŸ¡ããããšã«ããŸããã ç§ã¯ããã®ã·ã¹ãã éšåã«ãã£ãšèå³ããããŸããïŒ github.com/UbiquityRobotics/raspicam_node/tree/kinetic/src
ãŸããã¿ããªã¯ãã©ã€ããŒãMMALã¬ãã«ã«çªå ¥ãããŸããã ãŸããã¹ãã¬ãªã¢ãŒãã§ã®ã©ãºããªãŒã®ãœãŒã¹ã³ãŒããå ¬éãããŠããããšãæãåºããŸããïŒé²åã¯ããã§ã©ãºããªãŒãã©ãŒã©ã ã§è¿œè·¡ã§ããŸã ïŒããŸããæ¬æ Œçãªã¹ãã¬ãªãã©ã€ããŒãäœæããã¿ã¹ã¯ã¯è§£æ±ºå¯èœã§ããã倧èŠæš¡ã§ãã ä»ã®ã«ã¡ã©ã®ãã©ã€ããŒã®èª¬æãèŠãŠãå·Šå³ã®åçãå ¬éããã ãã§ãªããäž¡æ¹ã®ã«ã¡ã©ã®ãã©ã¡ãŒã¿ãŒãæäŸããããããã«ãã£ãªãã¬ãŒã·ã§ã³çµæãé©çšããä»ã®å€ãã®ããšãè¡ãå¿ èŠãããããšã«æ°ä»ããŸããã ããã¯1ãæã2ãæã®å®éšãåŒãä»ããŸããã ãããã£ãŠããã®ã¢ãããŒãã䞊ååããããšã«ããŸãããã€ãŸããã¹ãã¬ãªãµããŒãã«é¢ãã質åãèè ã«æžããèªåã§ããã·ã³ãã«ã§å®çšçãªãœãªã¥ãŒã·ã§ã³ãæ¢ãããšã§ãã
5.èè ãšã®å¯Ÿè©±
githubã®ã¹ãã¬ãªã¢ãŒãã«é¢ããã¹ã¬ããã§ãèè ã«è³ªåãããã¹ãã¬ãªã¯2014幎以éã©ãºããªãŒã«ãã£ãŠãµããŒããããŠããããšãè¿°ã¹ãå¿ èŠã«å¿ããŠãå®éšçšã®ãããã°ããŒããéä¿¡ããããšãææ¡ããŸããã ãã®ãã£ã¹ããªãã¥ãŒã·ã§ã³ã§ã¯ã¹ãã¬ãªããã€ãã£ãã®Raspbianã®ããã«æ©èœããããšããŸã çã£ãŠããŸãã
Rohanã¯é©ãã»ã©è¿ éã«å¿çãã圌ãã®distribã¯ã©ãºããªãŒã«ãŒãã«ã䜿çšããŠããããã¹ãŠãæ©èœããã¯ãã ãšè¿°ã¹ãŸããã ãããŠã圌ãã®ã¢ã»ã³ããªã®1ã€ã§ããããã§ãã¯ããããã«é ŒãŸããŸããã
ã©ãºããªãŒã³ã¢ïŒ ãã£ãïŒ çè«çã«ã¯ãã¿ã³ããªã³ãšãã³ã¹ããã«ã¹ãã¬ãªç»åããã£ããã£ããå¿ èŠããããŸãïŒ
Rohanã®ãªã³ã¯ã䜿çšããŠææ°ã®ç»åãããŠã³ããŒãããŠå±éããã·ã³ãã«ãªpythonã¹ã¯ãªãããå®è¡ããŠã¹ãã¬ãªãã¢ããã£ããã£ããŸããã ããŸããããŸããïŒ
ãã®åŸãRohanã¯ã¹ãã¬ãªã¢ãŒãã®ãã©ã€ããŒã³ãŒãã調ã¹ãããšãæžããããã€ãã®è³ªåãæžããŸããã ããšãã°ãã¹ãã¬ãªã¢ãŒãã§ã¯æ¥çãããç»åã1ã€çæããããããå·Šå³ã«2ã€ã«åå²ããå¿ èŠããããŸãã ãŸããåã«ã¡ã©ã®ãã£ãªãã¬ãŒã·ã§ã³ãã©ã¡ãŒã¿ãŒã«é¢ãã2çªç®ã®è³ªåã¯ããã®å¯ŸåŠæ¹æ³ã§ãã
æåã®ã¹ããããšããŠãã«ã¡ã©ããç¬ç«ããŠåçãæ®ãããšãã§ãããšèšããŸããã ã¯ãããããã¯ãã£ããã£æéãšèšå®ïŒæãããã³ã³ãã©ã¹ãããã¯ã€ããã©ã³ã¹ãªã©ïŒã§åæãããŸããããæåã®ã¹ããããšããŠãããã¯ããŸããããããããŸããã
Rohanã¯ããã«ãROSããåçãæ®ãã«ã¡ã©ãçŽæ¥æå®ã§ããããããå ¬éããŸãã ã ç§ã¯ããããã§ãã¯ããŸãã-ã«ã¡ã©ã®éžæã¯ããŸããããŸããããã¯ãã§ã«çŽ æŽãããçµæã§ãã
6.äºæããªããã«ã
ãããŠãWezzoidãŠãŒã¶ãŒããã®ã³ã¡ã³ããã¹ã¬ããã«è¡šç€ºãããŸãã 圌ã¯ãã©ãºããªãŒéçºããŒãã䜿çšããŠPi Compute 3ã§ã¹ãã¬ãªã«ã¡ã©ãããŒã¹ã«ãããããžã§ã¯ããè¡ã£ãŠãããšèšããŸããã 圌ã®4足æ©è¡ããããã¯ã空éå ã®ãªããžã§ã¯ãã®äœçœ®ã远跡ããã«ã¡ã©ã®äœçœ®ãå€æŽããã«ã¡ã©ãŸã§ã®è·é¢ãç¶æããŸããïŒãããžã§ã¯ãã¯hackaday.ioã«æçš¿ãããŠããŸã ïŒã
ãããŠã圌ã¯ç»åãååŸããã³ãŒããå ±æããPythonã®æ段ã§ååã«åãåããå·Šå³ã®ã«ã¡ã©ã®ããŒãã®ããã«å ±æããŸããã
Pythonã¯ããããã®åé¡ã«é¢ããŠã¯ããŸãéããªãããã320x240ã®äœè§£å床ãšåªããã©ã€ãããã¯ã䜿çšããŸããã ãµã€ããã€ãµã€ãã®ã¹ãã¬ãªç»åïŒã¹ãã¬ãªç»åã®å·ŠåŽã«1ã€ã®ã«ã¡ã©ãå³åŽã«2çªç®ã®ã«ã¡ã©ïŒããã£ããã£ããå ŽåãPythonã¯240è¡ã®ãããããååã«ã«ããããå¿ èŠããããŸãã ãã ããäžäžã®ç»åãäœæããå ŽåïŒå·Šã®ã«ã¡ã©ã¯ãã¬ãŒã ã®äžååãå³ã¯äžïŒãPythonã¯1åã®æäœã§é åãååã«ã«ããããŸãã ããã¯ããŠãŒã¶ãŒWezzoidã«ãã£ãŠæ£åžžã«è¡ãããŸããã
ããã«ã圌ã¯èªåã®pythonã³ãŒããPastebinã«æçš¿ãããã®æäœãè¡ããŸããã ããã«ãããŸãïŒ
ã¹ãã¬ãªãã¢ãã2å°ã®ã«ã¡ã©ã®ããŒããå
¬éããããã®ãŠã§ãŸã€ãã³ãŒã
#!/usr/bin/env python # picamera stereo ROS node using dual CSI Pi CS3 board # Wes Freeman 2018 # modified from code by Adrian Rosebrock, pyimagesearch.com # and jensenb, https://gist.github.com/jensenb/7303362 from picamera.array import PiRGBArray from picamera import PiCamera import time import rospy from sensor_msgs.msg import CameraInfo, Image import yaml import io import signal # for ctrl-C handling import sys def parse_calibration_yaml(calib_file): with file(calib_file, 'r') as f: params = yaml.load(f) cam_info = CameraInfo() cam_info.height = params['image_height'] cam_info.width = params['image_width'] cam_info.distortion_model = params['distortion_model'] cam_info.K = params['camera_matrix']['data'] cam_info.D = params['distortion_coefficients']['data'] cam_info.R = params['rectification_matrix']['data'] cam_info.P = params['projection_matrix']['data'] return cam_info # cam resolution res_x = 320 #320 # per camera res_y = 240 #240 target_FPS = 15 # initialize the camera print "Init camera..." camera = PiCamera(stereo_mode = 'top-bottom',stereo_decimate=False) camera.resolution = (res_x, res_y*2) # top-bottom stereo camera.framerate = target_FPS # using several camera options can cause instability, hangs after a while camera.exposure_mode = 'antishake' #camera.video_stabilization = True # fussy about res? stream = io.BytesIO() # ---------------------------------------------------------- #setup the publishers print "init publishers" # queue_size should be roughly equal to FPS or that causes lag? left_img_pub = rospy.Publisher('left/image_raw', Image, queue_size=1) right_img_pub = rospy.Publisher('right/image_raw', Image, queue_size=1) left_cam_pub = rospy.Publisher('left/camera_info', CameraInfo, queue_size=1) right_cam_pub = rospy.Publisher('right/camera_info', CameraInfo, queue_size=1) rospy.init_node('stereo_pub') # init messages left_img_msg = Image() left_img_msg.height = res_y left_img_msg.width = res_x left_img_msg.step = res_x*3 # bytes per row: pixels * channels * bytes per channel (1 normally) left_img_msg.encoding = 'rgb8' left_img_msg.header.frame_id = 'stereo_camera' # TF frame right_img_msg = Image() right_img_msg.height = res_y right_img_msg.width = res_x right_img_msg.step = res_x*3 right_img_msg.encoding = 'rgb8' right_img_msg.header.frame_id = 'stereo_camera' imageBytes = res_x*res_y*3 # parse the left and right camera calibration yaml files left_cam_info = parse_calibration_yaml('/home/pi/catkin_ws/src/mmstereocam/camera_info/left.yaml') right_cam_info = parse_calibration_yaml('/home/pi/catkin_ws/src/mmstereocam/camera_info/right.yaml') # --------------------------------------------------------------- # this is supposed to shut down gracefully on CTRL-C but doesn't quite work: def signal_handler(signal, frame): print 'CTRL-C caught' print 'closing camera' camera.close() time.sleep(1) print 'camera closed' sys.exit(0) signal.signal(signal.SIGINT, signal_handler) #----------------------------------------------------------- print "Setup done, entering main loop" framecount=0 frametimer=time.time() toggle = True # capture frames from the camera for frame in camera.capture_continuous(stream, format="rgb", use_video_port=True): framecount +=1 stamp = rospy.Time.now() left_img_msg.header.stamp = stamp right_img_msg.header.stamp = stamp left_cam_info.header.stamp = stamp right_cam_info.header.stamp = stamp left_cam_pub.publish(left_cam_info) right_cam_pub.publish(right_cam_info) frameBytes = stream.getvalue() left_img_msg.data = frameBytes[:imageBytes] right_img_msg.data = frameBytes[imageBytes:] #publish the image pair left_img_pub.publish(left_img_msg) right_img_pub.publish(right_img_msg) # console info if time.time() > frametimer +1.0: if toggle: indicator = ' o' # just so it's obviously alive if values aren't changing else: indicator = ' -' toggle = not toggle print 'approx publish rate:', framecount, 'target FPS:', target_FPS, indicator frametimer=time.time() framecount=0 # clear the stream ready for next frame stream.truncate(0) stream.seek(0)
7.å·Šå³ã®ã«ã¡ã©ã®ããŒãã®å ¬éãéå§ããŸã
æåã®éå§æã«ãã³ãŒãã¯ã«ã¡ã©ã®ãã©ã¡ãŒã¿ãŒãæã€YMLãã¡ã€ã«ãžã®ã¢ã¯ã»ã¹ããªãããšãåªããŸããã ã©ãºããªãŒè²ã®V2ã«ã¡ã©ã䜿çšããããŸããŸãªã«ã¡ã©ã¢ãã«ã®ãã£ãªãã¬ãŒã·ã§ã³çµæãå«ãæ¢è£œã®ãã¡ã€ã«ãgithubã®raspicam_nodeã«å±ããããšãæãåºããŸããïŒ github.com/UbiquityRobotics/raspicam_node/tree/kinetic/camera_info
ãã®ãã¡ã®1ã€ãåãã2ã€ã®ã³ããŒãäœæããŠãleft.ymlããã³right.ymlãšããååã§ä¿åããäœæè ã®ã¹ã¯ãªããããã«ã¡ã©ã®è§£å床ãæžã蟌ã¿ãŸããã å·Šã®ã«ã¡ã©ã§äœãèµ·ãã£ãã®ãã次ã«ç€ºããŸãã
left.yml
image_width: 320 image_height: 240 camera_name: left camera_matrix: rows: 3 cols: 3 data: [1276.704618338571, 0, 634.8876509199106, 0, 1274.342831275509, 379.8318028940378, 0, 0, 1] distortion_model: plumb_bob distortion_coefficients: rows: 1 cols: 5 data: [0.1465167016954302, -0.2847343180128725, 0.00134017721235817, -0.004309553450829512, 0] rectification_matrix: rows: 3 cols: 3 data: [1, 0, 0, 0, 1, 0, 0, 0, 1] projection_matrix: rows: 3 cols: 4 data: [1300.127197265625, 0, 630.215390285608, 0, 0, 1300.670166015625, 380.1702884455881, 0, 0, 0, 1, 0]
å³åŽã®å Žåãã«ã¡ã©åã¯rightã«çœ®ãæãããããã¡ã€ã«èªäœã®ååã¯right.ymlã«ãªããŸãã ãã¡ã€ã«ã®æ®ãã¯åãã§ãã
è€éãªãããžã§ã¯ããäœæããäºå®ã¯ãªãã£ãã®ã§ããµããã©ã«ããŒã§äœæè ã®é·ããã¹ãç¹°ãè¿ããããã¡ã€ã«ãPythonã¹ã¯ãªããã®é£ã®ããŒã ãã©ã«ããŒã®ã«ãŒãã«é 眮ããŸããã ã³ãŒããæ£åžžã«éå§ãããã³ã³ãœãŒã«ã«ã¹ããŒã¿ã¹ã¡ãã»ãŒãžã衚瀺ãããŸããã
å·Šå³ã®ã«ã¡ã©ã§æçµçã«å ¬éããããã®ãèŠãã ãã§ããã ãããè¡ãããã«ãrqt_image_viewãèµ·åããŸããã ããããããŠã³ã¡ãã¥ãŒã«ã¢ã€ãã / left / image_rawããã³/ right / image_rawã衚瀺ãããããããéžæãããšãå·Šå³ã®ã«ã¡ã©ã®ç»åã衚瀺ãããŸããã
ãŸãããã®ããšã¯ç²åŸããŠããŸãïŒ ä»ãã楜ããéšåã§ãã
8.深床ã®ãããã確èªããŸãã
ããã¹ãããã衚瀺ããããã«ãç§ã¯ç¬èªã®ã¢ãããŒããèãåºãããšãªãã ã¹ãã¬ãªãã©ã¡ãŒã¿ãŒãèšå®ããããã®å€å žçãªROSããã¥ã¢ã«ã調ã¹ãŸãã ã
ãããããWezzoidã®ããã«ã«ãŒãã§ã¯ãªããç¹å®ã®åå空éã§äž¡æ¹ã®ããŒããå ¬éããã®ãè¯ãããšãããããŸããã ãã®çµæããã©ãŒã ã®å€ãåºçã©ã€ã³
left_img_pub = rospy.Publisher('left/image_raw', Image, queue_size=1)
ãã®ããã«èŠãå§ããŸããïŒ
left_img_pub = rospy.Publisher('stereo/right/image_raw', Image, queue_size=1)
ãã®åŸãstereo_image_procã¹ãã¬ãªã¢ãŒãåŠçããŒããå®è¡ããŸãã
ROS_NAMESPACE=stereo rosrun stereo_image_proc stereo_ige_proc
ããŠãçµæã確èªãããã®ã§ããŠã©ããã£ãŒãéå§ããŸãã
rosrun image_view stereo_view stereo:=/stereo image:=image_rect_color
ãŸãã深床ãããã®ãã©ã¡ãŒã¿ãŒãæ§æããã«ã¯ãæ§æãŠãŒãã£ãªãã£ãå®è¡ããŸãã
rosrun rqt_reconfigure rqt_reconfigure
ãã®çµæãèšäºã®åé ã«åçã衚瀺ãããŸãã å°ã倧ãããªããŸããïŒ
ãã¹ãŠã®ãã¡ã€ã«ãgithubã«æçš¿ããŸããïŒ github.com/realizator/StereoPi-ROS-depth-map-test
9.å³æèšç»
githubã§ã®ãã£ã¹ã«ãã·ã§ã³ã§çµæãå ¬éããåŸãRohanã¯ãCoolïŒ StereoPiãåãã«è¡ãå¿ èŠããããŸããã ç§ãã¡ã¯åœŒã«éµäŸ¿ã§æçŽãæžããç§ã¯åœŒã«ææ°æãéã£ãã åäœäžã®ããŒããŠã§ã¢ãæå ã«ããããšã§ãROSãšRaspberryåãã®æ¬æ Œçãªã¹ãã¬ãªãã©ã€ããŒãç°¡åã«ä»äžããŠãããã°ã§ããããã«ãªãããšãé¡ã£ãŠããŸãã
10.ãŸãšã
ROSã®ã©ãºããªãŒã®ã¹ãã¬ãªç»åããã®æ·±åºŠãããã¯ãããã€ãã®æ¹æ³ã§ååŸã§ããŸãã è¿ éãªæ€èšŒã®ããã«éžæããããã¹ã¯ãããã©ãŒãã³ã¹ã®ç¹ã§ã¯æé©ã§ã¯ãããŸããããã¢ããªã±ãŒã·ã§ã³ã«äœ¿çšã§ããŸãã ãã®ã·ã³ãã«ãã®çŸãããšãããã«å®éšãéå§ã§ããèœåã
é¢çœãããšã«ãçµæãåãåã£ãåŸã解決çãææ¡ããWezzoidã2ã€ã®ã¹ãã¬ãªåçã®å ¬éã«é¢ãã質åã®èè ã§ããããšã«æ°ä»ããŸããã 圌ã¯èªåããã圌ã¯æ±ºããã