Ch5. Python์ผ๋ก ์๋น์ค ํด๋ผ์ด์ธํธ ๋ค๋ฃจ๊ธฐ์ ๋ํด์ ์์๋ณด๊ณ ์ ํ๋ค.
์ด๋ฒ ์ฅ์์๋ ์์์ ํ ํฝ์ ๋ฐํํ๊ณ ๊ตฌ๋ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์ด์ผ๊ธฐํ ๊ฒ์ฒ๋ผ ์๋ฒ๊ฐ ๋ง๋ค์ด์ ธ ์๋ ์๋น์ค ํด๋ผ์ด์ธํธ๋ฅผ ๊ตฌ์ฑํ๋ Python ์ฝ๋๋ฅผ ๋ค๋ค๋ณผ ๊ฒ์ด๋ค. ์ดํ ๋ค์์๋ ํจํค์ง๋ฅผ ์ง์ ๋ง๋๋ ๋จ๊ณ์์์ ์๋น์ค ์๋ฒ๋ฅผ ๊ตฌ์ฑํ๊ณ ๋๋ง์ ๋ฉ์์ง ํ์ ์ ์ ์ํด ๋ณผ ๊ฒ์ด๋ค.
1. ์ค๋น ๋ฐ Service Client ๋ ธ๋ ์์ฑ
๊ฐ์ฅ ๋จผ์ ์ค๋น์ Sercive Client๋ฅผ ์ํ ๋ ธ๋๋ฅผ ์์ฑํ๋ค. ์ด๋ ์ค๋น๋ jupyter notebook์ home\python ์์ ์ด๊ณ , ros2 run turtlesim turtlesim_node ๋ช ๋ น์ ์ด์ฉํด ํฐํ์ฌ์ ์คํํ๋ค.
์ฌ๊ธฐ์ Service Client Test๋ผ๋ ipynb ํ์ผ์ ๋ง๋ ๋ค.
์ด๋ฒ์ ํ๊ณ ์ ํ๋ ๊ฒ
: /turtle1/teleport_absolute ์๋น์ค๋ฅผ Python์ผ๋ก ์ ๊ทผํ๊ธฐ
>> ์๋น์ค ์ ์ : turtlesim.srv.TeleportAbsolute
import rclpy as rp
from turtlesim.srv import TeleportAbsolute
rp.init()
test_node = rp.create_node('client_test')
๋ค์ ์ฝ๋๋ฅผ ์ด์ฉํ์ฌ turtlesim.srv.TeleportAbsloute๋ฅผ import ํ ๋ค
rclpy๋ฅผ ์ด๊ธฐํ ํ๊ณ , client_test๋ผ๋ ์ด๋ฆ์ ๋ ธ๋๋ฅผ test_node๋ก ํ๋ ๋ง๋ค๋๋ก ํ๋ค.
์ด ์ฝ๋๊ฐ ์คํ๋๋ฉด test_node ๋ผ๋ ๋ณ์๋ rclpy์ create_node๊ฐ ๋ฐํํ node๋ผ๋ class๋ฅผ ๋ฐ๊ฒ ๋๋ค.
์ด ๋ป์ ์์๋ณด๊ธฐ ์ํด์ ๋จผ์ rclpy์ create_node ์ ์ค๋ช ์ ์ฐพ์๋ณธ๋ค๋ฉด https://docs.ros2.org/latest/api/rclpy/api/init_shutdown.html
Return type์ ์ ์ธ ๋งํฌ๋ฅผ ๋ฐ๋ผ๊ฐ๋ค๋ฉด ๊ฒฐ๊ตญ ๋ฆฌํด์ rclpy.node.Node๋ก ํด์ค๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก test_node๋ผ๋ ๋ณ์์ create_node ํด๋์ค๋ฅผ ์ง์ ํ์๋ค.
2. ์๋น์ค๋ฅผ ์์ฒญํ๋ service client ์์ฑ
service_name = '/turtle1/teleport_absolute'
cli = test_node.create_client(TeleportAbsolute, service_name)
์ด๋ ์ง๊ธ ๋ค๋ฃจ๋ ค๋ ์๋น์ค๊ฐ turtle1/teleop_absolute ์ด๊ธฐ ๋๋ฌธ์ service_name์ ์ด๋ฅผ ์ ์ฅํ ํ
cli๋ผ๋ ๋ณ์์ create_client ํจ์๋ฅผ ์ด์ฉํด ๋ฐ์ดํฐ ํ์ ์ด TeleportAbsolute์ธ ๊ฒ์ ์ ์ฅํจ.
3. ์๋น์ค ์ ์๋ฅผ Python์์ ์ฌ์ฉํ ์ค๋นํ๊ธฐ
์๋น์ค๋ ์์ฒญํ๋ฉด ์๋ต์ ๋ฐ๋ ๊ฒ์ผ๋ก, ๊ทธ๋์ ๋ฐ์ดํฐ ํ์ ์ srv ํ์ผ์ ์ ์ฅํ๋ค.
๋ํ ๊ทธ srv ํ์ผ์ ์๋น์ค ์ ์๋ผ๊ณ ํ๋ค. ๋ฐ๋ผ์ ํ์ฌ ์ง๊ธ turtle1/teleop_absolute ์๋น์ค๋ฅผ ๋ค๋ฃจ๊ธฐ ์ํด์ ๊ทธ ์๋น์ค์ ์ ์์ธ TeleportAbsolute๋ฅผ import ํ ์ํฉ์ด๋ค. ์ด์ importํ TeleportAbsolute๋ฅผ ์ฌ์ฉํ๊ณ ์ ํ๊ณ , ์ด๋ ์์ฒญ๊ณผ ์๋ต์ผ๋ก ๋๋์ด ์๊ธฐ ๋๋ฌธ์ ์์ฒญ ๋ถ๋ถ๋ง ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋ค์์ ์ฝ๋๋ฅผ ์์ฑํด์ผ ํ๋ค.
req = TeleportAbsolute.Request()
req
๊ทธ๋ฆฌ๊ณ ์ดํ req.x, req.y, req.theta๋ฅผ ๋ฐ๊พผ๋ค๋ฉด reqํ ๊ฐ์ด ๋ฌ๋ผ์ง๊ฒ ๋๋ค.
4. ๊ฐ๋จํ service call ์คํํ๊ธฐ
์ดํ ์ด ์ฝ๋๋ฅผ ํตํด ์์ฒญํ ์ค๋น๊ฐ ๋ค ๋์๊ณ , ์์ doc.ros2.org์์์ Return type์ ๋ณธ๋ค๋ฉด Client๋ก ๋์ด ์๊ธฐ ๋๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ ๋ช ๋ น์ด๋ฅผ ์์ฑํ๋ค.
req.x = 3.
cli.call_async(req)
rp.spin_once(test_node)
5. wait_for_service ์ฌ์ฉํด๋ณด๊ธฐ
์ง๊ธ๊ณผ ๊ฐ์ ์ฝ๋๋ ์์ turtlesim_node๊ฐ ์คํ๋๋ ๊ฒ์ฒ๋ผ ๋จผ์ ์คํ๋ผ์ผ ํ ์ฝ๋๊ฐ ์กด์ฌํด์ผ ํ๋ค.
ํ์ง๋ง ๊ทธ๋ ์ง ์์ ์ํฉ์ด ์์ ๋ ์๋ฌ๊ฐ ๋ ์ ์๊ธฐ ๋๋ฌธ์ wait_for_service๋ฅผ ์ด์ฉํ ์ ์๋ค.
๋ค์ ์ฝ๋๋ฅผ ์ ๋ ฅํด ๋ณด์.
req.y = float(9)
while not cli.wait_for_service(timeout_sec=1.0):
print("Waiting for service")
cli.call_async(req)
rp.spin_once(test_node)
์ด๋ while not ๋ถ๋ถ์ ํตํด์ ํด๋น ์๋น์ค๊ฐ ์คํ๋์ง ์์ผ๋ฉด False๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์คํ๋์ง ์์์ ๋ true๋ก ๋ฐ๊พธ์ด ๋ฉ์ถ๊ฒ ๋ง๋ ๋ค.
6. ์๋น์ค ํด๋ผ์ด์ธํธ๊ฐ ์คํ๋๋ ์ํฉ ํ์ธํ๊ธฐ
ROS2 ๋ฌธ์์์ sercive client๋ฅผ ์ค๋ช ํ๋ ๋ถ๋ถ์ ๋ณด๋ฉด call_async๋ Future๋ผ๋ ๊ฒ์ ๋ฐํํ๋ฉฐ ์ด๋ done()๊ณผ result()๋ผ๋ ํจ์๊ฐ ์๋น์ค ํด๋ผ์ด์ธํธ๋ฅผ ํธ์ถํ ํ์ ์ํฉ์ ์๋ ค์ค๋ค.
๋ฐ๋ผ์ ๋ค์์ ์ฝ๋๋ฅผ ํตํด์ future.done()์ด ์ ๊ณตํ๋ ์๋ฃ๊ฐ ๋ํ๋๋ future.done()์ด True๊ฐ ๋ ๋๊น์ง spin_once๋ฅผ ๊ณ์ ์คํ ํ ๋ค ์๋ฃ ๋๋ฉด Responce()๊ฐ ๋ช ์๋์ด ์๋น์ค๋ฅผ ์๋ฃ์ํจ๋ค.
req.x = float(9)
future = cli.call_async(req)
while not future.done():
rp.spin_once(test_node)
print(future.done(), future.result())
์ดํ ๋ค์ ๊ธ์์๋ Ch6. ROS2 ํ์ต์ ์ํ python class ์ดํดํ๊ธฐ์ ๋ํด์ ์์๋ณด๊ณ ์ ํ๋ค.
์๋ ํ์ผ์ ์ ipynb ํ์ผ์ ์ฌ๋ฆฐ ๊ฒ์ด๋ค.