๐ก ๋ณธ ๋ฌธ์๋ 'ROS TF ์ขํ๊ณ ๋ฐ ๋ณํ'์ ๋ํด ์ ๋ฆฌํด๋์ ๊ธ์ ๋๋ค.
์ด ํํ ๋ฆฌ์ผ์์๋ ROS๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ฐ์ผ ๋ก๋ด์ ํ์ค ์ขํ๊ณ(์: x,y,z ์ถ )์ ๊ธฐ๋ณธ ์ฌํญ์ ๋ค๋ฃน๋๋ค. ๋ํ ๊ธฐ๋ณธ์ ์ธ 2๋ฅ ์ฐจ๋ ๊ตฌ๋ ๋ชจ๋ฐ์ผ ๋ก๋ด ์ ์ขํ๊ณ๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ๋ ๋ค๋ฃฐ ๊ฒ์ด๋ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
1. Why Coordinate Frames Are Important?
๋ฐํด ๋ฌ๋ฆฐ ๋ก๋ด ์์ LIDAR๊ฐ ์ฅ์ฐฉ๋์ด ์๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. LIDAR์ ์๋ฌด๋ ํ๊ฒฝ ๋ด ๋ฌผ์ฒด๊น์ง์ ๊ฑฐ๋ฆฌ์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ ๋๋ค.
ํ์ง๋ง ์ฌ๊ธฐ์ LIDAR๋ ๋ณดํต ๋ก๋ด์ ์ค์ฌ์ ์ ์์นํ์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ์ค์ ์๋๋ฆฌ์ค์์๋ ๋ก๋ด์ด ํ๊ฒฝ์์ ์ด๋ํ ๋ ์ฅ์ ๋ฌผ์ ํผํ๋ ค๋ฉด LIDAR ์ขํ๊ณ์์ ๊ฐ์ง๋ ๊ฐ์ฒด์ ์ขํ๋ฅผ ๋ก๋ด ๋ฒ ์ด์ค ํ๋ ์์ ํด๋น ์ขํ๋ก ๋ณํํด์ผ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด LIDAR๋ 100cm ๋จ์ด์ง ๋ฌผ์ฒด๋ฅผ ๊ฐ์งํ๋๋ผ๋ LIDAR๊ฐ ๋ก๋ด์ ์ ๋ฉด๋ถ(๋ก๋ด ๋ฒ ์ด์ค ํ๋ ์์ ์ค์ฌ์ ์์ 10cm ์์ชฝ)์ ์ฅ์ฐฉ๋ ๊ฒฝ์ฐ, ๋ฌผ์ฒด๋ ์ค์ ๋ก ๋ก๋ด์ผ๋ก๋ถํฐ 110cm ๋จ์ด์ ธ ์์ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ ์ ํํ ์์จ์ฃผํ์ ์ํด์๋ ์ขํ ํ๋ ์๊ณผ ๋ฐ์ดํฐ๋ฅผ ํ ์ขํ ํ๋ ์์์ ๋ค๋ฅธ ์ขํ ํ๋ ์์ผ๋ก ๋ณํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
2. ๋ชจ๋ฐ์ผ ๋ก๋ด์ ์ํ ROS์ ํ์ค ์ขํ๊ณ
์๋๋ ๊ธฐ๋ณธ 2๋ฅ ์ฐจ๋ ๊ตฌ๋ ๋ก๋ด์ ํ์ค ์ขํ๊ณ์ ๋๋ค. ๋นจ๊ฐ์ ํ์ดํ๋ x์ถ, ํ๋์ ํ์ดํ๋ z์ถ, ๋ น์ ์ ์ y์ถ์ ๋ํ๋ ๋๋ค.
๊ณต์ ROS ๋ฌธ์์๋ ์ด๋ฌํ ์ขํ ํ๋ ์์ ๋ํ ์ค๋ช ์ด ์์ง๋ง ์ฃผ์ ์ขํ ํ๋ ์์ ๊ฐ๋ตํ๊ฒ ์ ์ํ๊ฒ ์ต๋๋ค.
- map ํ๋ ์์ world์์ ์์๋ก ์ ํํ ์ง์ ์์ ์์๋ฉ๋๋ค. ์ด ์ขํ๊ณ๋ world ์ขํ๊ณ์ ๊ณ ์ ๋์ด ์์ต๋๋ค.
- odom ํ๋ ์์ ๋ก๋ด์ด ์ด๊ธฐํ๋๋ ์ง์ ์์ ์์๋ฉ๋๋ค. ์ด ์ขํ๊ณ๋ world ์ขํ๊ณ์ ๊ณ ์ ๋์ด ์์ต๋๋ค.
- base_footprint ์ ์์ ์ ๋ก๋ด ์ค์ฌ ๋ฐ๋ก ์๋์ ์์ต๋๋ค. ๋ก๋ด์ 2D ํฌ์ฆ์ ๋๋ค. ์ด ์ขํ๊ณ๋ ๋ก๋ด์ด ์์ง์ผ ๋ ์์ง์ ๋๋ค.
- base_link ์ ์์ ์ ๋ก๋ด์ ํผ๋ฒ์ ์ด๋ ์ค์ฌ์ ์ง์ ์์ต๋๋ค. ์ด ์ขํ๊ณ๋ ๋ก๋ด์ด ์์ง์ผ ๋ ์์ง์ ๋๋ค.
- laser_link๋ ๋ ์ด์ ์ผ์(์: LIDAR)์ ์ค์ฌ์์ ์์๋ฉ๋๋ค. ์ด ์ขํ ํ๋ ์์ base_link๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ณ ์ ๋(์ฆ, "์ ์ ") ์ํ๋ก ์ ์ง๋ฉ๋๋ค.
๋ง์ฝ ๋ก๋ด์ IMU ์ ๊ฐ์ ๋ค๋ฅธ ์ผ์๊ฐ ์๋ ๊ฒฝ์ฐ, ์ด์ ๋ํ ์ขํ๊ณ๋ ๊ฐ์ง ์ ์์ต๋๋ค.
3. TF(Transform) Publisher: Static, Broadcaster
ํ ์ขํ๊ณ์ ๊ฒ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅธ ์ขํ๊ณ์ ํด๋น ๋ฐ์ดํฐ๋ก ์๋ ๋ณํํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํฉ๋๊น? ์๋ฅผ ๋ค์ด map ์ขํ๊ณ์ ์ขํ (x=3.7, y=1.23, z = 0.0)์ ๊ฐ์ฒด๊ฐ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๋ก๋ด์ ์ด ๊ฐ์ฒด๋ก ์ด๋์ํค๊ณ ์ถ์ต๋๋ค. base_link ์ขํ๊ณ๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฐ์ฒด์ ์์น๋ฅผ ์ด๋ป๊ฒ ์ ์ ์์๊น์? ๋คํํ ROS ์๋ ์ด๋ฌํ ๋ชจ๋ ์ขํ ๋ณํ์ ์ฒ๋ฆฌํ๋ tf๋ผ๋ ํจํค์ง๊ฐ ์์ต๋๋ค.
- ์ ์ ์ขํ๊ณ: ์๊ฐ์ด ์ง๋๋ ์๋ก ์๋์ ์ผ๋ก ๋ณํ์ง ์๋ ์ขํ ํ๋ ์์ ๊ฒฝ์ฐ(์: ๋ ์ด์ ๊ฐ ๋ก๋ด์ ๋ถ์ฐฉ๋์ด ์๊ธฐ ๋๋ฌธ์ base_link์ ๋ํ laser_link๊ฐ ์ ์ ์ผ๋ก ์ ์ง๋จ) Static Transform Publisher๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ๋์ ์ขํ๊ณ: ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์๋ก ์๋์ ์ผ๋ก ๋ณ๊ฒฝ๋๋ ์ขํ ํ๋ ์์ ๊ฒฝ์ฐ(์: base_link์ ๋งคํ) tf broadcasters and listeners๋ฅผ ์ฌ์ฉํฉ๋๋ค . ๋ง์ ROS ํจํค์ง๊ฐ ์ด๋ฌํ ์ด๋ ์ขํ๊ณ ๋ณํ์ ์ฒ๋ฆฌํ๋ฏ๋ก ์ง์ ์์ฑํ ํ์๊ฐ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
์์)
Static transform
ROS์์ ์ ์ ๋ณํ ๊ฒ์์๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๋ช ๊ฐ์ง ์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฌํ ์ ์ ๋ณํ ๊ฒ์์๋ ์ผ๋ฐ์ ์ผ๋ก ์์ ์ค์ธ ๋ก๋ด์ ๋ํ ์คํ ํ์ผ ๋ด๋ถ์ ๋ํ๋ฉ๋๋ค.
๊ตฌ๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_ms
ROS ์น์ฌ์ดํธ์์: “๋ฏธํฐ ๋จ์์ x/y/z ์คํ์ ๊ณผ ๋ผ๋์ ๋จ์์ ์/ํผ์น/๋กค์ ์ฌ์ฉํ์ฌ tf์ ์ ์ ์ขํ ๋ณํ์ ๊ฒ์ํฉ๋๋ค. (์๋ Z์ ๋ํ ํ์ , ํผ์น๋ Y์ ๋ํ ํ์ , ๋กค์ X์ ๋ํ ํ์ ) ๊ธฐ๊ฐ(๋ฐ๋ฆฌ์ด)์ ๋ณํ์ ๋ณด๋ด๋ ๋น๋๋ฅผ ์ง์ ํฉ๋๋ค. 100ms(10hz)๊ฐ ์ข์ ๊ฐ์ ๋๋ค.”
Map to Odom
์๋ฅผ ๋ค์ด, ์ง๋ ์ ์ฃผํ ๊ฑฐ๋ฆฌ ์ธก์ ํ๋ ์์ ๋๋ฑํ๊ฒ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด ROS ์คํ ํ์ผ ๋ด์ ์์ฑํ๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
<node pkg="tf" type="static_transform_publisher" name="map_to_odom" args="0 0 0 0 0 0 map odom 30" />
map -> odom ๋ณํ์ ์ง๋์ ์ขํ๊ณ(์ฆ, ์์) ๋ด๋ถ์์ ๋ก๋ด์ ์์์ (์ฆ, ํ์์ธ odom ์ขํ๊ณ)์ ์์น์ ๋ฐฉํฅ์ ์๋ ค์ค๋๋ค.
์์ ์์์๋ Odom ํ๋ ์์ด ์๊ฐ์ด ์ง๋๋ ๋งต ํ๋ ์์ ๊ธฐ์ค์ผ๋ก ์์ง์ด์ง ์๋๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
Odom to Base Footprint
odom -> base_footprint ๋ณํ์ ๋ก๋ด์ด ์ ์ธ๊ณ๋ฅผ ์ด๋ํ๊ธฐ ๋๋ฌธ์ ์ ์ ์ด ์๋๋๋ค. base_footprint ์ขํ๊ณ๋ ๋ฐํด๊ฐ ํ์ ํจ์ ๋ฐ๋ผ ์ง์์ ์ผ๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค. ์ด ๋น์ ์ ๋ณํ์ ์ข ์ข robots_pose_ekf ํจํค์ง ์ ๊ฐ์ ํจํค์ง์์ ์ ๊ณต๋ฉ๋๋ค .
Base Footprint to Base Link
base_footprint -> base_link๋ ๋ ์ขํ ํ๋ ์์ด ์๋ก ๊ณ ์ ๋์ด ์์ผ๋ฏ๋ก ์ ์ ๋ณํ์ ๋๋ค. ๋ก๋ด์ด ์์ง์ด๊ณ ๋ก๋ด์ "๋ฐ์๊ตญ"์ ์ขํ๊ณ๊ฐ ์์ง์ ๋๋ค.
<node pkg="tf" type="static_transform_publisher" name="base_link_broadcaster" args="0 0 0.09 0 0 0 base_footprint base_link 30" />
์์ ๊ฒฝ์ฐ, base_link ์ขํ๊ณ์ ์์ (์ฆ, ๋ก๋ด์ ์ค์ฌ)์ด ๋ฐ์๊ตญ ์ 0.09๋ฏธํฐ์ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
Base Link to Laser
base_link -> Laser ๋ณํ์ base_link์ ์ขํ๊ณ ๋ด๋ถ์์ ๋ ์ด์ ์ ์์น์ ๋ฐฉํฅ์ ์ ๊ณตํฉ๋๋ค. ์ด ๋ณํ์ ์ ์ ์ ๋๋ค.
<node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.06 0 0.08 0 0 0 base_link laser 30" />
๋ ์ด์ ๋ ๋ก๋ด ์ค์ฌ์์ ์์ชฝ์ผ๋ก 0.06m, ๋ก๋ด ์ค์ฌ์์ ์์ชฝ์ผ๋ก 0.08m์ ์์นํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
Base Link to IMU
base_link -> imu ๋ณํ์ base_link์ ์ขํ ํ๋ ์ ๋ด IMU(๊ด์ฑ ์ธก์ ์ฅ์น…์ผ๋ฐ์ ์ผ๋ก BNO055 ์ผ์)์ ์์น์ ๋ฐฉํฅ์ ์ ๊ณตํฉ๋๋ค. ์ด ๋ณํ์ ์ ์ ์ ๋๋ค.
<node pkg="tf" type="static_transform_publisher" name="imu_broadcaster" args="0 0.06 0.02 0 0 0 base_link imu 30" />
์ฌ๊ธฐ๊น์ง๊ฐ ROS์ ์ขํ ํ๋ ์ ๋ฐ ์ ์ ๋ณํ ๊ฒ์์์ ๊ธฐ๋ณธ ์ฌํญ์ ๋๋ค.
Dynamic Publisher
TF Broadcaster
์ฐ์ , ๋ก๋ด์ ๊ทํ์ง๋ฅผ ์์ ์ผ๋ก ํ๋ ์ขํ๊ณ์ ์ด๋ฆ์ home์ด๋ผ๊ณ ํด๋ณด์. ๊ทธ๋ ๋ค๋ฉด, home ํ๋ ์ ์์์ (-5, 10, 0) ๋งํผ ๋จ์ด์ง ์์น๋ ์๋์ ๊ฐ์ด ํํ๋ ๊ฒ์ด๋ค.
#!/usr/bin/python
import rospy
import tf
from geometry_msgs.msg import PoseStamped
class Robot(object):
def __init__(self):
position = PoseStamped()
position.header.frame_id = "home"
position.pose.position.x = -5
position.pose.position.y = 10
position.pose.orientation.w = 1
self.position = position
self.pub = rospy.Publisher("robot_pose", PoseStamped, queue_size=1)
def publishPose(self):
self.position.header.stamp = rospy.Time.now()
self.pub.publish(self.position)
if __name__ == '__main__':
rospy.init_node("tf_pub")
robot = Robot()
r = rospy.Rate(1)
while not rospy.is_shutdown():
robot.publishPose()
r.sleep()
์ด๋ฒ์๋ home ํ๋ ์๊ณผ world ํ๋ ์ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ ์ํด์ผ ํ๋ค. ์ฌ๊ธฐ์๋ tf.TransformBroadcaster() ํด๋์ค์, ํด๋น ํด๋์ค์ ์ ์ธ๋ sendTransform ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ค.
sendTransform ๋ฉ์๋๋ ์๋์ ๊ฐ์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์, TF ๊ด๊ณ๋ฅผ ๋ฐํํ๋ค.
- translation: (x, y, z), ์ขํ๊ณ ๊ฐ์ ๋ณ์ง์ด๋์ ์ ์ํ๋ ๊ฐ
- rotation: (x, y, z, w), ์ขํ๊ณ ๊ฐ์ ํ์ ์ด๋์ ์ ์ํ๋ ๊ฐ
- time: time, transform์ ๊ฐ์ง๋ ์์
- child: string, ์์ ํ๋ ์์ ์ด๋ฆ
- parent: string, ๋ถ๋ชจ ํ๋ ์์ ์ด๋ฆ
์ฌ๊ธฐ์ ๋ถ๋ชจ์ ์์์ด๋, ์ด๋ค ํ๋ ์์ ๋ ์์์ ํ๋ ์์ผ๋ก ์ทจ๊ธํ ์ง๋ฅผ ์๋ฏธํ๋ค.
๋ฐ๋ผ์ ์์ ๋ด์ฉ์ ์ฝ๋ฉํ๋ฉด ์๋์ ๊ฐ๋ค.
tf_broadcaster = tf.TransformBroadcaster()
r = rospy.Rate(1)
while not rospy.is_shutdown():
tf_broadcaster.sendTransform(
translation=[10, 10, 0],
rotation=[0., 0., 0., 1],
time=rospy.Time.now(),
child="home",
parent="world"
)
robot.publishPose()
r.sleep()
TF Listener
๋ณด๋ค์ถ์ด TF ๊ด๊ณ์ ๋ฐํ์ ROS Publisher์ ๋งค์ฐ ์ ์ฌํ ํํ๋ฅผ ๊ฐ์ง๊ณ ์๋๋ฐ, ์ด์ ๋น์ทํ๊ฒ TF๊ด๊ณ ๋ํ, ๊ตฌ๋ ํ์ฌ ์ค์ ํ๋ ์ ๊ฐ์ ์ขํ ๋ณํ์ ์ํฌ ์ ์๋ค.
๊ตฌ์ฒด์ ์ผ๋ก๋ tf.TransformListener ํด๋์ค๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์ฌ์ฉ๋ฒ์ ์๋์ ๊ฐ์ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋๋ค.
#!/usr/bin/python
import rospy
import tf
from geometry_msgs.msg import PoseStamped
if __name__ == '__main__':
rospy.init_node("tf_listener")
tf_listener = tf.TransformListener() # TF Listener ๊ฐ์ฒด ์ ์ธ
r = rospy.Rate(1)
while not rospy.is_shutdown():
if tf_listener.canTransform(
target_frame="world", source_frame="home", time=rospy.Time(0)):
# TF ๋ณํ์ด ๊ฐ๋ฅํ์ง ๊ฒ์ฌ. ๋ถ๊ฐ๋ฅ ํ ๋, lookupTransform์ ํธ์ถํ ๊ฒฝ์ฐ ์์ธ ๋ฐ์
# TF ๋ณํ์ ์๊ฐ์ rospy.Time.now()๊ฐ ์๋๋ผ Time(0)์ ์จ์ผํ๋ค!!
tf_matrix = tf_listener.lookupTransform(
target_frame="world", source_frame="home", time=rospy.Time(0))
# ๋ณํ ํ๋ ฌ ๋ฆฌํด. ๋ฆฌํด ๊ฐ์ ([x, y, z], [x, y, z, w])
rospy.loginfo(tf_matrix)
else:
rospy.logwarn("Cannot lookup transform between world and home")
r.sleep()
์์ ์ฝ๋๋ฅผ ์คํํ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
๋ํ, ROS Docs๋ฅผ ์ฐธ๊ณ ํ๋ฉด, TransformListener๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํ ์ฌ๋ฌ ๋ฉ์๋๋ฅผ ํ์ธํ ์ ์๋ค.
์ด ์ค์์ transformPose๋ฅผ ์ฌ์ฉํ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
#!/usr/bin/python
import rospy
import tf
from geometry_msgs.msg import PoseStamped
msg = None
def poseCallback(m):
global msg
m.header.stamp = rospy.Time(0)
msg = m
if __name__ == '__main__':
rospy.init_node("tf_listener")
tf_listener = tf.TransformListener()
pose_subscriber = rospy.Subscriber(
"robot_pose", PoseStamped, callback=poseCallback)
r = rospy.Rate(1)
while not rospy.is_shutdown():
if tf_listener.canTransform(
target_frame="world", source_frame="home", time=rospy.Time(0)) and msg is not None:
res = tf_listener.transformPose(ps=msg, target_frame="world")
rospy.loginfo(res)
else:
rospy.logwarn("Cannot lookup transform between world and home")
r.sleep()
ํน์ ์ด๋ฐ ์๋ฌธ์ด ๋ค์ง๋ ์์๊น. TF๋ ์ ํ ์๋ก์ด ๋ด์ฉ์ด ์๋๋ฉฐ, ๋ณํ ํ๋ ฌ์ ๊ณ์ฐ์ numpy ๋ฑ ๋จ์ ํ๋ ฌ ๊ณ์ฐ์ ํตํ์ฌ ์ผ๋ง๋ ์ง ๋์ ํ ์ ์๊ณ , ์คํ๋ ค ๊ทธ์ชฝ์ด ๋น ๋ฅด์ง ์์๊น?
๋ฌผ๋ก ์์ ํ ํ๋ฆฐ ๋ง์ ์๋์ง๋ง, ROS์ tf ํจํค์ง๋ฅผ ์ฌ์ฉํ๋ฉด, ์๊ฐ์ ๋ฐ๋ผ ๋ณํํ๋ ๋ณํ ํ๋ ฌ์ ์ถ์ ํ๊ธฐ ํธ๋ฆฌํ๋ฉฐ, ๋ค๋ฅธ ROS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฐ๋๋์ด ๊ท์ฐฎ์ ์์ ์ ๋ํญ ๊ฐ์์ํฌ ์ ์๋ค.
๋ํ, ํ๋ ์ ๊ฐ ๋ถ๋ชจ-์์ ๊ด๊ณ๋ ๋จ์ํ ํ๋๋ง ์กด์ฌํ๋ ๊ฒ์ด ์๋๋ผ, ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ๋ฌดํํ๊ฒ ํ์ฅํ ์ ์์ผ๋ฉฐ, TransformListener๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, ์ฌ๋ฌ ์ขํ๊ณ ๊ฐ์ ๋ณํ ํ๋ ฌ์ ํ๋ฒ์ ๊ณ์ฐ ๊ฐ๋ฅํ๋ค๋ ์ฅ์ ์ด ์กด์ฌํ๋ค.
tf_broadcaster.sendTransform(
translation=[10, 10, 0],
rotation=[0., 0., 0., 1],
time=rospy.Time.now(),
child="home",
parent="world"
)
tf_broadcaster.sendTransform(
translation=[10, 10, 0],
rotation=[0., 0., 0., 1],
time=rospy.Time.now(),
child="world",
parent="utm"
)
if tf_listener.canTransform(
target_frame="utm", source_frame="home", time=rospy.Time(0)) and msg is not None:
res = tf_listener.transformPose(ps=msg, target_frame="utm")
rospy.loginfo(res)
๋ํ, ์ด ์ญ์๋ ROS์ ์ผ๋ถ์ด๊ธฐ ๋๋ฌธ์, ๊ฐ๋จํ๊ฒ ์๊ฐํ ํ ์ ์๋ค๋ ์ ๋ํ, ์ฅ์ ์ผ๋ก ๋ณผ ์ ์์ ๊ฒ์ด๋ค.
$ rosrun tf view_frames
์ฐธ๊ณ
- [Blog] Coordinate Frames and Transforms for ROS-based Mobile Robots: https://automaticaddison.com/coordinate-frames-and-transforms-for-ros-based-mobile-robots/
- [Blog] ์ด๋ณด์๋ฅผ ์ํ ROS : TF๋ ๋ฌด์์ธ๊ฐ: https://velog.io/@7cmdehdrb/whatIsTF
'Study: Robotics(Robot) > Robot: ROS(Robot Operating Sytem)' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ROS] apt ์ค์นํ ํจํค์ง์ buildํ ํจํค์ง(catkin, colcon) ์ค ์ด๋ค ๊ฒ์ ์ฌ์ฉ? (0) | 2023.11.10 |
---|---|
[ROS] ROS URDF vs. Gazebo SDF: Link Pose, Joint Pose, Visual & Collision (0) | 2023.10.27 |
[ROS] ROS rosrun ์คํํ์ผ ๋ง๋ค๊ธฐ(python, cpp) (0) | 2023.10.12 |
[ROS] ROS Docker Official Image, Docker Compose ํ์ผ (0) | 2023.05.03 |
[ROS] Why ROS2? (feat. ROS1 vs ROS2) (0) | 2022.11.30 |