- 2025-02-20
-
回复了主题帖:
读书入围名单: 《具身智能机器人系统》
个人信息无误,确认可以完成阅读分享计划
- 2025-02-01
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享9-机器人建模仿真
ROS2智能机器人开发实践-阅读分享9-机器人建模仿真
首先我们要清楚建模和仿真并不是直接关联的,因为仿真使用的是单独的gazeboo,我们可以只建模不仿真这是完全没有问题的。
再建模中我们可以使用urdf文件
先新建一个工作包空间(c和python类型都行,因为不需要写代码只需要launch发布节点就行)
root@ubuntu:~/dev_ws_voice/src# ros2 pkg create mycar_description --build-type ament_cmake
在urdf里面分为连杆和关节,连杆可以通过关节来定义位置,并且关节之间的位置会被一些节点以tf形式发出。我们这里来建模一个麦克纳姆轮小车和一个摄像头(建模比较简单,大家感兴趣细节可以前往图书观看参数细节)
<?xml version="1.0" ?>
<!-- 定义一下这个urdf的名字 -->
<robot name="wheeltec_robot">
<!-- link也称作连杆 -->
<link name="base_link">
<visual>
<!-- 基座坐标可以高一点-->
<origin xyz=" 0 0 0.05" rpy="0 0 0" />
<geometry>
<box size="0.4 0.26 0.03"/>
</geometry>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
</visual>
</link>
<!--关节-->
<!--关节是连接两个连杆之间的关系-->
<joint name="left_wheel_joint" type="continuous">
<origin xyz="-0.15 0.15 0.05" rpy="1.57 0 0"/>
<parent link="base_link"/>
<child link="left_wheel_link"/>
<axis xyz="0 1 0"/>
<!--定义关节旋转轴为y轴-->
</joint>
<link name="left_wheel_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder radius="0.1" length = "0.04"/>
</geometry>
<material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
</link>
<joint name="right_wheel_joint" type="continuous">
<origin xyz="-0.15 -0.15 0.05" rpy="1.57 0 0"/>
<parent link="base_link"/>
<child link="right_wheel_link"/>
<axis xyz="0 1 0"/>
</joint>
<link name="right_wheel_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder radius="0.1" length = "0.04"/>
</geometry>
<material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
</link>
<joint name="left_front_joint" type="continuous">
<origin xyz="0.15 0.15 0.05" rpy="1.57 0 0"/>
<parent link="base_link"/>
<child link="left_front_link"/>
<axis xyz="0 1 0"/>
</joint>
<link name="left_front_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder radius="0.1" length = "0.04"/>
</geometry>
<material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
</link>
<joint name="right_front_joint" type="continuous">
<origin xyz="0.15 -0.15 0.05" rpy="1.57 0 0"/>
<parent link="base_link"/>
<child link="right_front_link"/>
<axis xyz="0 1 0"/>
</joint>
<link name="right_front_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder radius="0.1" length = "0.04"/>
</geometry>
<material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
</link>
<!--除了几个轮子我这里还需要添加我的单目摄像头在前面-->
<joint name="camera_joint" type="fixed">
<origin xyz="0.2 0 0.05" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="camera_link"/>
</joint>
<link name="camera_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size="0.02 0.08 0.06"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
</link>
</robot>
写完urdf文件之后,我们需要启动两个节点来使用功能包进行转化,我们在这个工作包下的launch文件夹下面新建一mycar.launch.py(名字自己起).
import os
from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
package_name = 'mycar_description'
urdf_name = "mycar.urdf"
ld = LaunchDescription()
pkg_share = FindPackageShare(package=package_name).find(package_name)
urdf_model_path = os.path.join(pkg_share, f'urdf/{urdf_name}')
#发布joint_state话题
robot_state_publisher_node = Node(
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
arguments=[urdf_model_path]
)
# 这个通常和urdf在一起发布一些joint
# 这个节点读取joint_states (sensor_msgs/JointState)然后转换转换成tf
# 可能开发者忘记删除了
# 具体作用可以查看ros2的wiki
# http://wiki.ros.org/joint_state_publisher
joint_state_publisher_node = Node(
package='joint_state_publisher',
executable='joint_state_publisher',
name='joint_state_publisher',
)
ld.add_action(robot_state_publisher_node)
ld.add_action(joint_state_publisher_node)
return ld
然后我们需要在cmakelist2把我们的文件复制到install里面
install(DIRECTORY launch urdf
DESTINATION share/${PROJECT_NAME}
)
随后编译执行就行了
colcon build
source install/setup.bash
ros2 launch (自己填)
打开虚拟机可以看一下 topic然后打开rviz2之后添加一下tf就可以了。
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享8-cartograph建图
ROS2智能机器人开发实践-阅读分享8-cartograph建图
在讲这个之前我们需要了解slam的主要建图方向,滤波和图优化。
SLAM问题主要分为滤波和图优化两大类。以扩展卡尔曼滤波为例,滤波就是通过当前时刻状态+输入+运动模型来估计下一时刻的状态,然后通过观测模型来纠正,因为其计算量小,只考虑相邻帧,因此被广泛应用到嵌入式中。在图优化(graph-based slam)的方法中,处理数据的方式就和滤波不同了,它不是在线的纠正位姿,而是把所有的数据记录下来,最后一次算总账。
可以参考文章如下:【转】graph slam tutorial:1 什么是图优化 - 知乎
这些细节当然很复杂,咱们就直接使用代码来建图吧。由于使用slam-toolbox有点问题我们直接使用cartographer来进行建图仿真。
本文前置环境介绍,up主手上的开发板是rdkx3,刷了官方的20.04+foxy版本(其实也不是官方版本,而是地平线智能车竞赛的版本,里面有内置的初始化ros2代码。ros2 launch origincar_base origincar_bringup.launch.py 主要是启动和stm32板子的联系并且发布/odom等话题,毕竟建图有一些依赖,毕竟我这不是仿真,大家可以看一看手头上有没有啥小车)
我的激光雷达使用的是乐动的stl06nbj,这个型号应该是stl06p同一个版本,我使用的是相同的驱动代码没啥问题。AlgoPathfinder/sdk_ldrobotsensorteam_stl: sdk for ldrobot lidar这是github历程(主要是这个激光雷达二手99也挺便宜的,使用一个ch340的串口就可以读取了)
然后我的的嵌入式板子使用的是轮趣科技的stm32的ros开发板(四驱的版本)
自己搞了一个四轮的麦克纳木轮小车
大家有任何疑问可以询问我,分享可能不够仔细。
重要参考文章:10.5配置Fishbot进行建图
注意注意这是foxy版本,大家的jazzy版本大致相同但是总有一些可能不同,遇到问题可以自己搜索。
其次就是本书内容(书本上的注释更多但是步骤有点不详细)
ros2 pkg create mycar_cartographer
cd mycar_cartographer
mkdir config
mkdir launch
mkdir rviz
在config目录下创建mycar_2d.lua文件,这是一个建图的配置文件,我们来一一解释。
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
--下面两个不过多解释了
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
--下面5个仔细解释,看下文
map_frame = "map",
tracking_frame = "base_link",
published_frame = "odom_combined",
odom_frame = "odom_combined",
provide_odom_frame = false,
-- false改为true,仅发布2D位资
publish_frame_projected_to_2d = true,
-- false改为true,使用里程计数据,这里需要使用里程计话题
use_odometry = true,
--是否使用gps
use_nav_sat = false,
--是否使用路标
use_landmarks = false,
-- 0改为1,使用一个雷达
num_laser_scans = 1,
-- 1改为0,不使用多波雷达
num_multi_echo_laser_scans = 0,
-- 10改为1,1/1=1等于不分割,将一次/scan分成一次一次来处理
num_subdivisions_per_laser_scan = 1,
--是否使用点云数据(这个应该是深度相机)
num_point_clouds = 0,
--查找tf变换坐标的超时时间
lookup_transform_timeout_sec = 0.2,
--发布submap子图的周期,单位为s
submap_publish_period_sec = 0.3,
--发布姿态的周期
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
}
-- false改为true,启动2D SLAM
MAP_BUILDER.use_trajectory_builder_2d = true
-- 0改成0.10,比机器人半径小的都忽略
TRAJECTORY_BUILDER_2D.min_range = 0.15
-- 30改成3.5,限制在雷达最大扫描范围内,越小一般越精确些
TRAJECTORY_BUILDER_2D.max_range = 3.5
-- 5改成3,传感器数据超出有效范围最大值
TRAJECTORY_BUILDER_2D.missing_data_ray_length = 3.
-- 不使用IMU数据,大家可以开启,然后对比下效果(这里如果开启会有一些问题)
-- 我的tf节点里面没有imu_link(他的名字是groy_link貌似是),这里必须要imu_link
-- 而且建议imu_link和base_link之间转换为零平移(重合)
TRAJECTORY_BUILDER_2D.use_imu_data = false
-- false改成true,使用实时回环检测来进行前端的扫描匹配
TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true
-- 1.0改成0.1,提高对运动的敏感度
-- 仅当角度变化超过0.1弧度(~5.7°)时处理新扫描,减少冗余计算
TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians = math.rad(0.1)
-- 0.55改成0.65,Fast csm的最低分数,高于此分数才进行优化。
POSE_GRAPH.constraint_builder.min_score = 0.65
--0.6改成0.7,全局定位最小分数,低于此分数则认为目前全局定位不准确
POSE_GRAPH.constraint_builder.global_localization_min_score = 0.7
-- 设置0可关闭全局SLAM
-- POSE_GRAPH.optimize_every_n_nodes = 0
return options
map_frame = "map",
tracking_frame = "base_link",
published_frame = "odom",
odom_frame = "odom",
provide_odom_frame = false,
以下的解释由deepseek解释:
这几个参数涉及到ROS中的坐标系(TF)设置,理解它们的含义对于正确配置SLAM系统非常重要。首先我们先看一下我们的tf图和节点图再来讨论。
map_frame
含义:map_frame 是地图的坐标系名称,通常为 "map"。
作用:SLAM系统会构建一个全局地图,并将机器人定位到这个地图中。map_frame 就是这个全局地图的坐标系。
实际情况:如果你的系统中已经有 map 坐标系(例如通过其他SLAM系统或手动发布),确保这里的 map_frame 名称与现有系统一致即可。
2. tracking_frame
含义:tracking_frame 是机器人本体的坐标系名称,通常为 "base_link"。
作用:SLAM系统需要知道机器人本体的坐标系,以便将传感器数据(如激光雷达、IMU等)与机器人本体对齐。
实际情况:我的机器人本体坐标系是 "base_link",这里不需要修改。
3. published_frame
含义:published_frame 是SLAM系统发布的坐标系名称,这里设置为 "odom_combined"。
作用:SLAM系统会发布从 map_frame 到 published_frame 的位姿变换(即 map 到 odom_combined 的变换)。这个变换表示机器人在地图中的位置。
实际情况:如果你已经有 odom_combined(通过EKF融合得到的里程计),可以将 published_frame 设置为 "odom_combined",这样SLAM系统会发布 map 到 odom_combined 的变换。
4. odom_frame
含义:odom_frame 是里程计的坐标系名称,通常为 "odom"。
作用:SLAM系统需要知道里程计的坐标系,以便将里程计数据与地图对齐。
实际情况:如果你已经有 odom_combined,可以将 odom_frame 设置为 "odom_combined",这样SLAM系统会使用 odom_combined 作为里程计的坐标系。
5. provide_odom_frame
含义:provide_odom_frame 表示是否由SLAM系统提供 odom_frame。
作用:
如果设置为 true,SLAM系统会发布 odom_frame 到 base_link 的变换。
如果设置为 false,SLAM系统不会发布 odom_frame 到 base_link 的变换,而是依赖外部系统(如EKF)提供这个变换。
实际情况:因为你已经有 odom_combined(通过EKF融合得到的里程计),所以这里应该设置为 false,表示SLAM系统不提供 odom_frame 到 base_link 的变换,而是使用 odom_combined。
我们来看一下实际的建图过程
[传感器数据源]
│
├─── /laserscan(激光雷达数据)
│
├─── /odom(里程计数据)
│
└─── /imu(IMU惯性测量单元数据)
│
│
▼
/cartographer_node(Cartographer核心处理节点)
│
├──── /submap_list(实时子地图列表)
│
└──── /occupancy_grid_node(最终栅格地图)
│
▼
/map(可视化地图)
[TF 坐标系流]
map(全局地图坐标系) → odom(里程计坐标系) → base_link(机器人本体坐标系)
▲ ▲
└───── 由 Cartographer 发布 ────────────┘
在路径src/mycar_cartographer/launch/下新建cartographer.launch.py文件,接着我们将cartographer两个节点加入到这个launch文件中。
import os
from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
# 定位到功能包的地址
pkg_share = FindPackageShare(package='mycar_cartographer').find('mycar_cartographer')
#=====================运行节点需要的配置=======================================================================
# 是否使用仿真时间,我们用不使用gazeboo这里填写false
use_sim_time = LaunchConfiguration('use_sim_time', default='false')
# 地图的分辨率
resolution = LaunchConfiguration('resolution', default='0.05')
# 地图的发布周期
publish_period_sec = LaunchConfiguration('publish_period_sec', default='1.0')
# 配置文件夹路径
configuration_directory = LaunchConfiguration('configuration_directory',default= os.path.join(pkg_share, 'config') )
# 配置文件
configuration_basename = LaunchConfiguration('configuration_basename', default='mycar_2d.lua')
#=====================声明两个个节点,cartographer/occupancy_grid_node=================================
cartographer_node = Node(
package='cartographer_ros',
executable='cartographer_node',
name='cartographer_node',
output='screen',
parameters=[{'use_sim_time': use_sim_time}],
arguments=[
'-configuration_directory', configuration_directory,
'-configuration_basename', configuration_basename
],
# 添加重映射规则(格式:原始话题 → 新话题)
remappings=[
('/scan', '/scan'), # 激光雷达数据
('/odom', '/odom_combined'), # 里程计数据
# ('/imu', '/imu/data') # IMU 数据(按需添加)
]
)
occupancy_grid_node = Node(
package='cartographer_ros',
executable='occupancy_grid_node',
name='occupancy_grid_node',
output='screen',
parameters=[{'use_sim_time': use_sim_time}],
arguments=['-resolution', resolution, '-publish_period_sec', publish_period_sec])
#定义启动文件
ld = LaunchDescription()
ld.add_action(cartographer_node)
ld.add_action(occupancy_grid_node)
return ld
这里没有rviz2,大家可以自己在虚拟机执行。
打开CmakeLists.txt,添加下面一条指令,将三个目录安装到install目录。
install(
DIRECTORY config launch rviz
DESTINATION share/${PROJECT_NAME}
)
#编译执行
colcon build --packages-select mycar_cartographer
source install/setup.bash
ros2 launch mycar_cartographer cartographer.launch.py
我们打开rviz2来看一看咯
看见map显示没什么问题,我现在放在地上来跑一下。(在宿舍没啥位置后面去社团再试一试)
然后我们来保存一下地图
sudo apt install ros-foxy-nav2-map-server
先将地图保存到src/mycar_cartographer/map目录下
ros2 run nav2_map_server map_saver_cli -t map -f mycar_map
10.6导航地图概述
地图文件保存后我们可以直接加载使用了
本文tip(我的开发板上面有有好几个usb设备)
查看串口
ls命令:
ls -l /dev/tty*
查看有哪些设备连接在你的电脑上:
lsusb
产看串口个数以及对应的tty:
dmesg | grep ttyS*
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享7-ros2动作服务和参数
ROS2智能机器人开发实践-阅读分享7-ros2动作服务和参数
一个action里面常常含有请求,响应,还有一个反馈来实时检测响应的情况。
ros2 run learning_action action_move_server
ros2 run learning_action action_move_client
可以看到这里有feekback传回来,具体的代码大家可以自己下载源码自己查看,如有不会可以使用ai辅助,如图其实我也使用了marscode来辅助。
介绍参数
参数是ros2的一个全局字典,常常用来配置参数。举例:我们有一个相机的初始化函数,但是我们手上可能有多种不同类型的相机,他们的分辨率不一样我们不可能再源码中来不断的修改数据或者为了其他相机重建一个源码,因此我们需要再运行代码的时候传进去一个分辨率参数使得代码调整,这是python和c++非常常见的手段。
我们直接启用小乌龟节点
ros2 run turtlesim turtlesim_node
ros2 run turtlesim turtle_teleop_key
我们可以看到param的命令行使用,我们讲背景设置成绿色了,但是我们如果重启小乌龟节点后有变成蓝色了,这是因为重启后使用的是默认参数,因此如果我们想配置参数。
ros2 param dump turtlesim >> turtlesim.yaml #将某个节点参数保存到参数文件里面
ros2 param load turtlesim turtlesim.yaml #加载参数
大家可以保存完参数后关闭小乌龟然后重启加载配置。
使用完命令行后我们自己的工作包该如何使用参数来进行配置呢?
ros2 run learning_parameter param_declare
ros2 param set param_declare robot_name turtle
我这里修改了以下代码(如图),源代码并没有修改参数,ok就这样了。
最后的最后,再多介绍一点分布式通信远程登录,我们一般情况下会在板端部署ros2但是我们的开发板一般性能较弱对于可视化的支持不好,我们常常会使用各种可视化工具因此我们需要远程登录开发板获得话题信息再电脑端可视化。
这里我们假设自己手上有开发板比如:树莓派,地平线rdk,泰山派等
我们需要这些开发板连接一个路由器,然后电脑也连接同一个路由器然后插卡板卡的ip,如图我以我的rdkx3为例子:
这时我们的虚拟机的网络模式一定要设置为侨联模式,然后尝试 ping 192.168.142.91
可以ping通那说明没有问题!!!
以上就是关于本书的第六次分享,分享内容多为书本内容,本人在此由于篇幅有限只是介绍核心内容,其实还有很多没有讲,书中的前面的基础都已经讲完了,后面会分享以下ros2的常用工具!!!已经看的有点小累了,虽然书写的挺好,这个的电子版也有,本书使用说明 - 图书资源这本是古月居写的,可以在他们的官网看见,想要实体书的可以直接买。
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享6-ros2常用工具分享
ROS2智能机器人开发实践-阅读分享6-ros2常用工具分享
launch多节点启动和脚本配置
我们在启动节点时通常会想要一起启动多个节点时我们就可以使用launch工具:
ros2 launch learning_launch simple.launch.py
具体的代码如图所示,package是功能包的名字,executable是可执行文件的名字,除了需要编写launch.py文件,我们还需要把这个文件拷贝到install里面,这需要在setup.py里面实现。
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),
(os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.*'))),
(os.path.join('share', package_name, 'rviz'), glob(os.path.join('rviz', '*.*'))),
],
以上就是launch的使用方法,当然具体的细节大家可以自己查看代码理解。
tf机器人坐标管理系统
我们需要先下载tf的功能包:
sudo apt install ros-jazzy-turtle-tf2-py ros-jazzy-tf2-tools
#这里我的版本是foxy那么就将jazzy换成foxy
sudo pip3 install transforms3d
安装完成后
ros2 launch turtle_tf2_py turtle_tf2_demo.launch.py
ros2 run turtlesim turtle_teleop_key
然后我们可以查看tf树:
ros2 run tf2_tools view_frames
这里要注意啦,由于不同版本的执行文件的名字不同,如果无法执行可以尝试:
发现我的版本的名字果然不一样需要添加.py
然后打开这个pdf可以看见这个tf关系了。
当然这个很不直观我们可以使用rviz2来可视化:如图
以上我们了解了tf,然后我们来学习如何使用(发布接收tf),tf分为静态和动态,顾名思义,静态的一般发布后不再改变,动态需要实时更新。
可能会运行不成功,如果你发现你的static_tf_broadcaster里面的import tf_transformations 报错那么你需要再执行:sudo apt-get install ros-<ros_distro>-tf-transformations 里面的ros_distro是你的版本
ros2 run learning_tf static_tf_broadcaster
ros2 run tf2_tools view_frames
动态广播和静态及其类似,这里的动态广播是在启动小乌龟后,获得小乌龟的pose话题然后发出tf话题。
ros2 run turtlesim turtlesim_node
ros2 run learning_tf turtle_tf_broadcaster --ros-args -p turtlename:=turtle1
ros2 run tf2_tools view_frames
最后我们来看一下tf监听的代码
ros2 run turtlesim turtlesim_node
ros2 run learning_tf turtle_tf_broadcaster --ros-args -p turtlename:=turtle1
ros2 run learning_tf tf_listener --ros-args -p target_frame:=turtle1
ros2 run turtlesim turtle_teleop_key
随后我们操控键盘就可以看见tf在变化了,具体的代码大家可以自己看,其实不难理解,主要是一些消息接口大家可能有点迷糊可以使用ros2 interface show来查看。
gazebo:机器人仿真平台
gazebo分为两大版本类似于ros和ros2,gazebo classic是旧的版本(之前看鱼香ros的教程教的就是旧版本),于此对应的有gazebo sim 新版本。不同的ros2和gazebo版本有关,大家要自行选择啊,别安装了错误版本,但是gazebo官网有下载教程,网址如下:
Ubuntu 上的二进制安装 — Gazebo citadel documentation --- Binary Installation on Ubuntu — Gazebo citadel documentation
·
对于我个人的foxy版本对应的版本的安装代码(不用复制我的,前往官网复制):
sudo apt-get update
sudo apt-get install curl lsb-release gnupg
sudo curl https://packages.osrfoundation.org/gazebo.gpg --output /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null
sudo apt-get update
sudo apt-get install gz-harmonic
然后启动 ign gazebo
这个版本的ign gazebo取代了gz sim大家要注意,其他的倒没有什么关系。
rviz2 和rqt
这两个的使用大家后续用到再说吧,可以自己搜说一下如何下载,都是我们最为常用的工具。
以上就是关于本书的第六次分享,分享内容多为书本内容,本人在此由于篇幅有限只是介绍核心内容,本文我介绍了一些ros2常用工具,当然我介绍的并不详细,但是大家至少都知道了我们的主要的使用工具,在后续的ros2开发中同学们可以边开发边学习,后续我们会结合书本和rdkx3开发板尽可能以实物为主来给大家介绍(仿真实际上起到的作用有限,限于篇幅作用,我会优先结合实物进行分析)!!!呜呜呜,看书累死了。。。。。
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享5-ros2消息接口
ROS2智能机器人开发实践-阅读分享5-ros2消息接口
在前文学习中,我们学习topic和service都接触到了消息接口,他们分别是话题消息接口和服务消息接口,这些接口都是人为定义的,这些接口很重要,如图是三大主要服务的流程图,他们都有各自的消息接口。
这里的3个服务的话题类型如上图:所有的接口内部的数据的基础类型有以下几种:
zy@ubuntu:~/dev_ws$ ros2 interface package std_msgs
std_msgs/msg/UInt8
std_msgs/msg/Header
std_msgs/msg/MultiArrayDimension
std_msgs/msg/UInt64
std_msgs/msg/Float32MultiArray
std_msgs/msg/Int16MultiArray
std_msgs/msg/ByteMultiArray
std_msgs/msg/Char
std_msgs/msg/MultiArrayLayout
std_msgs/msg/UInt16MultiArray
std_msgs/msg/Int32
std_msgs/msg/Int32MultiArray
std_msgs/msg/UInt8MultiArray
std_msgs/msg/Int16
std_msgs/msg/ColorRGBA
std_msgs/msg/UInt32MultiArray
std_msgs/msg/Int8MultiArray
std_msgs/msg/Int64
std_msgs/msg/Int64MultiArray
std_msgs/msg/Bool
std_msgs/msg/Float64MultiArray
std_msgs/msg/UInt32
std_msgs/msg/UInt64MultiArray
std_msgs/msg/Byte
std_msgs/msg/UInt16
std_msgs/msg/Float64
std_msgs/msg/Int8
std_msgs/msg/Float32
std_msgs/msg/String
std_msgs/msg/Empty
通信接口命令行
ros2 interface list
ros2 interface show <interface_name>
ros2 interface package <package_name>
自定义接口
需要先创建一个c++的功能包
zy@ubuntu:~/dev_ws/src/ros2_21_tutorials$ ros2 pkg create --build-type ament_cmake learning_interface_zy
我们如图创建一个msg文件夹后创建一个.msg后缀的文件。
我们需要在cmakelist和package.xml里面添加东西:
cmakelist.txt
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/ObjectPosition.msg"
)
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>
colcon build --packages-select learning_interface_zy
source install/setup.bash
ros2 interface package learning_interface_zy
让背后你就看见了这个接口被定义好了,我们后续只需要调用就可以了。
同理,我们也可以定义srv
最后的action的接口我们后续有机会再讲吧。
以上就是关于本书的第五次分享,分享内容多为书本内容,本人在此由于篇幅有限只是介绍核心内容,本文我介绍了我们该如何创键我们自己的消息接口,在下次分享我将尽力分享动作action!!!
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享4-ros2服务通信
ROS2智能机器人开发实践-阅读分享4-ros2服务通信
服务通信
服务的通信类似与”你问我答“,当一个节点发送请求时,服务通信机制会前往一些节点获得反馈(response)。
并且服务通信是同步通信,它同时也有特定的服务接口,这和前面的topic接口不同,我们可以来查看一番,我们可以运行小乌龟程序然后咱们一起看一看有哪些service:
ros2 run turtlesim turtlesim_node
rcl_interfaces/srv/GetParameters服务
# TODO(wjwwood): Decide on the rules for grouping, nodes, and parameter "names"
# in general, then link to that.
#
# For more information about parameters and naming rules, see:
# https://design.ros2.org/articles/ros_parameters.html
# https://github.com/ros2/design/pull/241
# A list of parameter names to get.
string[] names
---
# List of values which is the same length and order as the provided names. If a
# parameter was not yet set, the value will have PARAMETER_NOT_SET as the
# type.
ParameterValue[] values
这个服务用于从 ROS 2 节点中获取参数值。以下是各字段的含义:
请求(输入)
string[] names:
这是一个字符串数组,每个字符串是你想要获取的参数的名称。例如:
names: ["param1", "param2"]
响应(输出)
ParameterValue[] values:
这是一个 ParameterValue 对象数组,对应于请求中参数的返回值。值的顺序与请求中的名称顺序一致。
如果某个参数未设置,其值的类型将为 PARAMETER_NOT_SET。
ParameterValue 是 rcl_interfaces 包中定义的一种 ROS 2 消息类型。它表示参数的值,可以是多种类型之一(例如整数、浮点数、字符串、布尔值等)。你可以通过以下命令查看其定义:
ros2 interface show rcl_interfaces/msg/ParameterValue
rcl_interfaces/srv/GetParameters 用于从节点中获取参数值。它接收一个参数名称列表作为输入,并返回对应的参数值。
服务通信编写代码
这样我们是不是就理解了,service的消息接口含有请求和响应,那么我们来写一个python的客户端和服务端。
我们新建两个python文件(在哪一个工作包都可以,我这里就在阅读分享2里面的工作包),service_adder_client.py和service_adder_server.py。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#client文件
"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2服务示例-发送两个加数,请求加法器计算
"""
import sys
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
from learning_interface.srv import AddTwoInts # 自定义的服务接口
class adderClient(Node):
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.client = self.create_client(AddTwoInts, 'add_two_ints') # 创建服务客户端对象(服务接口类型,服务名)
while not self.client.wait_for_service(timeout_sec=1.0): # 循环等待服务器端成功启动
self.get_logger().info('service not available, waiting again...')
self.request = AddTwoInts.Request() # 创建服务请求的数据对象
def send_request(self): # 创建一个发送服务请求的函数
self.request.a = int(sys.argv[1])
self.request.b = int(sys.argv[2])
self.future = self.client.call_async(self.request) # 异步方式发送服务请求
def main(args=None):
rclpy.init(args=args) # ROS2 Python接口初始化
node = adderClient("service_adder_client") # 创建ROS2节点对象并进行初始化
node.send_request() # 发送服务请求
while rclpy.ok(): # ROS2系统正常运行
rclpy.spin_once(node) # 循环执行一次节点
if node.future.done(): # 数据是否处理完成
try:
response = node.future.result() # 接收服务器端的反馈数据
except Exception as e:
node.get_logger().info(
'Service call failed %r' % (e,))
else:
node.get_logger().info( # 将收到的反馈信息打印输出
'Result of add_two_ints: for %d + %d = %d' %
(node.request.a, node.request.b, response.sum))
break
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#client文件
"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2服务示例-提供加法器的服务器处理功能
"""
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
from learning_interface.srv import AddTwoInts # 自定义的服务接口
class adderServer(Node):
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.adder_callback) # 创建服务器对象(接口类型、服务名、服务器回调函数)
def adder_callback(self, request, response): # 创建回调函数,执行收到请求后对数据的处理
response.sum = request.a + request.b # 完成加法求和计算,将结果放到反馈的数据中
self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b)) # 输出日志信息,提示已经完成加法求和计算
return response # 反馈应答信息
def main(args=None): # ROS2节点主入口main函数
rclpy.init(args=args) # ROS2 Python接口初始化
node = adderServer("service_adder_server") # 创建ROS2节点对象并进行初始化
rclpy.spin(node) # 循环等待ROS2退出
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
写完代码后我们照常要在setup.py里面添加文件
entry_points={
'console_scripts': [
'node_helloworld_class = learning_pkg_python_zy.node_helloworld_class:main',
'topic_helloworld_sub = learning_pkg_python_zy.topic_helloworld_sub:main',
'topic_helloworld_pub = learning_pkg_python_zy.topic_helloworld_pub:main',
'service_adder_client = learning_pkg_python_zy.service_adder_client:main',
'service_adder_server = learning_pkg_python_zy.service_adder_server:main',
],
},
代码里面的服务接口的名称叫做AddTwoIntsm,这是一个自定义接口,需要我们自定义,这里可以看到这个消息接口的定义,输入为一个a和一个b输出为sum。
ok,我们在上面已经编译好了,然后我们首先要执行服务段:
ros2 run learning_pkg_python_zy service_adder_server
ros2 run learning_pkg_python_zy service_adder_client 2 3
效果如下:
服务通信补充
通常我们会编写终端指令来进行service,我们以上面的为例子:消息接口我们清楚那么来写一下,我们先打开服务端,然后再打开一个终端输入下面的指令,/add_two_ints是消息接口名称,后面是消息类型。
ros2 service call /add_two_ints learning_interface/srv/AddTwoI
nts "{a: 3, b: 5}"
- 2025-01-26
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享3-ros2节点和话题通信
ROS2智能机器人开发实践-阅读分享3-ros2节点和话题通信
话题是ros2最重要的通信方式,其余的三个通信都是以此为基础的。
继续上一次的分享,我们已经创建了一个python功能包,我建议大家可以在这个功能包里面添加功能文件,一个功能包可以添加很多个功能文件。
在此之前我们需要先配置开发环境,使用不方便的ubuntu自带的编辑器是很麻烦且不友好(其实书籍并没有提及这一点,因为此书主要是介绍ros2的),我在这里使用的是主机的vscode使用ssh连接虚拟机,实际上因为我比较懒不想再一次下载vscode了。如何连接大家可以自己搜索了解。
连接之后我们可以在我的指示的位置创建一个python文件,名字为node_helloworld_class.py
然后我们可以进行编写,代码如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2节点示例-发布“Hello World”日志信息, 使用面向对象的实现方式
"""
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
import time
"""
创建一个HelloWorld节点, 初始化时输出“hello world”日志
"""
class HelloWorldNode(Node):
def __init__(self, name):
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接口
这里的代码中我们创建一个类helloworld,它继承了Node类,在这个节点中我们不停的发布日志,最后我们实例化这个类。
随后我们需要对编译文件进行简单描述.在setup.py文件中修改文件如下:
'console_scripts': [
'node_helloworld_class = learning_pkg_python_zy.node_helloworld_class:main',
],
然后我们就可以编译运行了,这里的colcon build后面添加 --packages-select可以添加我们需要编译的功能包,我们这里只修改了一个功能包所以不要编译其他的。
cd ~/dev_ws
colcon build --packages-select learning_pkg_python_zy
source install/setup.bash
ros2 run learning_pkg_python_zy node_helloworld_class
在上面我们基本已经学会了使用节点,下面我们来添加一点其余东西-话题通信。
话题通信
我们要要了解话题是一个什么东西???我的理解是话题是一种数据形式,在代码中我们常用的有int,float等格式,但是对于ros2来说这些单独一个int数据几乎不能表达含义,比如一张rgb类型的image,我们需要数组来表示,除了图片外,我们通常还需要图片的拍摄时间,图片名字等,我们把他们组合在一起就是一个话题。
除了话题,我们还要了解通信机制特点,话题本身需要一个消息接口也就是数据的类型,如下图所示 sensor_msgs/msg/Image就是一种数据类型,这个数据的格式如下展现。
除了数据类型,话题通信的一大特点就是独立于节点,一个话题可以接收多个节点的数据,也可以给多个节点提供数据,话题和节点之间并没有耦合关系。
另外就是:异步。话题的发送和订阅是不同步的,发布节点和订阅节点并不知道这个话题啥时候订阅的也不知道啥时候发布的,所以叫做异步。
那么我们来写一个话题发布者和接收者吧!!!
我们在上节课node_helloworld_class.py的地方在此创建文件topic_helloworld_pub.py文件。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2话题示例-发布“Hello World”话题
"""
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
from std_msgs.msg import String # 字符串消息类型
"""
创建一个发布者节点
"""
class PublisherNode(Node):
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.pub = self.create_publisher(String, "chatter", 10) # 创建发布者对象(消息类型、话题名、队列长度)
self.timer = self.create_timer(0.5, self.timer_callback) # 创建一个定时器(单位为秒的周期,定时执行的回调函数)
def timer_callback(self): # 创建定时器周期执行的回调函数
msg = String() # 创建一个String类型的消息对象
msg.data = 'Hello World' # 填充消息对象中的消息数据
self.pub.publish(msg) # 发布话题消息
self.get_logger().info('Publishing: "%s"' % msg.data) # 输出日志信息,提示已经完成话题发布
def main(args=None): # ROS2节点主入口main函数
rclpy.init(args=args) # ROS2 Python接口初始化
node = PublisherNode("topic_helloworld_pub") # 创建ROS2节点对象并进行初始化
rclpy.spin(node) # 循环等待ROS2退出
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
然后我们创建订阅者,新建文件topic_helloworld_sub.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2话题示例-订阅“Hello World”话题消息
"""
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
from std_msgs.msg import String # ROS2标准定义的String消息
"""
创建一个订阅者节点
"""
class SubscriberNode(Node):
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.sub = self.create_subscription(\
String, "chatter", self.listener_callback, 10) # 创建订阅者对象(消息类型、话题名、订阅者回调函数、队列长度)
def listener_callback(self, msg): # 创建回调函数,执行收到话题消息后对数据的处理
self.get_logger().info('I heard: "%s"' % msg.data) # 输出日志信息,提示订阅收到的话题消息
def main(args=None): # ROS2节点主入口main函数
rclpy.init(args=args) # ROS2 Python接口初始化
node = SubscriberNode("topic_helloworld_sub") # 创建ROS2节点对象并进行初始化
rclpy.spin(node) # 循环等待ROS2退出
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
前往setup.py
entry_points={
'console_scripts': [
'node_helloworld_class = learning_pkg_python_zy.node_helloworld_class:main',
'topic_helloworld_sub = learning_pkg_python_zy.topic_helloworld_sub:main',
'topic_helloworld_pub = learning_pkg_python_zy.topic_helloworld_pub:main',
],
},
随后编译执行:
colcon build
source install/setup.bash
ros2 run learning_pkg_python_zy topic_helloworld_pub
# 这里运行后要打开第二个终端,然后进入dev_ws路径下
source install/setup.bash
ros2 run learning_pkg_python_zy topic_helloworld_sub
效果如下:
以上就是关于本书的第三次分享,分享内容多为书本内容,本人在此由于篇幅有限只是介绍核心内容,本文我介绍了我们该如何创建一个节点和如何使用话题通信,在下次分享我将尽力分享服务,动作和参数通信!!!如果大家有任何疑問可以發我郵箱或者直接評論(不一定準時),郵箱3499248831@qq.com.
- 2025-01-24
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享2-ros2开发流程
ROS2智能机器人开发实践-阅读分享2-ros2开发流程
ros2机器人开发流程
1.创建工作空间
2.创建功能包
3.编写源代码
4.设置编译规则
5.编译调试
6.功能验证
详细例子分享
多说无益,我们直接来进行一个”机器人“功能的开发来学习机器人的开发流程!!!
首先我们需要一个工作空间,这里我们使用命令行创建:
mkdir -p ~/dev_ws/src
cd ~/dev_ws/src
git clone https://gitee.com/guyuehome/ros2_21_tutorials.git
学习代码已经开源,大家可以前往gitee或者github下载。
下载完成后进行编译
cd ~/dev_ws
colcon build
编译之后的文件夹里面除了我们自己建立的src还多了3个文件夹:
build:存放需要编译文件的目录,每一个功能包就会有一个文件夹。
install:安装目录,以及编译好的目录。
log:日志
src:功能包源码
这里我们需要执行的文件已经纯在与install里面了,如果我们想要执行使用ros2 run命令并不可以,因为这里面的文件并没有配置到环境中。
source install/setup.bash
然后我们就可以使用ros2 run或者ros2 launch来执行文件啦!!!
创建自己的python功能包
在ros2的开发中,我们使用两种语言c++和python,这是非常有意思的,c++和python之间有很多相似的地方,但是c++在大的开源ros2功能包中较为常见的,但是python有更多的开源库可以使用,在平常开发中我们可以两者都使用,这并不影响。
ros2 pkg create --build-type ament_python learning_pkg_python_zy
# 最后一个参数是功能包名字,大家可以自己命名
创建之后是这个样子的,后面的具体操作我们后续再讲!!!
以上就是关于本书的第二次分享,分享内容多为书本内容,本人在此由于篇幅有限只是介绍核心内容,本文我介绍了我们该如何创建一个工作空间并创建一个python类型功能包,后续我将介绍python类型功能包里面的话题,服务,参数,动作等,至于c++的内容我将不过多介绍(本人的c++确实不会,平常使用较少)!!!
-
回复了主题帖:
ROS2智能机器人开发实践-阅读分享1-ros2介绍和安装验证
Jacktang 发表于 2025-1-24 09:12
按这个步骤,先安装虚拟机,然后再虚拟机上安装ros2,虚拟机的安装可以在vmware等虚拟机软件上安装,,,,
...
是的,理解正确,当然安装ros2可以使用小鱼的ros2一键安装工具(没有最新版本),
- 2025-01-23
-
发表了主题帖:
ROS2智能机器人开发实践-阅读分享1-ros2介绍和安装验证
ROS2智能机器人开发实践-阅读分享1-ros2介绍和安装验证
ROS2与ROS1对比
如图所示:ros1的application_layer里面有一个master节点管理的角色,它类似于一个公司的ceo管理所有的节点,然而在ros2里面截然不同,ros2依赖与“数据分发服务”-DDS。
于此同时,ros2的系统层可以选择的更多,几乎所有主流操作系统都适用。
ros2的通信系统
DDS是物联网中一种广泛应用的一种系统通信机制,有许多不同的商家提供不同的DDS,每一家的性能和应用场景各不相同,ROS2为了提高软件复用率,定制了一个接口标准,当DDS供应商希望接入ros社区那么需要按照标准来适配接口,因此ros2用户可以方便的更换dds。
ros2的常见名词解释
在后续学习中我们经常会遇到以下名词,大家需要记住:
工作空间(workspace):放置所有开发文件的地方,命名含义就和写代码时一样,也就是存放项目文件的地方。
功能包(package):类似与代码里面的函数,我么可以调用这些功能包也可以将多个功能包一起调用。
节点(node):机器人的工作单元,代码编译生成的课执行文件。
话题(topic):节点之间转递数据的桥梁。
服务(service):节点之间的“你问我答”,用于调用机器人的功能或者进行机器人参数配置。
通信接口:数据传递的标准规范,规范数据传递的形式。
参数:机器人的配置参数。
ros2命令行工具
这是ubuntu20.04的foxy版本ros2的命令行工具,对于各个版本的命令行工具基本一样对于各个命令行大家可以在后续使用中学习到。书籍内选用的版本是ubuntu24.04的jazzy。
ubuntu和ros2下载
虽然ros2可以在各个平台运行但是选择使用linux操作系统任然是最优选择,建议使用vmware安装ubuntu操作系统(也可以选择使用wsl2安装),同时各个ros2版本通常依赖与固定版本ubuntu,这可能和各种环境有关,而且旧版本的开源包可能有些功能不支持,总之建议下载对应版本ros2,本书下载为ubuntu24.04+jazzy。
#### 下载完成验证
ros2 run turtlesim turtlesim_node
ros2 run turtlesim turtle_teleop_key
ros2常用命令示例
上文的乌龟的终端不要关闭!!!
以上就是关于本书的第一次分享,分享内容多为书本内容,本人在此由于篇幅有限只是介绍核心内容,在安装好ros2后我们将会详细的介绍它的使用!!!
对于ros2的安装,大家如果有疑惑可以搜说以下,总之就是先安装虚拟机,然后再虚拟机上安装ros2,虚拟机的安装可以在vmware等虚拟机软件上安装,然后建议安装书本的ubuntu24.04+jazzy版本,以防有问题!!
- 2025-01-21
-
回复了主题帖:
读书活动入围名单:《ROS2智能机器人开发实践》
个人信息无误,确认可以完成阅读分享计划