赞
踩
笔者跟着鱼香ROS的ROS2学习之旅
学习参考:
【ROS2机器人入门到实战】
笔者的学习目录
重要学习:
(1)仅编译指定软件包
colcon build --packages-select [pkg_name]
(2)编译软件包及其依赖
colcon build --packages-up-to [pkg_name]
IDL(Interface Definition Language) 接口定义语言
接口其实是一种规范
ros2 interface package std_msgs
std_msgs/msg/String std_msgs/msg/ByteMultiArray std_msgs/msg/UInt16 std_msgs/msg/UInt64 std_msgs/msg/UInt8 std_msgs/msg/Int64MultiArray std_msgs/msg/UInt32MultiArray std_msgs/msg/UInt16MultiArray std_msgs/msg/Float32MultiArray std_msgs/msg/MultiArrayDimension std_msgs/msg/Float64MultiArray std_msgs/msg/Int8 std_msgs/msg/Byte std_msgs/msg/Bool std_msgs/msg/Int32 std_msgs/msg/Int16 std_msgs/msg/Float64 std_msgs/msg/Header std_msgs/msg/Char std_msgs/msg/Int64 std_msgs/msg/MultiArrayLayout std_msgs/msg/Int16MultiArray std_msgs/msg/Float32 std_msgs/msg/UInt64MultiArray std_msgs/msg/UInt8MultiArray std_msgs/msg/Int8MultiArray std_msgs/msg/Int32MultiArray std_msgs/msg/UInt32 std_msgs/msg/ColorRGBA std_msgs/msg/Empty
以下是一些 std_msgs 中的常见消息类型:
Header: 包含 ROS 消息的标准头部信息,如时间戳和坐标系。
uint32 seq
time stamp
string frame_id
String: 代表字符串。
string data
Bool: 代表布尔值。
bool data
Int8, Int16, Int32, Int64: 代表有符号整数,分别为 8 位、16 位、32 位和 64 位。
int8 data
int16 data
int32 data
int64 data
UInt8, UInt16, UInt32, UInt64: 代表无符号整数,分别为 8 位、16 位、32 位和 64 位。
uint8 data
uint16 data
uint32 data
uint64 data
Float32, Float64: 代表单精度和双精度浮点数。
float32 data
float64 data
这些消息类型可以广泛应用于 ROS 中的不同节点,用于传递基本的数据信息。例如,一个节点可以发布一个包含测量值的 Float32 消息,而另一个节点可以订阅这个消息以获取测量值。
ros2 interface package sensor_msgs
sensor_msgs/msg/PointCloud sensor_msgs/msg/CompressedImage sensor_msgs/msg/Image sensor_msgs/msg/PointField sensor_msgs/msg/LaserEcho sensor_msgs/msg/BatteryState sensor_msgs/msg/MultiDOFJointState sensor_msgs/msg/NavSatFix sensor_msgs/msg/Joy sensor_msgs/msg/MultiEchoLaserScan sensor_msgs/msg/LaserScan sensor_msgs/msg/JoyFeedbackArray sensor_msgs/msg/MagneticField sensor_msgs/msg/ChannelFloat32 sensor_msgs/msg/RegionOfInterest sensor_msgs/msg/NavSatStatus sensor_msgs/msg/Range sensor_msgs/msg/Illuminance sensor_msgs/msg/RelativeHumidity sensor_msgs/msg/Temperature sensor_msgs/msg/FluidPressure sensor_msgs/msg/JointState sensor_msgs/srv/SetCameraInfo sensor_msgs/msg/Imu sensor_msgs/msg/CameraInfo sensor_msgs/msg/JoyFeedback sensor_msgs/msg/TimeReference sensor_msgs/msg/PointCloud2
以下是 sensor_msgs 中的一些常见消息类型:
Image: 用于传递图像数据,包括图像的像素数据、编码格式、时间戳等。
Header header
uint32 height
uint32 width
string encoding
uint8 is_bigendian
uint32 step
uint8[] data
CameraInfo: 包含相机的信息,如相机矩阵、畸变参数等。
Header header
uint32 height
uint32 width
string distortion_model
float64[] D
float64[] K
float64[] R
float64[] P
uint32[] binning_x
uint32[] binning_y
sensor_msgs/RegionOfInterest roi
PointCloud2: 用于传递点云数据,包括点的坐标、颜色等信息。
Header header bool is_dense string[] fields uint8 INT8 = 1 uint8 UINT8 = 2 uint8 INT16 = 3 uint8 UINT16 = 4 uint8 INT32 = 5 uint8 UINT32 = 6 uint8 FLOAT32 = 7 uint8 FLOAT64 = 8 uint8 point_step uint8[] data uint32 row_step uint32 width uint32 height sensor_msgs/PointField[] fields bool is_bigendian uint32 point_step uint32 row_step uint32 data_length uint8[] data
LaserScan: 用于传递激光扫描数据。
Header header
float32 angle_min
float32 angle_max
float32 angle_increment
float32 time_increment
float32 scan_time
float32 range_min
float32 range_max
float32[] ranges
float32[] intensities
IMU:惯性测量单元的方向、角速度和线性加速度
Header header
geometry_msgs/Quaternion orientation
float64[9] orientation_covariance
geometry_msgs/Vector3 angular_velocity
float64[9] angular_velocity_covariance
geometry_msgs/Vector3 linear_acceleration
float64[9] linear_acceleration_covariance
header: 用于包含时间戳等信息的标准 ROS 消息头。
orientation: 包含四元数表示的方向。
orientation_covariance: 一个长度为 9 的数组,表示方向协方差矩阵。
angular_velocity: 包含角速度信息的三维向量。
angular_velocity_covariance: 一个长度为 9 的数组,表示角速度协方差矩阵。
linear_acceleration: 包含线性加速度信息的三维向量。
linear_acceleration_covariance: 一个长度为 9 的数组,表示线性加速度协方差矩阵。
这些消息类型可以用于在 ROS 系统中传递从各种传感器获得的数据。节点可以发布这些消息,而其他节点则可以订阅它们以获取传感器数据。
ros2 interface package geometry_msgs
geometry_msgs/msg/Quaternion geometry_msgs/msg/WrenchStamped geometry_msgs/msg/Point32 geometry_msgs/msg/Accel geometry_msgs/msg/Pose geometry_msgs/msg/Vector3 geometry_msgs/msg/PoseArray geometry_msgs/msg/PoseWithCovarianceStamped geometry_msgs/msg/Polygon geometry_msgs/msg/AccelWithCovarianceStamped geometry_msgs/msg/AccelStamped geometry_msgs/msg/PoseWithCovariance geometry_msgs/msg/TransformStamped geometry_msgs/msg/PointStamped geometry_msgs/msg/PolygonStamped geometry_msgs/msg/Vector3Stamped geometry_msgs/msg/Inertia geometry_msgs/msg/Wrench geometry_msgs/msg/AccelWithCovariance geometry_msgs/msg/Pose2D geometry_msgs/msg/InertiaStamped geometry_msgs/msg/PoseStamped geometry_msgs/msg/QuaternionStamped geometry_msgs/msg/Transform geometry_msgs/msg/Twist geometry_msgs/msg/TwistStamped geometry_msgs/msg/TwistWithCovarianceStamped geometry_msgs/msg/TwistWithCovariance geometry_msgs/msg/Point
以下是一些常见的 geometry_msgs 中的消息类型:
Point: 代表三维空间中的点。
float64 x
float64 y
float64 z
Quaternion: 代表四元数,通常用于表示旋转。
float64 x
float64 y
float64 z
float64 w
Pose: 代表包含位置和方向的位姿。
Point position
Quaternion orientation
Transform: 代表变换矩阵。
Vector3 translation
Quaternion rotation
这些消息类型可以用于 ROS 中的各种应用,例如机器人运动、感知、导航等。通过使用这些消息,ROS 中的不同节点可以相互通信,共享几何信息,从而实现协同工作。
查看接口列表
ros2 interface list
查看某一个接口详细的内容
ros2 interface show std_msgs/msg/String
基本数据类型,每一个都可以在后面加上[]将其变成数组形式(从一个变成多个)
bool
byte
char
float32, float64
int8, uint8
int16, uint16
int32, uint32
int64, uint64
string
对数据类型进行剥洋葱
ros2 interface show sensor_msgs/msg/Image
终端显示如下:
# This message contains an uncompressed image
# (0, 0) is at top-left corner of image
std_msgs/Header header # Header timestamp should be acquisition time of image
uint32 height # image height, that is, number of rows
uint32 width # image width, that is, number of columns
string encoding # Encoding of pixels -- channel meaning, ordering, size
uint8 is_bigendian # is this data bigendian?
uint32 step # Full row length in bytes
uint8[] data # actual matrix data, size is (step * rows)
对非基类的数据数据类型std_msgs/Header header
进行剥洋葱
ros2 interface show std_msgs/msg/Header
终端显示如下:
# Two-integer timestamp that is expressed as seconds and nanoseconds.
builtin_interfaces/Time stamp
# Transform frame with which this data is associated.
string frame_id
对非基类的数据数据类型builtin_interfaces/Time
进行剥洋葱
ros2 interface show builtin_interfaces/msg/Time
终端显示如下:
int32 sec
uint32 nanosec
最后只剩下基类了
说明:这部分笔者主要是将鱼香ROS2的示例成功跑通,具体流程如下:
示例链接:
1.创建接口功能包
ros2 pkg create alian_ros2_interfaces --build-type ament_cmake --dependencies rosidl_default_generators geometry_msgs destination-directory src
注意功能包类型必须为:ament_cmake
依赖rosidl_default_generators:用于生成ROS中的消息、服务和行为的代码。ROS中的消息和服务是通过IDL(接口定义语言)描述的,而rosidl_default_generators则负责将这些IDL文件转换为各种编程语言的实际代码。
具体来说,rosidl_default_generators 支持将ROS接口定义语言(ROS IDL)文件转换为C、C++等语言的源代码。这包括生成用于发布/订阅消息、提供/调用服务以及执行行为所需的代码。
2.编写接口脚本文件
接着创建文件夹(msg、srv)和文件(RobotPose.msg、RobotStatus.msg、MoveRobot.srv),如下图。
├── CMakeLists.txt
├── msg
│ ├── RobotPose.msg
│ └── RobotStatus.msg
├── package.xml
└── srv
└── MoveRobot.srv
2 directories, 5 files
RobotPose.msg
uint32 STATUS_MOVEING = 1
uint32 STATUS_STOP = 2
uint32 status
geometry_msgs/Pose pose
RobotStatus.msg
uint32 STATUS_MOVEING = 1
uint32 STATUS_STOP = 2
uint32 status
float32 pose
MoveRobot.srv
# 前进后退的距离
float32 distance
---
# 当前的位置
float32 pose
3.设置配置文件
CMakeLists.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>
4.编译接口功能包
colcon build --packages-select alian_ros2_interfaces
1.创建功能包和节点
cd alian_ws/ # 自定义的工作空间
ros2 pkg create alian_interfaces_rclpy --build-type ament_python --dependencies rclpy alian_ros2_interfaces --destination-directory src --node-name alian_interfaces_robot
touch src/alian_interfaces_rclpy/alian_interfaces_rclpy/alian_interfaces_control.py
2. 编写节点脚本
alian_interfaces_robot.py
#!/usr/bin/env python3 import rclpy from rclpy.node import Node from alian_ros2_interfaces.msg import RobotStatus import math from time import sleep from alian_ros2_interfaces.srv import MoveRobot class Robot(): def __init__(self) -> None: self.current_pose_ = 0.0 self.target_pose_ = 0.0 self.status_ = RobotStatus.STATUS_STOP def get_status(self): return self.status_ def get_current_pose(self): return self.current_pose_ def move_distance(self,distance): self.status_ = RobotStatus.STATUS_MOVEING # 更新状态为移动、 self.target_pose_ += distance # 更新目标位置 while math.fabs(self.target_pose_ - self.current_pose_) > 0.01: step = distance / math.fabs(distance) * math.fabs(self.target_pose_ - self.current_pose_) * 0.1 # 计算一步移动距离 self.current_pose_ += step # 移动一步 print(f"移动了:{step}当前位置:{self.current_pose_}") sleep(0.5) #休息0.5s self.status_ = RobotStatus.STATUS_STOP # 更新状态为停止 return self.current_pose_ class AlianInterfacesRobot(Node): def __init__(self,name): super().__init__(name) self.get_logger().info("节点已启动:%s!" % name) self.robot = Robot() self.move_robot_server_ = self.create_service(MoveRobot,"move_robot", self.handle_move_robot) self.robot_status_publisher_ = self.create_publisher(RobotStatus,"robot_status", 10) self.publisher_timer_ = self.create_timer(0.5, self.publisher_timer_callback) def publisher_timer_callback(self): """ 定时器回调发布数据函数 """ msg = RobotStatus() #构造消息 msg.status = self.robot.get_status() msg.pose = self.robot.get_current_pose() self.robot_status_publisher_.publish(msg) # 发布消息 self.get_logger().info(f'发布了当前的状态:{msg.status} 位置:{msg.pose}') def handle_move_robot(self,request, response): self.robot.move_distance(request.distance) response.pose = self.robot.get_current_pose() return response def main(args=None): rclpy.init(args=args) # 初始化rclpy node = AlianInterfacesRobot("alian_interfaces_robot") # 新建一个节点 rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C) rclpy.shutdown() # 关闭rclpy
alian_interfaces_control.py
#!/usr/bin/env python3 import rclpy from rclpy.node import Node from alian_ros2_interfaces.msg import RobotStatus from alian_ros2_interfaces.srv import MoveRobot class AlianInterfacesControl(Node): def __init__(self,name): super().__init__(name) self.get_logger().info("节点已启动:%s!" % name) self.client_ = self.create_client(MoveRobot,"move_robot") self.robot_status_subscribe_ = self.create_subscription(RobotStatus,"robot_status",self.robot_status_callback,10) def robot_status_callback(self,msg): self.get_logger().info(f"收到状态数据位置:{msg.pose} 状态:{msg.status}") def move_result_callback_(self, result_future): response = result_future.result() self.get_logger().info(f"收到返回结果:{response.pose}") def move_robot(self, distance): while rclpy.ok() and self.client_.wait_for_service(1)==False: self.get_logger().info(f"等待服务端上线....") request = MoveRobot.Request() request.distance = distance self.get_logger().info(f"请求服务让机器人移动{distance}") self.client_.call_async(request).add_done_callback(self.move_result_callback_) def main(args=None): rclpy.init(args=args) # 初始化rclpy node = AlianInterfacesControl("alian_interfaces_control") # 新建一个节点 node.move_robot(5.0) #移动5米 rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C) rclpy.shutdown() # 关闭rclpy
3.修改配置文件setup.py
entry_points={
'console_scripts': [
'alian_interfaces_control = alian_interfaces_rclpy.alian_interfaces_control:main',
'alian_interfaces_robot = alian_interfaces_rclpy.alian_interfaces_robot:main'
],
},
4.编译功能包+运行测试
# 新终端
colcon build --packages-up-to alian_interfaces_rclpy
source install/setup.bash
ros2 run alian_interfaces_rclpy alian_interfaces_robot
# 新终端
source install/setup.bash
ros2 run alian_interfaces_rclpy alian_interfaces_control
上图则说明自定义接口测试成功!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。