文章目录

  • 1.话题、服务模式的ROS程序设计实践
    • 创建工作空间
    • 话题编程
    • 服务编程
  • 2.ROS kinetic 动作编程实践
  • 3.ROS实现多机通讯实践
  • 4.总结
  • 5.参考

1.话题、服务模式的ROS程序设计实践

创建工作空间

  • 先介绍一下工作空间,简单地说吧,ROS workspace (工作空间)就是统一存放 ROS 文件的地方,比如一个项目的所有 ROS 文件最好都放在一个 workspace 中,便于统一管理、编译和调用
  • 创建工作空间的代码:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace

编译工作空间代码

cd ..
catkin_make
  • 设置检查环境变量代码
source devel/setup.bash
echo $ROS_PACKAGE_PATH
  • 创建功能包代码
cd ~/comm_ws/src
catkin_create_pkg learning_communication std_msgs rospy roscpp

编译功能包代码

cd ~/catkin_ws
catkin_make
source ~/catkin__ws/devel/setup.bash

话题编程

  • 先了解一下话题通讯的流程

    其次是话题编程的流程:
    1、创建发布者(talker);
    2、创建订阅者(listener);
    3、添加编译选项;
    4、运行可执行文件;

  • 通过例题进行实践:编写代码实现 ROS 中消息的发布与订阅: 创建一个发布者,每隔 100ms 依次发送斐波拉契数列的数字到话题/fibonacci 中;创建一个订阅者,订阅该话题,输出订阅结果。如,订阅者依次输出: 1 1 2 3 5 8 ··

  • 自定义话题消息

先定义msg文件,在工作空间catkin_ws/src内learning_communication的功能包内创建文件夹msg,并在msg内创建文件number.msg文件,在把上面的文件内容复制进文件。

int32 number

在package.xml中添加动态生成message的功能包依赖

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>


在CMakeLists.txt添加编译选项

1.在findpacksge(……)结尾添加messagegeneration

2.在写有关于message内容下面添加

add_message_files(FILESnumber.msg
)
generate_messages(DEPENDENCIESstd_msgs
)

在catkinpackage(….)结尾添加messageruntime

回到工作空间的根目录下编译生成相应的头文件

cd catkin_ws
catkin_make
  • 创建发布者和订阅者代码实现(C++)
    在工作空间catkin*_ws/src内的learning_communication功能包src内创建文件编写代码
    number_publisher.cpp:
#include<ros/ros.h>
#include"learning_communication/number.h"
int f(int count) {if (count == 1 || count == 2) {return 1;}else {return f(count - 2) + f(count - 1);}
}
int main(int argc, char** argv) {setlocale(LC_ALL,"");//ROS节点初始化ros::init(argc, argv, "number_publisher");//创建节点句柄ros::NodeHandle n;//创建一个publisher,发布名为/fibonacci的topic,消息类型为std_msgs::Int32,队>列长度为10ros::Publisher fibonacci_pub = n.advertise<learning_communication::number>("/fibonacci", 100);//设置循环频率ros::Rate loop_rate(10);int count = 1;while (ros::ok()) {//初始化geometry_sgs::Twist类型消息homework_pkg::number1 msg;msg.number = f(count);//发布消息fibonacci_pub.publish(msg);ROS_INFO("%d",msg.number);//按循环频率延时loop_rate.sleep();count++;}return 0;
}

number_subscriber.cpp:

#include<ros/ros.h>
#include"learning_communication/number.h"
int f(int count) {if (count == 1 || count == 2) {return 1;}else {return f(count - 2) + f(count - 1);}
}
int main(int argc, char** argv) {setlocale(LC_ALL,"");//ROS节点初始化ros::init(argc, argv, "number_publisher");//创建节点句柄ros::NodeHandle n;//创建一个publisher,发布名为/fibonacci的topic,消息类型为std_msgs::Int32,队>列长度为10ros::Publisher fibonacci_pub = n.advertise<learning_communication::number>("/fibonacci", 100);//设置循环频率ros::Rate loop_rate(10);int count = 1;while (ros::ok()) {//初始化geometry_sgs::Twist类型消息homework_pkg::number1 msg;msg.number = f(count);//发布消息fibonacci_pub.publish(msg);ROS_INFO("%d",msg.number);//按循环频率延时loop_rate.sleep();count++;}return 0;
}
  • 编译测试

编译前先要在功能包内的CMakeList.txt内配置编译规则
设置需要编译的代码和生成的可执行文件,设置链接库

add_executable(number_publisher src/number_publisher.cpp)
target_link_libraries(number_publisher ${catkin_LIBRARIES})add_executable(number_subscriber src/number_subscriber.cpp)
target_link_libraries(number_subscriber ${catkin_LIBRARIES})

回到根目录进行编译

cd catkin_ws
catkin_make

依次开三个终端跑命令

roscore
rosrun learning_communication number_publisher
rosrun learning_communication number_subscriber

运行结果:



服务编程

  • 服务编程流程
    1.创建服务器
    2.创建客户端
    3.添加编译选项
    4.运行可执行程序

图示:

  • 通过例题进行实践:编写代码实现 ROS 中的服务请求与答复: 创建服务端,注册 Service,当服务端收到客户端 Service 请求(携带整型参数 a.b) 后,服务端返回 a.b 的和给客户端,客户端输出结果。如,客户端给服务端 Service 发送参数 3,9,服务端返回 12,客户端输出: 12。
    如何自定义服务数据
  • 自定义服务数据
    先定义srv文件
int32 num1
int32 num2
---
int32 sum

在工作空间catkin_ws/src内learning_communication功能包内创建文件夹srv,并在srv内创建文件number.srv文件,在把上面的文件内容复制进文件。

在package.xml中添加动态生成message的功能包依赖

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

在CMakeLists.txt添加编译选项

1.在findpacksge(……)结尾添加messagegeneration

2.在写有关于service内容下面添加

add_service_files(FILESnumber.srv
)
generate_messages(DEPENDENCIESstd_msgs
)

在catkinpackage(….)结尾添加messageruntime

回到工作空间的根目录下编译生成相应的头文件

cd ~、catkin_ws
catkin_make
  • 创建服务端和客户端代码实现(C++)

在工作空间catkin_ws/src内learning_communication功能包src内创建文件编写代码

number_client.cpp:

#include "ros/ros.h"
#include "learning_communication/number.h"
int main(int argc, char **argv)
{// 初始化 ROS 节点ros::init(argc, argv, "xiaomei");// 创建 ROS 句柄ros::NodeHandle n;// 创建 客户端 对象ros::ServiceClient client = n.serviceClient<learning_communication::number>("number");// 提交请求并处理响应learning_communication::number a;//提交请求a.request.num1 = 3;a.request.num2 = 9;//处理响应bool flag = client.call(a);if (flag){ROS_INFO(" 响应成功!两个数的和为:%d", a.response.sum);}else{ROS_INFO("响应失败");}// ros::spin()循环等待回调函数ros::spin();
}

number_server.cpp:

#include "ros/ros.h"
#include "learning_communication/number.h"// 回调函数:bool 返回值由于标志是否处理成功
bool Callback(learning_communication::number::Request& req,learning_communication::number::Response& resp)
{//1处理请求int num1 = req.num1;int num2 = req.num2;ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d", num1, num2);//2组织响应int sum = num1 + num2;resp.sum = sum;ROS_INFO("两个数的和:sum = %d", sum);return true;
}int main(int argc, char **argv)
{// 初始化 ROS 节点ros::init(argc, argv, "number_Server");// 创建 ROS 句柄ros::NodeHandle n;// 创建 服务 对象ros::ServiceServer server = n.advertiseService("number", Callback);ROS_INFO("服务启动....");//     回调函数处理请求并产生响应//     由于请求有多个,需要调用 ros::spin()
}
  • 编译测试

编译前先要在功能包 learning_communication内的CMakeList.txt内配置编译规则

设置需要编译的代码和生成的可执行文件,设置链接库

add_executable(number_client src/number_client.cpp)
target_link_libraries(number_client ${catkin_LIBRARIES})add_executable(number_server src/number_server.cpp)
target_link_libraries(number_server ${catkin_LIBRARIES})

addexecutable(numberclient src/numberclient.cpp),src/numberclient.cpp是指的前面编写代码的文件,numberclient是设置src/numberclient.cpp编译后形成的可执行文件的名字

targetlinklibraries(numberclient ${catkinLIBRARIES})是将可执行文件与对应的链接库链接。

回到catkin_ws工作空间根目录下编译

cd ~/catkin_ws
catkin_make

依次开三个终端跑命令

roscore
rosrun learning_communication number_client
rosrun learning_communication number_server

运行结果:


2.ROS kinetic 动作编程实践

目标:客户端发送一个运动目标,模拟机器人运动到目标位置的过程,带有实时位置反馈

  • 创建工作区间

创建功能包:

mkdir -p ~/catkin_ws/src
cd catkin_ws/src/
catkin_create_pkg learn_action std_msgs rospy roscpp

编译功能包:

cd ~/catkin_ws
catkin_make
source ~/catkin_ws/devel/setup.bash
  • 动作编程

定义action文件

在learn_action文件下创建action文件,在action文件下创建TurtleMove.action文件


在TurtleMove.action文件内输入代码:

# Define the goal
float64 turtle_target_x
# Specify Turtle's target position
float64 turtle_target_y
float64 turtle_target_theta
---
# Define the result
float64 turtle_final_x
float64 turtle_final_y
float64 turtle_final_theta
---
# Define a feedback message
float64 present_turtle_x
float64 present_turtle_y
float64 present_turtle_theta

在learn_actTurtleMove_server.cppion的src文件夹下,创建TurtleMove_server.cpp文件,TurtleMove_client.cpp文件
TurtleMove_server.cpp

  /*      此程序通过通过动作编程实现由client发布一个目标位置    然后控制Turtle运动到目标位置的过程  */
#include <ros/ros.h> #include <actionlib/server/simple_action_server.h>
#include "learn_action/TurtleMoveAction.h"
#include <turtlesim/Pose.h>
#include <turtlesim/Spawn.h>
#include <geometry_msgs/Twist.h>
typedef actionlib::SimpleActionServer<learn_action::TurtleMoveAction> Server;
struct Myturtle
{     float x;     float y;     float theta; }turtle_original_pose,turtle_target_pose;   ros::Publisher turtle_vel;  void posecallback(const turtlesim::PoseConstPtr& msg)  {    ROS_INFO("Turtle1_position:(%f,%f,%f)",msg->x,msg->y,msg->theta);   turtle_original_pose.x=msg->x;    turtle_original_pose.y=msg->y;   turtle_original_pose.theta=msg->theta;  }   // 收到action的goal后调用该回调函数 void execute(const learn_action::TurtleMoveGoalConstPtr& goal, Server* as) {     learn_action::TurtleMoveFeedback feedback;       ROS_INFO("TurtleMove is working.");     turtle_target_pose.x=goal->turtle_target_x;     turtle_target_pose.y=goal->turtle_target_y;      turtle_target_pose.theta=goal->turtle_target_theta;          geometry_msgs::Twist vel_msgs;     float break_flag;          while(1)     {           ros::Rate r(10);                  vel_msgs.angular.z = 4.0 * (atan2(turtle_target_pose.y-turtle_original_pose.y,                                    turtle_target_pose.x-turtle_original_pose.x)-turtle_original_pose.theta);         vel_msgs.linear.x = 0.5 * sqrt(pow(turtle_target_pose.x-turtle_original_pose.x, 2) +                                       pow(turtle_target_pose.y-turtle_original_pose.y, 2));          break_flag=sqrt(pow(turtle_target_pose.x-turtle_original_pose.x, 2) +                                         pow(turtle_target_pose.y-turtle_original_pose.y, 2));         turtle_vel.publish(vel_msgs);feedback.present_turtle_x=turtle_original_pose.x;         feedback.present_turtle_y=turtle_original_pose.y;         feedback.present_turtle_theta=turtle_original_pose.theta;         as->publishFeedback(feedback);         ROS_INFO("break_flag=%f",break_flag);         if(break_flag<0.1) break;         r.sleep();     }         // 当action完成后,向客户端返回结果         ROS_INFO("TurtleMove is finished.");         as->setSucceeded();
}
int main(int argc, char** argv)
{     ros::init(argc, argv, "TurtleMove_server");     ros::NodeHandle n,turtle_node;     ros::Subscriber sub =turtle_node.subscribe("turtle1/pose",10,&posecallback);//订阅小乌龟的位置信息     turtle_vel = turtle_node.advertise<geometry_msgs::Twist>("turtle1/cmd_vel",10);//发布控制小乌龟运动的速度     // 定义一个服务器         Server server(n, "TurtleMove", boost::bind(&execute, _1, &server), false);        // 服务器开始运行         server.start();         ROS_INFO("server has started.");     ros::spin();       return 0;
}

TurtleMove_client.cpp

#include <actionlib/client/simple_action_client.h>
#include "learn_action/TurtleMoveAction.h"
#include <turtlesim/Pose.h>
#include <turtlesim/Spawn.h>
#include <geometry_msgs/Twist.h>
typedef actionlib::SimpleActionClient<learn_action::TurtleMoveAction> Client;
struct Myturtle
{     float x;     float y;   float theta;
}turtle_present_pose;
// 当action完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,         const learn_action::TurtleMoveResultConstPtr& result)
{     ROS_INFO("Yay! The TurtleMove is finished!");     ros::shutdown();
}
// 当action激活后会调用该回调函数一次
void activeCb()
{     ROS_INFO("Goal just went active");
}
// 收到feedback后调用该回调函数
void feedbackCb(const learn_action::TurtleMoveFeedbackConstPtr& feedback)
{     ROS_INFO(" present_pose : %f  %f  %f", feedback->present_turtle_x,                    feedback->present_turtle_y,feedback->present_turtle_theta);
}
int main(int argc, char** argv)
{     ros::init(argc, argv, "TurtleMove_client");       // 定义一个客户端     Client client("TurtleMove", true);       // 等待服务器端     ROS_INFO("Waiting for action server to start.");     client.waitForServer();     ROS_INFO("Action server started, sending goal.");      // 创建一个action的goal     learn_action::TurtleMoveGoal goal;    goal.turtle_target_x = 1;     goal.turtle_target_y = 1;     goal.turtle_target_theta = 0;       // 发送action的goal给服务器端,并且设置回调函数     client.sendGoal(goal,  &doneCb, &activeCb, &feedbackCb);       ros::spin();      return 0;
}

修改package.xml文件:

<build_depend>message_generation</build_depend>
<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<exec_depend>message_runtime</exec_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>

修改 ~/catkin_ws/src/learn_action/CMakeLists.txt



继续在末尾添加

add_executable(TurtleMove_client src/TurtleMove_client.cpp)
target_link_libraries(TurtleMove_client ${catkin_LIBRARIES})
add_dependencies(TurtleMove_client ${PROJECT_NAME}_gencpp)  add_executable(TurtleMove_server src/TurtleMove_server.cpp)
target_link_libraries(TurtleMove_server ${catkin_LIBRARIES})
add_dependencies(TurtleMove_server ${PROJECT_NAME}_gencpp)
  • 编译测试

设置环境变量

source ~/catkin_ws/devel/setup.bash

分别新建4个终端,运行如下代码

roscore
source ~/catkin_ws/devel/setup.bash
rosrun turtlesim turtlesim_node
source ~/catkin_ws/devel/setup.bash
rosrun learn_action TurtleMove_server
source ~/catkin_ws/devel/setup.bash
rosrun learn_action TurtleMove_client
  • 运行结果

3.ROS实现多机通讯实践

  • 主机配置

查看主机地址

ifconfig

输入

export ROS_IP=192.168.182.139

开启

rocore

开启一个新的终端

export ROS_IP=192.168.182.139
export ROS_MASTER_URI=http://192.168.183.128:11311/
rosrun turtlesim turtlesim_node __name:=my_turtle
  • 从机配置

开启一个终端,输入

export ROS_IP= 192.168.182.126
export ROS_MASTER_URI=http://192.168.183.128:11311/

继续输入

rosnode ping my_turtle
rosrun turtlesim turtle_teleop_key

遥控结果:

4.总结

在ROS程序设计实践中,需要掌握ROS节点、话题和服务的定义和使用方法,了解ROS的消息传递机制和服务调用机制,同时还需要掌握编写ROS程序的基本方法和技巧,才能实现机器人的各项功能,然后就是ROS Kinetic动作编程实践的代码结构比较复杂,包含了多个ROS节点和多个源文件。因此,需要仔细学习其代码结构,并了解每个源文件和ROS节点的作用和功能,最后多机通讯最基本的则是搞正确主从机的ip地址。

5.参考

https://blog.csdn.net/qq_42585108/article/details/104852100?

【嵌入式系统应用开发第2周作业】----ROS通信模式编程相关推荐

  1. 嵌入式系统基础A就9周作业

    一.实验内容和任务 使用TIM3和TIM4,分别输出一个PWM波形,PWM的占空比随时间变化,去驱动你外接的一个LED以及最小开发板上已焊接的LED(固定接在 PC13 GPIO端口),实现2个 LE ...

  2. 20189200余超 2018-2019-2 移动平台应用开发实践第九周作业

    20189200余超 2018-2019-2 移动平台应用开发实践第九周作业 图形和制定视图 Android视图系统.层次关系 Android应用设计和Web应用设计类似,也分前端和后端设计.Andr ...

  3. 嵌入式系统实验 构建嵌入式Linux系统,《嵌入式系统与开发》构建嵌入式Linux系统-实验报告.doc...

    <嵌入式系统与开发>构建嵌入式Linux系统-实验报告 <嵌入式数据库sqlite移植及使用> 实验报告 学生姓名: 陈 彤 学 号: 1座机电话号码 专业班级: 130044 ...

  4. 20189200余超 2018-2019-2 移动平台应用开发实践第二周作业

    2018-2019-2 移动平台应用开发实践第二周作业 实验部分,在linux中用git命令将代码传到码云上 成功上传的截图 码云上的截图 遇到如下的问题 解决方法 我发现在进行第一步git clon ...

  5. 嵌入式系统的开发流程

    嵌入式系统的概念: 以应用为中心,以计算机技术为基础,且软硬件可裁减,适应应用系统对功能.可靠性.成本.体积.功耗有严格要求的专用计算机系统. 嵌入式系统与普通PC机的对比: 软件上的对比: 名称 嵌 ...

  6. Windows CE嵌入式系统程序开发

    <Windows CE嵌入式系统程序开发> 基本信息 作者: 胡文    冯剑    姜海涛    胡玥    丛书名: 单片机与嵌入式丛书 出版社:机械工业出版社 ISBN:978711 ...

  7. 嵌入式系统linux开发流程,嵌入式系统的定义及嵌入式系统的开发流程

    描述 1.嵌入式系统的定义 以应用为中心,以计算机技术为基础,且软硬件可裁减,适应应用系统对功能.可靠性.成本.体积.功耗的严格要求的专用计算机系统. 2.嵌入式系统的组成 硬件部分:嵌入式微处理器. ...

  8. 基于机智云的嵌入式系统应用开发—空调远程智能控制系统

    摘要: 文章主要介绍了一种基于机智云iot开发平台的空调远程控制模块的应用开发,模块功能是通过智能手机的用户界面远程控制空调的工作,包括工作条件的设置和温度环境监测,开发内容包含了硬件和软件两部分,硬 ...

  9. linux编译运行uart,嵌入式Linux裸机开发(七)——UART串口通信

    嵌入式Linux裸机开发(七)--UART串口通信 一.UART串口通信简介 通用异步收发器简称UART,即UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTE ...

最新文章

  1. 强化学习中的脉冲神经网络
  2. 帝国cms调用缩略图和具体文章的方法
  3. 【Java】SpringBoot入门学习及基本使用
  4. 数据库原理与应用(SQL Server)笔记 第七章 流程控制语句、系统内置函数
  5. LeetCode 774. 最小化去加油站的最大距离(极小极大化 二分查找)
  6. 使用 lsof 代替 Mac OS X 中的 netstat 查看占用端口的程序
  7. ICCV2021 | 最新ICCV2021论文抢先看,附全部下载链接!ICCV2021下载
  8. 攻击者巧妙滥用谷歌 DoH 下载恶意软件
  9. python装饰器快速入门
  10. 使用下面的方法有利于提高JS代码的执行效率
  11. DB: 20 个数据库设计最佳实践
  12. 创建Orcale数据库链接访问外部数据库
  13. Ctrl + R 后,悲剧咯、、、、
  14. Vivado 开发教程 汇总
  15. Oracle sqluldr2
  16. 经典日内策略分析(收藏版)Dual Thrust、ATR、R-Breaker、菲阿里四价
  17. nas 微型计算机,快速做种,PT上传更方便 用NAS玩转PT
  18. matlab-基础 plot linewidth 设置图像的线粗细
  19. python中的slice用法
  20. Loopback接口的主要作用

热门文章

  1. unicode 解码
  2. vue组件引入外部js同时获取变量,解决重复引入
  3. 看完我工资从12K变成了20K!被腾讯辞退的高级Android工程师现在怎么了?Android篇
  4. 同济大学计算机专业学德语,公共德语
  5. vue列表显示时间、电子字体引入
  6. android studio设置字体代码,android studio 改变主题及字体大小
  7. 华为ensp nat转换实验
  8. 车道线检测和基于RGB交通标志检测系统
  9. 6-C++中继承的权限有三种情况、创建和销毁的执行过程、多继承、菱形继承、多态的相关知识点
  10. 【适合搁收藏夹里吃灰的】国外少儿编程平台/教程推荐