로보테크AI

융합_로보테크 AI 자율주행 로봇 개발자 과정-26/03/12

steezer 2026. 3. 12. 18:30

복습

ROS

이기종 간 메시지 통신을 위해 사용하는 소프트웨어 플랫폼

메타 운영체제

 

노드 대 노드 메시지 통신

노드는 한 기기 안에 있는 노드들일 수도 있고

서로 다른 기기에 존재하는 노드일 수도 있음

 

steezer@DESKTOP-TF8J569:~$ ros2 node list
/turtlesim
steezer@DESKTOP-TF8J569:~$ ros2 node info /turtlesim
/turtlesim
  Subscribers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /turtle1/cmd_vel: geometry_msgs/msg/Twist
  Publishers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /rosout: rcl_interfaces/msg/Log
    /turtle1/color_sensor: turtlesim/msg/Color
    /turtle1/pose: turtlesim/msg/Pose
  Service Servers:
    /clear: std_srvs/srv/Empty
    /kill: turtlesim/srv/Kill
    /reset: std_srvs/srv/Empty
    /spawn: turtlesim/srv/Spawn
    /turtle1/set_pen: turtlesim/srv/SetPen
    /turtle1/teleport_absolute: turtlesim/srv/TeleportAbsolute
    /turtle1/teleport_relative: turtlesim/srv/TeleportRelative
    /turtlesim/describe_parameters: rcl_interfaces/srv/DescribeParameters
    /turtlesim/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
    /turtlesim/get_parameters: rcl_interfaces/srv/GetParameters
    /turtlesim/list_parameters: rcl_interfaces/srv/ListParameters
    /turtlesim/set_parameters: rcl_interfaces/srv/SetParameters
    /turtlesim/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
  Service Clients:

  Action Servers:
    /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
  Action Clients:

steezer@DESKTOP-TF8J569:~$ ros2 service list
/clear
/kill
/reset
/spawn
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/describe_parameters
/turtlesim/get_parameter_types
/turtlesim/get_parameters
/turtlesim/list_parameters
/turtlesim/set_parameters
/turtlesim/set_parameters_atomically
steezer@DESKTOP-TF8J569:~$ ros2 service type /turtle1/teleport_absolute
turtlesim/srv/TeleportAbsolute
steezer@DESKTOP-TF8J569:~$ ros2 interface show turtlesim/srv/TeleportAbsolute
float32 x
float32 y
float32 theta
---
steezer@DESKTOP-TF8J569:~$ ros2 service call
usage: ros2 service call [-h] [-r N] service_name service_type [values]
ros2 service call: error: the following arguments are required: service_name, service_type
steezer@DESKTOP-TF8J569:~$ ros2 service call /turtle1/teleport_absolute turtlesim/srv/TeleportAbsolute "{x: 0.2, y: 0.1, theta: 0}"
requester: making request: turtlesim.srv.TeleportAbsolute_Request(x=0.2, y=0.1, theta=0.0)

response:
turtlesim.srv.TeleportAbsolute_Response()

 

서비스 사용 방법

 

1. 서비스 종류 확인

ros2 service list

 

2.서비스 선택, 타입 확인

ros2 service type 서비스명

 

3. 서비스 요청할 때 어떤 정보를 제공해야 하는지 확인

ros2 interface show 서비스 타입명

 

4. 실제 확인한 내용을 토대로 서비스 콜

ros2 service call 서비스명 서비스타입명 "데이터"

 

미션

터틀심 서비스 중 /set pen 활용하여 원하는 색상 원하는 두께로 그림이 그려지도록 만들기

 

steezer@DESKTOP-TF8J569:~$ ros2 service list
/clear
/kill
/reset
/spawn
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/describe_parameters
/turtlesim/get_parameter_types
/turtlesim/get_parameters
/turtlesim/list_parameters
/turtlesim/set_parameters
/turtlesim/set_parameters_atomically
steezer@DESKTOP-TF8J569:~$ ros2 service type /turtle1/set_pen
turtlesim/srv/SetPen
steezer@DESKTOP-TF8J569:~$ ros2 interface show turtlesim/srv/SetPen
uint8 r
uint8 g
uint8 b
uint8 width
uint8 off
---
steezer@DESKTOP-TF8J569:~$ ros2 service call /turtle1/set_pen turtlesim/srv/SetPen "
{'r': 242, 'g': 150, 'b': 97, 'width': 3, 'off': 0}"
requester: making request: turtlesim.srv.SetPen_Request(r=242, g=150, b=97, width=3, off=0)

response:
turtlesim.srv.SetPen_Response()

steezer@DESKTOP-TF8J569:~$ ros2 service call /turtle1/teleport_absolute turtlesim/srv/TeleportAbsolute "{x: 2, y: 3, theta: 0}"
requester: making request: turtlesim.srv.TeleportAbsolute_Request(x=2.0, y=3.0, theta=0.0)

response:
turtlesim.srv.TeleportAbsolute_Response()

steezer@DESKTOP-TF8J569:~$ ros2 service call /turtle1/set_pen turtlesim/srv/SetPen "{'r': 242, 'g': 150, 'b': 97, 'width': 5, 'off': 0}"
requester: making request: turtlesim.srv.SetPen_Request(r=242, g=150, b=97, width=5, off=0)

response:
turtlesim.srv.SetPen_Response()

steezer@DESKTOP-TF8J569:~$ ros2 service call /turtle1/teleport_absolute turtlesim/srv/TeleportAbsolute "{x: 0, y: 0, theta: 0}"
requester: making request: turtlesim.srv.TeleportAbsolute_Request(x=0.0, y=0.0, theta=0.0)

response:
turtlesim.srv.TeleportAbsolute_Response()

 

Topic

노드 간에 데이터를 일방향으로 주고받기 위한 메시지 기반 통신 방식

 

Publisher: 데이터를 보내는 쪽
Subscriber: 데이터를 받는 쪽
Topic: 그 데이터를 흘려보내는 통로

 

ros2 topic list
ros2 topic /turtle1/pose
turtlesim/msg/Pose
ros2 topic list-t
ros2 topic info /turtle1/pose
ros2 topic list -v
ros2 interface show turtlesim/msg/Pose
ros2 topic echo /turtle1/pose
ros2 topic list -t
ros2 interface show geometry_msgs/msg/Twist
---
x: 5.544444561004639
y: 5.544444561004639
theta: 0.0
linear_velocity: 0.0
angular_velocity: 0.0
---
^Csteezer@DESKTOP-TF8J569:~$ ros2 topic list -t
/parameter_events [rcl_interfaces/msg/ParameterEvent]
/rosout [rcl_interfaces/msg/Log]
/turtle1/cmd_vel [geometry_msgs/msg/Twist]
/turtle1/color_sensor [turtlesim/msg/Color]
/turtle1/pose [turtlesim/msg/Pose]
steezer@DESKTOP-TF8J569:~$ ros2 interface show geometry_msgs/msg/Twist
# This expresses velocity in free space broken into its linear and angular parts.

Vector3  linear
        float64 x
        float64 y
        float64 z
Vector3  angular
        float64 x
        float64 y
        float64 z

 

공간상 6자유도 표현

x, y, z축(3)을 중심으로 회전(*2)

x축 중심 회전 roll

y축 중심 회전 pitch

z축 중심 회전 yaw

 

steezer@DESKTOP-TF8J569:~$ ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0))

steezer@DESKTOP-TF8J569:~$ ros2 topic pub -r 1 /turtle1/cmd_vel geometry_msgs/msg/Tw
ist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.5}}"
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.5))

publishing #2: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.5))

publishing #3: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.5))

publishing #4: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.5))

 

노드 / 토픽 + 노드

 

ROS Action

액션을 제공하는 액션 서버를 구현하는 노드에 클라이언트 노드에서 먼저 서비스를 목표로 요청

그러면 서버가 응답

여기까진 서비스와 같지만 액션은 목표를 달성할 때까지 그 중간을 토픽으로 피드백 함

목표에 도달할 때까지 중간을 확인 가능

끝나면 결과 서비스 사용

 

turtle_teleop_key

steezer@DESKTOP-TF8J569:~$ ros2 run turtlesim turtlesim_node
[INFO] [1773281773.350865953] [turtlesim]: Starting turtlesim with node name /turtlesim
[INFO] [1773281773.359474744] [turtlesim]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]

steezer@DESKTOP-TF8J569:~$ ros2 run turtlesim turtle_teleop_key
Reading from keyboard
---------------------------
Use arrow keys to move the turtle.
Use G|B|V|C|D|E|R|T keys to rotate to absolute orientations. 'F' to cancel a rotation.
'Q' to quit.
rqt_graph

 

ros2 action list

steezer@DESKTOP-TF8J569:~$ ros2 action list
/turtle1/rotate_absolute
steezer@DESKTOP-TF8J569:~$ ros2 action list -t
/turtle1/rotate_absolute [turtlesim/action/RotateAbsolute]

 

패키지 안에는 이름이 정해져 있는 몇 개의 디렉터리 존재

srv: 서비스 타입이 정리되어 있는 디렉터리

msg: 토픽 타입이 정리되어 있는 디렉터리

action: 액션 타입이 정리되어 있는 디렉터리

 

steezer@DESKTOP-TF8J569:~$ ros2 interface show turtlesim/action/RotateAbsolute
# The desired heading in radians
float32 theta
---
# The angular displacement in radians to the starting position
float32 delta
---
# The remaining rotation in radians
float32 remaining

 

ros2 action send_goal

steezer@DESKTOP-TF8J569:~$ ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 3.14}"
Waiting for an action server to become available...
Sending goal:
     theta: 3.14

Goal accepted with ID: ef0a780943de4e7dbc4836e7fb11ed90

Result:
    delta: -2.6080000400543213

Goal finished with status: SUCCEEDED

 

 

Python으로 ROS2 토픽 다루기

steezer@DESKTOP-TF8J569:~$ python3 --version
Python 3.10.12
steezer@DESKTOP-TF8J569:~$ sudo apt install python3-pip
[sudo] password for steezer:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  python3-wheel
The following NEW packages will be installed:
  python3-pip python3-wheel
0 upgraded, 2 newly installed, 0 to remove and 6 not upgraded.
Need to get 1,338 kB of archives.
After this operation, 7,214 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 python3-wheel all 0.37.1-2ubuntu0.22.04.1 [32.0 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 python3-pip all 22.0.2+dfsg-1ubuntu0.7 [1,306 kB]
Fetched 1,338 kB in 3s (417 kB/s)
Selecting previously unselected package python3-wheel.
(Reading database ... 139050 files and directories currently installed.)
Preparing to unpack .../python3-wheel_0.37.1-2ubuntu0.22.04.1_all.deb ...
Unpacking python3-wheel (0.37.1-2ubuntu0.22.04.1) ...
Selecting previously unselected package python3-pip.
Preparing to unpack .../python3-pip_22.0.2+dfsg-1ubuntu0.7_all.deb ...
Unpacking python3-pip (22.0.2+dfsg-1ubuntu0.7) ...
Setting up python3-wheel (0.37.1-2ubuntu0.22.04.1) ...
Setting up python3-pip (22.0.2+dfsg-1ubuntu0.7) ...
Processing triggers for man-db (2.10.2-1) ...
steezer@DESKTOP-TF8J569:~$ pip3 install upgrade pip
Defaulting to user installation because normal site-packages is not writeable
ERROR: Could not find a version that satisfies the requirement upgrade (from versions: none)
ERROR: No matching distribution found for upgrade
steezer@DESKTOP-TF8J569:~$ pip3 install --upgrade pip
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: pip in /usr/lib/python3/dist-packages (22.0.2)
Collecting pip
  Downloading pip-26.0.1-py3-none-any.whl (1.8 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 19.9 MB/s eta 0:00:00
Installing collected packages: pip
  WARNING: The scripts pip, pip3 and pip3.10 are installed in '/home/steezer/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pip-26.0.1
pip3 install jupyter ipywidgets pyyaml bqplot

 

http://localhost:8888/tree

ROS2 humble is activated!
steezer@DESKTOP-TF8J569:~$ cd python/
steezer@DESKTOP-TF8J569:~/python$

# 제목

## 제목

### 제목

백틱은 물결과 같이 있음

steezer@DESKTOP-TF8J569:~/python$ ros2 run turtlesim turtlesim_node
[INFO] [1773286151.648554049] [turtlesim]: Starting turtlesim with node name /turtlesim
[INFO] [1773286151.660248493] [turtlesim]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
import rclpy as rp # ROS를 위해 제공되는 파이썬 패키지
from turtlesim.msg import Pose # 거북이의 위치 정보를 읽어들일 때 사용하는 인터페이스

rp.init() # ROS 제어를 위한 초기화 함수 호출
test_node =rp.create_node("sub_test") # 이름을 지정하여 노드 생성

 

steezer@DESKTOP-TF8J569:~$ ros2 node list
/sub_test
/turtlesim

 

def callback(data):
    print("--->")
    print("/turtle1/pose : ", data)
    print("X : ", data.x)
    print("Y : ", data.y)
    print("Theta : ", data.theta)

 

토픽 subscriber 만들기

test_node.create_subscription(Pose, '/turtle1/pose', callback, 10)

rp.spin_once(test_node)

<rclpy.subscription.Subscription at 0x7da588276f50>

--->
/turtle1/pose :  turtlesim.msg.Pose(x=5.544444561004639, y=5.544444561004639, theta=0.0, linear_velocity=0.0, angular_velocity=0.0)
X :  5.544444561004639
Y :  5.544444561004639
Theta :  0.0

 

spin_once를 실행해서 토픽을 한번 구독함

 

주의할것

spin_once가 아닌 spin을 쓸 경우 무한 루프로 다운될 수 있음

 

현재까지 구현된 것

1.필요 패키지 임포트

2.노드 생성(이름 지정)

3.구독용 콜백함수 선언

4.노드에 구독시 사용할 콜백함수 지정

5.실행

 

토픽을 받는 횟수 제한해보기

cnt = 0
def callback(data):
    global cnt
    cnt += 1
    print(">", cnt, " -> X : ", data.x, ", Y : ", data.y)
    if cnt > 3:
        raise Exception("Subscription Stop")
        
test_node.create_subscription(Pose, 'turtle1/pose', callback, 10)

rp.spin(test_node)
> 1  -> X :  5.544444561004639 , Y :  5.544444561004639
> 2  -> X :  5.544444561004639 , Y :  5.544444561004639
> 3  -> X :  5.544444561004639 , Y :  5.544444561004639
> 4  -> X :  5.544444561004639 , Y :  5.544444561004639

 

파이썬으로 서비스 클라이언트 다루기

 

 

ROS2 학습을 위한 Python Class 이해하기

 

 

패키지 만들고 토픽 다루기

https://docs.ros.org/en/humble/Installation/Alternatives/Ubuntu-Development-Setup.html

steezer@DESKTOP-TF8J569:~$ mkdir -p ~/ros2_study/src
steezer@DESKTOP-TF8J569:~$ ls
260309  260310  260311  greetings  normal_file  python  ros2_study  snap  Untitled.ipynb
steezer@DESKTOP-TF8J569:~$ cd ros2_study/
steezer@DESKTOP-TF8J569:~/ros2_study$ ls
src
steezer@DESKTOP-TF8J569:~/ros2_study$ colcon build

Summary: 0 packages finished [0.60s]
steezer@DESKTOP-TF8J569:~/ros2_study$ ls
build  install  log  src
steezer@DESKTOP-TF8J569:~/ros2_study$ rm -rf build install log
steezer@DESKTOP-TF8J569:~/ros2_study$ ls
src
steezer@DESKTOP-TF8J569:~/ros2_study/src$ ros2 pkg create --build-type ament_python --node-n
ame my_first_node my_first_package
going to create a new package
package name: my_first_package
destination directory: /home/steezer/ros2_study/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['steezer <steezer@todo.todo>']
licenses: ['TODO: License declaration']
build type: ament_python
dependencies: []
node_name: my_first_node
creating folder ./my_first_package
creating ./my_first_package/package.xml
creating source folder
creating folder ./my_first_package/my_first_package
creating ./my_first_package/setup.py
creating ./my_first_package/setup.cfg
creating folder ./my_first_package/resource
creating ./my_first_package/resource/my_first_package
creating ./my_first_package/my_first_package/__init__.py
creating folder ./my_first_package/test
creating ./my_first_package/test/test_copyright.py
creating ./my_first_package/test/test_flake8.py
creating ./my_first_package/test/test_pep257.py
creating ./my_first_package/my_first_package/my_first_node.py

[WARNING]: Unknown license 'TODO: License declaration'.  This has been set in the package.xml, but no LICENSE file has been created.
It is recommended to use one of the ament license identitifers:
Apache-2.0
BSL-1.0
BSD-2.0
BSD-2-Clause
BSD-3-Clause
GPL-3.0-only
LGPL-3.0-only
MIT
MIT-0
steezer@DESKTOP-TF8J569:~/ros2_study/src$ ls
my_first_package

 

ROS 패키지 안에 Python 패키지 들어있는 구조로 만들어짐

 

steezer@DESKTOP-TF8J569:~/ros2_study$ ls
src
steezer@DESKTOP-TF8J569:~/ros2_study$ colcon build
Starting >>> my_first_package
Finished <<< my_first_package [0.87s]

Summary: 1 package finished [1.47s]

steezer@DESKTOP-TF8J569:~/ros2_study$ ls
build  install  log  src
steezer@DESKTOP-TF8J569:~/ros2_study$ cd install
steezer@DESKTOP-TF8J569:~/ros2_study/install$ ls
COLCON_IGNORE     local_setup.sh            local_setup.zsh   setup.ps1
local_setup.bash  _local_setup_util_ps1.py  my_first_package  setup.sh
local_setup.ps1   _local_setup_util_sh.py   setup.bash        setup.zsh
steezer@DESKTOP-TF8J569:~/ros2_study/install$ cd ..
steezer@DESKTOP-TF8J569:~/ros2_study$ source ./install/local_setup.bash
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 run my_first_package my_first_node
Hi from my_first_package.

 

패키지명, 노드명은 정해진 것 X

 

source ~~.bash는 사라짐

 

steezer@DESKTOP-TF8J569:~$ nano .bashrc

ㄴ추가: source ~/ros2_study/install/local_setup.bash