ROS2

ROS의 Topic에 대해서 이해해 보자

trustworthyhand 2025. 7. 10. 14:03

ROS1에서는 Service 외에도 Topic이 가장 많이 사용되는 기본 통신 구조입니다.
요청-응답 방식의 Service와 다르게, Topic은 비동기 스트리밍 통신이에요.

 

노드(Node) 간에 연속적인 메시지를 주고받는 방식
Publisher가 데이터를 보내고, Subscriber는 그 데이터를 수신함
→ 1:N 또는 N:M 통신 가능 (여러 노드가 동시에 같은 Topic 수신 가능)

┌────────────┐      topic name     ┌────────────┐
│    Node 1          ─────────────▶────▶   Node 2      │
│   Publishe                       /cmd_vel                   Subscriber     │
      (발행자)                                                            (구독자)
└────────────┘                             └────────────┘
                        /cmd_vel   ← Topic 이름 (문자열)

 

 

📤 Publisher 예 (명령 보내기)

pub = rospy.Publisher('/cmd_vel', Twist, queue_size=10)
  • 이 노드는 /cmd_vel 토픽에 Twist 메시지를 보냄
  • 즉, 발행

📥 Subscriber 예 (센서 듣기)

sub = rospy.Subscriber('/scan', LaserScan, callback)
  • 이 노드는 /scan 토픽을 받아들임
  • 즉, 구독자
Publisher 발행자 데이터를 보냄 (pub)
Subscriber 구독자 데이터를 받음 (sub)
Topic 주제/신문 데이터를 주고받는 채널 이름

📰 신문 예시로 비유:

  • 🗞 Publisher (발행자): 신문을 만드는 사람
  • 👓 Subscriber (구독자): 신문을 받아보는 사람

신문 = 토픽

→ 신문사(노드 A)가 /news라는 신문을 발행하면
→ 여러 사람이(노드 B, C, ...) /news를 구독해서 받아보는 구조예요.

 

 

 

        [Node A]                        [Node B]
     ┌────────────┐                 ┌────────────┐
     │ Publisher  │ ── /scan ──▶──▶ │ Subscriber │
     └────────────┘                 └────────────┘
                                  ↑                                 ↓
                        /cmd_vel                          /odom
     ┌────────────┐                 ┌────────────┐
     │ Subscriber │ ◀── /cmd_vel ──            │ Publisher  │
     └────────────┘                 └────────────┘

 

kys_talker.py 라는 Publisher 코드를 만들어보았다

#!/usr/bin/env python3   
import rospy
import curses
from geometry_msgs.msg import Twist

def main(stdscr):
    rospy.init_node('keyboard_control_curses')
    pub = rospy.Publisher('/cmd_vel', Twist, queue_size=10)
    rate = rospy.Rate(10)

    curses.curs_set(0)
    stdscr.nodelay(True)
    stdscr.clear()
    stdscr.addstr(0, 0, "TurtleBot3 키보드 제어 (w: 전진 | z: 후진 | a: 좌회전 | d: 우회전 | s: 정지 | z: 종료)")
    stdscr.refresh()

    twist = Twist()

    while not rospy.is_shutdown():
        try:
            key = stdscr.getch()

            if key != -1:
                twist = Twist()

                if key == ord('w'):
                    twist.linear.x = 0.1
                    twist.angular.z = 0.0
                    stdscr.move(2, 0)
                    stdscr.clrtoeol()
                    stdscr.addstr(2, 0, "전진")
                
                elif key == ord('s'):
                    twist.linear.x = 0.0
                    twist.angular.z = 0.0
                    stdscr.move(2, 0)
                    stdscr.clrtoeol()
                    stdscr.addstr(2, 0, "정지")

                elif key == ord('a'):
                    twist.linear.x = 0.0
                    twist.angular.z = 0.5
                    stdscr.move(2, 0)
                    stdscr.clrtoeol()
                    stdscr.addstr(2, 0, "좌회전")

                elif key == ord('d'):
                    twist.linear.x = 0.0
                    twist.angular.z = -0.5
                    stdscr.move(2, 0)
                    stdscr.clrtoeol()
                    stdscr.addstr(2, 0, "우회전")

                elif key == ord('x'):
                    twist.linear.x = -0.1
                    twist.angular.z = 0.0
                    stdscr.move(2, 0)
                    stdscr.clrtoeol()
                    stdscr.addstr(2, 0, "후진")
                
                elif key == ord('z'):
                    twist.linear.x = 0.0
                    twist.angular.z = 0.0
                    pub.publish(twist)
                    stdscr.addstr(2, 0, "종료")
                    break

            # 항상 현재 상태를 publish
            pub.publish(twist)
            stdscr.refresh()
            rate.sleep()

        except rospy.ROSInterruptException:
            break

curses.wrapper(main)

 

!/usr/bin/env python3  
**리눅스에서 실행 가능한 파이썬 스크립트**임을 나타냅니다`python3`로 이
파일을 실행하도록 지정하는 **실행 환경 선언**입니다


import rospy 
ROS에서 Python으로 노드를 작성하려면 이 라이브러리가 필수


import curses   # **터미널에서 텍스트 기반의 UI(User Interface)**를 만들기 위한 표준 파이썬 모듈**
| 기능                |      설명                                 |
| -------------      | ---------------------------------------- |
| 키보드 입력 감지      | `getch()`로 특정 키 입력 감지                |
| 텍스트 출력 위치 제어  | 원하는 위치(`x, y`)에 글자 출력 가능           |
| 화면 클리어 / 새로고침 | `clear()`, `refresh()`로 전체 갱신          |
| 커서 숨기기          | `curs_set(0)`                             |
| 비동기 입력 처리      | `nodelay(True)` 사용 시 입력이 없어도 루프 유지 |


rostopic list를 통하여
cmd_vel이 있는지 확인하고 rostopic_type /cmdvel 확인하여
geometry_msgs/Twist 인것을 확인하였다 
geometry_msgs/Vector3 linear
  float64 x
  float64 y
  float64 z
geometry_msgs/Vector3 angular
  float64 x
  float64 y
  float64 z


🔹 linear: 직선 속도
x: 앞뒤 (전진/후진) 속도
y: 좌우 (옆으로 밀기, 일반 로봇은 보통 0)
z: 위아래 (비행 드론 등에서 사용)

🔹 angular: 회전 속도 (각속도)
x: x축 회전 (롤) → 로봇에는 거의 안 씀
y: y축 회전 (피치) → 거의 안 씀
z: z축 회전 (요) → 바닥에서 회전, 가장 많이 씀

from geometry_msgs.msg import Twist
정리중

 

 

kys_listener.py라는 Subscriber 코드를 만들어봤다 

#!/usr/bin/env python3  

import rospy
from geometry_msgs.msg import Twist

def callback(msg):
    rospy.loginfo("📩 받은 메시지 - linear.x: %.2f, angular.z: %.2f",
                  msg.linear.x, msg.angular.z)

def listener():
    rospy.init_node('keyboard_listener', anonymous=True)
    rospy.Subscriber('/cmd_vel', Twist, callback)
    rospy.spin()

if __name__ == '__main__':
    listener()

 

둘다 실행을 하면 아래와 같은 화면이 나온다

현재 나는 터틀봇을 ssh연결을 통하여 연결된상태에서 

sudo apt update

roscore

 

ssh연결한 sbc에서 

roslaunch turtlebot3_bringup turtlebot3_robot.launch 을 실행하고

remotepc(노트북)에서

roslaunch turtlebot3_slam turtlebot3_slam.launch

 

remotepc(노트북) 에서 새로운터미널에서 talker와 listener 가 저장된주소를 찾아 파일을 실행하였다