1.ROS工作空间
存放项目开发相关文件的文件夹;
- src:代码空间(Source Space)
- install:安装空间(Install Space)
- build:编译空间(Build Space)
- log:日志空间(Log Space)
2.colcon是一个包构建工具
sudo apt install python3-colcon-ros
sudo apt install python3-colcon-ros
3.source命令
在当前bash环境下读取并执行FileName中的命令。
source命令(从 C Shell 而来)是bash shell的内置命令。点命令,就是个点符号,(从Bourne Shell而来)是source的另一名称。
source(或点)命令通常用于重新执行刚修改的初始化文档,如 .bash_profile 和 .profile 这些配置文件。
4.功能包
不同的功能代码放在不同的功能包中,降低耦合,提高软件复用率
创建功能包完整流程
#1.新建工作空间文件夹
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/
#2.创建或复制功能包
cd ~/ros2_ws/src
mkdir Ros2
cd Ros2
ros2 pkg create --build-type ament_python my_package
#3.在完成功能包的创建或添加后,你需要构建工作空间:
cd ~/ros2_ws
#构建工作空间:
colcon build
#4.设置环境变量:
source install/setup.bash
为了避免每次都手动设置环境变量,你可以将上述命令添加到 ~/.bashrc 中:
echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc
source ~/.bashrc
#5.运行 ROS 2 功能包
ros2 run demo_nodes_cpp talker
5.节点:机器人的工作细胞
第一个节点(面向过程编程)
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
import time
def main(args=None): # ROS2节点主入口main函数
rclpy.init(args=args) # ROS2 Python接口初始化
node = Node("node_helloworld") # 创建ROS2节点对象并进行初始化
while rclpy.ok(): # ROS2系统是否正常运行
node.get_logger().info("Hello World") # ROS2日志输出
time.sleep(0.5) # 休眠控制循环时间
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
面向对象编程
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
import time
"""
创建一个HelloWorld节点, 初始化时输出“hello world”日志
"""
class HelloWorldNode(Node):
def __init__(self, name): # 构造函数
# 调用父类 Node 的构造函数来初始化父类部分。super() 函数返回父类对象的实例,super().__init__(name) 调用父类 Node 的初始化方法,将 name 参数传递给父类的构造函数
# super().__init__() 是 Python 中的一个方法,常用于调用父类的构造函数(__init__())。它的作用是让子类能够继承并正确初始化父类的属性和行为。
super().__init__(name) # ROS2节点父类初始化
while rclpy.ok(): # ROS2系统是否正常运行
self.get_logger().info("Hello World") # ROS2日志输出
time.sleep(0.5) # 休眠控制循环时间
def main(args=None): # ROS2节点主入口main函数
rclpy.init(args=args) # ROS2 Python接口初始化
node = HelloWorldNode("node_helloworld_class") # 创建ROS2节点对象并进行初始化
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
在编写程序之后或者更改程序之后一定要进行重新编译
colcon build
实际运行的程序位于
~/dev_ws/install/learning_node/lib/python3.10/site-packages/learning_node
6.话题:节点间传递数据的桥梁(特性:单向传输,无法满足所有数据传输需求)
安装ROS2中针对相机的标准驱动
sudo apt install ros-humble-usb-cam
ros2 run usb_cam usb_cam_node_exe
ros2 topic list
usb_cam_node_exe
会从连接的 USB 摄像头(通常是 /dev/video0
设备)读取图像数据。它会定期获取摄像头帧并将图像转换为 ROS 2 的消息格式。
-
节点初始化
- 在 ROS 2 中,
usb_cam_node_exe
通过继承 ROS 2 的Node
类来创建一个节点。这个节点负责捕获图像数据并将其发布到 ROS 话题上。 - 当启动
usb_cam_node_exe
时,它会初始化 ROS 2 接口,并创建一个节点对象。节点会使用相机驱动库(例如v4l2
)来获取摄像头的图像数据。
- 在 ROS 2 中,
-
图像数据捕获
usb_cam_node_exe
会从连接的 USB 摄像头(通常是/dev/video0
设备)读取图像数据。它会定期获取摄像头帧并将图像转换为 ROS 2 的消息格式。
-
图像消息发布
- 一旦图像数据被获取,
usb_cam_node_exe
会将图像数据包装到一个 ROS 2 消息中,通常是sensor_msgs/msg/Image
消息类型。 - 该节点通过 ROS 2 的 发布者(Publisher)机制,将
sensor_msgs/msg/Image
类型的消息发布到相应的话题上(如/usb_cam/image_raw
)。 - 消息的内容包含图像的像素数据以及一些附加的元数据,如图像的大小、编码格式、时间戳等。
- 一旦图像数据被获取,
-
摄像头信息发布
- 除了图像数据外,
usb_cam_node_exe
还会发布相机的相关信息,通常是通过sensor_msgs/msg/CameraInfo
消息。这些信息包括相机的内参、畸变系数、投影矩阵等。 - 这些数据通过
sensor_msgs/msg/CameraInfo
类型的消息发布到/usb_cam/camera_info
话题。
- 除了图像数据外,
-
循环和定时发布
- 通常,图像捕获和发布操作会在一个循环中进行,确保定期地从摄像头获取图像数据并发布。为了避免过度占用 CPU,通常会添加一定的延时(例如,每帧捕获后暂停一定时间)。
- 发布间隔通常取决于相机的帧率和节点的配置。
#include "rclcpp/rclcpp.hpp"
#include "sensor_msgs/msg/image.hpp"
#include "sensor_msgs/msg/camera_info.hpp"
#include "cv_bridge/cv_bridge.h"
#include "usb_cam/usb_cam.h" // USB摄像头的驱动
class UsbCamNode : public rclcpp::Node
{
public:
UsbCamNode()
: Node("usb_cam_node")
{
// 创建一个发布者来发布图像数据
image_pub_ = this->create_publisher<sensor_msgs::msg::Image>("/usb_cam/image_raw", 10);
// 创建一个发布者来发布相机信息
camera_info_pub_ = this->create_publisher<sensor_msgs::msg::CameraInfo>("/usb_cam/camera_info", 10);
// 初始化摄像头(例如:设置设备文件、分辨率等)
usb_cam_ = std::make_shared<UsbCam>("video0", 640, 480);
// 循环捕获并发布图像
timer_ = this->create_wall_timer(
std::chrono::milliseconds(100), // 定时器:每100ms执行一次
std::bind(&UsbCamNode::publish_image, this)
);
}
private:
void publish_image()
{
// 从USB摄像头捕获一帧图像
auto frame = usb_cam_->capture_frame();
// 将图像转换为ROS消息(cv_bridge帮助进行转换)
sensor_msgs::msg::Image::SharedPtr msg = cv_bridge::CvImage(std_msgs::msg::Header(), "bgr8", frame).toImageMsg();
// 设置时间戳和其他信息
msg->header.stamp = this->get_clock()->now();
// 发布图像消息
image_pub_->publish(*msg);
// 发布摄像头信息(如果需要)
sensor_msgs::msg::CameraInfo camera_info_msg;
camera_info_msg.header.stamp = msg->header.stamp;
camera_info_pub_->publish(camera_info_msg);
}
rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr image_pub_;
rclcpp::Publisher<sensor_msgs::msg::CameraInfo>::SharedPtr camera_info_pub_;
std::shared_ptr<UsbCam> usb_cam_; // 用于处理USB摄像头
rclcpp::TimerBase::SharedPtr timer_; // 定时器,用于定期捕获和发布
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<UsbCamNode>());
rclcpp::shutdown();
return 0;
}
内部结构详解
- 节点创建:
UsbCamNode
继承自rclcpp::Node
,通过调用this->create_publisher<sensor_msgs::msg::Image>
创建图像发布者。 - USB 摄像头初始化:通过
UsbCam
类(假设是自定义的摄像头驱动类)初始化摄像头设备(例如/dev/video0
)。 - 定时器:
create_wall_timer
用于设置一个定时器,每 100 毫秒调用一次publish_image
方法。该方法从摄像头捕获一帧图像,并将其转换为 ROS 2 消息后发布。 - 图像数据转换:使用
cv_bridge
库将 OpenCV 图像转换为 ROS 消息。cv_bridge::CvImage
会将 OpenCV 格式的图像(cv::Mat
)转换为 ROS 图像消息(sensor_msgs::msg::Image
)。 - 消息发布:每次捕获一帧图像后,图像消息通过
image_pub_
发布到/usb_cam/image_raw
,并通过camera_info_pub_
发布相机信息到/usb_cam/camera_info
。
rqt_graph # 查看节点间的关系
7.服务:节点间的你问我答
ros2 service
ros2 service list
# 通过命令行发送请求
ros2 service call /get_target_position learning_interface/srv/GetObjectPosition "get: True"
8.通信接口:数据传递的标准结构
/opt/ros/humble/share目录下有.msg/.srv/.action文件格式的定义
#查看ros下所有的标准接口定义
ros2 interface list
# 查看某个指定格式的定义
ros2 interface show sensor_msgs/msg/Image
新增一个 msg/Point3D.msg
文件
1.创建一个新包
ros2 pkg create --build-type ament_cmake interface_pkg
2.在interface_pkg文件夹下新建msg和srv文件夹
mkdir msg
mkdir srv
3.在包的 msg
目录中新增消息文件
-
创建消息文件:首先在你的 ROS 2 包中创建一个新的消息文件。例如,在
msg
目录下创建Point3D.msg
文件。- 路径:
your_package/msg/Point3D.msg
- 内容示例:
float64 x float64 y float64 z
该文件定义了一个
Point3D
消息,包含 3 个浮动变量x
、y
和z
,通常用于表示三维坐标。 - 路径:
4.:修改 CMakeLists.txt
-
修改
CMakeLists.txt
文件:你需要在CMakeLists.txt
文件中增加新增的消息定义,并重新生成接口代码。假设你已经有了类似以下的代码:
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"srv/Cal.srv"
)
5.:修改 package.xml
文件
-
修改
package.xml
文件:确保你已经在package.xml
文件中声明了对消息生成的依赖。你需要确保已包含以下依赖项:
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
6.构建包
colcon build --packages-select your_package
这将重新编译包,并根据你在 CMake 文件中指定的接口生成相应的代码(例如 C++ 和 Python 代码)。
7.确认msg和srv的创造
. install/setup.bash
#确认接口创建是否有效
ros2 interface show test_interfaces/srv/Cal
9.分布式通信:多计算平台的任务分配
1.ROS2怎么将树莓派和笔记本进行通信如话题,服务
只要保证在同一网段下即可
2.为了网络中存在多个计算机,不希望互通互联,希望进行分组通讯,可以使用以下指令:
#1.使用vi 命令打开.bashrc
vi .bshrc
#2. 在最下面一行加入
export ROS_DOMAIN_ID=<your_domain_id>
如 export ROS_DOMAIN_ID=31
#3.使用source 使.bashrc生效
source .bashrc
#4.此时,设置上述过程的电脑或者树莓派在31组,再进行talker和listener时,无法通信
配置DDS
# 发布
ros2 topic pub /chatter std_msgs/msg/Int32 "data: 31" --qos-reliability best_effort
# 接收(要qos模式一样才能接收)
ros2 topic echo /chatter --qos-reliability best_effort
10.Launch:多节点启动与配置脚本
11.TF:机器人坐标系管理神器
12.URDF:ROS机器人建模方法
13.Gazebo:三维物理仿真平台
启动Gazebo
teleop_twist_keyboard
teleop_twist_keyboard发布 geometry_msgs/Twist
消息到一个控制话题,通常是 /cmd_vel
,来控制机器人的速度和方向。你可以通过简单的键盘按键来控制机器人运动,提供线性移动和角速度控制。