1 回顾Linux基础
(1)打开终端:Ctrl + Alt + T
(2)ls
(3)cd
cd ~
cd /
(4)pwd
(5)mkdir -p catkin_ws/src
(6)rm -rf
(7)mv
(8)cp
(9)gedit
python:解释性语言
python3 test.py
C++:编译性语言
g++ ().cpp
./a.out
2 ROS2介绍
需要ROS
轮式移动机器人:感知、决策、控制
感知:激光雷达、深度相机、IMU、里程计、碰撞感知、建图
决策:路径规划算法、定位算法
控制:轮子驱动
ROS将上面的部分整合到一起
ROS2 vs ROS1
(1)OS层:ROS2相比ROS1支持的平台更多
(2)中间件层:ROS2相比ROS1去中心化master、通信更换为DDS实现
(3)应用层:ROS2支持的python版本更高、编译系统改进、c++11、可以使用相同的API进程间和进程内通信
ROS2入门操作
一、你说我听
打开两个终端
ros2 run demo_nodes_py listener
ros2 run demo_nodes_cpp talker
二、海龟
ros2 run turtlesim turtlesim_node
ros2 run turtlesim turtle_teleop_key
三、rqt:选择插件
3 ROS2节点
编程基础
gcc编译ROS2节点
make编译ROS2节点
CMakeList.txt编译ROS2节点
遇到undefined reference to xxxxx
和No such file or directory
参考:ROS2
启动一个节点:
ros2 run <package_name> <executable_name>
查看节点列表(常用):
ros2 node list
查看节点信息(常用):
ros2 node info <node_name>
重映射节点名称:
ros2 run turtlesim turtlesim_node --ros-args --remap __node:=my_turtle
运行节点时设置参数:
ros2 run example_parameters_rclcpp parameters_basic --ros-args -p rcl_log_level:=10
工作空间找包,包里面去找节点(可执行文件)
与功能包相关的指令 ros2 pkg
create Create a new ROS2 package
executables Output a list of package specific executables
list Output a list of available packages
prefix Output the prefix path of a package
xml Output the XML of the package manifest or a specific tag
colcon:类似于ROS中的catkin
colcon build
source install/setup.bash
只编译一个包
colcon build --packages-select YOUR_PKG_NAME
不编译测试单元
colcon build --packages-select YOUR_PKG_NAME --cmake-args -DBUILD_TESTING=0
运行编译的包的测试
colcon test
允许通过更改src下的部分文件来改变install(重要)
每次调整 python 脚本时都不必重新build
colcon build --symlink-install
使用RCLCPP编写节点
面向对象的编程方法OOP
人身上有大脑、有手有脚这些部分,人还能通过这些部分做出一系列行为
对象=属性+行为
五个重要概念:类与对象、封装、继承、多态
mkdir -p catkin_ws/src
cd catkin_ws
ros2 pkg create test1 --build-type ament_cmake --dependencies rclcpp
在功能包的src上新建node.cpp
#include "rclcpp/rclcpp.hpp"
class Node01 : public rclcpp::Node {
public:
Node01(std::string name) : Node(name) {
RCLCPP_INFO(this->get_logger(), "大家好,我是%s.", name.c_str());
}
private:
};
int main(int argc, char**argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared<Node01>("node_01");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
CMakeList.txt
cmake_minimum_required(VERSION 3.8)
project(test1)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
add_executable(node_01 src/node.cpp)
ament_target_dependencies(node_01 rclcpp)
install(TARGETS node_01 DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
test1.cpp
#include "rclcpp/rclcpp.hpp"
int main(int argc, char **argv)
{
/* 初始化rclcpp */
rclcpp::init(argc, argv);
/*产生一个node_01的节点*/
auto node = std::make_shared<rclcpp::Node>("node_01");
// 打印一句自我介绍
RCLCPP_INFO(node->get_logger(), "node_01节点已经启动.");
/* 运行节点,并检测退出信号 Ctrl+C*/
rclcpp::spin(node);
/* 停止运行 */
rclcpp::shutdown();
return 0;
}
colcon使用进阶
4 订阅者发布者
rqt_graph
ros2 topic -h
ros2 topic list # 返回系统中当前活动的所有主题的列表
ros2 topic list -t # 增加消息类型
ros2 topic echo <topic_name> # 打印实时话题内容
ros2 interface show # 查看消息类型
ros2 topic pub /chatter std_msgs/msg/String 'data: "123"'
publisher.cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class Publisher : public rclcpp::Node
{
public:
Publisher(std::string name) : Node(name) {
RCLCPP_INFO(this->get_logger(), "%s节点", name.c_str());
publisher_ = this->create_publisher<std_msgs::msg::String>("command", 10);
timer_ = this->create_wall_timer(std::chrono::milliseconds(500), std::bind(&Publisher::timer_callback, this));
}
private:
void timer_callback()
{
std_msgs::msg::String message;
message.data = "forward";
RCLCPP_INFO(this->get_logger(), "Publishing:%s", message.data.c_str());
publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
};
int main(int argc, char** argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<Publisher>("topic");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
subscriber.cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class TopicSubscribe01 : public rclcpp::Node
{
public:
TopicSubscribe01(std::string name) : Node(name)
{
RCLCPP_INFO(this->get_logger(), "大家好,我是%s.", name.c_str());
// 创建一个订阅者订阅话题
command_subscribe_ = this->create_subscription<std_msgs::msg::String>("command", 10, std::bind(&TopicSubscribe01::command_callback, this, std::placeholders::_1));
}
private:
// 声明一个订阅者
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr command_subscribe_;
// 收到话题数据的回调函数
void command_callback(const std_msgs::msg::String::SharedPtr msg)
{
double speed = 0.0f;
if(msg->data == "forward")
{
speed = 0.2f;
}
RCLCPP_INFO(this->get_logger(), "收到[%s]指令,发送速度 %f", msg->data.c_str(),speed);
}
};
int main(int argc, char** argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared<TopicSubscribe01>("Subscribe01");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
CMakeList.txt
cmake_minimum_required(VERSION 3.8)
project(topicc)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
add_executable(publisher src/publisher.cpp)
ament_target_dependencies(publisher rclcpp std_msgs)
add_executable(subscriber src/subscriber.cpp)
ament_target_dependencies(subscriber rclcpp std_msgs)
install(TARGETS
publisher
subscriber
DESTINATION lib/${PROJECT_NAME}
)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
package.xml
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>topicc</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="bigdavid@todo.todo">bigdavid</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>rclcpp</depend>
<depend>std_msgs</depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
5 ROS2接口
字符串和32位二进制的整型数据
std_msgs/msg/String
std_msgs/msg/UInt32
ros2 interface package sensor_msgs
可以定义的接口三种类型
话题接口、服务接口、动作接口
话题接口格式:xxx.msg
int64 num
服务接口格式:xxx.srv
int64 a
int64 b
---
int64 sum
动作接口格式:xxx.action
int32 order
---
int32[] sequence
---
int32[] partial_sequence
接口数据类型:基础类型和包装类型
基础类型有(同时后面加上[]可形成数组)
bool
byte
char
float32, float64
int8 uint8
int16 uint16
int32 uint32
int64 uint64
string
包装类型
即在已有的接口类型上进行包含
uint32 id
string image_name
sensor_msgs/Image
自定义接口
机器人开发中的常见控制场景,设计满足要求的服务接口和话题接口
机器人节点:对外提供移动指定距离服务,移动完成后返回当前位置,同时对外发布机器人的位置和状态(是否在移动)
机器人控制节点:通过服务控制机器人移动指定距离,并实时获取机器人的当前位置和状态
服务接口MoveRobot.srv
float32 distance
---
float32 pose
话题接口,采用基础类型 RobotStatus.msg
uint32 STATUS_MOVING = 1
uint32 STATUS_STOP = 1
uint32 status
float32 pose
话题接口,混合包装类型 RobotPose.msg
uint32 STATUS_MOVING = 1
uint32 STATUS_STOP = 2
uint32 status
geometry_msgs/Pose pose
查看接口列表
:ros2 interface list
查看某一个接口详细的内容
:ros2 interface show std_msgs/msg/String
创建功能包:
ros2 pkg create example_ros2_interfaces --build-type ament_cmake --dependencies rosidl_default_generators geometry_msgs
修改CMakeList.txt
find_package(rosidl_default_generators REQUIRED)
find_package(geometry_msgs REQUIRED)
# 添加下面的内容
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/RobotPose.msg"
"msg/RobotStatus.msg"
"srv/MoveRobot.srv"
DEPENDENCIES geometry_msgs
)
修改package.xml
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>rosidl_default_generators</depend>
<depend>geometry_msgs</depend>
<member_of_group>rosidl_interface_packages</member_of_group> #添加这一行
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
6 Nav2
行为树:什么时候规划,什么时候脱困,用行为树来描述和管理机器人,Nav2用这个进行机器人行为调度
通过输入的 XML 格式的行为树描述文件,调用下面三个服务器中中对应的模块完成对机器人的行为控制
Planner Server:全局路径规划
Controller Server:根据全局路径,结合实时障碍物和局部代价地图完成机器人的控制
Recovery Server:加载不同的恢复行为完成机器人的脱困
BT Navigation Server 收到目标点后,由规划器服务器进行 CP(ComputePathToPose)即计算路径 ,然后由控制器服务器进行 FP(FollowPath)即路径跟随,如果遇到卡住等困境则调用规划器服务器完成脱困。这三个模块协同工作,完成了整个 Navigation 2 的导航任务。
持续更新