여러 거북이를 원 모양으로 배치하기 위한 고민
Jupyter Notebook | Python/Calc Position
개수가 정해졌을 때 각 원 사이의 각도를 구하기
import numpy as np
n = 3 # 3개로 원 두르기 가정
to_degree = 180/np.pi # 라디안을 쓰므로 변환해야
gap_theta = 2*np.pi / n
gap_theta * to_degree
119.99999999999999
list형으로 원의 각도를 저장
theta = [gap_theta*n for n in range(n)]
[each * to_degree for each in theta]
[0.0, 119.99999999999999, 239.99999999999997]
theta에 따라 x, y를 생성
r = 3
x = [r*np.cos(th) for th in theta]
y = [r*np.sin(th) for th in theta]
x
[np.float64(3.0),
np.float64(-1.4999999999999993),
np.float64(-1.5000000000000013)]
y
[np.float64(0.0),
np.float64(2.598076211353316),
np.float64(-2.598076211353315)]
결과를 scatter 함수로 그린 결과
import matplotlib.pyplot as plt
plt.scatter(x, y)
plt.axis('equal')
plt.show()

원을 배치하는 코드 함수로 작성
def calc_position(n, r):
gap_theta = 2*np.pi / n
theta = [gap_theta*n for n in range(n)]
x = [r*np.cos(th) for th in theta]
y = [r*np.sin(th) for th in theta]
return x, y, theta
결과를 그래프로 확인하기 위한 코드
def draw_pos(x,y):
plt.scatter(x, y)
plt.axis('equal')
plt.show()
원 4개를 배치해보는 것을 테스트
X, Y, theta = calc_position(4, 3)
draw_pos(X, Y)

원 15개 배치해보는 것을 테스트
X, Y, theta = calc_position(15, 3)
draw_pos(X, Y)

8장 마무리 실습
1. 주피터 노트북을 통해 거북이의 배치를 어떻게 계산하는지 실험 완료하기
2. 244~245p 소개된 final 버전 코드를 워크스페이스의 src 폴더 안에 완성하기
3. 워크스페이스(ros2_study)에서 colcon build하기
4. source install/local_setup.bash 명령어 실행하기
5. 실행 절차에 맞춰 노드 실행해보기
여러 거북이 배치하는 서비스 서버 구현
from my_first_package_msgs.srv import MultiSpawn
from turtlesim.srv import TeleportAbsolute
from turtlesim.srv import Spawn
import rclpy as rp
import numpy as np
from rclpy.node import Node
class MultiSpawning(Node):
def __init__(self):
super().__init__('multi_spawn')
self.server = self.create_service(MultiSpawn, 'multi_spawn', self.callback_service)
self.teleport = self.create_client(TeleportAbsolute, '/turtle1/teleport_absolute')
self.spawn = self.create_client(Spawn, '/spawn')
self.req_teleport = TeleportAbsolute.Request()
self.req_spawn = Spawn.Request()
self.center_x = 5.54
self.center_y = 5.54
def calc_position(self, n, r):
gap_theta = 2*np.pi / n
theta = [gap_theta*n for n in range(n)]
x = [r*np.cos(th) for th in theta]
y = [r*np.sin(th) for th in theta]
return x, y, theta
def callback_service(self, request, response):
x, y, theta = self.calc_position(request.num, 3)
for n in range(len(theta)):
self.req_spawn.x = x[n] + self.center_x
self.req_spawn.y = y[n] + self.center_y
self.req_spawn.theta = theta[n]
self.spawn.call_async(self.req_spawn)
response.x = x
response.y = y
response.theta = theta
return response
def main(args=None):
rp.init(args=args)
multi_spawn = MultiSpawning()
rp.spin(multi_spawn)
rp.shutdown()
if __name__ == '__main__':
main()
자율주행로봇 전문기업 트위니 기업 특강[트위니 천홍석 대표이사]
자율주행 물류로봇 전문기업 | 주식회사 트위니
주요 제품: 자율주행물류로봇(나르고 오더피킹, 나르고 팩토리)
AI
인간의 지능을 모방
인공 신경망
파라미터 조정을 통한 학습
학습: 모델의 파라미터(가중치)를 데이터로부터 최적화하는 과정
추론: 학습이 완료된 모델로 새로운 입력에 대한 출력을 계산하는 과정
GPU: 병렬 연산에 특화된 범용 프로세서
행렬 연산, 벡터 연산을 대규모 병렬로 처리
원래 그래픽 렌더링 목적 → AI/딥러닝 연산에 전용
NPU : 신경망 연산만을 위해 설계된 전용 프로세서
행렬 곱셈, 활성화 함수 등 딥러닝 특화 연산만 처리
GPU보다 전력 효율 높음, 속도 빠름
HVM: CPU 하드웨어 수준에서 가상화를 지원하는 기술
소프트웨어만으로 하드웨어를 에뮬레이션하면 느림
CPU 자체에 가상화 명령어 내장 → 오버헤드 최소화
학습
지도: 정답 레이블이 있는 데이터로 학습
비지도 : 정답 레이블 없이 데이터의 구조/패턴을 스스로 파악
강화: 에이전트가 환경과 상호작용하며 보상을 최대화하는 정책을 학습
뉴럴 네트워크 -> 수학적 접근은 어디?
딥러닝의 과정은? 알수 없음
이제와서 뉴럴 네트워크 붐이 된 이유
하드웨어(그래픽카드)의 성능이 올라가면서 학습 시간이 줄어듦
에이전트 AI
목표가 주어지면 스스로 계획을 세우고, 도구를 사용하며, 행동을 순차적으로 실행하는 AI 시스템단순히 질문에 답하는 것을 넘어서 "무엇을 어떻게 할지"를 스스로 결정하고 실행
Physical AI =/= 휴머노이드
휴머노이드에는 AI가 없음(과거 기준)
이제는 수학적인 연산보다 딥러닝으로
이전엔 관절 하나하나를 수학적 연산으로 통제했으나 현재는 딥러닝으로
AI 기반 사고를 하는 옵티머스(테슬라)는 Physical AI라 할 수 있음
테슬라(자동차)에는 카메라가 전부 달려 있음 -> 운전 데이터를 가져와 학습
AI vs Physical AI
모터(관절)의 차이
사람을 모사하여 생각하고 관절을 통한 Output
사람이 기존에 머리 써서 하던 일을 컴퓨터가 대신 하는 것
ㄴ> 사람이 기존에 머리+관절을 써서 하던 일을 기계가 대신 하는 것
협동 로봇
사람과 같은 공간에서 직접 상호작용하며 작업하도록 설계된 로봇기존 산업용 로봇과 달리
사람을 대체하는 것이 아닌 사람과 협력하는 것이 목적
공장의 로봇 팔 같은 것
먼저 생각할 것(생산성, 비용절감, 효율성)
휴머노이드, 견마로봇(스팟) -> 더 저렴하고 효율적이게 대체 가능
시장에서 팔릴 수 없음
공학적으로 어려운 것이 중요한 것이 아님
오더피킹
물류센터에서 작업자가 보관용 랙에 담긴 물품을 가져올 때 미리 주문 건별로 물품을 구분하여 포장 장소로 가져오는 방식
현재
물류 70% 공장 30%
계획
테슬라 휴머노이드에 올릴 소프트웨어
ROS2 이어서
빌드
steezer@DESKTOP-TF8J569:~/ros2_study$ rm -rf build install log
steezer@DESKTOP-TF8J569:~/ros2_study$ colcon build
[0.807s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/steezer/ros2_study/install/my_first_package_msgs' in the environment variable AMENT_PREFIX_PATH doesn't exist
[0.807s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/steezer/ros2_study/install/my_first_package' in the environment variable AMENT_PREFIX_PATH doesn't exist
[0.808s] WARNING:colcon.colcon_ros.prefix_path.catkin:The path '/home/steezer/ros2_study/install/my_first_package_msgs' in the environment variable CMAKE_PREFIX_PATH doesn't exist
Starting >>> my_first_package
Starting >>> my_first_package_msgs
Finished <<< my_first_package [0.90s]
Finished <<< my_first_package_msgs [5.47s]
Summary: 2 packages finished [6.12s]
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 run turtlesim turtlesim_node
[INFO] [1773630353.650666672] [turtlesim]: Starting turtlesim with node name /turtlesim
[INFO] [1773630353.661893072] [turtlesim]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 run my_first_package my_service_server
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 service call /multi_spawn my_first_package_msgs/srv/MultiSpawn "{num: 9}"
waiting for service to become available...
requester: making request: my_first_package_msgs.srv.MultiSpawn_Request(num=9)
response:
my_first_package_msgs.srv.MultiSpawn_Response(x=[3.0, 2.298133329356934, 0.5209445330007912, -1.4999999999999993, -2.819077862357725, -2.8190778623577253, -1.5000000000000013, 0.5209445330007899, 2.2981333293569333], y=[0.0, 1.9283628290596178, 2.954423259036624, 2.598076211353316, 1.0260604299770066, -1.026060429977006, -2.598076211353315, -2.9544232590366244, -1.9283628290596186], theta=[0.0, 0.6981317007977318, 1.3962634015954636, 2.0943951023931953, 2.792526803190927, 3.490658503988659, 4.1887902047863905, 4.886921905584122, 5.585053606381854])


액션 익숙해지기
steezer@DESKTOP-TF8J569:~/ros2_study/src$ cd my_first_package_msgs/
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package_msgs$ mkdir action
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package_msgs$ ls
action build CMakeLists.txt include install log msg package.xml src srv
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package_msgs$

# Request
float32 linear_x
float32 angular_z
float32 dist
---
# Result
float32 pos_x
float32 pos_y
float32 pos_theta
float32 result_dist
---
# Feedback
float32 remained_dist

"action/DistTuretle.action"

<depend>action_msgs</depend>
my_first_package / my_first_package / dist_turtle_action_server.py
import rclpy as rp
from rclpy.action import ActionServer
from rclpy.node import Node
from my_first_package_msgs.action import DistTurtle
class DistTurtleServer(Node):
def __init__(self):
super().__init__('dist_turtle_action_server')
self._action_server = ActionServer(
self,
DistTurtle,
'dist_turtle',
self.execute_callback)
def execute_callback(self, goal_handle):
goal_handle.succeed()
result = DistTurtle.Result()
return result
def main(args=None):
rp.init(args=args)
dist_turtle_action_server = DistTurtleServer()
rp.spin(dist_turtle_action_server)
if __name__ == '__main__':
main()
setup.py
entry_points={
'console_scripts': [
'my_first_node = my_first_package.my_first_node:main',
'my_subscriber = my_first_package.my_subscriber:main',
'my_publisher = my_first_package.my_publisher:main',
'turtle_cmd_and_pose = my_first_package.turtle_cmd_and_pose:main',
'my_service_server = my_first_package.my_service_server:main',
'dist_turtle_action_server = my_first_package.dist_turtle_action_server:main'
],
},
)
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 run my_first_package dist_turtle_action_server
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 action send_goal /dist_turtle my_first_package_msgs/action/DistTurtle "{'linear_x': 0, 'angular_z': 0, 'dist': 0}"
Waiting for an action server to become available...
Sending goal:
linear_x: 0.0
angular_z: 0.0
dist: 0.0
Goal accepted with ID: b0ee19a3499d4620809894e42a568b38
Result:
pos_x: 0.0
pos_y: 0.0
pos_theta: 0.0
result_dist: 0.0
Goal finished with status: SUCCEEDED
dist_turtle_action_server.py 수정
import rclpy as rp
from rclpy.action import ActionServer
from rclpy.node import Node
import time
from my_first_package_msgs.action import DistTurtle
class DistTurtleServer(Node):
def __init__(self):
super().__init__('dist_turtle_action_server')
self._action_server = ActionServer(
self,
DistTurtle,
'dist_turtle',
self.execute_callback)
def execute_callback(self, goal_handle):
feedback_msg = DistTurtle.Feedback()
for n in range(0,10):
feedback_msg.remained_dist = float(n)
goal_handle.publish_feedback(feedback_msg)
time.sleep(0.5)
goal_handle.succeed()
result = DistTurtle.Result()
return result
def main(args=None):
rp.init(args=args)
dist_turtle_action_server = DistTurtleServer()
rp.spin(dist_turtle_action_server)
if __name__ == '__main__':
main()
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 run my_first_package dist_turtle_action_server
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 action send_goal --feedback /dist_turtle my_first_package_msgs/action/DistTurtle "{'linear_x': 0, 'angular_z': 0, 'dist': 0}"
Waiting for an action server to become available...
Sending goal:
linear_x: 0.0
angular_z: 0.0
dist: 0.0
Goal accepted with ID: 81e2be7d5697416194334182519a677d
Feedback:
remained_dist: 0.0
Feedback:
remained_dist: 1.0
Feedback:
remained_dist: 2.0
Feedback:
remained_dist: 3.0
Feedback:
remained_dist: 4.0
Feedback:
remained_dist: 5.0
Feedback:
remained_dist: 6.0
Feedback:
remained_dist: 7.0
Feedback:
remained_dist: 8.0
Feedback:
remained_dist: 9.0
Result:
pos_x: 0.0
pos_y: 0.0
pos_theta: 0.0
result_dist: 0.0
Goal finished with status: SUCCEEDED
ROS2 Multi Thread 기초
my_first_package/ my_first_package/ my_multithread.py
import rclpy as rp
from rclpy.executors import MultiThreadedExecutor
from rclpy.node import Node
from my_first_package.my_publisher import TurtlesimPublisher
from my_first_package.my_subscriber import TurtlesimSubscriber
def main(args=None):
rp.init()
sub = TurtlesimSubscriber()
pub = TurtlesimPublisher()
executor = MultiThreadedExecutor()
executor.add_node(sub)
executor.add_node(pub)
try:
executor.spin()
finally:
executor.shutdown()
#sub.destroy_node()
pub.destroy_node()
rp.shutdown()
if __name__ == '__main__':
main()
entry_points={
'console_scripts': [
'my_first_node = my_first_package.my_first_node:main',
'my_subscriber = my_first_package.my_subscriber:main',
'my_publisher = my_first_package.my_publisher:main',
'turtle_cmd_and_pose = my_first_package.turtle_cmd_and_pose:main',
'my_service_server = my_first_package.my_service_server:main',
'dist_turtle_action_server = my_first_package.dist_turtle_action_server:main',
'my_multi_thread = my_first_package.my_multi_thread:main'
],
},
)
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 run turtlesim turtlesim_node
steezer@DESKTOP-TF8J569:~$ cd ros2_study
steezer@DESKTOP-TF8J569:~/ros2_study$ rm -rf build install log
steezer@DESKTOP-TF8J569:~/ros2_study$ colcon build
[0.340s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/steezer/ros2_study/install/my_first_package_msgs' in the environment variable AMENT_PREFIX_PATH doesn't exist
[0.340s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/steezer/ros2_study/install/my_first_package' in the environment variable AMENT_PREFIX_PATH doesn't exist
[0.340s] WARNING:colcon.colcon_ros.prefix_path.catkin:The path '/home/steezer/ros2_study/install/my_first_package_msgs' in the environment variable CMAKE_PREFIX_PATH doesn't exist
Starting >>> my_first_package
Starting >>> my_first_package_msgs
Finished <<< my_first_package [0.81s]
Finished <<< my_first_package_msgs [6.08s]
Summary: 2 packages finished [6.33s]
ros2 run my_first_package my_multi_thread
X : 6.399092197418213 , Y : 6.052364349365234
X : 6.414387226104736 , Y : 6.080472469329834
X : 6.428775787353516 , Y : 6.109055042266846
X : 6.44224214553833 , Y : 6.1380839347839355
X : 6.45477294921875 , Y : 6.16752815246582
X : 6.466355323791504 , Y : 6.19735860824585
X : 6.476977348327637 , Y : 6.22754430770874
X : 6.48662805557251 , Y : 6.258054256439209
X : 6.495297431945801 , Y : 6.288857460021973


코드, 데이터, 힙은 공유
스택은 별도로
프로세스 안에서 스택 데이터만 나눠서 할당 받음 -> 프로세스 스레드
지정한 거리만큼 이동하는 액션 서버 만들기
import rclpy as rp
from rclpy.action import ActionServer
from rclpy.executors import MultiThreadedExecutor
from rclpy.node import Node
from turtlesim.msg import Pose
from geometry_msgs.msg import Twist
from my_first_package_msgs.action import DistTurtle
from my_first_package.my_subscriber import TurtlesimSubscriber
import math
import time
class TurtleSub_Action(TurtlesimSubscriber):
def __init__(self, ac_server):
super().__init__()
self.ac_server = ac_server
def callback(self, msg):
self.ac_server.current_pose = msg
class DistTurtleServer(Node):
def __init__(self):
super().__init__('dist_turtle_action_server')
self.total_dist = 0
self.is_first_time = True
self.current_pose = Pose()
self.previous_pose = Pose()
self.publisher = self.create_publisher(Twist, '/turtle1/cmd_vel', 10)
self._action_server = ActionServer(self, DistTurtle, 'dist_turtle', self.execute_callback)
def calc_diff_pose(self):
if self.is_first_time:
self.previous_pose.x = self.current_pose.x
self.previous_pose.y = self.current_pose.y
self.is_first_time = False
diff_dist = math.sqrt((self.current_pose.x - self.previous_pose.x)**2 +\
(self.current_pose.y - self.previous_pose.y)**2)
self.previous_pose = self.current_pose
return diff_dist
def execute_callback(self, goal_handle):
feedback_msg = DistTurtle.Feedback()
msg = Twist()
msg.linear.x = goal_handle.request.linear_x
msg.angular.z = goal_handle.request.angular_z
while True:
self.total_dist += self.calc_diff_pose()
feedback_msg.remained_dist = goal_handle.request.dist - self.total_dist
goal_handle.publish_feedback(feedback_msg)
self.publisher.publish(msg)
time.sleep(0.01)
if feedback_msg.remained_dist < 0.2:
break
goal_handle.succeed()
result = DistTurtle.Result()
result.pos_x = self.current_pose.x
result.pos_y = self.current_pose.y
result.pos_theta = self.current_pose.theta
result.result_dist = self.total_dist
self.total_dist = 0
self.is_first_time = True
return result
def main(args=None):
rp.init(args=args)
executor = MultiThreadedExecutor()
ac = DistTurtleServer()
sub = TurtleSub_Action(ac_server = ac)
executor.add_node(sub)
executor.add_node(ac)
try:
executor.spin()
finally:
executor.shutdown()
sub.destroy_node()
ac.destroy_node()
rp.shutdown()
if __name__ == '__main__':
main()
액션 서버 간단히 사용해보기
steezer@DESKTOP-TF8J569:~/ros2_study$ rm -rf build install log
steezer@DESKTOP-TF8J569:~/ros2_study$ colcon build
[0.335s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/steezer/ros2_study/install/my_first_package_msgs' in the environment variable AMENT_PREFIX_PATH doesn't exist
[0.335s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/steezer/ros2_study/install/my_first_package' in the environment variable AMENT_PREFIX_PATH doesn't exist
[0.335s] WARNING:colcon.colcon_ros.prefix_path.catkin:The path '/home/steezer/ros2_study/install/my_first_package_msgs' in the environment variable CMAKE_PREFIX_PATH doesn't exist
Starting >>> my_first_package
Starting >>> my_first_package_msgs
Finished <<< my_first_package [0.82s]
Finished <<< my_first_package_msgs [6.01s]
Summary: 2 packages finished [6.26s]
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 run turtlesim turtlesim_node
[INFO] [1773642671.492339381] [turtlesim]: Starting turtlesim with node name /turtlesim
[INFO] [1773642671.496131775] [turtlesim]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 run my_first_package dist_turtle_action_server
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 action send_goal --feedback /dist_turtle my_first_package_msgs/action/DistTurtle "{'linear_x': 0.8, 'angular_z': 0.4, 'dist': 2.}"
Waiting for an action server to become available...
Sending goal:
linear_x: 0.8
angular_z: 0.4
dist: 2.0
Goal accepted with ID: 59444f6920aa41b3a4e95a62fdcb29e1
Feedback:
remained_dist: 2.0
Feedback:
remained_dist: 1.9872000217437744
Feedback:
remained_dist: 1.9872000217437744
Feedback:
remained_dist: 1.9872000217437744
Feedback:
remained_dist: 1.9616000652313232
Feedback:
remained_dist: 1.9616000652313232
Feedback:
remained_dist: 1.948799967765808
Feedback:
remained_dist: 1.9360003471374512
Feedback:
remained_dist: 1.859204649925232
Feedback:
remained_dist: 1.8464049100875854
Feedback:
remained_dist: 1.8336046934127808
Feedback:
remained_dist: 1.8336046934127808
Feedback:
remained_dist: 1.7952051162719727
Feedback:
remained_dist: 1.680021047592163
Feedback:
remained_dist: 1.552042841911316
Feedback:
remained_dist: 1.5392423868179321
Feedback:
remained_dist: 1.5392423868179321
Feedback:
remained_dist: 1.5264426469802856
Feedback:
remained_dist: 1.5264426469802856
Feedback:
remained_dist: 1.5008429288864136
Feedback:
remained_dist: 1.4880427122116089
Feedback:
remained_dist: 1.4880427122116089
Feedback:
remained_dist: 1.4752426147460938
Feedback:
remained_dist: 1.4752426147460938
Feedback:
remained_dist: 1.4496427774429321
Feedback:
remained_dist: 1.436842918395996
Feedback:
remained_dist: 1.436842918395996
Feedback:
remained_dist: 1.424042820930481
Feedback:
remained_dist: 1.4112427234649658
Feedback:
remained_dist: 1.4112427234649658
Feedback:
remained_dist: 1.3984428644180298
Feedback:
remained_dist: 1.3856427669525146
Feedback:
remained_dist: 1.3728429079055786
Feedback:
remained_dist: 1.3728429079055786
Feedback:
remained_dist: 1.360042929649353
Feedback:
remained_dist: 1.347243070602417
Feedback:
remained_dist: 1.347243070602417
Feedback:
remained_dist: 1.3344428539276123
Feedback:
remained_dist: 1.3216427564620972
Feedback:
remained_dist: 1.3216427564620972
Feedback:
remained_dist: 1.3088430166244507
Feedback:
remained_dist: 1.296042799949646
Feedback:
remained_dist: 1.296042799949646
Feedback:
remained_dist: 1.2832428216934204
Feedback:
remained_dist: 1.2832428216934204
Feedback:
remained_dist: 1.2576431035995483
Feedback:
remained_dist: 1.2448428869247437
Feedback:
remained_dist: 1.2448428869247437
Feedback:
remained_dist: 1.2320430278778076
Feedback:
remained_dist: 1.219243049621582
Feedback:
remained_dist: 1.219243049621582
Feedback:
remained_dist: 1.2064430713653564
Feedback:
remained_dist: 1.1936428546905518
Feedback:
remained_dist: 1.1936428546905518
Feedback:
remained_dist: 1.1808429956436157
Feedback:
remained_dist: 1.1680428981781006
Feedback:
remained_dist: 1.1424429416656494
Feedback:
remained_dist: 1.1296430826187134
Feedback:
remained_dist: 1.1296430826187134
Feedback:
remained_dist: 1.1168432235717773
Feedback:
remained_dist: 1.1040431261062622
Feedback:
remained_dist: 1.1040431261062622
Feedback:
remained_dist: 1.0912432670593262
Feedback:
remained_dist: 1.078443169593811
Feedback:
remained_dist: 1.065643072128296
Feedback:
remained_dist: 1.0528430938720703
Feedback:
remained_dist: 1.0272432565689087
Feedback:
remained_dist: 1.0144431591033936
Feedback:
remained_dist: 1.0144431591033936
Feedback:
remained_dist: 0.988843560218811
Feedback:
remained_dist: 0.9760433435440063
Feedback:
remained_dist: 0.9760433435440063
Feedback:
remained_dist: 0.9632435441017151
Feedback:
remained_dist: 0.9504435062408447
Feedback:
remained_dist: 0.9504435062408447
Feedback:
remained_dist: 0.9376433491706848
Feedback:
remained_dist: 0.9248433113098145
Feedback:
remained_dist: 0.9248433113098145
Feedback:
remained_dist: 0.912043571472168
Feedback:
remained_dist: 0.8992432355880737
Feedback:
remained_dist: 0.8992432355880737
Feedback:
remained_dist: 0.8864436149597168
Feedback:
remained_dist: 0.8864436149597168
Feedback:
remained_dist: 0.8480438590049744
Feedback:
remained_dist: 0.8480438590049744
Feedback:
remained_dist: 0.8352438807487488
Feedback:
remained_dist: 0.8224440217018127
Feedback:
remained_dist: 0.8096436262130737
Feedback:
remained_dist: 0.7968440055847168
Feedback:
remained_dist: 0.7840439677238464
Feedback:
remained_dist: 0.7712438106536865
Feedback:
remained_dist: 0.7712438106536865
Feedback:
remained_dist: 0.7584436535835266
Feedback:
remained_dist: 0.7456438541412354
Feedback:
remained_dist: 0.7456438541412354
Feedback:
remained_dist: 0.7328441143035889
Feedback:
remained_dist: 0.7328441143035889
Feedback:
remained_dist: 0.7328441143035889
Feedback:
remained_dist: 0.6944441795349121
Feedback:
remained_dist: 0.6176490187644958
Feedback:
remained_dist: 0.592049241065979
Feedback:
remained_dist: 0.592049241065979
Feedback:
remained_dist: 0.5792491436004639
Feedback:
remained_dist: 0.5664488673210144
Feedback:
remained_dist: 0.5536492466926575
Feedback:
remained_dist: 0.5408493876457214
Feedback:
remained_dist: 0.5152494311332703
Feedback:
remained_dist: 0.5024494528770447
Feedback:
remained_dist: 0.5024494528770447
Feedback:
remained_dist: 0.4896491765975952
Feedback:
remained_dist: 0.4896491765975952
Feedback:
remained_dist: 0.46404948830604553
Feedback:
remained_dist: 0.45124953985214233
Feedback:
remained_dist: 0.4384492337703705
Feedback:
remained_dist: 0.4384492337703705
Feedback:
remained_dist: 0.42564940452575684
Feedback:
remained_dist: 0.41284945607185364
Feedback:
remained_dist: 0.41284945607185364
Feedback:
remained_dist: 0.4000492990016937
Feedback:
remained_dist: 0.4000492990016937
Feedback:
remained_dist: 0.3488506078720093
Feedback:
remained_dist: 0.33605068922042847
Feedback:
remained_dist: 0.32325077056884766
Feedback:
remained_dist: 0.27205201983451843
Feedback:
remained_dist: 0.27205201983451843
Feedback:
remained_dist: 0.22085340321063995
Feedback:
remained_dist: 0.20805321633815765
Feedback:
remained_dist: 0.19525322318077087
Result:
pos_x: 7.11163854598999
pos_y: 6.310008525848389
pos_theta: 0.902400016784668
result_dist: 1.8047467470169067
Goal finished with status: SUCCEEDED

main
멀티스레드 적용
TurtleSub_action
pose 토픽 구독
DistTurtleServer
사용자가 지정한 거리만큼 이동
10장 Parameter 다루기
책이 입문자라 생략된 내용 있음
조사할 것
1. yaml이라는 형식은 어떤 것이고, 어떻게 사용하는가?
Yet Another Markup Language
데이터를 구조적으로 표현하기 위한 텍스트 기반 데이터 직렬화 형식
주로 설정 파일, 데이터 교환에 사용되며 JSON보다 가독성이 높음
2. yaml과 ros parameter가 어떤 관계인가?
ros parameter
노드가 실행될 때 외부에서 주입할 수 있는 변수
코드를 수정하고 재빌드하지 않아도 노드의 동작을 바꿀 수 있음
YAML(YAML Ain't Markup Language)은 서로 다른 데이터 구조를 가진 언어들 간의 데이터 교환을 위해 설계된, 사람이 읽기 쉬운 데이터 직렬화(Data Serialization) 언어
주로 설정(Configuration) 파일 작성, 시스템 간 데이터 교환, 그리고 복잡한 데이터 구조를 직관적이고 읽기 쉬운 형태로 표현하는 데 사용
주요 특징 (Key Features)
가독성 (Human Readable): 사람과 기계 모두가 직관적으로 읽고 쓰기 쉬움
언어 독립성 (Language Independent): 특정 프로그래밍 언어에 종속되지 않으며 다양한 플랫폼에서 작동
계층적 구조 (Hierarchical): 들여쓰기를 통해 복잡하게 중첩된(Nested) 데이터 구조를 쉽게 지원
확장성 (Extensible): 사용자 정의 데이터 타입(Custom data types)을 추가하여 확장 가능
보안성 (Secure): 처음부터 보안을 고려하여 설계
AML은 복잡한 기호나 괄호 대신, 들여쓰기(Space)와 하이픈(-), 콜론(:)만으로 데이터 구조를 표현
# 1. 주석은 '#' 기호를 사용합니다.
# 2. Key와 Value 사이에는 반드시 콜론(:) 뒤에 띄어쓰기가 하나 있어야 합니다.
이름: 김로봇
나이: 25
학생여부: true
# 리스트(배열)는 같은 들여쓰기 라인에서 하이픈(-)으로 시작합니다.
사용언어:
- Python
- C++
- JavaScript
# 중첩된 데이터(딕셔너리)는 들여쓰기(보통 스페이스 2칸)로 계층을 표현합니다.
연락처:
이메일: robot@example.com
전화번호: "010-1234-5678" # 숫자로만 된 문자열은 따옴표로 묶어주는 것이 안전합니다.
steezer@DESKTOP-TF8J569:~$ ros2 run turtlesim turtlesim_node
[INFO] [1773648302.436125131] [turtlesim]: Starting turtlesim with node name /turtlesim
[INFO] [1773648302.448123061] [turtlesim]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
ROS2 humble is activated!
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.
steezer@DESKTOP-TF8J569:~$ ros2 param list
/teleop_turtle:
qos_overrides./parameter_events.publisher.depth
qos_overrides./parameter_events.publisher.durability
qos_overrides./parameter_events.publisher.history
qos_overrides./parameter_events.publisher.reliability
scale_angular
scale_linear
use_sim_time
/turtlesim:
background_b
background_g
background_r
qos_overrides./parameter_events.publisher.depth
qos_overrides./parameter_events.publisher.durability
qos_overrides./parameter_events.publisher.history
qos_overrides./parameter_events.publisher.reliability
use_sim_time
steezer@DESKTOP-TF8J569:~$ ros2 param get /turtlesim background_g
Integer value is: 86
steezer@DESKTOP-TF8J569:~$ ros2 param set /turtlesim background_r 250
Set parameter successful
steezer@DESKTOP-TF8J569:~$ ros2 param set /turtlesim background_b 250
Set parameter successful
steezer@DESKTOP-TF8J569:~$ ros2 param set /turtlesim background_g 250
Set parameter successful

steezer@DESKTOP-TF8J569:~$ cd ros2_study/src/my_first_package
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package$ mkdir params
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package$ cd params
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package/params$ ros2 param dump /turtlesim > turtlesim.yaml
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package/params$ ls
turtlesim.yaml
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package/params$ cd src
-bash: cd: src: No such file or directory
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package/params$ cd ..
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package$ cd ..
steezer@DESKTOP-TF8J569:~/ros2_study/src$ subl .
/turtlesim:
ros__parameters:
background_b: 250
background_g: 250
background_r: 250
qos_overrides:
/parameter_events:
publisher:
depth: 1000
durability: volatile
history: keep_last
reliability: reliable
use_sim_time: false
191 * 3
/turtlesim:
ros__parameters:
background_b: 191
background_g: 191
background_r: 191
qos_overrides:
/parameter_events:
publisher:
depth: 1000
durability: volatile
history: keep_last
reliability: reliable
use_sim_time: false
steezer@DESKTOP-TF8J569:~/ros2_study/src/my_first_package/params$ ros2 param load /turtlesim ./turtlesim.yaml
Set parameter background_b successful
Set parameter background_g successful
Set parameter background_r successful
Set parameter qos_overrides./parameter_events.publisher.depth failed: parameter 'qos_overrides./parameter_events.publisher.depth' cannot be set because it is read-only
Set parameter qos_overrides./parameter_events.publisher.durability failed: parameter 'qos_overrides./parameter_events.publisher.durability' cannot be set because it is read-only
Set parameter qos_overrides./parameter_events.publisher.history failed: parameter 'qos_overrides./parameter_events.publisher.history' cannot be set because it is read-only
Set parameter qos_overrides./parameter_events.publisher.reliability failed: parameter 'qos_overrides./parameter_events.publisher.reliability' cannot be set because it is read-only
Set parameter use_sim_time successful

코드로 접근하는 파라미터
import rclpy as rp
from rclpy.action import ActionServer
from rclpy.executors import MultiThreadedExecutor
from rclpy.node import Node
from turtlesim.msg import Pose
from geometry_msgs.msg import Twist
from my_first_package_msgs.action import DistTurtle
from my_first_package.my_subscriber import TurtlesimSubscriber
import math
import time
class TurtleSub_Action(TurtlesimSubscriber):
def __init__(self, ac_server):
super().__init__()
self.ac_server = ac_server
def callback(self, msg):
self.ac_server.current_pose = msg
class DistTurtleServer(Node):
def __init__(self):
super().__init__('dist_turtle_action_server')
self.total_dist = 0
self.is_first_time = True
self.current_pose = Pose()
self.previous_pose = Pose()
self.declare_parameter('quatile_time', 0.75)
self.declare_parameter('almost_goal_time', 0.95)
self.publisher = self.create_publisher(Twist, '/turtle1/cmd_vel', 10)
self._action_server = ActionServer(self, DistTurtle, 'dist_turtle', self.execute_callback)
def calc_diff_pose(self):
if self.is_first_time:
self.previous_pose.x = self.current_pose.x
self.previous_pose.y = self.current_pose.y
self.is_first_time = False
diff_dist = math.sqrt((self.current_pose.x - self.previous_pose.x)**2 +\
(self.current_pose.y - self.previous_pose.y)**2)
self.previous_pose = self.current_pose
return diff_dist
def execute_callback(self, goal_handle):
feedback_msg = DistTurtle.Feedback()
msg = Twist()
msg.linear.x = goal_handle.request.linear_x
msg.angular.z = goal_handle.request.angular_z
while True:
self.total_dist += self.calc_diff_pose()
feedback_msg.remained_dist = goal_handle.request.dist - self.total_dist
goal_handle.publish_feedback(feedback_msg)
self.publisher.publish(msg)
time.sleep(0.01)
if feedback_msg.remained_dist < 0.2:
break
goal_handle.succeed()
result = DistTurtle.Result()
result.pos_x = self.current_pose.x
result.pos_y = self.current_pose.y
result.pos_theta = self.current_pose.theta
result.result_dist = self.total_dist
self.total_dist = 0
self.is_first_time = True
return result
def main(args=None):
rp.init(args=args)
executor = MultiThreadedExecutor()
ac = DistTurtleServer()
sub = TurtleSub_Action(ac_server = ac)
executor.add_node(sub)
executor.add_node(ac)
try:
executor.spin()
finally:
executor.shutdown()
sub.destroy_node()
ac.destroy_node()
rp.shutdown()
if __name__ == '__main__':
main()
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 param list
/dist_turtle_action_server:
almost_goal_time
quatile_time
use_sim_time
/turtlesim_subscriber:
use_sim_time
steezer@DESKTOP-TF8J569:~/ros2_study$ ros2 param get /dist_turtle_action_server quatile_time
Double value is: 0.75'로보테크AI' 카테고리의 다른 글
| 융합_로보테크 AI 자율주행 로봇 개발자 과정-26/03/18[ML, DL] (0) | 2026.03.18 |
|---|---|
| 융합_로보테크 AI 자율주행 로봇 개발자 과정-26/03/17 (0) | 2026.03.17 |
| 융합_로보테크 AI 자율주행 로봇 개발자 과정-26/03/13 +자소서 특강 (0) | 2026.03.13 |
| 융합_로보테크 AI 자율주행 로봇 개발자 과정-26/03/12 (0) | 2026.03.12 |
| 융합_로보테크 AI 자율주행 로봇 개발자 과정-26/03/11[ROS2] (0) | 2026.03.11 |