This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
courses:ros:class3 [2016/09/16 17:50] anton.filatov |
courses:ros:class3 [2022/12/10 09:08] (current) |
||
---|---|---|---|
Line 148: | Line 148: | ||
ros::spin(); | ros::spin(); | ||
return 0; | return 0; | ||
- | }; | + | } |
</code> | </code> | ||
- | Как понятно из кода, | + | Как понятно из кода, в проргамме создаётся нода, которая подписывается на turtle1/pose (имя взято по-умолчанию). В этот топик нода черепашки пишет координаты черепашки в мире. Как только в этот топик поступает какая-то информация (а поступает она туда постоянно, даже если черепашка стоит на месте), запускается функция, считывающая информацию с этого топика и записывающая её в tf. |
+ | |||
+ | Обратите внимание на механизм создания transform: координаты задаются, как члены данные, а поворот при помощи tf:Quaternion. | ||
+ | |||
+ | В функции sendTransform указаны две строковые переменные: "world" и turtle_name. Они будут записаны в сообщение, которое будет отправлено в топик tf. Когда сообщение будет извлекаться, можно будет получить доступ к этим переменным. Их смысловая нагрузка показать, что и в каких координатах считается. В данном случае показано, что в tf отправлены координаты объекта turtle_name относительно world. \\ | ||
+ | Становится понятно, что с помощью такого механизма организации сообщений всегда можно будет восстановить координаты любого объекта, даже если известны лишь его координаты относительно другого объекта, но про тот нам всё известно. \\ | ||
+ | Заметим, что в tf то, относительно чего считаются координаты называется base_frame_id, а то, чьи координты, называется base_frame_id. | ||
+ | |||
+ | Теперь разберёмся, как считывать и обрабатывать сообщения из tf. Рассмотрим, например, такой код: | ||
+ | |||
+ | <code c> | ||
+ | #include <ros/ros.h> | ||
+ | #include <tf/transform_listener.h> | ||
+ | #include <geometry_msgs/Twist.h> | ||
+ | #include <turtlesim/Spawn.h> | ||
+ | |||
+ | int main(int argc, char** argv){ | ||
+ | ros::init(argc, argv, "my_tf_listener"); | ||
+ | |||
+ | ros::NodeHandle node; | ||
+ | |||
+ | ros::service::waitForService("spawn"); | ||
+ | ros::ServiceClient add_turtle = | ||
+ | node.serviceClient<turtlesim::Spawn>("spawn"); | ||
+ | turtlesim::Spawn srv; | ||
+ | add_turtle.call(srv); | ||
+ | |||
+ | ros::Publisher turtle_vel = | ||
+ | node.advertise<geometry_msgs::Twist>("turtle2/cmd_vel", 10); | ||
+ | |||
+ | tf::TransformListener listener; | ||
+ | |||
+ | ros::Rate rate(10.0); | ||
+ | while (node.ok()){ | ||
+ | tf::StampedTransform transform; | ||
+ | try{ | ||
+ | listener.lookupTransform("/turtle2", "/turtle1", | ||
+ | ros::Time(0), transform); | ||
+ | } | ||
+ | catch (tf::TransformException &ex) { | ||
+ | ROS_ERROR("%s",ex.what()); | ||
+ | ros::Duration(1.0).sleep(); | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | geometry_msgs::Twist vel_msg; | ||
+ | vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(), | ||
+ | transform.getOrigin().x()); | ||
+ | vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) + | ||
+ | pow(transform.getOrigin().y(), 2)); | ||
+ | turtle_vel.publish(vel_msg); | ||
+ | |||
+ | rate.sleep(); | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | В программе вызывается сервис "spawn". Таким образом, теперь в turtle_sim_node будет находится две черепашки. Для корректной работы необходимо запустить двух бродкастеров: для turtle1 и для turtle2. | ||
+ | |||
+ | Разберёмся подробно, что делает такой код. \\ | ||
+ | Выходным параметром является направление движения для turtle2, записанное в turtle2/cmd_vel. | ||
+ | |||
+ | Самую важную роль здесь играет функция listener.lookupTransform, которая в переменную transform записывает координаты turtle1 относительно turtle2. Обратите внимание, что в этой функции переменные base_frame_id и child_frame_id стоят в том же порядке, что в sendTransform: сначала base - относительно чего, а потом child - тот, кого. | ||
+ | |||
+ | Теперь, когда координаты первой черепашки посчитаны (нам не пришлось прилагать усилий для подсчёта этих координат), можно сформировать сообщение и послать в топик, который прослушивает turtle2. | ||
+ | |||
+ | Резюмируя, можно сказать, что tf это очень сильный механизм определения относительных координат объектов. В реальных роботах необходимо ослеживать перемещения десятков движущихся механизмов и конечностей робота. Для того, чтобы легко рассчитывать их взаимное расположение и используется tf. |