๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

22. [ROS RC์นด] ์นด๋ฉ”๋ผ ROS ์—ฐ๋™

๐ŸŽฅ

22. [ROS RC์นด] ์นด๋ฉ”๋ผ ROS ์—ฐ๋™

ํŒŒ์ด์ฌ์„ ์‚ฌ์šฉํ•ด์„œ ์ ฏ์Šจ ์นด๋ฉ”๋ผ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด์ „ ์‹œ๊ฐ„์˜ ๋ณต์Šต์„ ํ•ด๋ณผ๊นŒ์š”??

์นด๋ฉ”๋ผ ์—ฐ๊ฒฐ ํ™•์ธ


$ cd ~/Downloads
$ git clone https://github.com/JetsonHacksNano/CSI-Camera.git

$ gst-launch-1.0 nvarguscamerasrc sensor_id=0 ! \
   'video/x-raw(memory:NVMM),width=3280, height=2464, framerate=21/1, format=NV12' ! \
   nvvidconv flip-method=2 ! 'video/x-raw,width=960, height=720' ! \
   nvvidconv ! nvegltransform ! nveglglessink -e

# ์ข…๋ฃŒ๋Š” ctrl + c๋กœ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค!!

sensor_id์™€ flip์„ ๋ฐ˜๋“œ์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š”!! - ์ด๋Š” ์นด๋ฉ”๋ผ ์—ฐ๊ฒฐ ์‹œ ์‚ฌ์šฉํ•œ ์Šฌ๋กฏ๊ณผ ์—ฐ๊ด€์žˆ์Šต๋‹ˆ๋‹ค!!

์ด๋ฒˆ ์‹œ๊ฐ„์— ๋‹ค๋ฃจ๋Š” ์˜ˆ์ œ๋“ค์€ ๋ชจ๋‘ donkey_ros/csi_camera ํด๋”์— ์œ„์น˜ํ•ด ์žˆ์Šต๋‹ˆ๋‹ค.

OpenCV4 ์„ค์น˜, Setup


์ถ”ํ›„ ๋งŽ์€ ํ”„๋กœ์ ํŠธ์— ๋Œ€๋น„ํ•˜์—ฌ Jetson์— OpenCV4๋ฅผ ์„ค์น˜ํ•˜๊ณ , ๊ทธ ์ดํ›„ ROS cv_bridge๊ฐ€ ์ƒˆ๋กœ ์„ค์น˜ํ•œ OpenCV๋ฅผ ๋ฐ”๋ผ๋ณด๋„๋ก ์ˆ˜์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ๋Œ€๋žต 2์‹œ๊ฐ„ 30๋ถ„ ์ •๋„๊ฐ€ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค. ๐Ÿ˜•๐Ÿ˜•
$ cd ~/Downloads
$ git clone https://github.com/JetsonHacksNano/buildOpenCV
$ cd buildOpenCV
$ ./buildOpenCV.sh |& tee openCV_build.log
OPENCV 4 + CUDA on Jetson Nano
How to build and package OpenCV with CUDA support on the NVIDIA Jetson Nano Developer Kit. Please Like, Share and Subscribe! Full article on JetsonHacks: htt...
https://www.youtube.com/watch?v=tFGZjVUR_Ck

$ sudo gedit /opt/ros/melodic/share/cv_bridge/cmake/cv_bridgeConfig.cmake

# ์ˆ˜์ • ์ „
set(_include_dirs "include;/usr/include;/usr/include/opencv")
# ์ˆ˜์ • ํ›„
set(_include_dirs "include;/usr/include;/usr/include/opencv4")
Project 'cv_bridge' can not find opencv ยท Issue #345 ยท ros-perception/vision_opencv
You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or window. Reload to refresh your session. Reload to refresh your session.
https://github.com/ros-perception/vision_opencv/issues/345

Webcam Publish - Desktop


#!/usr/bin/env python

import rospy
import cv2

from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError

cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
cap.set(cv2.CAP_PROP_FPS, 30)

rospy.init_node("webcam_pub", anonymous=True)
image_pub = rospy.Publisher("webcam_image", Image, queue_size=1)

bridge = CvBridge()

while not rospy.is_shutdown():
    # Capture frame-by-frame
    ret, cv_image = cap.read()

    # Display the resulting frame
    # cv2.imshow('frame',cv_image)
    # cv2.waitKey(3)
    image_pub.publish(bridge.cv2_to_imgmsg(cv_image, "bgr8"))


# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

  • ๋จผ์ € ์‹คํ–‰๋ถ€ํ„ฐ ์‹œ์ผœ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ˜‡
$ roscore 
$ rosrun csi_camera webcam_pub.py
$ rosrun image_view image_view image:=/webcam_image

# jetson
$ roscore 
$ rosrun csi_camera csi_pub.py
$ rosrun image_view image_view image:=/csi_image

image_view


์ด๋ฏธ์ง€ topic์„ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํˆด์ž…๋‹ˆ๋‹ค. ๋”๋ถˆ์–ด, ๋งˆ์šฐ์Šค ์˜ค๋ฅธ์ชฝ ํด๋ฆญ์„ ํ•˜๋ฉด, ํ˜„ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•  ์ˆ˜๋„ ์žˆ๋‹ต๋‹ˆ๋‹ค. ๐Ÿ•ต๏ธโ€โ™‚๏ธ

image:=/ ๋’ค์— ์‚ดํŽด๋ณด๊ณ  ์‹ถ์€ ์ด๋ฏธ์ง€ ํ† ํ”ฝ ์ด๋ฆ„์„ ์จ์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ์„ค๋ช…์œผ๋กœ ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

  • import
import rospy
import cv2

from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError

์•ž์„œ cv_bridge๊ฐ€ opencv4๋ฅผ ๋ฐ”๋ผ๋ณด๋„๋ก ๋ฐ”๊พธ์—ˆ์ง€์š”??

  • video stream ์„ค์ •
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
cap.set(cv2.CAP_PROP_FPS, 30)

rospy.init_node("webcam_pub", anonymous=True)
image_pub = rospy.Publisher("webcam_image", Image, queue_size=1)

bridge = CvBridge()

๊ฐ€๋กœ, ์„ธ๋กœ, Frame Per Second ๋“ฑ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ง€์ •ํ•˜๊ณ  Publisher๋ฅผ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • Publish
while not rospy.is_shutdown():
    # Capture frame-by-frame
    ret, cv_image = cap.read()

    # Display the resulting frame
    # cv2.imshow('frame',cv_image)
    # cv2.waitKey(3)
    image_pub.publish(bridge.cv2_to_imgmsg(cv_image, "bgr8"))

opencv์™€ ros์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ด๋ฏธ์ง€ ํฌ๋งท์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์—, cv2_to_imgmsg๋ฅผ ํ†ตํ•ด ๋ณ€ํ™˜ํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ข…๋ฃŒ ์ฒ˜๋ฆฌ

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

์›น์บก์ด ์•„๋‹Œ, CSI ์นด๋ฉ”๋ผ๋ฅผ ์‚ฌ์šฉํ•ด ๋ด…์‹œ๋‹ค.

csi_pub


$ roscore 
$ rosrun csi_camera csi_pub.py
$ rosrun image_view image_view image:=/csi_image

  • csi_pub.py
#!/usr/bin/env python

import rospy
import cv2

from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError


def gstreamer_pipeline(
    capture_width=640,
    capture_height=480,
    display_width=640,
    display_height=480,
    framerate=60,
    flip_method=0,
):
    return (
        "nvarguscamerasrc ! "
        "video/x-raw(memory:NVMM), "
        "width=(int)%d, height=(int)%d, "
        "format=(string)NV12, framerate=(fraction)%d/1 ! "
        "nvvidconv flip-method=%d ! "
        "video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "
        "videoconvert ! "
        "video/x-raw, format=(string)BGR ! appsink"
        % (
            capture_width,
            capture_height,
            framerate,
            flip_method,
            display_width,
            display_height,
        )
    )


cap = cv2.VideoCapture(gstreamer_pipeline(flip_method=2), cv2.CAP_GSTREAMER)

rospy.init_node("csi_pub", anonymous=True)
image_pub = rospy.Publisher("csi_image", Image, queue_size=1)

bridge = CvBridge()

while not rospy.is_shutdown():
    # Capture frame-by-frame
    ret, cv_image = cap.read()

    # Display the resulting frame
    # cv2.imshow('frame',cv_image)
    # cv2.waitKey(3)
    image_pub.publish(bridge.cv2_to_imgmsg(cv_image, "bgr8"))


# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

ํ•จ์ˆ˜ ํ•˜๋‚˜๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋Š”๋ฐ์š”, ์ด๊ฒƒ์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

        "nvarguscamerasrc ! "
        "video/x-raw(memory:NVMM), "
        "width=(int)%d, height=(int)%d, "
        "format=(string)NV12, framerate=(fraction)%d/1 ! "
        "nvvidconv flip-method=%d ! "
        "video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "
        "videoconvert ! "
        "video/x-raw, format=(string)BGR ! appsink"

์ด ๊ธด ๋ฌธ์ž์—ด์€ ๋ฌด์—‡์ผ๊นŒ์š”?? ๊ฐ•์˜ ์ดˆ๋ฐ˜์— ๋ณต์Šตํ•˜๋ฉด์„œ ์‚ดํŽด๋ณด์•˜๋˜ ์ปค๋งจ๋“œ ๋ผ์ธ์ด ๊ธฐ์–ต๋‚˜์‹œ๋‚˜์š”?

$ gst-launch-1.0 nvarguscamerasrc sensor_id=0 ! \
   'video/x-raw(memory:NVMM),width=3280, height=2464, framerate=21/1, format=NV12' ! \
   nvvidconv flip-method=2 ! 'video/x-raw,width=960, height=720' ! \
   nvvidconv ! nvegltransform ! nveglglessink -e

์ด ํ•จ์ˆ˜๋Š” ๋น„๋””์˜ค ํŒŒ์ดํ”„๋ผ์ธ์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ์ด ์ปค๋งจ๋“œ ๋ผ์ธ์„ ํŒŒ์ด์ฌ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด๋ž๋‹ˆ๋‹ค. ๐Ÿ™‚

๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์€ ์•ž์„  ์˜ˆ์ œ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ณด๋„ˆ์Šค!! ์ด๋ฏธ์ง€ Streaming ์„œ๋ฒ„


$ sudo apt-get install ros-melodic-web-video-server -y
$ roscore
$ rosrun csi_camera csi_pub.py
$ rosrun web_video_server web_video_server

# chrome
http://localhost:8080

ros์—์„œ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋Š” ์ด๋ฏธ์ง€ ์ŠคํŠธ๋ฆฌ๋ฐ ์›น์„œ๋ฒ„์ž…๋‹ˆ๋‹ค. ์›น ๊ฐœ๋ฐœ์ž์‹œ๋ผ๋ฉด, ์ด๋ฅผ ์ด์šฉํ•œ ์—ฌ๋Ÿฌ๋ถ„๋งŒ์˜ ์›น์•ฑ์„ ๋งŒ๋“ค์–ด ๋ณผ ์ˆ˜ ์žˆ๊ฒ ์ง€์š”? ๐Ÿ‘๐Ÿ‘๐Ÿ‘

Wiki
HTTP Streaming of ROS Image Topics in Multiple Formats This package provides a video stream of a ROS image transport topic that can be accessed via HTTP. Parameters ~port ( integer, default: 8080) ~address ( string, default: 0.0.0.0) ~server_threads ( integer, default: 1) ~ros_threads ( integer, default: 2) The web_video_server opens a local port and waits for incoming HTTP requests.
http://wiki.ros.org/web_video_server

์นด๋ฉ”๋ผ๋ฅผ ROS๋กœ ๋‹ค๋ค„๋ณด๋Š” ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋ฐฐ์›Œ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๊ฐ•์˜์—์„œ๋Š” ๋˜๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿ“ธ๐Ÿ“ธ๐Ÿ“ธ