一.创建 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++源码实现(文件名自定义)
#include "ros/ros.h"

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. 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.发布方创建

#include "ros/ros.h"
#include "demo02_talker_listener/Person.h"

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()

*/
#include "ros/ros.h"
#include "demo03_server_client/AddInts.h"

// 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 gzserverkillall gzclient

6.2 URDF集成Rviz基本流程

实现流程:

  1. 准备:新建功能包,导入依赖
  2. 核心:编写 urdf 文件
  3. 核心:在 launch 文件集成 URDF 与 Rviz
  4. 在 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