一.创建 ROS 工作空间
mkdir -p xxx_ws/src(必须得有 src)
cd xxx_ws
catkin_make
1.进入 xxx_ws启动 vscode
code .
快捷键 ctrl + shift + B 调用编译,选择:catkin_make:build
可以点击配置设置为默认,修改.vscode/tasks.json 文件
{
// 有关 tasks.json 格式的文档,请参见
// https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"label": "catkin_make:debug", //代表提示的描述性信息
"type": "shell", //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
"command": "catkin_make",//这个是我们需要运行的命令
"args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
"group": {"kind":"build","isDefault":true},
"presentation": {
"reveal": "always"//可选always或者silence,代表是否输出信息
},
"problemMatcher": "$msCompile"
}
]
}
2.创建 ROS 功能包
选定 src 右击 ---> create catkin package
设置包名 添加依赖
roscpp rospy std_msgs
3.使用C++编写程序实现
1.进入 ros 包的 src 目录编辑源文件
cd 自定义的包
2.创建文件.cpp C++源码实现(文件名自定义)
int main(int argc, char *argv[])
{
//执行 ros 节点初始化
ros::init(argc,argv,"hello");
//创建 ros 节点句柄(非必须)
ros::NodeHandle n;
//控制台输出 hello world
ROS_INFO("hello world!");
return 0;
}
4.编辑 ros 包下的 Cmakelist.txt文件
add_executable(步骤3的源文件名
src/源文件名.cpp
)
target_link_libraries(源文件名
${catkin_LIBRARIES}
)
5.进入工作空间目录并编译
cd 自定义空间名称
catkin_make
生成 build devel ....
6.执行
先启动命令行1:
roscore
再启动命令行2:
cd 工作空间
source ./devel/setup.bash
rosrun 包名 C++节点
2.话题通信概念**
以发布订阅的方式实现不同节点之间数据交互的通信模式。
作用
用于不断更新的、少逻辑处理的数据传输场景。
- 1.编写发布方实现;
在功能包下的src目录下创建.cpp.包含头文件 #include "ros/ros.h" #include "std_msgs/String.h" //普通文本类型的消息 #include <sstream> int main(int argc, char *argv[]) { //设置编码 setlocale(LC_ALL,""); //2.初始化 ROS 节点:命名(唯一) // 参数1和参数2 后期为节点传值会使用 // 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一 ros::init(argc,argv,"talker"); //3.实例化 ROS 句柄 ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能 //4.实例化 发布者 对象 //泛型: 发布的消息类型 //参数1: 要发布到的话题 //参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁) ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10); //5.组织被发布的数据,并编写逻辑发布数据 //数据(动态组织) std_msgs::String msg; // msg.data = "你好啊!!!"; std::string msg_front = "Hello 你好!"; //消息前缀 int count = 0; //消息计数器 //逻辑(一秒10次) ros::Rate r(1); //节点不死 while (ros::ok()) { //使用 stringstream 拼接字符串与编号 std::stringstream ss; ss << msg_front << count; msg.data = ss.str(); //发布消息 pub.publish(msg); //加入调试,打印发送的消息 ROS_INFO("发送的消息:%s",msg.data.c_str()); //根据前面制定的发送贫频率自动休眠 休眠时间 = 1/频率; r.sleep(); count++;//循环结束前,让 count 自增 //暂无应用 ros::spinOnce(); } return 0; }
2. 配置 CMakeLists.txt
add_executable(Hello_pub
src/Hello_pub.cpp
)
target_link_libraries(Hello_pub
${catkin_LIBRARIES}
)
三、话题通信自定义msg调用(C++)
0.vscode 配置
将前面生成的 head 文件路径配置进 c_cpp_properties.json 的 includepath属性:
"/xxx/yyy工作空间/devel/include/**" //配置 head 文件的路径
1.发布方创建
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//1.初始化 ROS 节点
ros::init(argc,argv,"talker_person");
//2.创建 ROS 句柄
ros::NodeHandle nh;
//3.创建发布者对象
ros::Publisher pub = nh.advertise<demo02_talker_listener::Person>("chatter_person",1000);
//4.组织被发布的消息,编写发布逻辑并发布消息
demo02_talker_listener::Person p;
p.name = "sunwukong";
p.age = 2000;
p.height = 1.45;
ros::Rate r(1);
while (ros::ok())
{
pub.publish(p);
p.age += 1;
ROS_INFO("我叫:%s,今年%d岁,高%.2f米", p.name.c_str(), p.age, p.height);
r.sleep();
ros::spinOnce();
}
return 0;
}
注:订阅编写逻辑和发布一致
2.配置 CMakeLists.txt
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
add_executable(person_talker src/person_talker.cpp)
add_dependencies(person_talker ${PROJECT_NAME}_generate_messages_cpp)
target_link_libraries(person_talker
${catkin_LIBRARIES}
)
3执行话题:
1.启动 roscore;
roscore
2.启动发布节点;
cd xx_ws
source ./devel/setup.bash
rosrun plumbing_pub_sub demo03_pub_person
3.启动订阅节点。
rosrun plumbing_pub_sub demo04_sub_person
启动节点信息图:
rqt_graph
二.服务通信的创建
在src目录下创建功能包,功能包下新建 srv 目录,添加 xxx.srv 文件 src->plumbing_server_client->srv->Addints.srv
1.内容:
srv 文件中请求和响应使用---
分割
# 客户端请求时发送的两个数字
int32 num1
int32 num2
---
# 服务器响应发送的数据
int32 sum
2.编辑配置文件
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
)
服务通信自定义srv调用
0.配置vscode
/demo03_ws/devel/include/piumbing_server_client$
pwd
在配置c_cpp_properies.json 文件,把上一步打印出的路径复制进来即可。
1.创建服务端文件:
在功能包下src目录下创建demo01_server.cpp文件
/*
需求:
编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析
服务器实现:
1.包含头文件
2.初始化 ROS 节点
3.创建 ROS 句柄
4.创建 服务 对象
5.回调函数处理请求并产生响应
6.由于请求有多个,需要调用 ros::spin()
*/
// bool 返回值由于标志是否处理成功
bool doReq(demo03_server_client::AddInts::Request& req,
demo03_server_client::AddInts::Response& resp){
int num1 = req.num1;
int num2 = req.num2;
ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d",num1, num2);
//逻辑处理
if (num1 < 0 || num2 < 0)
{
ROS_ERROR("提交的数据异常:数据不可以为负数");
return false;
}
//如果没有异常,那么相加并将结果赋值给 resp
resp.sum = num1 + num2;
return true;
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"AddInts_Server");
// 3.创建 ROS 句柄
ros::NodeHandle nh;
// 4.创建 服务 对象
ros::ServiceServer server = nh.advertiseService("AddInts",doReq);
//ros打印语句
ROS_INFO("服务已经启动....");
// 5.回调函数处理请求并产生响应
// 6.由于请求有多个,需要调用 ros::spin()
ros::spin();
return 0;
}
2.配置 CMakeLists.txt
add_executable(demo01_server src/demo01_server.cpp)
add_dependencies(demo01_server ${PROJECT_NAME}_gencpp)
target_link_libraries(demo01_server
${catkin_LIBRARIES}
)
同理穿件客户端消息
3.执行
流程:
- 需要先启动服务:
rosrun 包名 服务
- 然后再调用客户端 :
rosrun 包名 客户端 参数1 参数2
- 测试服务端消息 在ws中 rosserver call addints 加tab补齐
常用命令
- rosnode : 操作节点
- rostopic : 操作话题
- rosservice : 操作服务
- rosmsg : 操作msg消息
- rossrv : 操作srv消息
- rosparam : 操作参数
绕Z:偏航
绕X:翻滚
绕Y:俯仰
话题订阅配置文件:
src>plumbing>package.xml
<buildtool_depend>catkin</buildtool_depend>
<build_depend>geometry_msgs</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>turtlesim</build_depend>
<build_export_depend>geometry_msgs</build_export_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>geometry_msgs</exec_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>turtlesim</exec_depend>
实现简单的服务调用:cly@cly-virtual-machine:~$ rosservice call /spawn
常用的api
ros::init_options::AnonymousName 解决节点重命名问题
latch(可选),如果设置为ture,会保存发布方的最后一条信息,并且新的订阅对象连接到发布方时,发布方会将这条信息发送给订阅者。
在导航订阅中,可以将地图发布对象的latch设置为ture,并且发布方只发布一次数据,每当订阅者连接时,将地图数据发送给订阅者(只发布一次),提高数据的发送效率。
C++
1.时刻
获取时刻,或是设置指定时刻:
注意:1,时刻与持续时间可以执行加减2,持续时间之间也可以执行加减3.时刻之间值可以相减,不可以相加
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;//必须创建句柄,否则时间没有初始化,导致后续API调用失败
ros::Time right_now = ros::Time::now();//将当前时刻封装成对象
//获取距离 1970年01月01日 00:00:00 的秒数,以此为时间参考系
ROS_INFO("当前时刻:%.2f",right_now.toSec());
ROS_INFO("当前时刻:%d",right_now.sec);//获取距离 1970年01月01日 00:00:00 的秒数
//设置时间
ros::Time t1(100,100000000);// 参数1:秒数 参数2:纳秒
ROS_INFO("t1=%.2f",t1.toSec()); //100.10
//第2种:直接传入 double 类型的秒数
ros::Time t2(100.3);
ROS_INFO("t2=%.2f",t2.toSec()); //100.30
//3.持续时间
ros::Time start = ros::Time::now();
ROS_INFO("当前时刻:%.2f",start.toSec());
ros::Duration du(10);//持续10秒钟,参数是double类型的,以秒为单位
du.sleep();//按照指定的持续时间休眠
ros::Time end = ros::Time::now();
ROS_INFO("当前时刻:%.2f",end.toSec());
//ROS中提供了时间与时刻的运算:
ros::Time begin= ros::Time::now();
ros::Duration du1(10);
//ros::Duration du2(20);
//ROS_INFO("当前时刻:%.2f",now.toSec());
//1.time 与 duration 运算
ros::Time stop = begin + du1;
//ros::Time stop = now - du1;
ROS_INFO("当前时刻之前:%.2f",begin.toSec());
ROS_INFO("当前时刻之后:%.2f",stop.toSec());
//PS: time 与 time 不可以相加运算
ROS 中内置了专门的定时器,可以实现与 ros::Rate 类似的效果:
//回调函数
void cd(const ros::TimerEvent& event){
ROS_INFO("-------------");
ROS_INTO("-----定时器-----");
ros::Timer timer = nh.createTimer(ros::Duration(0.5),cd);//只执行一次
ros::spin();
ROS中的源文件的调用
自定义源文件的配置:
//118
include_directories(
include
${catkin_INCLUDE_DIRS}
)
//123
add_library(head_src
include/${PROJECT_NAME}/head.h
src/hello.cpp
)
//137
add_executable(use_hello src/ues_hello.cpp)
//147
add_dependencies(head_src ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(use_hello ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
target_link_libraries(head_src
${catkin_LIBRARIES}
)
target_link_libraries(use_hello
head_src
${catkin_LIBRARIES}
)
4.ROS元功能包
首先:新建一个功能包,不需要添加依赖
然后:修改package.xml ,内容如下:
<exec_depend>被集成的功能包</exec_depend>
.....
<export>
<metapackage />
</export>
最后:修改 CMakeLists.txt,内容如下:
cmake_minimum_required(VERSION 3.0.2)
project(demo)
find_package(catkin REQUIRED)
catkin_metapackage()//这个是函数的调用
注:CMakeLists.txt 中不可以有换行。把注释全部删了,只留这四行。
5.1.2 静态坐标变换
1.创建功能包
创建项目功能包依赖于
tf2 tf2_ros tf2_geometry_msgs roscpp rospy std_msgs geometry_msgs
查看方式:1.rviz
rostopic list
rostopic echo /tf_static
动态坐标转换:打开小乌龟的节点
先订阅后发布。
//计算son1和son2的相对关系,函数为lookupTransform
参数1:目标坐标系
参数2:源坐标系
参数3:ros::Time(0) 取间隔最短的两个坐标关系帧计算的相对关系
返回值geometry_msgs::TransformStamped 源相对于目标坐标系的相对关系
5.2 rosbag
在ROS中关于数据的留存以及读取实现,提供了专门的工具: rosbag。
gazebo 启动异常以及解决
- 问题1:VMware: vmw_ioctl_command error Invalid argument(无效的参数)
解决:echo "export SVGA_VGPU10=0" >> ~/.bashrc
source .bashrc
- 问题2:[Err] [REST.cc:205] Error in REST request
解决:sudo gedit ~/.ignition/fuel/config.yaml
然后将url : https://api.ignitionfuel.org
使用 # 注释
再添加url: https://api.ignitionrobotics.org
- 问题3:启动时抛出异常:
[gazebo-2] process has died [pid xxx, exit code 255, cmd.....
解决:killall gzserver
和killall gzclient
6.2 URDF集成Rviz基本流程
实现流程:
- 准备:新建功能包,导入依赖
- 核心:编写 urdf 文件
- 核心:在 launch 文件集成 URDF 与 Rviz
- 在 Rviz 中显示机器人模型
T1、解决urdf中含有中文字符导致出现:UnicodeEncodeError: ‘ascii‘ codec can‘t encode characters in position:
在根目录下:/opt/ros/melodic/lib/python2.7/dist-packages
新建一个sitecustomize.py文件
cd /opt/ros/melodic/lib/python2.7/dist-packages
sudo gedit sitecustomize.py
在其中添加内容:
#coding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
重启ROS即可解决。
先写urdf 再配置launch
<mesh filename="package://urdf01_rviz/meshes/xxx.stl"/>
6.6.1 URDF与Gazebo基本集成流程
urdf xacro gazebo_ros gazebo_ros_control gazebo_plugins
7.2.1 导航实现01_SLAM建图
安装相关功能包:
sudo apt install ros-melodic-gmapping
sudo apt install ros-melodic-map-server
sudo apt install ros-melodic-navigation