文章目录
01 服务调用 plumbing_test
1.0 需求 - 分析 - 流程
- 需求描述:编码实现向 turtlesim 发送请求,在乌龟显示节点的窗体指定位置生成一乌龟,这是一个服务请求操作。
实现分析:
- 首先,需要启动乌龟显示节点。
- 要通过ROS命令,来获取乌龟生成服务的服务名称以及服务消息类型。
- 编写服务请求节点,生成新的乌龟。
实现流程:
- 通过ros命令获取服务与服务消息信息。
- 编码实现服务请求节点。
- 启动 roscore、turtlesim_node 、乌龟生成节点,生成新的乌龟。
1.1 服务名称与服务消息获取
1.1.0 启动控制乌龟运动节点(获得话题和消息) start_turtle.launch
<!-- 启动乌龟GUI与键盘控制节点-->
<launch>
<!-- 乌龟GUI-->
<!-- pkg——包,type——被执行的节点,name——节点取的名字,output = "screen"——日志输出到屏幕上-->
<!-- rosrun turtlesim(pkg)功能包 turtlrsim_node(type)-->
<node pkg = "turtlesim" type = "turtlesim_node" name = "turtle1" output = "screen"/>
<!-- 键盘控制-->
<node pkg = "turtlesim" type = "turtle_teleop_key" name = "key" output = "screen" />
</launch>
1.1.0.0 vscode终端启动 launch 文件
cd demo01_ws
source ./devel/setup.bash
roslaunch plumbing_test start_turtle.launch
1.1.1 获取话题 /spawn(产卵) (addInts)
- 在终端ternimal新建窗口
- rosservice list (不是rostopic)
/clear
/key/get_loggers
/key/set_logger_level
/kill
/reset
/rosout/get_loggers
/rosout/set_logger_level
/spawn
/turtle1/get_loggers
/turtle1/set_logger_level
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
1.1.2 获取服务消息类型 turtlesim/Spawn (AddInts.srv)
- rosservice info /spawn:获取 turtlesim/Spawn
Node: /turtle1
URI: rosrpc://rosnoetic-VirtualBox:60831
Type: turtlesim/Spawn
Args: x y theta name
1.1.3 获取服务消息格式
- theta是弧度制,范围是3.14rad——(-3.14)rad,逆时针为正,顺时针为负
- rossrv info turtlesim/Spawn
- 说明:x与y是乌龟的坐标,theta是乌龟的朝向,name是乌龟的名字
float32 x (上半部分是请求)
float32 y
float32 theta
string name
string name(下半部分是响应)
1.2 实现服务客户端 —— plumbing_test
1.2.1 C++实现 —— test03_server_client.cpp
#include"ros/ros.h"
#include"turtlesim/Spawn.h"
/*
需求:向服务器发送请求,生成一个新的乌龟
话题:/spawn
消息:turtlesim/Spawn
1.包含头文件
2.初始化ROS节点
3.创建节点句柄
4.创建客户端对象
5.组织数据并发送
6.处理响应
*/
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化ROS节点
ros::init(argc,argv,"service_call");
// 3.创建节点句柄
ros::NodeHandle nh;
// 4.创建客户端对象
ros::ServiceClient client = nh.serviceClient<turtlesim::Spawn>("/spawn"); // /spawn是话题名称
// 5.组织数据并发送
// 5.1 组织请求数据
turtlesim::Spawn spawn;
spawn.request.x = 1.0;
spawn.request.y = 4.0;
spawn.request.theta = 4.0;
spawn.request.name = "turtle2";
// 5.2 发送请求
//判断服务器状态
// ros::service::waitForService("/spawn");
client.waitForExistence();
bool flag = client.call(spawn);//flag 接受响应状态,响应结果也会被设置进spawn对象
// 6.处理响应
if(flag) // 响应成功
{
ROS_INFO("乌龟生成成功,新乌龟叫:%s",spawn.response.name.c_str());
}
else
{
ROS_INFO("请求失败!!!");
}
return 0;
}
1.2.2 配置 CMakeLists.txt
add_executable(test03_server_client src/test03_server_client.cpp)
add_dependencies(test03_server_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) —— 可以不添加,因为没有自定义消息
target_link_libraries(test03_server_client
${catkin_LIBRARIES}
)
1.2.3 编译运行
- 编译:Ctrl + Shift + B
- 启动 launch vscode终端窗口 —— 要把光标放在vscode终端启动launch文件的位置!!!
source ./devel/setup.bash
roslaunch plumbing_test start_turtle.launch
-
ctrl+alt+t:开新的窗口
-
启动 roscore(窗口1)
roscore
- 启动客户端(窗口2)
cd demo01_ws
source ./devel/setup.bash
rosrun plumbing_test test03_service_client
1.2.4 Python实现 —— test03_server_client_p.py
#! /usr/bin/env python
"""
需求:向服务器发送请求生成一个乌龟
话题:/spawn
消息类型:turtlesim/Spawn
1. 导包
2. 初始化ROS节点
3. 创建服务的客户端对象
4. 组织数据并发送请求
5. 处理响应结果
"""
import rospy
from turtlesim.srv import Spawn,SpawnRequest,SpawnResponse
if __name__ == "__main__":
# 2. 初始化ROS节点
rospy.init_node("service_call")
# 3. 创建服务的客户端对象
client = rospy.ServiceProxy("/spawn",Spawn) # /spawn是话题名称
# 4. 组织数据并发送请求
# 4.1 组织数据
request = SpawnRequest()
request.x = 4.5
request.y = 2.0
request.theta = -3 # 向右转3个rad
request.name = "turtle3"
# 4.2 判断服务器状态并发送
client.wait_for_service() # 服务端开启则执行,否则挂起
# 防止抛出异常
try:
response = client.call(request)
# 5. 处理响应结果
rospy.loginfo("生成乌龟的名字叫:%s",response.name)
except Exception as e:
rospy.logerr("请求处理异常")
1.2.5 添加可执行权限
scripts文件右击,在终端中打开
终端下进入 scripts 执行
chmod +x *.py
ll
1.2.6 配置 CMakeLists.txt
catkin_install_python(PROGRAMS
scripts/test03_server_client_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
1.2.7 编译运行
- 编译:Ctrl + Shift + B
- 启动 launch vscode终端窗口 —— 要把光标放在vscode终端启动launch文件的位置!!!
source ./devel/setup.bash
roslaunch plumbing_test start_turtle.launch
-
ctrl+alt+t:开新的窗口
-
启动 roscore(窗口1)
roscore
- ctrl+alt+t:开新窗口
- 启动客户端(窗口2)
cd demo01_ws
source ./devel/setup.bash
rosrun plumbing_test test03_server_client_p.py
02 参数设置 plumbing_test
2.0 需求 - 分析 - 流程
- 需求描述:修改turtlesim乌龟显示节点窗体的背景色,已知背景色是通过参数服务器的方式以 rgb 方式设置的。
实现分析:
- 首先,需要启动乌龟显示节点。
- 要通过ROS命令,来获取参数服务器中设置背景色的参数。
- 编写参数设置节点,修改参数服务器中的参数值。
实现流程:
- 通过ros命令获取参数。
- 编码实现服参数设置节点。
- 启动 roscore、turtlesim_node 与参数设置节点,查看运行结果。
2.1 参数名获取
2.1.0 启动键盘控制乌龟运动(获得话题和消息,没有用launch文件)
- 窗口1
roscore
- 窗口2
rosrun turtlesim turtlesim_node
2.1.1 获取参数列表
- 窗口3:获取参数列表rosparam list
/rosdistro
/roslaunch/uris/host_rosnoetic_virtualbox__43129
/rosversion
/run_id
/turtlesim/background_b
/turtlesim/background_g
/turtlesim/background_r
- 获取参数值rosparam get /turtlesim/background_r/b/g
- 使用命令方式修改颜色 rosparam set /turtlesim/background_r 255,然后重新启动节点 rosrun turtlesim turtlesim_node 就可以修改成功
2.2 实现参数修改
2.2.1 C++实现 —— test04_param.cpp
#include"ros/ros.h"
/*
需求:修改参数服务器中turtlesim背景色相关参数
1.初始化ROS节点
2.不一定需要创建节点句柄(和后续API有关)
3.修改参数
*/
int main(int argc, char *argv[])
{
// 1.初始化ROS节点
ros::init(argc,argv,"change_bgcolor");
// 2.不一定需要创建节点句柄(和后续API有关)
// ros::NodeHandle nh("turtlesim");//设置命名空间
// nh.setParam("background_r",255);
// nh.setParam("background_g",255);
// nh.setParam("background_b",255);
ros::NodeHandle nh;
nh.setParam("/turtlesim/background_r",0);
nh.setParam("/turtlesim/background_g",50);
nh.setParam("/turtlesim/background_b",100);
// 3.修改参数
// 方式1:如果调用ros::param 不需要创建节点句柄
// ros::param::set("/turtlesim/background_r",0);
// ros::param::set("/turtlesim/background_g",0);
// ros::param::set("/turtlesim/background_b",0);
// 方式2:使用nodehandle
return 0;
}
2.2.2 配置 CMakeLists.txt
add_executable(test04_param src/test04_param.cpp)
add_dependencies(test04_param ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(test04_param
${catkin_LIBRARIES}
)
2.2.3 编译运行(不用启动launch文件)
-
编译:Ctrl + Shift + B
-
启动 roscore(窗口1)
roscore
- 启动参数服务器(窗口2) 先不用 rosrun turtlesim turtlesim_node
cd demo01_ws
source ./devel/setup.bash
rosrun plumbing_test test04_param
- 启动窗口3
rosrun turtlesim turtlesim_node(最后启动)
2.2.4 Python实现 —— test04_param_p.py
#! /usr/bin/env python
"""
需求:修改乌龟GUI的背景色
1.初始化ros节点
2.设置参数
"""
import rospy
if __name__ == "__main__":
rospy.init_node("change_bgcolor")
# 修改背景色
rospy.set_param("/turtlesim/background_r",100)
rospy.set_param("/turtlesim/background_g",50)
rospy.set_param("/turtlesim/background_b",200)
2.2.5 添加可执行权限
scripts文件右击,在终端中打开
终端下进入 scripts 执行
chmod +x *.py
ll
2.2.6 配置 CMakeLists.txt
catkin_install_python(PROGRAMS
scripts/test04_param_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
2.2.7 编译运行(不启动launch文件)
-
编译:Ctrl + Shift + B
-
启动 roscore(窗口1)
roscore
- ctrl+alt+t:开新窗口
- 启动参数服务器(窗口2) 先不用 rosrun turtlesim turtlesim_node
cd demo01_ws
source ./devel/setup.bash
rosrun plumbing_test test04_param_p.py
- 启动窗口3
rosrun turtlesim turtlesim_node(最后启动)
03 通信机制比较
三种通信机制中,参数服务器是一种数据共享机制,可以在不同的节点之间共享数据,话题通信与服务通信是在不同的节点之间传递数据的,三者是ROS中最基础也是应用最为广泛的通信机制。
这其中,话题通信和服务通信有一定的相似性也有本质上的差异,在此将二者做一下简单比较:
二者的实现流程是比较相似的,都是涉及到四个要素:
- 要素1:消息的发布方/客户端(Publisher/Client)
- 要素2:消息的订阅方/服务端(Subscriber/Server)
- 要素3:话题名称(Topic/Service)
- 要素4:数据载体(msg/srv)
概括为: 两个节点通过话题关联到一起,并使用某种类型的数据载体实现数据传输。
二者的实现也是有本质差异的,具体比较如下:
Topic(话题) | Service(服务) | |
---|---|---|
通信模式 | 发布/订阅 | 请求/响应 |
同步性 | 异步 | 同步 |
底层协议 | ROSTCP/ROSUDP | ROSTCP/ROSUDP |
缓冲区 | 有 | 无 |
时时性 | 弱 | 强 |
节点关系 | 多对多 | 一对多(一个 Server) |
通信数据 | msg | srv |
使用场景 | 连续高频的数据发布与接收:雷达、里程计 | 偶尔调用或执行某一项特定功能:拍照、语音识别 |
- 不同通信机制有一定的互补性,都有各自适应的应用场景。尤其是话题与服务通信,需要结合具体的应用场景与二者的差异,选择合适的通信机制。