[ROS2] Topic 통신 - Publisher & Subscriber 생성

TaerinLog·2025년 5월 27일

Topic

  • 노드간 통신을 위한 방식 중 하나
  • 노드 간의 데이터를 publish 하고 subscribe 하는 방식
  • 노드 <-> 토픽 <-> 노드

명령어

1. 토픽 목록

  • 존재하는 토픽의 리스트를 볼 수 있음
    ros2 topic list

  • gazebo 시뮬레이터를 실행 시키고 토픽의 목록을 조회

2. 토픽 정보

  • 토픽의 정보 출력
    ros2 topic info [argument]
  • ros2 topic info /cmd_vel의 결과
    ㄴ Type : 메세지의 형태
    ㄴ pub & sub 을 하고 있는 노드의 개수

3. 토픽의 메세지 보기

  • 토픽의 메세지 출력
    ros2 topic echo 'argument'

4. 특정 토픽에 메세지 보내기

  • 메세지 publish
    ros2 topic pub [topic] [msg/Type] "msg String"
  • 예시
    ros2 topic pub /chatter std_msgs/msg/String "data: 'Hello ROS 2'"

명령어 요약

명령어설명
list현재 사용 가능한 토픽 목록
echo특정 토픽에서 publish되는 메시지를 출력
info특정 토픽의 정보(타입, 퍼블리셔 수, 서브스크라이버 수 등)
pub특정 토픽에 메시지를 publish
hz특정 토픽의 퍼블리시 주기(Hz)를 측정
type특정 토픽이 사용하는 메시지 타입을 출력
bw특정 토픽의 대역폭 사용량을 측정

Publisher & Subscriber 생성

  • 벽을 만나면 회전하는 로직
    • lidar센서 데이터 받아옴
    • 장애물(벽)과 거리가 1미터 이하면 로봇을 회전시킴

1. 노드 작성

# turn_robot.py
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist

class MOVE_TO_WALL(Node):
    def __init__(self):
        super().__init__('publisher_node')
        self.subscription = self.create_subscription(
            LaserScan,
            '/scan_raw',  # Lidar 센서의 토픽 (이 예시에서는 'scan' 사용)
            self.lidar_callback,
            10)
        self.control_rb = self.create_publisher(Twist, 'cmd_vel', 10) # cmd_vel은 로봇을 제어하는 토픽
        self.get_logger().info("MOVE_TO_WALL node has started!")

    def lidar_callback(self,msg):
        min_distance = min(msg.ranges)  # 가장 가까운 거리 측정값 찾기
        
        if min_distance < 1.0:
            self.get_logger().info((f"Obstacle detected! Min distance: {min_distance}m"))
            self.turn_robot()
        else:
            self.move_robot()

    def move_robot(self):
        move_cmd = Twist()
        move_cmd.linear.x = 0.5  # 전진 속도 (m/s)
        self.control_rb.publish(move_cmd)
        self.get_logger().info('Moving robot forward with speed: 0.5 m/s')

    def turn_robot(self):
        # 장애물이 있으면 회전하여 피함
        move_cmd = Twist()
        move_cmd.linear.x = 0.0  # 멈춤
        move_cmd.angular.z = 0.5  # 회전 속도
        self.control_rb.publish(move_cmd)
        self.get_logger().info("Avoiding obstacle by turning")


def main(args=None):
    rclpy.init(args=args)
    robot_mover = MOVE_TO_WALL()
    rclpy.spin(robot_mover)
    rclpy.shutdown()


if __name__ == '__main__':
    main()

2. setup.py 수정

    entry_points={
        'console_scripts': [
        	# 추가
            'turn_robot_node = test_package.turn_robot:main',
        ],
    },

3. 패키지 빌드 및 실행

  • 노드가 있는 패키지 빌드
    colcon build --symlink-install --packages-select test_package
  • 환경 설정 적용
    source install/local_setup.bash
  • 노드 실행
    ros2 run test_package turn_robot_node

4. 결과

새로운 interface 생성

  • ROS2에서 제공하는 표준 메시지 타입외에 새로운 메시지가 필요할때
  • 메시지를 정의할 .msg 파일을 생성하고, 이를 패키지 내에서 빌드할 수 있게 설정

1. Package 생성

  • 새로운 메시지를 포함할 ROS2 패키지를 만듬
  • --dependencies 옵션을 사용하면 특정 패키지나 라이브러리들이 포함되어야 한다는 것을 colcon build 명령어에 명시함

    의존성을 추가하는 이유
    ㅇ 패키지 빌드에 필요시
    ㅇ 런타임에서의 의존성 - 프로그램 실행 중에 필요하게 되는 라이브러리나 패키지

ros2 pkg create --build-type ament_cmake my_custom_msgs --dependencies rclcpp std_msgs
ㄴ rclcpp와 std_msgs가 이 패키지의 의존성으로 포함되도록 지정

2. msg 생성

  • 패키지 하위에 msg 디렉터리 추가
    mkdir msg
  • custom.msg 생성
    • 메시지 명에 '_'와 같은 특수문자의 사용은 금지

robotInfo.msg

string name
int32 age
float32 height
bool is_active

3. CMakeLists.txt 및 package.xml 수정

  • CMakeLists.txt
# 이 부분 추가
find_package(rosidl_default_generators REQUIRED)

# 아래는 패키지 생성시 --dependencies std_msgs 시 자동 생성
# find_package(std_msgs REQUIRED)

set(msg_files "msg/robotInfo.msg")
# 여러개 추가할 때
# set(msg_files "msg/robotInfo.msg" "msg/OtherMessage.msg" "msg/AnotherMessage.msg" )

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
  DEPENDENCIES std_msgs
)
  • package.xml
# 아래 내용 추가
# 빌드할 때 메시지를 컴파일하기 위해 rosidl_default_generators가 필요하다고 선언
<build_depend>rosidl_default_generators</build_depend>

# 실행 시간(runtime)에 메시지를 해석하거나 사용하는 데 필요한 의존성
<exec_depend>rosidl_default_runtime</exec_depend>

# 인터페이스 패키지 그룹(메시지나 서비스 정의하는 패키지)에 속함을 선언
# ROS2에서 메시지 정의 패키지로 자동 인식되기 위해 필요
<member_of_group>rosidl_interface_packages</member_of_group>

요약

추가 항목역할
find_package(rosidl_default_generators REQUIRED).msg 빌드 도구 찾기
rosidl_generate_interfaces(...).msg를 코드로 변환
<build_depend>rosidl_default_generators</build_depend>빌드 시 의존성
<exec_depend>rosidl_default_runtime</exec_depend>실행 시 메시지 사용 가능
<member_of_group>rosidl_interface_packages</member_of_group>메시지 패키지로 식별되도록

4. 패키지 빌드 및 메세지 확인

  • 패키지 빌드
cd ~/ros2_ws
colcon build --symlink-install --packages-select my_custom_msgs
source install/local_setup.bash # 환경에 따라 local_setup.zsh
  • 인터페이스 생성 확인
    ros2 interface show my_custom_msgs/msg/robotInfo
profile
taerin

0개의 댓글