Chapter2 ROS通信机制----基础篇(Ⅲ)&ROS常用命令及实操训练

目录

一、ROS常用命令

1.1 ROS常用命令

1.1.1 为什么要学习这些命令

1.1.2 rosnode 命令

1.1.3 rostopic 命令

1.1.4 rosservice 命令 

1.1.5 rosmsg 命令

1.1.6 rossrv 命令

1.1.7 rosparam 命令

二、通信机制实操

2.1 本节内容概述

2.2 实操01_话题发布

2.2.1 需求分析

2.2.2 话题与消息的获取

2.2.3 C++实现发布节点 

2.2.4 python实现发布节点

2.3 实操02_话题订阅

2.3.1 需求分析

2.3.2 话题与消息的获取

2.3.3 C++实现话题订阅

2.3.4 python实现话题订阅

2.4 实操03_服务调用

2.4.1 需求分析

2.4.2 服务名称与服务信息获取

2.4.3 C++实现服务调用

2.4.4 python实现服务调用 

2.4 实操04_参数设置

2.4.1 需求分析

2.4.2 服务名称与服务信息获取

2.4.3 C++实现更改参数

2.4.4 python实现更改参数

2.5 通信机制比较

2.6 本章小结


一、ROS常用命令

1.1 ROS常用命令

1.1.1 为什么要学习这些命令

机器人系统中启动的节点少则几个,多则十几个、几十个,不同的节点名称各异,通信时使用话题、服务、消息、参数等等都各不相同,一个显而易见的问题是: 当需要自定义节点和其他某个已经存在的节点通信时,如何获取对方的话题、以及消息载体的格式呢。

和之前介绍的文件系统操作命令比较,文件操作命令是静态的,操作的是磁盘上的文件,而上述命令是动态的,在ROS程序启动后,可以动态的获取运行中的节点或参数的相关信息。 

1.1.2 rosnode 命令

1.介绍

rosnode是获取节点信息的命令

2. rosnode list :列出活跃的节点

Ⅰ.以话题通信的代码为例练习rosnode命令

#include "ros/ros.h"
#include"plumbing_pub_sub/Person.h"

int main(int argc ,char * argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"banZhuren");
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<plumbing_pub_sub::Person>("liaoTian",10);
    //创建发布数据
    plumbing_pub_sub::Person person;
    person.name = "张三";
    person.age = 1;
    person.height = 180.78;
    //设置发布频率
    ros::Rate rate(1);
    //循环发布数据
    while(ros::ok())
    {
        person.age++;
        //数据发布
        pub.publish(person);
        rate.sleep();
        //建议
        ros::spinOnce();
    }
    return 0;
}
#include "ros/ros.h"
#include "plumbing_pub_sub/Person.h"

void doPerson(const plumbing_pub_sub::Person::ConstPtr & person)
{
    ROS_INFO("订阅人的信息:%s,%d,%.2f",person->name.c_str(),person->age,person->height);
}

int main(int argc,char * argv[])
{
    setlocale(LC_ALL,"");
    ROS_INFO("订阅方实现");
    ros::init(argc,argv,"jiaZhang");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe("liaoTian",10,doPerson);
    ros::spin();
    return 0;
}

Ⅱ.将源文件在终端命令行中运行

 Ⅲ.在终端中运行:一共有三个活跃的节点

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosnode list
/banZhuren
/jiaZhang
/rosout

3. rosnode ping 节点名称 :测试某个节点的连接状态

仍以上例为例 :测试班主任节点是否联通

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosnode ping banZhuren
rosnode: node is [/banZhuren]
pinging /banZhuren with a timeout of 3.0s
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.368118ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.463009ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.549078ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.633001ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.450850ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.592947ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.566959ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.498056ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.447035ms
xmlrpc reply from http://liuhongwei-virtual-machine:42805/	time=0.396967ms

4.rosnode info 节点名称:列出关于当前节点的信息

 仍以上例为例 :列出班主任节点相关信息

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosnode info banZhuren
--------------------------------------------------------------------------------
Node [/banZhuren]
Publications: 
 * /liaoTian [plumbing_pub_sub/Person]
 * /rosout [rosgraph_msgs/Log]

Subscriptions: None

Services: 
 * /banZhuren/get_loggers
 * /banZhuren/set_logger_level


contacting node http://liuhongwei-virtual-machine:42805/ ...
Pid: 75422
Connections:
 * topic: /rosout
    * to: /rosout
    * direction: outbound (47133 - 127.0.0.1:51692) [11]
    * transport: TCPROS
 * topic: /liaoTian
    * to: /jiaZhang
    * direction: outbound (47133 - 127.0.0.1:51752) [12]
    * transport: TCPROS

5.rosnode machine 机器名称:多台计算机协作时该计算机运行的节点信息

输出本电脑的节点信息 

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosnode machine liuhongwei-virtual-machine
/banZhuren
/jiaZhang
/rosout

 6.rosnode kill 节点名称:杀死某个正在运行中的节点 

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosnode kill banZhuren
killing /banZhuren
killed

这时,banZhuren节点被杀死,再看发布节点,抛出异常并终止

7.rosnode cleanup:杀死僵死进程(详见深入理解计算机系统--进程与线程)

1.1.3 rostopic 命令

1.介绍

rostopic包含rostopic命令行工具,用于显示有关ROS 主题的调试信息,包括发布者,订阅者,发布频率和ROS消息。它还包含一个实验性Python库,用于动态获取有关主题的信息并与之交互。

 2.rostopic list:列出所有话题

liuhongwei@liuhongwei-virtual-machine:~$ rostopic list
/liaoTian
/rosout
/rosout_agg

3.rostopic echo 话题:打印出某个话题下发布的消息

Ⅰ.若是自定义消息,应到工作空间下刷新环境变量后再使用

liuhongwei@liuhongwei-virtual-machine:~$ cd demo03_ws/
liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ source ./devel/setup.bash 
liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rostopic echo liaoTian
name: !!python/str "\u5F20\u4E09"
age: 249
height: 180.779998779
---
name: !!python/str "\u5F20\u4E09"
age: 250
height: 180.779998779
---

Ⅱ.非自定义消息,直接使用即可 

4.rostopic pub 话题 Tab补齐 :用命令行发布数据,做测试用

 然后自己修改这些空着的地方就好

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rostopic pub liaoTian plumbing_pub_sub/Person "name: ''
age: 0
height: 0.0" 

5.rostopic info 话题:显示话题具体信息

6.rostopic hz 话题:显示发布频率 

1.1.4 rosservice 命令 

1.准备工作:以下述代码为例演示rosservice命令

#include "ros/ros.h"
#include"plumbing_server_client/addints.h"
/*
服务端实现:解析客户端提交的数据,并运算再产生响应
1.包含相关头文件
2.初始化ros节点
3.创建节点句柄
4.创建服务对象
5.处理请求并产生响应
6.spin()
*/

bool doNums(plumbing_server_client::addints::Request & request,plumbing_server_client::addints::Response &response)             //返回bool值,表明成功或者失败
{
    //1.处理请求
    int num1 = request.num1;
    int num2 = request.num2;
    ROS_INFO("收到的请求数据为:num1=%d,num2=%d",num1,num2);
    //2.组织响应
    int sum = num1+num2;
    response.sum = sum;
    ROS_INFO("求和结果为%d",sum);
    return true;
}

int main(int argc, char  *argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"heishui");     //节点名称唯一
    ros::NodeHandle nh;
    ros::ServiceServer server = nh.advertiseService("addInts",doNums);  //话题名称、回调函数
    ros::spin();
    return 0;
}
#include "ros/ros.h"
#include "plumbing_server_client/addints.h"
/*
客户端:提交两个数据,处理响应结果
1.包含相关头文件
2.初始化ros节点
3.创建节点句柄
4.创建客户端对象
5.提交请求并产生响应
*/

int main(int argc, char  *argv[])
{
    setlocale(LC_ALL,"");
    //优化实现,获取命令中的参数
    if(argc!=3)
    {
        ROS_INFO("提交的参数个数不对");
        return 1 ;
    }


    
    ros::init(argc,argv,"daBao");
    ros::NodeHandle nh;
    ros::ServiceClient client = nh.serviceClient<plumbing_server_client::addints>("addInts");    //话题
    //5-1组织请求
    plumbing_server_client::addints ai;
    ai.request.num1 = atoi(argv[1]);
    ai.request.num2 = atoi(argv[2]);

    //调用判断服务器状态的函数
    client.waitForExistence();    //如果服务器没启动,服务器就会挂起

    //5-2处理响应
    bool flag = client.call(ai);   //客户端带着ai对象访问服务器
    if(flag)
    {
        ROS_INFO("响应成功");
        //获取sum
        ROS_INFO("响应结果 = %d",ai.response.sum);    //传进去是引用变量
    }
    else
    {
        ROS_INFO("处理失败.........");
    }
    return 0;
}

2.rosservice list:当前ros服务中启动的服务

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosservice list
/addInts
/banZhuren/get_loggers
/banZhuren/set_logger_level
/heishui/get_loggers
/heishui/set_logger_level
/jiaZhang/get_loggers
/jiaZhang/set_logger_level
/rosout/get_loggers
/rosout/set_logger_level

3.rosservice call 服务名称:扮演客户端的角色,向服务器发送请求 

4.rosservice info 服务名称:服务相关信息

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosservice info addInts
Node: /heishui
URI: rosrpc://liuhongwei-virtual-machine:59523
Type: plumbing_server_client/addints
Args: num1 num2

1.1.5 rosmsg 命令

1.作用

rosmsg是用于显示有关 ROS消息类型的 信息的命令行工具。主要用于发布订阅模型中

 2.准备工作:

执行两个发布订阅模型的文件

#include "ros/ros.h"
#include"plumbing_pub_sub/Person.h"

int main(int argc ,char * argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"banZhuren");
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<plumbing_pub_sub::Person>("liaoTian",10);
    //创建发布数据
    plumbing_pub_sub::Person person;
    person.name = "张三";
    person.age = 1;
    person.height = 180.78;
    //设置发布频率
    ros::Rate rate(1);
    //循环发布数据
    while(ros::ok())
    {
        person.age++;
        //数据发布
        pub.publish(person);
        rate.sleep();
        //建议
        ros::spinOnce();
    }
    return 0;
}
#include "ros/ros.h"
#include "plumbing_pub_sub/Person.h"

void doPerson(const plumbing_pub_sub::Person::ConstPtr & person)
{
    ROS_INFO("订阅人的信息:%s,%d,%.2f",person->name.c_str(),person->age,person->height);
}

int main(int argc,char * argv[])
{
    setlocale(LC_ALL,"");
    ROS_INFO("订阅方实现");
    ros::init(argc,argv,"jiaZhang");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe("liaoTian",10,doPerson);
    ros::spin();
    return 0;
}

 3.rosmsg list:列出所有消息类型

4.rosmsg info/show:列出消息信息

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosmsg show plumbing_pub_sub/Person 
string name
int32 age
float32 height

1.1.6 rossrv 命令

1.作用

 rossrv是用于显示有关 ROS消息类型的 信息的命令行工具。主要用于服务通信中

2.与rosmsg相同,不再演示。 

1.1.7 rosparam 命令

1.作用

rosparam包含rosparam命令行工具,用于使用YAML编码文件在参数服务器上获取和设置ROS参数。是ROS参数服务器的命令。

2.rosparam list:列出参数服务器里面的一些数据

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam list
/rosdistro
/roslaunch/uris/host_liuhongwei_virtual_machine__36123
/rosversion
/run_id
/type_p

3.rosparam set 键名 值名:向参数服务器设置数据 

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam set name xiaohuang
liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam list
/name
/rosdistro
/roslaunch/uris/host_liuhongwei_virtual_machine__36123
/rosversion
/run_id
/type_p

3.rosparam get  键名:获取键名所对应的值

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam get name
xiaohuang

4.rosparam delete 键名:删除参数服务器里面的键值对

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam list
/len
/name
/rosdistro
/roslaunch/uris/host_liuhongwei_virtual_machine__36123
/rosversion
/run_id
/type_p
/width
liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam delete name
liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam list
/len
/rosdistro
/roslaunch/uris/host_liuhongwei_virtual_machine__36123
/rosversion
/run_id
/type_p
/width

5.rosparam dump 文件名.yaml:将参数写入磁盘文件(序列化)

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam dump param.yaml

 

6.rosparam load 文件名.yaml:反序列化

二、通信机制实操

2.1 本节内容概述

本节主要是通过ROS内置的turtlesim案例,结合已经介绍ROS命令获取节点、话题、话题消息、服务、服务消息与参数的信息,最终再以编码的方式实现乌龟运动的控制、乌龟位姿的订阅、乌龟生成与乌龟窗体背景颜色的修改。 

2.2 实操01_话题发布

2.2.1 需求分析

1.需求描述

编码实现乌龟运动控制,让小乌龟做圆周运动。

2.实现分析

  1. 乌龟运动控制实现,关键节点有两个,一个是乌龟运动显示节点 turtlesim_node,另一个是控制节点,二者是订阅发布模式实现通信的,乌龟运动显示节点直接调用即可,运动控制节点之前是使用的 turtle_teleop_key通过键盘 控制,现在需要自定义控制节点。
  2. 控制节点自实现时,首先需要了解控制节点与显示节点通信使用的话题与消息,可以使用ros命令结合计算图来获取。
  3. 了解了话题与消息之后,通过 C++ 或 Python 编写运动控制节点,通过指定的话题,按照一定的逻辑发布消息即可。

 3.实现流程

  1. 通过计算图结合ros命令获取话题与消息信息。
  2. 编码实现运动控制节点。
  3. 启动 roscore、turtlesim_node 以及自定义的控制节点,查看运行结果。

 2.2.2 话题与消息的获取

1.话题的获取

Ⅰ.rostopic list 命令可以获取当前全部的话题

liuhongwei@liuhongwei-virtual-machine:~$ rostopic list
/liaoTian
/rosout
/rosout_agg
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

Ⅱ.rqt_graph 也可以显示不同结点之间的情况

Ⅲ.由此可见,小乌龟运动的话题为 /turtle1/cmd_vel 

2.消息的获取

Ⅰ.用rostpoic info 命令获取当前话题的一些信息

liuhongwei@liuhongwei-virtual-machine:~$ rostopic info /turtle1/cmd_vel
Type: geometry_msgs/Twist

Publishers: 
 * /teleop_turtle (http://liuhongwei-virtual-machine:46283/)

Subscribers: 
 * /turtlesim (http://liuhongwei-virtual-machine:36721/)

由此可见,话题的发布方是 /teleop_turtle ,话题的订阅方为 /turtlesim ,话题类型为 geometry_msgs/Twists 

 Ⅱ.消息格式的获取:用rosmsg show 获取消息格式

liuhongwei@liuhongwei-virtual-machine:~$ rosmsg show geometry_msgs/Twist
geometry_msgs/Vector3 linear
  float64 x
  float64 y
  float64 z
geometry_msgs/Vector3 angular
  float64 x
  float64 y
  float64 z

linear 线速度 ; abgular 角速度;

线速度:开车前进后退速度  

x:前进后退速度  y:平移速度 z:垂直方向运动

PS:小乌龟只有前进后退

角速度:开车转弯速度

 x:翻滚:贯穿整个机体的坐标系 Roll(机翼上下移动)

y:俯仰:贯穿机翼的坐标系 Pitch(机头上下移动)

z:偏航:垂直方向的坐标系 Yaw(往左偏移或者往右偏移)

PS:小乌龟运动只有偏航!

2.2.3 C++实现发布节点 

1.实现步骤

Ⅰ.新建功能包,plumbing_test。导入依赖包 roscpp rospy std_msgs geometry_msgs,在src目录下建立 test01_pub_twist.cpp 文件

Ⅱ.分析流程:

/*
需求:发布速度消息
话题:/turtle/cmd_vel
消息: geometry_msg/Twist
 */

Ⅲ.代码实现

#include "ros/ros.h"
#include "geometry_msgs/Twist.h"

/*
需求:发布速度消息
话题:/turtle/cmd_vel
消息: geometry_msg/Twist
步骤:包含头文件,初始化ros节点,创建节点句柄,创建发布对象,发布逻辑实现,spinonce
*/

int main(int argc, char  *argv[])
{
    ros::init(argc,argv,"my_control");
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("/turtle/cmd_vel",10);

    ros::Rate rate(10);

    //组织消息
    geometry_msgs::Twist twist;
    twist.linear.x = 1.0;
    twist.linear.y = 0;
    twist.linear.z = 0;
    twist.angular.x = 0;
    twist.angular.y = 0;
    twist.angular.z = 0.5;

    while(ros::ok())
    {
        pub.publish(twist);
        rate.sleep();
        ros::spinOnce();
    }

    return 0;
}

Ⅳ.修改配置文件

Ⅴ.执行流程

①启动roscore

②启动乌龟UI   rosrun turtlesim turtlesim_node

③切换到工作空间,刷新环境变量,执行文件

2.2.4 python实现发布节点

1.实现步骤

Ⅰ.新建目录scripts,新建文件 test01_pub_twist.py.

Ⅱ.代码

#! /usr/bin/env python
# encoding:utf-8

import rospy
from geometry_msgs.msg import Twist
"""
发布方实现:发布速度信息
话题: /turtle1/cmd_vel
消息:geometry_msg/Twist
"""

if __name__ == "__main__":
    ros,rospy.init_node("my_control_p")
    pub = rospy.Publisher("/turtle1/cmd_vel",Twist,10)

    rate = rospy.Rate(10)
    twist = Twist()
    twist.linear.x = 1.0
    twist.linear.y = 0
    twist.linear.z = 0
    twist.angular.x = 0
    twist.angular.y = 0
    twist.angular.z = 0.5
    while not rospy.is_shutdown():
        pub.publish(twist)
        rate.sleep()
    pass

Ⅲ.添加可执行权限,更改配置文件,编译

Ⅳ.执行

2.3 实操02_话题订阅

2.3.1 需求分析

1.需求描述

 已知turtlesim中的乌龟显示节点,会发布当前乌龟的位姿(窗体中乌龟的坐标以及朝向),要求控制乌龟运动,并时时打印当前乌龟的位姿。

2.实现分析

  1. 首先,需要启动乌龟显示以及运动控制节点并控制乌龟运动。
  2. 要通过ROS命令,来获取乌龟位姿发布的话题以及消息。
  3. 编写订阅节点,订阅并打印乌龟的位姿。

3.实现流程

  1. 通过ros命令获取话题与消息信息。
  2. 编码实现位姿获取节点。
  3. 启动 roscore、turtlesim_node 、控制节点以及位姿订阅节点,控制乌龟运动并输出乌龟的位姿。

2.3.2 话题与消息的获取

Ⅰ.新建launch文件夹,建立start_turtle.launch文件。

<!-- 启动乌龟GUI与键盘控制节点 -->
<launch>
    <!-- 乌龟GUI -->
    <node pkg = "turtlesim" type = "turtlesim_node" name = "turtle1" output = "screen"/>
    <!-- 乌龟键盘控制 -->
    <node pkg = "turtlesim" type = "turtle_teleop_key" name = "key" output = "screen"/>
</launch>

 Ⅱ.启动launch文件

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ source ./devel/setup.bash 
liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ roslaunch plumbing_test start_launch.launch 

Ⅲ.启动成功

 Ⅳ.获取话题

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rostopic list 
/rosout
/rosout_agg
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

Ⅳ.获取话题消息

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rostopic info /turtle1/pose
Type: turtlesim/Pose

Publishers: 
 * /turtle1 (http://liuhongwei-virtual-machine:43221/)

Subscribers: None

Ⅴ.获取消息格式

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosmsg info turtlesim/Pose
float32 x
float32 y
float32 theta
float32 linear_velocity
float32 angular_velocity

Ⅵ.用命令实现获取订阅信息

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rostopic echo /turtle1/pose
x: 5.42456293106
y: 4.59195899963
theta: 0.319999992847
linear_velocity: 0.0
angular_velocity: 0.0
---

2.3.3 C++实现话题订阅

1.追加功能包

 在package.xml下追加依赖包turtlesim

<build_depend>turtlesim</build_depend>
<exec_depend>turtlesim</exec_depend>

更改CMakeLists

find_package(catkin REQUIRED COMPONENTS
  geometry_msgs
  roscpp
  rospy
  std_msgs
  turtlesim
)

编译

2 .具体实现

Ⅰ.处理逻辑

需求:订阅乌龟的位置信息并输出到工作台
1.包含头文件
2.初始化ros节点
3.创建节点句柄
4.创建订阅对象
5.处理订阅数据(回调)
6.spin

Ⅱ.代码实现

#include "ros/ros.h"
#include "turtlesim/Pose.h"

/*
需求:订阅乌龟的位置信息并输出到工作台
1.包含头文件
2.初始化ros节点
3.创建节点句柄
4.创建订阅对象
5.处理订阅数据(回调)
6.spin
*/
void doPos(const turtlesim::Pose::ConstPtr &pose)
{
    ROS_INFO("乌龟的位置信息:坐标(%.2f,%.2f),朝向(%.2f),线速度(%.2f),角速度(%.2f)",pose->x,pose->y,pose->theta,pose->linear_velocity,pose->angular_velocity);
}

int main(int argc, char  *argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"sub_pose");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe("/turtle1/pose",100,doPos);
    ros::spin();
    return 0;
}

Ⅲ.编写配置信息,编译

Ⅳ.执行

①执行roslaunch文件

②执行此代码,观察

roslaunch plumbing_test start_launch.launch
rosrun plumbing_test test02_sub_pose

2.3.4 python实现话题订阅

1.需求

需求:订阅并输出乌龟的位置信息
1.导包
2.初始化ros节点
3.创建订阅对象
4.回调函数处理信息
5.spin

2.具体实现

Ⅰ.代码

#! /usr/bin/env python
#encoding:utf-8

import rospy
from turtlesim.msg import Pose

"""
需求:订阅并输出乌龟的位置信息
1.导包
2.初始化ros节点
3.创建订阅对象
4.回调函数处理信息
5.spin
"""

def doPos(pose):
    rospy.loginfo("乌龟的位置信息:坐标(%.2f,%.2f),朝向%.2f,线速度%.2f,角速度%.2f",pose.x,pose.y,pose.theta,pose.linear_velocity,pose.angular_velocity)

if __name__ == "__main__":
    rospy.init_node("sub_pose_p")
    sub = rospy.Subscriber("/turtle1/pose","Pose",doPos,queue_size=100)
    rospy.spin()
    pass

 Ⅱ.添加可执行权限,修改配置文件,编译

Ⅲ.执行(与C++流程相同,不再演示)

2.4 实操03_服务调用

2.4.1 需求分析

1.需求描述

编码实现向 turtlesim 发送请求,在乌龟显示节点的窗体指定位置生成一乌龟,这是一个服务请求操作。

2.需求分析

  1. 首先,需要启动乌龟显示节点。
  2. 要通过ROS命令,来获取乌龟生成服务的服务名称以及服务消息类型。
  3. 编写服务请求节点,生成新的乌龟。

3. 实现流程

  1. 通过ros命令获取服务与服务消息信息。
  2. 编码实现服务请求节点。
  3. 启动 roscore、turtlesim_node 、乌龟生成节点,生成新的乌龟。

2.4.2 服务名称与服务信息获取

操作步骤

Ⅰ.调用launch文件启动乌龟的GUI

roslaunch plumbing_test start_launch.launch

Ⅱ.新建窗口,获取服务话题

liuhongwei@liuhongwei-virtual-machine:~$ rosservice list
/clear
/kill
/reset
/rosout/get_loggers
/rosout/set_logger_level
/spawn
/sub_pose/get_loggers
/sub_pose/set_logger_level
/turtle1/get_loggers
/turtle1/set_logger_level
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative

生成新的小乌龟的话题是 /spawn

Ⅲ.获取更多话题的信息

liuhongwei@liuhongwei-virtual-machine:~$ rosservice info /spawn 
Node: /turtle1
URI: rosrpc://liuhongwei-virtual-machine:39847
Type: turtlesim/Spawn
Args: x y theta name

话题服务使用的消息类型:turtlesim/Spawn

请求服务提交的字段:x y theta name

Ⅳ.获取服务消息的数据格式

liuhongwei@liuhongwei-virtual-machine:~$ rossrv info turtlesim/Spawn
float32 x
float32 y
float32 theta
string name
---
string name

Ⅴ.通过命令实现

liuhongwei@liuhongwei-virtual-machine:~$ rosservice call /spawn "x: 0.0
y: 0.0
theta: 0.0
name: ''" 

 

2.4.3 C++实现服务调用

1.实现

Ⅰ.实现code

#include "ros/ros.h"
#include "turtlesim/Spawn.h"
/*
需求:向服务端发送请求,生成一只新乌龟
话题:/spawn
消息:turtlesim/Spawn
*/

int main(int argc, char  *argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"service_call");
    ros::NodeHandle nh;
    ros::ServiceClient client = nh.serviceClient<turtlesim::Spawn>("/spawn");
    
    turtlesim::Spawn spawn;
    spawn.request.name = "shazi";
    spawn.request.theta = 0.0;
    spawn.request.x = 1.0;
    spawn.request.y = 4.0;

    //ros::service::waitForService("/spawn");
    client.waitForExistence();

    bool flag = client.call(spawn);
    if(flag)
    {
        ROS_INFO("乌龟生成成功,新乌龟叫:%s",spawn.response.name.c_str());
    }
    else
    {
        ROS_INFO("请求失败");
    }
    return 0;
}

Ⅱ.编写配置文件,编译

Ⅲ.执行

首先,启动 roscore;

然后启动乌龟显示节点;

最后启动乌龟生成请求节点;

2.4.4 python实现服务调用 

1.实现代码

Ⅰ.code

#! /usr/bin/env python
#encoding:utf-8

import rospy
from turtlesim.srv import Spawn,SpawnRequest,SpawnResponse

if __name__ =="__main__":
    rospy.init_node("service_call_p")
    client = rospy.ServiceProxy("/spawn",Spawn)

    request = SpawnRequest()
    request.x = 4.5
    request.y = 2.0
    request.theta = -3
    request.name = "chenzhuo"

    client.wait_for_service()
    response = client.call(request)
    rospy.loginfo("生成乌龟的名字为:%s",response.name)
    pass

Ⅱ.修改配置文件并编译

Ⅳ.执行

2.4 实操04_参数设置

2.4.1 需求分析

1.需求描述

修改turtlesim乌龟显示节点窗体的背景色,已知背景色是通过参数服务器的方式以 rgb 方式设置的。

2.实现分析

  1. 首先,需要启动乌龟显示节点。
  2. 要通过ROS命令,来获取参数服务器中设置背景色的参数。
  3. 编写参数设置节点,修改参数服务器中的参数值。

3.实现流程

  1. 通过ros命令获取参数。
  2. 编码实现服参数设置节点。
  3. 启动 roscore、turtlesim_node 与参数设置节点,查看运行结果。

2.4.2 服务名称与服务信息获取

Ⅰ.参数名获取

先要启动乌龟UI节点,

rosrun turtlesim turtlesim_node

Ⅱ.利用命令列出所有参数

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam list
/rosdistro
/roslaunch/uris/host_liuhongwei_virtual_machine__40263
/roslaunch/uris/host_liuhongwei_virtual_machine__40397
/rosversion
/run_id
/turtle1/background_b
/turtle1/background_g
/turtle1/background_r
/turtlesim/background_b
/turtlesim/background_g
/turtlesim/background_r

Ⅲ.查看参数值

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam get /turtlesim/background_r
69

Ⅳ.此时背景色

Ⅴ.利用命令行修改参数 

liuhongwei@liuhongwei-virtual-machine:~/demo03_ws$ rosparam set /turtlesim/background_r 255

Ⅵ.结果演示

2.4.3 C++实现更改参数

Ⅰ.code1

#include "ros/ros.h"


/*
修改参数服务器中turtlesim背景色相关参数
*/


int main(int argc, char  *argv[])
{
    ros::init(argc,argv,"chage_bgcolor");
    ros::param::set("/turtlesim/background_r",0);
    ros::param::set("/turtlesim/background_g",0);
    ros::param::set("/turtlesim/background_b",0);

    return 0;
}

 2.运行测试1:

 3.code2

#include "ros/ros.h"


/*
修改参数服务器中turtlesim背景色相关参数
*/


int main(int argc, char  *argv[])
{
    ros::init(argc,argv,"chage_bgcolor");
    ros::NodeHandle nh("turtlesim");
    nh.setParam("background_r",255);
    nh.setParam("background_g",255);
    nh.setParam("background_b",255);

    return 0;
}

2.4.4 python实现更改参数

 Ⅰ.code

#! /usr/bin/env python 
#encoding:utf-8
import rospy

if __name__ == "__main__":
    rospy.init_node("change_bgColor")
    rospy.set_param("/turtlesim/background_r",100)
    rospy.set_param("/turtlesim/background_g",100)
    rospy.set_param("/turtlesim/background_b",100)

    pass

2.5 通信机制比较

三种通信机制中,参数服务器是一种数据共享机制,可以在不同的节点之间共享数据,话题通信与服务通信是在不同的节点之间传递数据的,三者是ROS中最基础也是应用最为广泛的通信机制。

这其中,话题通信和服务通信有一定的相似性也有本质上的差异,在此将二者做一下简单比较:

二者的实现流程是比较相似的,都是涉及到四个要素:

  • 要素1: 消息的发布方/客户端(Publisher/Client)
  • 要素2: 消息的订阅方/服务端(Subscriber/Server)
  • 要素3: 话题名称(Topic/Service)
  • 要素4: 数据载体(msg/srv)

可以概括为: 两个节点通过话题关联到一起,并使用某种类型的数据载体实现数据传输。

2.6 本章小结

本章主要介绍了ROS中最基本的也是最核心的通信机制实现: 话题通信、服务通信、参数服务器。每种通信机制,都介绍了如下内容:

  • 伊始介绍了当前通信机制的应用场景;

  • 介绍了当前通信机制的理论模型;

  • 分别介绍了当前通信机制的C++与Python实现。

除此之外,还介绍了:

  • ROS中的常用命令方便操作、调试节点以及通信信息;
  • 通过实操又将上述知识点加以整合;
  • 最后又着重比较了话题通信与服务通信的相同点以及差异。

掌握本章内容后,基本上就可以从容应对ROS中大部分应用场景了。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

APS2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值