ROS1學習第二彈
本文純屬記錄學習過程,所學教程來自B站古月居ROS入門21講
tf工具的使用
命令行中
1.rosrun tf view_frames
生成當前各個坐標的結構圖,導出pdf文件到當前終端所在文件夾下面2.rosrun rviz rviz -d
rospackage find turtle_tf
/rviz/turtle_rviz.rviz
在圖中藍色處要修改一下父親坐標系
代碼實現
廣播:
#include<ros/ros.h>
#include<tf/transform_broadcaster.h>
#include<turtlesim/Pose.h>std::string turtle_name; // 存儲烏龜名稱(由命令行參數傳入)// 回調函數:處理訂閱的烏龜位姿消息,并發布TF變換
void poseCallback(const turtlesim::PoseConstPtr& msg)
{// 創建TF廣播器(static確保只創建一次)static tf::TransformBroadcaster bro;// 創建變換對象,設置平移部分(x, y, z)tf::Transform transform;transform.setOrigin(tf::Vector3(msg->x, msg->y, 0.0));// 創建四元數對象,設置旋轉部分(由歐拉角轉換而來)tf::Quaternion q;q.setRPY(0, 0, msg->theta); // 繞Z軸旋轉theta角度(烏龜朝向)transform.setRotation(q);// 發送帶時間戳的變換:// 參數1:變換對象// 參數2:當前時間戳// 參數3:父坐標系名稱("world")// 參數4:子坐標系名稱(烏龜名稱,如"turtle1")bro.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
}int main(int argc, char **argv)
{// 初始化ROS節點,節點名稱必須唯一// 注意:節點名稱在命令行中通過__name:=參數指定,而非此處的硬編碼名稱ros::init(argc, argv, "my_tf_broadcaster");// 檢查命令行參數(必須提供烏龜名稱,如"turtle1"或"turtle2")if(argc != 2){ROS_ERROR("需要傳入烏龜名稱作為參數");return -1;}// 從命令行參數獲取烏龜名稱(argv[1])turtle_name = argv[1];// 創建節點句柄,用于與ROS系統通信ros::NodeHandle node;// 訂閱烏龜的位姿話題(如"/turtle1/pose")// 回調函數poseCallback將在收到消息時被調用ros::Subscriber sub = node.subscribe(turtle_name + "/pose", 10, &poseCallback);// 進入循環等待回調(阻塞當前線程)ros::spin();return 0;
}
監聽:
#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節點,命名為"my_tf_listener"ros::init(argc, argv, "my_tf_listener");ros::NodeHandle node;// 等待/spawn服務可用(用于創建新烏龜)ros::service::waitForService("/spawn");// 創建服務客戶端,連接到/spawn服務ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");// 準備Spawn服務請求(創建新烏龜)turtlesim::Spawn srv;// 注意:此處未設置srv.request參數,將使用默認值(可能導致重復創建同名烏龜)add_turtle.call(srv); // 調用服務創建烏龜// 創建速度指令發布者,發布到/turtle2/cmd_vel話題,控制turtle2移動ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("/turtle2/cmd_vel", 10);// 創建TF監聽器,用于接收和緩存TF變換數據tf::TransformListener listener;// 設置循環頻率為10Hzros::Rate rate(10.0);while(node.ok()) // 主循環,直到節點被關閉{tf::StampedTransform transform; // 存儲變換結果的對象try{// 等待并查找turtle1相對于turtle2的變換// 參數1:目標坐標系(turtle2)// 參數2:源坐標系(turtle1)// 參數3:時間戳(ros::Time(0)表示最新可用變換)// 參數4:超時時間(等待3秒)listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0));listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);}catch(tf::TransformException &ex){// 捕獲變換異常并打印錯誤信息ROS_ERROR("%s", ex.what());ros::Duration(1.0).sleep(); // 暫停1秒后繼續continue;}// 計算控制指令,使turtle2跟隨turtle1geometry_msgs::Twist vel_msg;// 角速度控制(轉向):// atan2計算turtle1相對于turtle2的角度,乘以4.0放大控制量vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(), transform.getOrigin().x());// 線速度控制(前進):// 計算turtle1與turtle2的距離,乘以0.5作為前進速度vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) + pow(transform.getOrigin().y(), 2));// 發布控制指令turtle_vel.publish(vel_msg);rate.sleep(); // 休眠以維持10Hz的頻率}return 0;
}
launch文件
launch語法
<launch><node pkg="pkg_name", node="node_name", type="executable_name"/>
</launch>
參數設置(param)
用于設置ROS系統運行中的參數,存儲在參數服務器中
<param name="output_frame" value="odom"/>
name
:參數名value
:參數值
參數文件加載(rosparam)
加載YAML文件中的多個參數
<rosparam file="params.yaml" command="load" ns="params"/>
局部變量(arg)
launch文件內部的局部變量,僅限于launch文件使用
<arg name="arg-name" default="arg-value"/>
name
:參數名default
:參數值(默認值)
局部變量調用方法
- 在param中調用:
<param name="foo" value="$(arg arg-name)"/>
- 在node中調用:
<node name="node" pkg="package" type="type" args="$(arg arg-name)"/>
重映射(remap)
重命名ROS計算圖資源(如Topic、Service等)
<remap from="/turtlebot/cmd_vel" to="/cmd_vel"/>
from
:原始名稱to
:映射后的新名稱
包含其他launch文件(include)
在launch文件中包含另一個launch文件,類似C語言中的頭文件包含
<include file="${dirname}/other.launch"/>
file
:被包含的launch文件路徑(可使用$(find pkg)
或變量如${dirname}
)
其余可參考官網
工作空間中
以最簡單的在同一終端下運行兩個節點為例:
<launch><node pkg="learning_topic" type="person_subscriber" name="talker" output="screen" /><node pkg="learning_topic" type="person_publisher" name="listener" output="screen" />
</launch>
<launch><!-- 全局參數 --><param name="/turtle_number" value="2"/><!-- 節點1 --><node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node" output="screen"><!-- 節點自己的參數 --><param name="turtle_name1" value="Tom"/><param name="turtle_name2" value="Jerry"/><!-- 加載YAML參數文件 --><rosparam file="$(find learning_launch)/config/param.yaml" command="load" /></node><!-- 節點2 --><node pkg="turtlesim" type="turtle_teleop_key" name="turtle_teleop_key" output="screen"/>
</launch>
調用之前的 learning_tf 功能包
<launch><node pkg="turtlesim" type="turtlesim_node" name="sim" /><node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen" /><node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster" /><node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster" /><node pkg="learning_tf" type="learning_tf_listener" name="listener" /></launch>
可視化工具
rqt_bag
rqt_graph
rqt_plot
rqt_console
rqt_image_view
rqt_shell
rqt_dep
rqt_logger_level
rqt_topic
rosrun rviz rivz