ROS tf tree๋ฅผ ์•Œ์•„๋ณด์ž!

ROS tf tree

Robot system์—๋Š” ์ˆ˜๋งŽ์€ 3D coordinates๋“ค์ด ์กด์žฌ

tf๋Š” ๋งŽ์€ frame๋“ค์„ ๊ณ„์† trackingํ•˜์—ฌ frame๋“ค๊ฐ„ ์ƒ๋Œ€์ ์ธ ์œ„์น˜๋ฅผ ๊ณ„์† ๊ธฐ๋ก

tf๋Š” distributed system์—์„œ ๊ตฌ๋™๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋กœ๋ด‡์˜ coordinate์— ๋Œ€ํ•œ ๋ชจ๋“  ์ •๋ณด๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ROS component๋“ค๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

์ฆ‰, transform information์˜ ์ค‘์‹ฌ์„œ๋ฒ„๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Œ


01

์—ฌ๊ธฐ์„œ ๋กœ๋ด‡์˜ ์‹ค์ œ ์ค‘์‹ฌ๋Š” base_link์ด๊ณ  ์Šค์บ๋„ˆ์˜ ์ขŒํ‘œ ์ค‘์‹ฌ์€ base_laser์ž„

๋”ฐ๋ผ์„œ ๋ผ์ด๋‹ค๋กœ๋ถ€ํ„ฐ ์Šค์บ”๋œ ์ •๋ณด๋ฅผ ๋กœ๋ด‡ ์ค‘์‹ฌ์—์„œ์˜ ์ขŒํ‘œ๋กœ transformationํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•จ!


odom -> base_footprint -> base_link -> sensor_link ์ˆœ์ด๋‹ค!!!

์ด๋ฅผ ์‰ฝ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ tf library ์ž„


1. Writing Code

In ${workspace}/src

$ catkin_create_pkg robot_setup_tf roscpp tf geometry_msgs


2. Broadcasting a Transform

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>

using namespace std;
 
int main(int argc, char** argv)
{
  ros::init(argc, argv, "tf_broadcaster");
  ros::NodeHandle nh;

  ros::Rate r(100);

  tf::TransformBroadcaster broadcaster;

  while(nh.ok())
  {
    broadcaster.sendTransform(
      tf::StampedTransform(
        tf::Transform(tf::Quaternion(0,0,0,1), tf::Vector3(0.1, 0.0, 0.2)),
        ros::Time::now(), "based_link", "base_laser"));
  }

  return 0;
}

TransformBroadcaster๋ฅผ ํ†ตํ•ด transform์„ ์†ก์‹ ํ•˜๋ ค๋ฉด 5๊ฐœ์˜ argument๊ฐ€ ํ•„์š”


3. Listening a Transform


#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <geometry_msgs/PointStamped.h>

using namespace std;

void transformPoint(const tf::TransformListener& listener)
{
  geometry_msgs::PointStamped laser_point;
  laser_point.header.frame_id = "base_laser";

  laser_point.header.stamp = ros::Time();

  // just an arbitrary point
  laser_point.point.x = 1.0;
  laser_point.point.x = 0.2;
  laser_point.point.x = 3;

  try
  {
    geometry_msgs::PointStamped base_point;
    listener.transformPoint("based_link", laser_point, base_point);

    ROS_INFO("base_laser: (%.2f, %.2f. %.2f) -----> base_link: (%.2f, %.2f, %.2f) at time %.2f",
           laser_point.point.x, laser_point.point.y, laser_point.point.z,
           base_point.point.x, base_point.point.y, base_point.point.z, base_point.header.stamp.toSec());
    
    
  }
  catch(const tf::TransformException& ex) //catch(const std::exception& e)
  {
    // std::cerr << e.what() << '\n';
    ROS_ERROR("Received an exception trying to transform a point from \"base_laser\" to \"base_link\": %s", ex.what());
  }
  
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "tf_listener");
  ros::NodeHandle nh;

  tf::TransformListener listener(ros::Duration(10));

  // 1์ดˆ์— a point๋ฅผ Transform ํ•  ๊ฑฐ์ž„
  ros::Timer timer = nh.createTimer(ros::Duration(1.0), boost::bind(&transformPoint, boost::ref(listener)));

  return 0;
}


4. CMakeLists.txt

add_executable(tf_broadcaster src/tf_broadcaster.cpp)
target_link_libraries(tf_broadcaster
  ${catkin_LIBRARIES}
)

add_executable(tf_listener src/tf_listener.cpp)
target_link_libraries(tf_listener
  ${catkin_LIBRARIES}
)


5. Run

$ roscore
$ rosrun robot_tf_tutorial tf_broadcaster
$ rosrun robot_tf_tutorial tf_listener


6. EASY


  <!-- Create a transform sender for linking these frames. -->
  <node name="tf_footprint_base" pkg="tf" type="static_transform_publisher" args="0 0 0 0 0 0 base_footprint base_link 40" />	

์ด๊ฑธ๋กœ ์‰ฝ๊ฒŒ ํ•˜์žโ€ฆ.
x y z r p y frame_id child_id Hz

Reference