ROS2(Topic)를 활용해 Webcam 사용해보기
제가 다니는 대학교에서 로봇운영체제(ROS) 관련 교과목을 들으며 진행한 프로젝트의 과정입니다.
앞선 게시물에서 저는 Virtual Box 를 이용해 Ubuntu 20.04, OpenCV4.0.0 개발환경을 구축하였습니다
오늘 ROS 2 Foxy Fitzroy 개발 환경을 구축할 예정입니다.
설치에는 아래 블로그 주소를 참고하면 됩니다.
ROS2 (Foxy Fitzroy)
https://makepluscode.tistory.com/18
Ubuntu 20.04 에서 ROS2 Foxy Fitzroy설치하기
Background 오픈소스 기반의 ROS (Robot Operating System)는 로봇 애플리케이션을 만들기 위한 라이브러리 및 도구 모음 입니다. 디바이스 드라이버에서 알고리즘에 이르기까지 강력한 개발자 도구를 갖
makepluscode.tistory.com
설치 후 원활한 코딩 작업을 위해 Ubuntu Software에서 VSCode를 설치합니다.
설치 한 후에는 맨 아래 아이콘을 클릭해 다음 목록들을 검색해 설치합니다.

설치 목록 - ( Python, C/C++, CMake, CMake Tools, ROS, URDF, Colcon Tasks, XML Tools, YAML , Markdown All in One, Hightlight Trailing White Spaces, Better Comments)
설치가 완료 되면 터미널을 열어 ( Ctrl + Alt + T) 작업을 진행할 폴더로 이동합니다. 저는 home으로 이동하겠습니다
cd ~
이동 후 현재 위치를 다시 한번 확인합니다.
pwd
설치가 완료되면 아래 명령어로 작업을 진행할 디렉토리를 만듭니다.
mkdir ros2_ws && cd ros2_ws && mkdir src
만든 디렉토리로 이동 합니다.
cd ~/ros2_ws/src
ROS2 환경을 불러옵니다
source /opt/ros/foxy/setup.bash
(저는 나중에 단축 실행키를 만들어 ros2foxy라는 단축어를 입력하면 setup.bash 파일을 불러오도록 했습니다. 단축어를 만들지 않으신 분들은 터미널을 열어 ros2를 사용할때마다 위에 명령어를 입력해 환경을 불러와야 합니다.)
이제 패키지를 만들건데 틀은 아래와 같습니다.
ros2 pkg create <패키지이름> --build-type <빌드타입> --node-name <노드명> --dependencies <의존하는 패키지1> <의존하는 패키지2>
저는 ros2_cv_webcam 이라는 이름을 패키지를 만들었습니다. (뒤에 의존하는 패키지는 각자 상황에 필요한 패키지를 입력합니다.)
ros2 pkg create --build-type ament_python ros2_cv_webcam --dependencies rclpy image_transport cv_bridge sensor_msgs std_msgs opencv2

다음으로 VSCode를 열어 ros2_ws 폴더를 엽니다.

src -> ros2_cv_webcam 폴더로 이동해 package.xml을 엽니다.

package.xml에서 사진 부분을

아래 명령어로 바꾼 후 저장합니다. (이메일 주소는 자신의 이메일 주소로 변경합니다)
<description>A minimal image publisher and subscriber node that uses OpenCV</description>
<maintainer email="sowhwa28@naver.com">automaticaddison</maintainer>
<license>Apache License 2.0</license>

이제 Image Publisher Node를 만들 차례입니다.
ros2_ws/src/ros2_cv_webcam/ros2_cv_webcam 폴더로 이동해 webcam.py 파일을 만듭니다.

파일에 아래의 내용을 입력한 후 저장합니다.
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
class ImagePublisher(Node):
def __init__(self):
super().__init__('image_publisher') # Node name
self.publisher_=self.create_publisher(
Image, # Message type
'video_frames', # Topic name
10)
timer_period=0.1
self.timer=self.create_timer(timer_period, self.timer_callback)
self.cap=cv2.VideoCapture(0)
self.br=CvBridge()
def timer_callback(self):
ret, frame=self.cap.read()
if ret==True:
self.publisher_.publish(self.br.cv2_to_imgmsg(frame))
self.get_logger().info('Publishing video frame')
def main():
rclpy.init() # ROS 통신 시작
image_publisher=ImagePublisher() # 클래스 생성
rclpy.spin(image_publisher)
image_publisher.destroy_node()
rclpy.shutdown() # ROS 통신 종료
if __name__=='__main__':
main()

다음 상위 폴더 ros2_cv_webcam 으로 올라가 setup.py를 찾은 후 열어서
entry_points={
'console_scripts': [
],
},
여기 'console_scripts':[ ] 사이에 아래의 코드를 입력해
'img_publisher = ros2_cv_webcam.webcam_pub:main',
아래와 같이 만들고 저장합니다.
entry_points={
'console_scripts': [
'img_publisher = ros2_cv_webcam.webcam_pub:main',
],
},

다음으로는 Image Subscriber Node를 만들겠습니다.
마찬가지로 동일한 경로에 (경로가 다르다면 ros2_ws/src/ros2_cv_webcam/ros2_cv_webcam로 이동) webcam_sub.py 파일을 만듭니다 .
( webcam_pub.py 과 webcam_sub.py 파일은 모두 ros2_ws/src/ros2_cv_webcam/ros2_cv_webcam 경로에 __init__.py와 함께 있어야 합니다.)
webcam_sub.py 파일에 아래의 내용을 입력한 후 저장합니다.
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
class ImageSubscriber(Node):
def __init__(self):
super().__init__('image_subscriber') # Node name
self.subscription=self.create_subscription(
Image, # Message type
'video_frames', # Topic name
self.listener_callback,
10)
self.subscription
self.br=CvBridge()
def listener_callback(self, data):
self.get_logger().info('Receiving Video frame')
current_frame=self.br.imgmsg_to_cv2(data)
cv2.imshow("camera",current_frame)
cv2.waitKey(1)
def main():
rclpy.init() # ROS 통신 시작
image_subscriber=ImageSubscriber() # 클래스 생성
rclpy.spin(image_subscriber)
image_subscriber.destroy_node()
rclpy.shutdown() # ROS 통신 종료
if __name__=='__main__':
main()

다시 상위 폴더 ros2_cv_webcam 으로 올라가 setup.py를 찾은 후 열어서 img_publisher 아래에 다음 코드를 추가한 뒤 저장합니다.
'img_subscriber = ros2_cv_webcam.webcam_sub:main',

수정이 완료 됬으면 가장 상위 폴더 ros2_ws로 이동합니다.
cd ~/ros2_ws
필요한 패키지가 이미 설치되어 있는지 다시 확인하는 명령어를 입력합니다.
rosdep install -i --from-path src --rosdistro foxy -y
명령어를 입력하면 다음과 같은 error가 발생합니다.
ERROR: the following packages/stacks could not have their rosdep keys resolved
to system dependencies:
ros2_cv_webcam: Cannot locate rosdep definition for [opencv2]
이것은 opencv 버전이 맞지 않아서 생기는 문제입니다.
src -> ros2_cv_webcam 폴더로 이동해 package.xml을 엽니다.

<depend>opencv2</depend>
이 부분을 아래와 같이 변경하고 저장합니다.
<depend>python3-opencv</depend>

다시 ros2_ws 파일로 돌아가 아래 코드를 실행하면 돌아갑니다.
rosdep install -i --from-path src --rosdistro foxy -y
colcon 명령어를 이용해 패키지 빌드를 진행합니다.
colcon build --packages-select ros2_cv_webcam

이제 결과를 확인할 차례입니다.
터미널을 세개를 엽니다. ( 두개만 열어도 됩니다. 마지막 하나는 topic 그래프 확인용입니다.)
1. 첫 번째 터미널
ros2foxy 단축어 입력 혹은 아래의 명령어로 환경 불러오기
source /opt/ros/foxy/setup.bash
Overlay 환경 불러오기
source install/setup.bash
publish node 실행
ros2 run ros2_cv_webcam img_publisher
2. 두 번째 터미널
ros2foxy 단축어 입력 혹은 아래의 명령어로 환경 불러오기
source /opt/ros/foxy/setup.bash
Overlay 환경 불러오기
source install/setup.bash
subscribe node 실행
ros2 run ros2_cv_webcam img_subscriber
결과

출력이 잘 되는 것을 확인할 수 있습니다.
3. 세 번째 터미널
ros2foxy 단축어 입력 혹은 아래의 명령어로 환경 불러오기
source /opt/ros/foxy/setup.bash
topic 그래프 확인하기
rqt_graph

이 모든 과정은 제가 수강하고 있는 교과목의 강의자료와 아래 사이트를 참고했습니다.
http://wiki.ros.org/cv_bridge/Tutorials/ConvertingBetweenROSImagesAndOpenCVImagesPython
cv_bridge/Tutorials/ConvertingBetweenROSImagesAndOpenCVImagesPython - ROS Wiki
Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. Converting between ROS images and OpenCV image
wiki.ros.org