【Gazebo/ROS】阿克曼小车仿真环境设置中的心得体会

最近科研需要在gazebo中做一个阿克曼小车的仿真,要求小车运动能够通过话题来控制,小车上要安装激光雷达、imu、相机等传感器用于SLAM定位建图。由于是第一次接触gazebo仿真,所以分享一下学习心得:

一、优秀资源

1\ 这位up做了现成的阿克曼小车模型,并出了视频演示运行效果 【模型代码】 【演示链接】

2\ 这位up出了一个从零搭建阿克曼小车的视频,让我弄懂了1\中代码的框架 【教学视频】

3\ 这位博主分享了自己对于gazebo与ROS联合进行小车仿真步骤的深入理解 【深入博文】

4\ 这里有一个开源的非平坦地面路径规划链路的项目,至此我基本理解完整过程 【开源项目】

二、心得体会

1\ 关于 .world的加载

如果world用到的模型全都是官方model,那么只需要把官方的model库下载下来,存到.gazebo的models下面就行了,但如果有些model是你自己定义的,例如自己定义的地图、障碍物等,那么你必须把对应的model文件放入.gazebo的models下面,当然,你也可以用prefix来设定gazebo对model的搜索路径,具体操作在13\

2\ 启动gazebo

roslaunch gazebo_ros emputy_world.launch 打开一个空白世界(直接输入gazebo也能打开gazebo软件,但是二者有区别的)

3\ 界面技巧

在gazebo中的view中,可以查看碰撞体积、等可视化

4\ 在环境中添加model

下面这句话是使用模型产生器spawn_model在gazebo中添加模型:<node name="spawn_model" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen" args="-urdf -x $(arg x) -y $(arg y) -z $(arg z) -model $(arg robot_name) -param robot_description"/>

其中,robot_description为:<param name="robot_description" command="$(find xacro)/xacro '$(arg urdf_robot_file)' roboname:='smart'" />

5\ 用topic简单控制gazebo中的小车动起来

如果想用rostopic控制gazebo里的小车动起来,在基本模型显示的基础上(empty_world + spawn_model + urdf_description),需要作的改动是:(1)在urdf中添加相应joint的transmission,从而定义joint的执行器类型 (2)在urdf中添加gazebo_ros_control插件(plugin),从而建立起外部控制gazebo中执行器的桥梁 (3)写一个config.yaml文件,来说明各joint的控制器和pid控制参数 (4)在roslaunch中,用controller_spawner功能生成一个控制器,并把控制器和urdf中定义的执行其连接在一起(根据config.yaml中的名字链接) ;当然如果想要实现这些功能,还要下载这些库才行:
    1. sudo apt install ros-melodic-gazebo-ros-control
    2. sudo apt install ros-melodic-ros-control
    3. sudo apt install ros-melodic-ros-controllers

6\ 获取car_model的状态

gazebo能够发布各joint的状态信息(主要是tf关系),如果想在5\的基础上,获取gazebo中,小车速度、姿态和位置,那么就需要在5/的基础上作以下操作:(1)在urdf中加joint_state_publisher插件(plugin),从而把joint和publisher关联在一起 (2)在roslaunch中,用robot_state_publisher功能生成一个状态发布器,从而实现对相关joint状态信息的发布 (3)在rostopic list中,找到“gazebo/model_states”话题,话题的组织形式是:列表[model1,model2,...] + pose + velocity,其中pose和velocity中会按照列表中model的顺序,分别给出,因此在接收这个话题消息后,首先要做的就是找到想要知道的model的index,然后根据index,索引到对应model的pose和velocity,然后进行重新发布即可 (4)上述操作的实质就是:gazebo可以发布其中所有model的pose和velocity,然后我们定义一个node节点,接受这个topic然后,定义回调函数来筛选所需信息,并且publish出自己想发布的信息就行了。

7\ 在urdf中添加gazebo中的额外属性

通常情况下,我们还会用<gazebo reference=“xxx”> 给机器人的xxx零件加上额外的属性,如摩擦力、颜色等,这些可以加在urdf中,到时候作为spawn_model的-param description传入模型

8\ 使用mesh模型

当我们想把更加好看的外部mesh模型作为机器人的一部分时,我们常使用<mesh filename="package://package_name/meshes/xxx.dae"/>来代替原来visual中的geometry中的box或者cylinder,注意这里的package://package_name相当于launch中的 $(find package_name)

9\ 根据阿克曼的输入(速度和打角)解算四轮的转速和转角

在5\的基础上,实现实现对车辆的话题控制(可以使用C++,也可以使用python,这里使用pyhton):(1)总的思路是生成一个发布话题的节点,接收我们发布的小车速度和转角的话题命令,并将之分解为小车四轮的转速和转角 (2)根据阿克曼模型,对模型的输入量为:小车后轮速度 和 小车中轴线处的虚拟车轮的打角;(3)处理输入量1:给打角加限制。根据轴距和车轮间距,可由实际车轮的最大打角半径,算出输入量中的最大打角 (4)处理输入量2:将车速转换为后轮角速度。后轮的线速度就是车速,要换算成后轮的角速度,才能后发送给后轮的执行器 (5)判断输入打角是否为0:如果为0,那就很简单,直接给前轮发送0角度,给后轮发送输入处理量2——后轮角速度 (6)判断输入打角是否为0:如果不为0,首先根据输入处理量2——后轮角速度由半径比例拓展到两个后轮的角速度(内圈慢,外圈快);然后根据前轮的actan值,得到两个前轮的打角;另,如果前轮也有驱动力,也可以根据前轮转弯半径和车速计算出两个前轮的驱动角速度 (7)将各轮的控制量按照对应的msgs格式发送到对应的话题就行了。

10\ 阿克曼模型的核心

在其他量已知的情况下,打角和转弯半径是相互决定的,知道其中一个,即可求另一个

11\ 在rviz中看到小车

想要在rviz中看到gazebo中的汽车模型和相关信息,最重要的是要关注tf坐标变换:(1)打开空白rviz,加入robotmodel,在参数服务器中填入事先写好的param(已在launch中定义好了,放在参数服务器中,叫做robot_description:<param name="robot_description" command="$(find xacro)/xacro '$(arg urdf_robot_file)' roboname:='smart'" />)  (2)使用rosrun rqt_tf_tree rqt_tf_tree查看当前tf树,发现没有/world坐标系,因此需要创建一个tf.TransformBroadcaster来广播world和base_link的关系,这个位置关系是随时间发生变化的,因此还要读取小车的位置和姿态(这个位置和姿态是6\中,最初由joint_state_publisher发布全体model,后续经过自定义节点发布的car_model的PoseStamped,我们只需要把这个消息接受起来,然后使用回调函数,把这个位姿信息当成world和baselink的关系广播出来即可) (3)在rviz中,将Fixed Frame设置为/world,即可在rviz中显示小车在world坐标系下的运动(如果想要显示小车的Pose,那么记得把5\中发布的car_model信息的frame_id 设置为 '/world'

12\ 踩坑

在重构代码时遇到各种各样样的问题,主要是以下几点

(1)urdf和xaro文件中,不能有中文注释,如果要写了,那就要加utf-8:<?xml version="1.0" encoding="utf-8"?>(2)对于那些fixed的joint,直接在launch中写一个robot_state_publisher就行了,但是如果还有其他运动型joint,就需要在xacro中插入joint_state_publisher的plugin,并把想要输出的tf的jointname写上去逗号\回车隔开,且其中最需要注意的是namespace要对应上,对于fixed,publisher默认输出的位置是/joint_states,而对于运动型,是在urdf中的plugin中决定的,robotNamespace+/joint_states,一定要把两者对应起来,否则会变成两颗tf树,无法在rviz中完整显示(具体可看这篇博文https://blog.csdn.net/blue_skyLZW/article/details/112394119) (3)在controller的config.ymal文件中,旋转joint不配置pid参数是可以的,只会报红然后生成一个理想控制器,但摆动joint如果不定义pid参数,会直接无法生成控制器,最好都把pid参数放进去,当然二者的存放方式要根据 (4)出现小车在地面慢慢滑动的问题:在车轮joint上加入摩擦力标签来让小车在零输入时稳定下来 <dynamics damping="0.0" friction="1.0"/> (5)小车打角、轮子转动出现较大波动,考虑两个问题:激光雷达等传感器点束过于密集,导致卡顿;控制器的pid参数需要调整(在config.yaml中调整) (6)出现[TF_REPEATED_DATA ignoring data with redundant timestamp for frame base_footprint at time...]的warning信息:这是一个很典型的问题,一般导致这个的原因其实不是gazebo而是你在其他ros节点发布了冗余的tf变换,说他冗余是因为tf_tree接收到了同一时刻至少两个tf变换信息。解决方法是,在发布之前先比较一下上一次发布的时间戳 ,如果相同,就不发布。(7)出现车轮跟不上车体运动的情况:这个原因是模型过于复杂,模型运动过于剧烈,或者tf发布频率太低等原因。(8)激光雷达采样点过于密集引起卡顿:这个暂时还没有好的办法,只能减少采样点数和缩短最大投射距离

13\ 将模型放在本地

在工作空间存放模型(考虑到模型的可移植性),步骤是:(1)在功能包package中建立一个models文件夹,然后把model文件都存在这个文件夹中 (2)在功能包的配置文件package.xml中的<export>标签中,加入<gazebo_ros gazebo_model_path="${prefix}/models"/> (解释一下,环境变量${prefix}表示指的是package.xml所在位置的路径信息)(3)此外,如果这个package.xml是自动生成的,还需要加上<depend>gazebo_ros</depend>和<exec_depend>gazebo</exec_depend> (4)改完package.xml要catkin_make以下才能生效 (5)当然,也可以使用另外的方式加载模型,但本方法是最推荐的。其他方法的参考链接放在这里【https://blog.csdn.net/benchuspx/article/details/116404058】

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值