3 ROS1通讯编程提高(1)
创始人
2025-06-01 21:21:42
0

3 ROS1通讯编程提高

  • 3.1 使用VS Code编译ROS1
    • 3.1.1 VS Code的安装和配置
      • 3.1.1.1 VS Code以及插件安装
      • 3.1.1.2 VS Code配置ROS1工作空间
      • 3.1.1.3 VS Code运行ROS1的方法
      • 3.1.1.3 参考资料
    • 3.1.2 使用VScode编译C++文件
    • 3.1.3使用VScode编译Python文件
  • 3.2 ROS1动作编程
    • 3.2.1 动作编程模型
    • 3.2.2 动作编程基础示例
      • 3.2.2.1 使用VS Code创建动作编程项目
      • 3.2.2.2 配置action动作文件
      • 3.2.2.3 C++实现action基本编程
      • 3.2.2.4 Python实现action基本编程\
    • 3.2.3 动作编程总结
      • 3.2.3.1 动作编程的顺序流程
      • 3.2.3.2 动作编程逻辑
    • 3.2.4 参考

  • 其他ROS1学习笔记: ROS1学习笔记
  • 代码仓库:Github连接地址
  • 欢迎各位互相学习交流

3.1 使用VS Code编译ROS1

3.1.1 VS Code的安装和配置

3.1.1.1 VS Code以及插件安装

  1. VS Code的下载安装:

VS Code的下载链接:VS Code 官网连接;历史版本下载链接:VS Code历史版本,选择合适的版本,对于Linux系统下载deb文件双击运行,或者输入命令sudo dpkg -i vscode安装包名.deb即可。

  1. VS Code的插件配置:
    1. VS Code编译ROS需要的插件主要包括:ROS、C/C++、Python、CMake、CMake Tools以及中文汉化插件Chinese(simplified) Language Pack for Visual Studio Code,如图所示:

在这里插入图片描述

    1. 其中Python可能需要设置解析器的位置即usr/bin/python2.7,重启VS Code,配置好的插件环境如图所示:

在这里插入图片描述

3.1.1.2 VS Code配置ROS1工作空间

  1. VS Code打开工作空间:
    1. 在终端进入到工作空间即cd catkin_ws
    1. 输入命令code .直接在VS Code打开工作空间,如图所示

在这里插入图片描述

  1. 配置工作空间下的json文件:在VS Code打开的工作空间,会出现一个.vscode文件夹,里面存放了三个json文件,用于配置C++和Python编译ROS,下面依次介绍:
    1. task.json文件:用于配置C++和Python编译ROS任务,配置好之后,可基本上后续不需要进行改动。
// /home/ubuntu/catkin_ws/.vscode/tasks.json
{"version": "2.0.0","tasks": [{"type": "shell","args": ["--directory","/home/ubuntu/catkin_ws"],"problemMatcher": ["$catkin-gcc"],"command":"catkin_make","group": "build","label": "catkin_make: build_by_vscode","presentation": {"reveal": "always"}}]
}
    1. c_cpp_properties.json:用于配置C++编译ROS时的一些C++特有的路径和代码规范,配置本次配置好,后续可能出现修改地方主要在于这些路径位置。
// /home/ubuntu/catkin_ws/.vscode/c_cpp_properties.json
{"configurations": [{"browse": {"databaseFilename": "","limitSymbolsToIncludedHeaders": true},"includePath": ["/opt/ros/melodic/include/**","${workspaceFolder}/devel/include/**",//配置成自身工作空间的devel文件夹的路径;//目的是指向自定义msg/action/srv等路径."/usr/include/**"],"name": "ROS","cppStandard":"c++17","intelliSenseMode": "gcc-x64","compilerPath": "/usr/bin/gcc","cStandard": "c11"}],"version": 4
}
    1. settings.json:用于配置Python编译ROS时的一些Python包路径和规范,配置好之后,可能出现变换的地方也在这些路径位置。
// /home/ubuntu/catkin_ws/.vscode/settings.json
{"python.autoComplete.extraPaths": ["/opt/ros/melodic/lib/python2.7/dist-packages","${workspaceFolder}/devel/lib/python2.7/dist-packages"// 如果是高版本ROS可能是Python3,按照自定义消息一样查看中间文件位置确定],"cmake.configureOnOpen": true,"cmake.sourceDirectory": "${workspaceFolder}/src"
}

3.1.1.3 VS Code运行ROS1的方法

  1. 编译运行:
  • 方法一:使用快捷键或者在VS Code的编译器【终端】–【运行生成任务】即Crtl+Shift+B,点击之后选择catkin_make: build_by_vscode(在task.json的label名字)即可编译整个工作空间。
  • 方法二:在VS Code下面的终端(或者在【终端】–【新终端】即Crtl+Shift+`)cd 到catkin_ws下进行catkin_make编译

3.1.1.3 参考资料

  1. 参考文献:
    VS Code的tast.json查考文件;
    VS Code的C++查考文件;
    VS Code的Python查考文件;
    【奥特学园】ROS机器人入门课程《ROS理论与实践》零基础教程

3.1.2 使用VScode编译C++文件

  1. catkin_ws/src/目录下右键create catkin package创建包,然后按照提示命名如test,然后输入依赖项roscpp rospy std_msgs

  2. catkin_ws/src/test/src下右键新建test_c.cpp文件,编辑test_c.cpp文件。

// test_c.cpp文件用于测试ROS1环境
#include "ros/ros.h"
int main(int argc, char* argv[])
{ros::init(argc,argv,"i_am_nodename");ROS_INFO("HELLO");return 0;
}
  1. 配置catkin_ws/src/test/src/CMakeLists.txt文件,然后编译运行。
    1. 在136行,取消 add_executable(${PROJECT_NAME}_node src/test_node.cpp)的注释,修改为 add_executable(i_am_nodename src/test_c.cpp)
    1. 其次在149-151行的target_link_libraries(${PROJECT_NAME}_node…) 修改为 target_link_libraries(i_am_nodename…)即可
    1. 编译运行(直接在VScode的终端下的+号新建终端,输入roscore,新建终端输入rosrun test i_am_nodename即可查看INFO的消息)。

3.1.3使用VScode编译Python文件

  1. 之前同编译C++是Step1-Step3,此时在catkin_ws/src/test/文件夹下创建Python文件夹scripts,在scripts文件夹里新建Python文件test_p.py
  2. 编写Python程序,赋予可执行权限,然后运行客户端roscore,最后rosrun test test_p.py即可。
#! /usr/bin/env python
import rospy
if __name__ =='__main__':rospy.init_node("test_p")rospy.loginfo("ok")

Tips:
在Ubuntu20.04版本的ROS需要配置CMakeLists文件,大约在161行处,类似C++一样添加Python文件的位置。同时对于高版本的Python编译ROS在Python文件头部是没有#!/usr/bin/env
python,采用命令:sudo ln -s /usr/bin/python3 /usr/bin/python创建Python的连接。

3.2 ROS1动作编程

3.2.1 动作编程模型

在任何ROS的大型系统中,如果向节点发送请求以执行某些任务,最后收到对请求的回复,这一操作主要是通过ROS的服务编程实现,但是如果服务需要很长时间来执行,用户可能希望能够在执行期间取消请求或获得有关请求进展情况的定期反馈,基本的服务编程的应答模式是满足不了的,因此ROS提供actionlib即动作编程完成这些操作。

  • 动作编程的作用:针对服务编程的应答模式的提升,在服务端执行过程中能够取消或者获得服务器状态,动作编程一般适用于耗时的请求响应场景,用以获取连续的状态反馈。

  • 动作编程的例子:如巡检机器人导航过程中,从A到B的导航过程,应该是一个动作编程,即目标是B,在A到B时,提供导航状态。

在这里插入图片描述
在动作编程中,客户端发送目标(goal)或者取消指令(cancel)给服务端,服务端提供状态(status)、实时反馈(feedback)和结果(result)。

官方以移动机器人为例解释goal、feedback和result,即

  • 1)目标(goal):为了使用动作完成任务,引入了可以由 ActionClient 发送到 ActionServer 的目标的概念。在移动基地的情况下,目标是 PoseStamped 消息,其中包含有关机器人应移动到世界何处的信息,在官方洗碗例子中对目标的描述也是需要选择的那个洗碗工是谁。
  • 2)回馈(feedback):服务器持续反馈 ActionClient目标的增量进度。对于移动机器人,这可能是机器人沿路径的当前位置。
  • 3)结果(result):目标完成后,结果从 ActionServer 发送到 ActionClient,这与反馈不同,因为它只发送一次。当客户端请求的目的(goal)是提供某种信息时,这就非常有用。对于移动机器人,结果不是很重要,但它可以是机器人的最终位置(不代表就是目的地)。

3.2.2 动作编程基础示例

动作编程的基本思想和自定义的消息话题编程是一致的。

动作编程内容:洗盘子动作编程,两个节点,一个为客户端一个为服务端,客户端发送数字1(代码实现)给给服务端,作为选择哪个洗碗工,服务端接收到之后持续反馈进度给客户端,最后发送数字100(代码实现)作为结果返回。

3.2.2.1 使用VS Code创建动作编程项目

(一)使用VS Code新建功能包:

  1. 打开VS Code和工作空间,新建动作编程功能包并创建ROS文件夹结构。
    1. 打开VS Code和工作空间,在工作空间catkin_ws下输入命令code .打开VS Code,打开后如果出现提示Select a kit for catkin_ws,则选择第一项Scan for kit即可。

在这里插入图片描述

    1. 新建动作编程功能包,右键工作空间catkin_ws的src目录,选择create catkin package然后在VS Code的提示下输入包名action_communication,回车之后输入依赖项roscpp rospy std_msgs即可

在这里插入图片描述

    1. 新建ROS结构的文件夹,即在功能包下新建action文件夹和scripts文件夹。

3.2.2.2 配置action动作文件

(二)定义action动作文件:

  1. 定义动作文件。在action_communication/action下创建自定义动作文件.action,这里为DoDishes.action文件。其中的内容分为三个部分:
  • 第一部分goal对应目标数据,即客户端发布数据。
  • 第二部分result定义结果,服务端应答给客户端的结果。
  • 第三部分是反馈部分,服务端反馈一些信息给客户端。
# catkin_ws/src/action_communication/action/DoDishes.action
# Define the goal
uint32 dishwasher_id  # Specify which dishwasher we want to use
---
# Define the result
uint32 total_dishes_cleaned
---
# Define a feedback message
float32 percent_complete

(三)配置action文件

  • 配置msg文件包括在package.xml和CMakeList.txt配置两部分。
  1. 在package.xml添加依赖项actionlib和actionlib_msgs四项,二者都是依赖项和执行依赖项。
// /catkin_ws/src/action_communication/package.xmlactionlibactionlib_msgsactionlibactionlib_msgs
  1. 在功能包的CmakeLists.txt添加编译选项,包括四部分。
    1. 添加编译依赖项功能包:find_package(catkin REQUIRED COMPONENTS ..+ 依赖项功能包),大约在第10行,添加actionlibactionlib_msgs两项:
# /catkin_ws/src/action_communication/CMakeLists.txt
find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsactionlibactionlib_msgs
)
    1. 添加自定义action文件:add_action_files(FILES 文件名),大约在第66行,如此时的文件名为DoDishes.action
# /catkin_ws/src/action_communication/CMakeLists.txt
add_action_files(FILESDoDishes.action
)
    1. 添加action的编译依赖项std_msgsactionlib_msgs:generate_messages(DEPENDENCIES 依赖项名),大约在第71行,即表示在编译msg时候得依赖于std_msgs
# /catkin_ws/src/action_communication/CMakeLists.txt
generate_messages(DEPENDENCIESstd_msgsactionlib_msgs
)
    1. 添加执行时的依赖:catkin_package的关键字CATKIN_DEPENDS后+包,大约在106行,添加actionlib和actionlib_msgs如:
# /catkin_ws/src/action_communication/CMakeLists.txt
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES action_communicationCATKIN_DEPENDS roscpp rospy std_msgs actionlib actionlib_msgs
#  DEPENDS system_lib
)

(四)编译action文件,查看中间文件:

  1. 在工作空间下编译,此时在工作空间的devel目录会多出几个文件,如C++的中间文件在/home/ubuntu/catkin_ws/devel/include/功能包名/文件夹下,Python的中间文件在/home/ubuntu/catkin_ws/devel/lib/python2.7/dist-packages/功能包名/msg

3.2.2.3 C++实现action基本编程

(五)C++实现action基本编程:

  1. 实现动作服务器
    1. 首先在工作空间的根目录的src文件夹里创建服务程序DoDishes_server_cpp.cpp
# catkin_ws/src/action_communication/src/DoDishes_server_cpp.cpp
#include 
#include 
#include "action_communication/DoDishesAction.h"typedef actionlib::SimpleActionServer Server;// 收到action的goal后调用该回调函数
void callback(const action_communication::DoDishesGoalConstPtr& goal, Server* server)
{ros::Rate r(1);action_communication::DoDishesFeedback feedback;ROS_INFO("收到客户端的goal,洗碗工 %d 开始洗盘子.", goal->dishwasher_id);// 假设洗盘子的进度,并且按照1hz的频率发布进度feedbackfor(int i=1; i<=10; i++){feedback.percent_complete = i * 10;server->publishFeedback(feedback);ROS_INFO("feedback ing ...");r.sleep();}// 当action完成后,向客户端返回结果ROS_INFO("洗碗工完成了工作,发送result(100个)给客户端.");action_communication::DoDishesResult res;res.total_dishes_cleaned = 100;server->setSucceeded(res);
}int main(int argc, char** argv)
{setlocale(LC_ALL,"");ros::init(argc, argv, "do_dishes_server");ros::NodeHandle nh;// 定义一个服务器Server server(nh, "do_dishes", boost::bind(&callback, _1, &server), false);// 服务器开始运行ROS_INFO("action服务端启动,等待指令");server.start();ros::spin();return 0;
}
    1. 创建客户端文件DoDishes_client_cpp.cpp
# catkin_ws/src/l_t/src/DoDishes_client_cpp.cpp
#include 
#include "action_communication/DoDishesAction.h"typedef actionlib::SimpleActionClient Client;// 当action完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,const action_communication::DoDishesResultConstPtr& result){ROS_INFO("result:洗碗工把盘子已经洗完啦!洗了%d个",result->total_dishes_cleaned);ros::shutdown();
}// 当action激活后会调用该回调函数一次
void activeCb(){ROS_INFO("服务器已经打开,可以执行任务");
}// 收到feedback后调用该回调函数
void feedbackCb(const action_communication::DoDishesFeedbackConstPtr& feedback)
{ROS_INFO("feedback:洗盘子的进度:%f", feedback->percent_complete);
}int main(int argc, char** argv)
{setlocale(LC_ALL,"");ros::init(argc, argv, "do_dishes_client");// 定义一个客户端Client client("do_dishes", true);// 等待服务器端client.waitForServer();ROS_INFO("goal:选择员工1洗盘子:");// 创建一个action的goalaction_communication::DoDishesGoal goal;goal.dishwasher_id = 1;// 发送action的goal给服务器端,并且设置回调函数client.sendGoal(goal,  &doneCb, &activeCb, &feedbackCb);ros::spin();return 0;
}
    1. 配置动作的服务端和客户端代码的编译选项。在功能包的目录下,打开其CMakeLists.txt文件。
# catkin_ws/src/action_communication/CMakeLists.txt
add_executable(dodisher_server_cpp src/DoDishes_server_cpp.cpp)
add_executable(dodisher_client_cpp src/DoDishes_client_cpp.cpp)add_dependencies(dodisher_server_cpp ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(dodisher_client_cpp ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})target_link_libraries(dodisher_server_cpp ${catkin_LIBRARIES})
target_link_libraries(dodisher_client_cpp ${catkin_LIBRARIES})
    1. 在工作空间的根目录下进行编译操作。
    1. 运行服务编程。首先打开一个终端输入roscore,打开ROS,再新建一个终端输入rosrun action_communication DoDishes_server运行服务程序。最后新建终端输入rosrun action_communication DoDishes_client即运行客户端并执行动作操作。

在这里插入图片描述

3.2.2.4 Python实现action基本编程\

(六)Python实现action基本编程:

  1. 在scripts文件夹创建Python服务端文件
    1. DoDishes_server_py.py,代码见注释

#!/usr/bin/env python
# -*- coding: utf-8 -*-# catkin_ws/src/action_communication/scripts/DoDishes_server_py.pyimport rospy
import actionlib
from action_communication.msg import *class myActionServer:def __init__(self):# 1.创建服务器,执行服务器回调函数self.server = actionlib.SimpleActionServer("dodishes", DoDishesAction, self.serverCb, False)self.server.start()rospy.loginfo("服务端启动")def serverCb(self,goal):id = goal.dishwasher_idrospy.loginfo("收到来自客户端的goal,洗碗工 %d 开始工作",id)rate = rospy.Rate(1)for i in range(1, 10):rospy.loginfo("feedback ing...")feedBack_obj = DoDishesFeedback()feedBack_obj.percent_complete = iself.server.publish_feedback(feedBack_obj)rate.sleep()res = DoDishesResult()res.total_dishes_cleaned = 100rospy.loginfo("洗碗工完成了工作,发送result(100个)给客户端.")self.server.set_succeeded(res)if __name__ == "__main__":rospy.init_node("action_server_py")server = myActionServer()rospy.spin()
    1. 编写客户端DoDishes_client_py.py文件
#!/usr/bin/env python
# -*- coding: utf-8 -*-# catkin_ws/src/action_communication/scripts/DoDishes_client_py.pyimport rospy
import actionlib
from action_communication.msg import *def result_cb(state,result):if state == actionlib.GoalStatus.SUCCEEDED:rospy.loginfo("result:洗碗工把盘子已经洗完啦!洗了%d个",result.total_dishes_cleaned)def active_cb():rospy.loginfo("服务被激活....")def feedback_cb(f):rospy.loginfo("当前进度:%.2f",f.percent_complete)if __name__ == "__main__":# 2.初始化 ROS 节点rospy.init_node("action_client_py")# 3.创建 action Client 对象client = actionlib.SimpleActionClient("dodishes",DoDishesAction)# 4.等待服务client.wait_for_server()# 5.组织目标对象并发送goal_obj = DoDishesGoal()goal_obj.dishwasher_id = 1rospy.loginfo("goal:选择员工1洗盘子:")client.send_goal(goal_obj,result_cb,active_cb,feedback_cb)# 6.编写回调, 激活、连续反馈、最终响应# 7.spinrospy.spin()
    1. 给Python文件赋予可执行权限,在script文件夹下输入命令sudo chmod +x *.py即可赋予所有Python可执行权限。
    1. 运行py文件

在这里插入图片描述

3.2.3 动作编程总结

3.2.3.1 动作编程的顺序流程

  1. 动作编程的顺序流程:
    1. 在action文件夹编写自定义action文件,配置package.xml文件包括actionlib和actionlib_msg,分别包括四项;
    1. 配置CMakeList.txt文件包括
      1. 添加编译依赖项功能包find_package
      1. 添加自定义action文件add_action_files
      1. 添加action的编译依赖项generate_messages里添加std_msgs和actionlib_msgs
      1. 添加执行时的依赖catkin_package里添加actionlib actionlib_msgs
    1. C++代码:
      1. 添加头文件(头文件为功能包名字/自定义动作.h)
      1. 正常编写代码;
      1. CMakeList.txt进行配置(不仅有add_executable和target_link_libraries还包括add_dependencies);
      1. 编译运行;
    1. Python代码:
      1. 添加包from 功能包名.msg import *
      1. 正常代码编写;②CMakeList.txt进行配置(目前配置不配置影响不大);
      1. 赋予py文件可执行权限
      1. 编译运行。

3.2.3.2 动作编程逻辑

  1. 编程逻辑顺序:

在这里插入图片描述

3.2.4 参考

  • ROS-WIKI:actionlib package summary(DoDishes)
  • 高级action教程-ROS-WIKI:cn/actionlib_tutorials/Tutorials
  • B站视频:【奥特学园】ROS机器人入门课程《ROS理论与实践》零基础教程

相关内容

热门资讯

原创 一... 标题:一份绝妙的鳗鱼饭是如何炼成的? 在追求极致美味的道路上,我们总在探寻那些能够触动味蕾的秘密。...
豆芽菜只知道泡水保存? 专家分... 想要延长豆芽菜的保存期限,日本料理达人分享「用50度水浸泡2分钟」就能保存一周还能维持蔬菜脆度。 豆...
原创 豆... 标题:豆腐与它绝配,天冷热乎乎来一锅,一咬满口爆鲜汁,连锅一起吃 在寻找那一份能够唤醒味蕾的美食时...
原创 大... 相比南方一个市一个主打汤,我觉得北方的汤要简单太多了。 基本都是清水煮汤,味道全凭对食材的拿捏。 ...
原创 6... 暑气蒸腾的季节,厨房灶火前多站片刻都是煎熬。偏是此时,一碗清清爽爽的瓠子鸡蛋汤端上桌,那水润鲜亮的汤...
原创 豆... 标题:豆腐新吃法,1瓶可乐就搞定,比可乐鸡还好吃,做法超简单 在这个快节奏的时代,我们总是在寻找那...
原创 鸡... 标题:鸡蛋的新做法,只需3步,口感和颜值并存,招待客人特别有面子。 在美食的世界里,鸡蛋以其简单而...
原创 1... 火爆全国的湘菜,迎来了新拐点。 爆红的湘菜有了新挑战。 近几年,湘菜成了中餐赛道的焦点,“排队王...
原创 强... 鸡蛋抱豆腐这道菜,简直是我家餐桌上的"核武器级"下饭神器!每次掀开锅盖的瞬间,金灿灿的鸡蛋裹着嫩滑的...
原创 一... 标题:一根香肠,三个鸡蛋,做道嫩滑可口又营养的早餐,10分钟搞定! 在忙碌的早晨,我们总是渴望一份...
安徽涡阳:粽香传古韵 民俗庆端... 端午期间,安徽涡阳县各地纷纷开展丰富多彩的活动,以粽香传递千年古韵,用民俗共庆传统端阳,让古老节日焕...
原创 舌... 咱们总说 “民以食为天”,其实每一口吃下去的,可不只是填饱肚子的东西,更是一部藏在舌尖上的文明史。今...
原创 炒... 说起炒豆角,多少主妇翻过车?不是炒得蔫黄软烂失了魂,就是硬邦邦一股子生豆腥气,嚼得腮帮子累!更有人图...
原创 一... 标题:一块南瓜,做出的糕点,香软Q弹,热量也不高,有没有诱惑到你? 在探索美食的旅程中,我们总能找...
走进乌兰布统 感受雄浑壮阔的塞... 本文转自:人民网-内蒙古频道6月2日,航拍克什克腾旗乌兰布统草原美景。李富摄在内蒙古自治区赤峰市克什...
重庆五天四晚旅游攻略,两个人去... 重庆五天四晚旅游攻略,两个人去重庆玩五天要消费多少? 最近,我和朋友一直计划着一场说走就走的旅行,而...
原创 黄... 斑马消费 杨伟 2025年A股酒水板块“冰火两重天”,白酒承压,啤酒失速,黄酒却异军突起! Wind...
原创 4... 在城市的喧嚣中,我们常常忽略了那些默默付出的劳动者。今天,我要讲述的是一位来自农村的大姐,她的故事让...
原创 鱼... 标题:鱼肉的最新吃法,不蒸不煮不烧,鲜香爽滑,可以吃下两大碗米饭! 在探索美食的旅途中,我们总在寻...