一.安装ROS
1.添加ROS软件源
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
2.添加密钥
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C654
3.安装ROS
sudo apt update
sudo apt-get install ros-melodic-desktop-full
根据Ubuntu的版本选择合适的ROS版本,我的18.04选择Melodic
4.初始化rosdep
sudo rosdep init
rosdep update
5.设置环境变量
echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc
6.安装rosinstall
sudo apt-get install python-rosinstall python-rosinstall-generator python-wstool build-essential
7.ROS启动!!!(初试小海龟)
7.1启动ROS Master
roscore
7.2启动小海龟仿真器
rosrun turtlesim turtlesim_node
7.3控制海龟控制节点
rosrun turtlesim turtle_teleop_key
7.4效果图
二.话题
话题通讯模型分为三个角色1.ROS Master(管理者)2.Talker(发布者)3.Listener(订阅者)
Taker 和Listener启动后,会通过RPC在ROS Master中注册自身信息,ROS Master 负责保管 Talker 和 Listener 注册的信息,并匹配话题相同的 Talker 与 Listener,帮助 Talker 与 Listener 建立连接(1.ROS Master向Listener发送Taker 的RPC地址2.Listener通过RPC向Talker发送连接请求3.Talker接收到请求后通过RPC确认连接并发送自己的TCP地址信息,注意换成了TCP4.使用了TCP建立了连接),连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅。
在工作空间生成一个功能包,添加依赖 roscpp rospy std_msgs
配置CMakeLists.txt
add_executable(发布方文件
src/发布方文件.cpp
)
add_executable(订阅方文件
src/订阅方文件.cpp
)
target_link_libraries(发布方文件
${catkin_LIBRARIES}
)
target_link_libraries(订阅方文件
${catkin_LIBRARIES}
)
发布者代码
#include "ros/ros.h"
#include "iostream"
#include "std_msgs/String.h"
int main(int argc, char *argv[])
{
//设置编码,这东西可以解除汉字乱码。
setlocale(LC_ALL,"");
// 初始化 ROS 节点
// 参数1和参数2 后期为节点传值会使用
// 参数3 是节点名称
ros::init(argc,argv,"Publisher");
// 实例化ROS节点句柄
ros::NodeHandle n;
// 实例化发布者对象
ros::Publisher fibonacci_pub = n.advertise<std_msgs::String>("/fibonacci",100);
// 组织被发布的数据,并编写逻辑发布数据
std_msgs::String msg;
int num = 1;
int temp = 0;
//设置循环频率
ros::Rate time(10);
ros::Rate time1(1);
time1.sleep();
while(ros::ok())
{
//发布消息
std::stringstream ss;
ss<<num;
msg.data = ss.str();
fibonacci_pub.publish(msg);
//打印发送的消息
ROS_INFO("发送数据:%s",msg.data.c_str());
int former = num;
num+=temp;
temp=former;
//设置休眠时间
time.sleep();
}
return 0;
}
订阅者代码
#include "ros/ros.h"
#include "std_msgs/String.h"
void callBack(const std_msgs::String::ConstPtr &msg)
{
//通过msg获取并操作订阅到的数据
ROS_INFO("订阅到的数:%s",msg->data.c_str());
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//2.初始化ROS节点
ros::init(argc,argv,"Subscriber");
//3.实例化ROS节点句柄
ros::NodeHandle n;
//4.实例化发布者对象
ros::Subscriber fibonacci_sub = n.subscribe<std_msgs::String>("/fibonacci",100,callBack);
//6.设置循环调用回调函数
ros::spin();
return 0;
}
结果
2.服务通讯模型
服务通讯涉及的三个角色是
- ROS master(管理者)
- Server(服务端)
- Client(客户端)
同样Server和Client启动后通过RPC在ROS Master中注册自身信息, ROS Master 负责保管 Server 和 Client 注册的信息,并匹配话题相同的 Server 与 Client(通过RPC向Client发送Server的TCP地址信息),帮助 Server 与 Client 建立连接,连接建立后,Client 发送请求信息,Server 返回响应信息。(相对于话题,感觉连接更快捷而且有返回)
课后
依赖还是 roscpp rospy std_msgs
定义srv文件
服务通信中,数据分成两部分,请求与响应,在 srv 文件中请求和响应使用---
分割,具体实现如下:
功能包下新建 srv 目录,添加 某某某.srv 文件,内容:
# 客户端请求时发送的两个数字
int32 num1
int32 num2
---
# 服务器响应发送的数据
int32 sum
编辑配置文件
package.xml中添加编译依赖与执行依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
CMakeLists.txt编辑 srv 相关配置
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
# 需要加入 message_generation,必须有 std_msgs
add_service_files(
FILES
AddInts.srv
)
generate_messages(
DEPENDENCIES
std_msgs
)
add_executable(服务端文件 src/服务端文件.cpp)
add_executable(客户端文件 src/客户端文件.cpp)
add_dependencies(服务端文件 ${PROJECT_NAME}_gencpp)
add_dependencies(客户端文件 ${PROJECT_NAME}_gencpp)
target_link_libraries(服务端文件
${catkin_LIBRARIES}
)
target_link_libraries(客户端文件
${catkin_LIBRARIES}
)
服务端代码
#include "ros/ros.h"
#include "plumbing_server_client/AddInts.h"
bool doNums(plumbing_server_client::AddInts::Request &request,plumbing_server_client::AddInts::Response &responce)
{
//a处理请求
int num1=request.num1;
int num2=request.num2;
ROS_INFO("受到的请求数据:a=%d,b=%d",num1,num2);
//b组织响应
int sum=num1+num2;
responce.sum=sum;
ROS_INFO("求得的结果是:%d",sum);
return true;
}
int main(int argc,char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化ros节点
ros::init(argc,argv,"heishui");//节点名字需要保证唯一
// 3.创建节点句柄
ros::NodeHandle nh;
// 4.创建服务对象
ros::ServiceServer server=nh.advertiseService("addInts",doNums);
ROS_INFO("服务器端启动");
// 6.spin()
ros::spin();
return 0;
}
客服端代码
#include "ros/ros.h"
#include "plumbing_server_client/AddInts.h"
int main(int argc,char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化ros节点
ros::init(argc,argv,"dabao");
// 3.创建节点句柄
ros::NodeHandle nh;
// 4.创建客户端对象
ros::ServiceClient client= nh.serviceClient<plumbing_server_client::AddInts>("addInts");
// 5.提交请求并处理响应
// 5.1 组织请求
plumbing_server_client::AddInts ai;
ai.request.num1=3;
ai.request.num2=9;
// 5.2 处理响应
bool flag =client.call(ai);
if(flag)
{
ROS_INFO("响应成功!");
//获取结果
ROS_INFO("%d",ai.response.sum);
}else
{
ROS_INFO("响应失败!");
}
return 0;
}
结果
四.动作
action 是一种类似于服务通信的实现,其实现模型也包含请求和响应,但是不同的是,在请求和响应的过程中,服务端还可以连续的反馈当前任务进度,客户端可以接收连续反馈并且还可以取消任务。
- goal:目标任务;
- cacel:取消任务;
- status:服务端状态;
- result:最终执行结果(只会发布一次);
- feedback:连续反馈(可以发布多次)。
添加的依赖roscpp rospy std_msgs actionlib actionlib_msgs
然后功能包下新建 action 目录,新增 Xxx.action(比如:AddInts.action)。
action 文件内容组成分为三部分:请求目标值、最终响应结果、连续反馈,三者之间使用---
分割示例内容如下:
#目标值
int32 num
---
#最终结果
int32 result
---
#连续反馈
float64 progress_bar
配置CMakeLists.txt
find_package
(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
actionlib
actionlib_msgs
)
add_action_files(
FILES
刚刚自定义的.action
)
generate_messages(
DEPENDENCIES
std_msgs
actionlib_msgs
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo04_action
CATKIN_DEPENDS roscpp rospy std_msgs actionlib actionlib_msgs
# DEPENDS system_lib
)
add_executable(服务端文件 src/服务端文件.cpp)
add_executable(客户端文件 src/客户端文件.cpp)
...
add_dependencies(服务端文件 ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(客户端文件 ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
...
target_link_libraries(服务端文件
${catkin_LIBRARIES}
)
target_link_libraries(客户端文件
${catkin_LIBRARIES}
)
服务端代码
#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"
#include "demo01_action/AddIntsAction.h"
typedef actionlib::SimpleActionServer<demo01_action::AddIntsAction> Server;
void cb(const demo01_action::AddIntsGoalConstPtr &goal,Server* server){
//获取目标值
int num = goal->num;
ROS_INFO("目标值:%d",num);
//累加并响应连续反馈
int result = 0;
demo01_action::AddIntsFeedback feedback;//连续反馈
ros::Rate rate(1);//通过频率设置休眠时间
for (int i = 1; i <= num; i++)
{
//组织连续数据并发布
feedback.progress_bar = i / (double)num;
server->publishFeedback(feedback);
rate.sleep();
}
//设置最终结果
demo01_action::AddIntsResult r;
r.result = result;
server->setSucceeded(r);
ROS_INFO("检测完成");
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ROS_INFO("action服务端实现");
// 2.初始化ROS节点;
ros::init(argc,argv,"AddInts_server");
// 3.创建NodeHandle;
ros::NodeHandle nh;
// 4.创建action服务对象;
/*SimpleActionServer(ros::NodeHandle n,
std::string name,
boost::function<void (const demo01_action::AddIntsGoalConstPtr &)> execute_callback,
bool auto_start)
*/
// actionlib::SimpleActionServer<demo01_action::AddIntsAction> server(....);
Server server(nh,"addInts",boost::bind(&cb,_1,&server),false);
server.start();
// 5.处理请求,产生反馈与响应;
// 6.spin().
ros::spin();
return 0;
}
客户端代码
#include "ros/ros.h"
#include "actionlib/client/simple_action_client.h"
//#include "demo01_action/AddIntsAction.h"
#include"/home/robolabccz/demo08_ws/devel/include/demo01_action/AddIntsAction.h"
typedef actionlib::SimpleActionClient<demo01_action::AddIntsAction> Client;
//处理最终结果
void done_cb(const actionlib::SimpleClientGoalState &state, const demo01_action::AddIntsResultConstPtr &result){
if (state.state_ == state.SUCCEEDED)
{
ROS_INFO("最终结果:%d",result->result);
} else {
ROS_INFO("任务失败!");
}
}
//服务已经激活
void active_cb(){
ROS_INFO("服务已经被激活....");
}
//处理连续反馈
void feedback_cb(const demo01_action::AddIntsFeedbackConstPtr &feedback){
ROS_INFO("已检测%.0f个当前进度:%.2f", feedback->progress_bar*40,feedback->progress_bar);
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化ROS节点;
ros::init(argc,argv,"AddInts_client");
// 3.创建NodeHandle;
ros::NodeHandle nh;
// 4.创建action客户端对象;
// SimpleActionClient(ros::NodeHandle & n, const std::string & name, bool spin_thread = true)
// actionlib::SimpleActionClient<demo01_action::AddIntsAction> client(nh,"addInts");
Client client(nh,"addInts",true);
//等待服务启动
client.waitForServer();
// 5.发送目标,处理反馈以及最终结果;
/*
void sendGoal(const demo01_action::AddIntsGoal &goal,
boost::function<void (const actionlib::SimpleClientGoalState &state, const demo01_action::AddIntsResultConstPtr &result)> done_cb,
boost::function<void ()> active_cb,
boost::function<void (const demo01_action::AddIntsFeedbackConstPtr &feedback)> feedback_cb)
*/
demo01_action::AddIntsGoal goal;
goal.num = 40;
client.sendGoal(goal,&done_cb,&active_cb,&feedback_cb);
// 6.spin().
ros::spin();
return 0;
}
结果截图