ROS 运行管理与常用组件

ROS 运行管理与常用组件

一、ROS 运行管理

节点名称重名

1. rosrun 设置命名空间

rosrun turtlesim turtlesim_node __ns:=/xxx
rosrun turtlesim turtlesim_node __ns:=/yyy

结果:

/xxx/turtlesim
/yyy/turtlesim

2. rosrun 名称重映射

rosrun turtlesim turtlesim_node __name:=t1
rosrun turtlesim turtlesim_node __name:=t2

结果:

/t1
/t2

3. rosrun 名称重映射与设置命名空间叠加

rosrun turtlesim turtlesim_node __ns:=/xxx __name:=tn

4. launch 文件设置命名空间与重映射

<launch>
    <node pkg="turtlesim" type="turtlesim_node" name="t1" />
    <node pkg="turtlesim" type="turtlesim_node" name="t2" />
    <node pkg="turtlesim" type="turtlesim_node" name="t1" ns="hello"/>
</launch>

结果:

/t1
/t2
/hello/t1

5. 编码设置命名空间与重映射

C++:

//名称别名
ros::init(argc,argv,"zhangsan",ros::init_options::AnonymousName);
//命名空间
std::map<std::string, std::string> map;
map["__ns"] = "xxxx";
ros::init(map,"wangqiang");

Python:

rospy.init_node("lisi",anonymous=True)

话题名称重名

1. rosrun 设置话题重映射

rosrun teleop_twist_keyboard teleop_twist_keyboard.py /cmd_vel:=/turtle1/cmd_vel
rosrun turtlesim turtlesim_node /turtle1/cmd_vel:=/cmd_vel

2. launch 文件设置话题重映射

<node pkg="xxx" type="xxx" name="xxx">
    <remap from="原话题" to="新话题" />
</node>

示例:

<launch>
    <node pkg="turtlesim" type="turtlesim_node" name="t1" />
    <node pkg="teleop_twist_keyboard" type="teleop_twist_keyboard.py" name="key">
        <remap from="/cmd_vel" to="/turtle1/cmd_vel" />
    </node>
</launch>

3. 编码设置话题名称

C++:

// 1)全局名称
ros::Publisher pub = nh.advertise<std_msgs::String>("/chatter",1000);
// /chatter

// 2)相对名称
ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",1000);
// xxx/chatter

// 3)私有名称
ros::NodeHandle nh("~");
ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",1000);
// /xxx/hello/chatter

Python:

# 1)全局名称
pub = rospy.Publisher("/chatter",String,queue_size=1000)
# /chatter

# 2)相对名称
pub = rospy.Publisher("chatter",String,queue_size=1000)
# xxx/chatter

# 3)私有名称
pub = rospy.Publisher("~chatter",String,queue_size=1000)
# /xxx/hello/chatter

参数名称设置

1. rosrun 设置参数

rosrun turtlesim turtlesim_node _A:=100

2. launch 文件设置参数

<launch>
    <param name="p1" value="100" />
    <node pkg="turtlesim" type="turtlesim_node" name="t1">
        <param name="p2" value="100" />
    </node>
</launch>

结果:

/p1
/t1/p1

3. 编码设置参数

C++ ros::param:

ros::param::set("/set_A",100); //全局,和命名空间以及节点名称无关
ros::param::set("set_B",100); //相对,参考命名空间
ros::param::set("~set_C",100); //私有,参考命名空间与节点名称

// /set_A
// /xxx/set_B
// /xxx/yyy/set_C

C++ ros::NodeHandle:

ros::NodeHandle nh;
nh.setParam("/nh_A",100); //全局,和命名空间以及节点名称无关
nh.setParam("nh_B",100); //相对,参考命名空间
ros::NodeHandle nh_private("~");
nh_private.setParam("nh_C",100);//私有,参考命名空间与节点名称

// /nh_A
// /xxx/nh_B
// /xxx/yyy/nh_C

Python:

rospy.set_param("/py_A",100)  #全局,和命名空间以及节点名称无关
rospy.set_param("py_B",100)  #相对,参考命名空间
rospy.set_param("~py_C",100)  #私有,参考命名空间与节点名称

# /py_A
# /xxx/py_B
# /xxx/yyy/py_C

分布式通信

1. 准备

先要保证不同计算机处于同一网络中,最好分别设置固定 IP,如果为虚拟机,需要将网络适配器改为桥接模式。

2. 配置文件修改

分别修改不同计算机的 /etc/hosts 文件,在该文件中加入对方的 IP 地址和计算机名:

主机端:

从机的IP    从机计算机名

从机端:

主机的IP    主机计算机名

设置完毕,可以通过 ping 命令测试网络通信是否正常。

IP地址查看名: ifconfig
计算机名称查看: hostname

3. 配置主机 IP

~/.bashrc 追加:

export ROS_MASTER_URI=http://主机IP:11311
export ROS_HOSTNAME=主机IP

4. 配置从机 IP

配置从机的 IP 地址,从机可以有多台,每台都做如下设置:

~/.bashrc 追加:

export ROS_MASTER_URI=http://主机IP:11311
export ROS_HOSTNAME=从机IP

测试

  1. 主机启动 roscore(必须)
  2. 主机启动订阅节点,从机启动发布节点,测试通信是否正常
  3. 反向测试,主机启动发布节点,从机启动订阅节点,测试通信是否正常

二、TF 坐标变换

静态坐标变换

现有一机器人模型,核心构成包含主体与雷达,各对应一坐标系,坐标系的原点分别位于主体与雷达的物理中心,已知雷达原点相对于主体原点位移关系如下: x 0.2 y0.0 z0.5。当前雷达检测到一障碍物,在雷达坐标系中障碍物的坐标为 (2.0 3.0 5.0),请问,该障碍物相对于主体的坐标是多少?

实现流程: C++ 与 Python 实现流程一致

  1. 新建功能包,添加依赖
  2. 编写发布方实现
  3. 编写订阅方实现
  4. 执行并查看结果

C++ 实现

发布方

#include "ros/ros.h"
#include "tf2_ros/static_transform_broadcaster.h"
#include "geometry_msgs/TransformStamped.h"
#include "tf2/LinearMath/Quaternion.h"

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"static_brocast");
    tf2_ros::StaticTransformBroadcaster broadcaster;
    geometry_msgs::TransformStamped ts;

    //----设置头信息
    ts.header.seq = 100;
    ts.header.stamp = ros::Time::now();
    ts.header.frame_id = "base_link";
    //----设置子级坐标系
    ts.child_frame_id = "laser";
    //----设置子级相对于父级的偏移量
    ts.transform.translation.x = 0.2;
    ts.transform.translation.y = 0.0;
    ts.transform.translation.z = 0.5;
    //----设置四元数:将 欧拉角数据转换成四元数
    tf2::Quaternion qtn;
    qtn.setRPY(0,0,0);
    ts.transform.rotation.x = qtn.getX();
    ts.transform.rotation.y = qtn.getY();
    ts.transform.rotation.z = qtn.getZ();
    ts.transform.rotation.w = qtn.getW();

    broadcaster.sendTransform(ts);
    ros::spin();
    return 0;
}

订阅方

#include "ros/ros.h"
#include "tf2_ros/transform_listener.h"
#include "tf2_ros/buffer.h"
#include "geometry_msgs/PointStamped.h"
#include "tf2_geometry_msgs/tf2_geometry_msgs.h"

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"tf_sub");
    ros::NodeHandle nh;
    tf2_ros::Buffer buffer;
    tf2_ros::TransformListener listener(buffer);

    ros::Rate r(1);
    while (ros::ok())
    {
        geometry_msgs::PointStamped point_laser;
        point_laser.header.frame_id = "laser";
        point_laser.header.stamp = ros::Time::now();
        point_laser.point.x = 1;
        point_laser.point.y = 2;
        point_laser.point.z = 7.3;

        try
        {
            geometry_msgs::PointStamped point_base;
            point_base = buffer.transform(point_laser,"base_link");
            ROS_INFO("转换后的数据:(%.2f,%.2f,%.2f),参考的坐标系是:",point_base.point.x,point_base.point.y,point_base.point.z,point_base.header.frame_id.c_str());
        }
        catch(const std::exception& e)
        {
            ROS_INFO("程序异常.....");
        }

        r.sleep();
        ros::spinOnce();
    }
    return 0;
}

补充:使用命令行工具

当坐标系之间的相对位置固定时,可以使用 ROS 系统封装好的专门节点:

rosrun tf2_ros static_transform_publisher x偏移量 y偏移量 z偏移量 z偏航角度 y俯仰角度 x翻滚角度 父级坐标系 子级坐标系

示例:

rosrun tf2_ros static_transform_publisher 0.2 0 0.5 0 0 0 /baselink /laser

可以借助于 rviz 显示坐标系关系,具体操作:

  • 新建窗口输入命令: rviz
  • 在启动的 rviz 中设置 Fixed Frame 为 base_link
  • 点击左下的 add 按钮,在弹出的窗口中选择 TF 组件,即可显示坐标关系

三、rosbag 使用

命令行使用

需求: ROS 内置的乌龟案例并操作,操作过程中使用 rosbag 录制,录制结束后,实现重放

实现:

  1. 准备 - 创建目录保存录制的文件
mkdir ./xxx
cd xxx
  1. 开始录制
rosbag record -a -O 目标文件

操作小乌龟一段时间,结束录制使用 ctrl + c,在创建的目录中会生成 bag 文件。

  1. 查看文件
rosbag info 文件名
  1. 回放文件
rosbag play 文件名

重启乌龟节点,会发现,乌龟按照录制时的轨迹运动。

编码使用

(具体实现见相关文档)


四、rqt 工具箱

rqt 基本使用

启动方式有两种:

  • 方式1: rqt
  • 方式2: rosrun rqt_gui rqt_gui

基本使用:

启动 rqt 之后,可以通过 plugins 添加所需的插件。

rqt 常用插件

(具体插件列表见相关文档)


总结

ROS 运行管理和常用组件是 ROS 开发中的重要组成部分:

  1. 运行管理 - 节点、话题、参数的命名空间和重映射
  2. TF 坐标变换 - 机器人坐标系之间的转换
  3. rosbag - 数据录制和回放工具
  4. rqt - ROS 可视化工具集

掌握这些工具和技巧,可以更高效地进行 ROS 机器人开发。




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • 灵巧手遥操方案调研
  • lerobot探索
  • 提问的智慧
  • Markdown 功能使用指南
  • ROS 机器人开发实践