一、IMU惯性测量单元消息包
IMU 是安装在机器人内部的一种传感器模块,用于测量机器人的空间姿态。
IMU的消息包定义在sensor_msgs包中的Imu中。头部是header,记录了消息发送的时间戳和坐标系ID。第二个是角速度。第三个是矢量加速度。三个数据成员都各自有一个协方差矩阵,主要用于后期的优化和滤波。
角速度:在x、y、z三个轴上的旋转角速度。矢量加速度:在x、y、z三个轴上的加速度。总共有6个数值,所以叫六轴IMU。另外还有一些IMU模块,额外提供了XYZ三个轴向的磁强计输出,就变成了九轴IMU。磁强计数据在ROS中有专门的消息格式,并没有包含在这个IMU消息包中。
角速度、矢量加速度这六个数值,都是IMU传感器直接测量到的数值,我们称之为裸数据。为了方便用户使用,IMU模块通常还会输出一个根据上述数值融合得到的空间姿态描述,也就是第一个数值orientation,它描述的是机器人朝向相对于空间中XYZ三个坐标轴的偏移量。
如果对消息包中IMU解算的这个orientation结果不满意,或者有其他的特殊需求,可以自行根据裸数据进行姿态信息的融合。这个orientation是一个Quaternion类型的数值,可以看到这是一个包含了xyzw四个数值的数据结构。
明明是相对于XYZ三个轴的旋转偏移量,怎么会整出四个值来?这是因为基于XYZ三个轴的旋转偏移量的描述,也就是欧拉角描述,在某些姿态下会存在一种叫做万向锁的问题。所以一位聪明的数学家发明了这种叫做Quaternion 的方法,也就是我们现在看到的,使用xyzw四个值来描述机器人朝向的方法,也叫做四元数描述法,有效的避免了万向锁问题。在实际的应用中,四元数描述法通常只在进行旋转变换的过程中使用,旋转后得到的结果,还是会转换成欧拉角来进行处理。
二、获取IMU数据的C++节点
为了获取IMU的数据,我们必须知道IMU数据格式,以及话题名称。IMU数据格式在上一节中具体讲述过。话题名称依据ROS的官方标准,分为以下三种。第一种只输出裸数据;第二种输出裸数据+orientation;第三输出磁强计数据(只有九轴IMU才会有)。
实现步骤:
step1:创建工作空间,创建imu_pag功能包。记得加入sensor_msgs依赖包。
step2:在功能包的src子目录中创建节点。
step3:需要使用tf工具来完成将四元数转换成欧拉角,所以要包含tf的头文件。main函数中第一行代码:将locale设置为当前的中文环境,避免显示的中文变成乱码。
step4:编写回调函数。第7行:判断imu数据是否存在。第9行:使用TF工具将四元数转换成欧拉角,需要将消息包里的四元数转换成tf的四元数对象。第16行:定义三个变量准备用来装载转换后的欧拉角结果。第17行:将quaternion对象转换成一个tf的3x3矩阵对象,然后调用矩阵对象的getRPY函数,这个RPY就是roll滚转pitch俯仰和yaw航向角的缩写,将其转换成欧拉角。第18行:这时候三个欧拉角变量里的数值单位是弧度,将其转换成360°的角度值。
step4:给这个节点设置编译规制,打开CMakeList.txt文件,找到build块,添加以下三行代码。
step5:编译+运行。
三、获取IMU数据的python节点
实现步骤:
step1:创建工作空间,新建功能包,创建python脚本。
step2:编写代码
step3:chmod添加可执行权限,运行。
四、IMU航向锁定的C++节点
让一个节点在订阅IMU数据的同时,还发布运动控制指令,使机器人能对姿态的变化做出反应,实现一个航向锁定的效果。我们可以直接在前面实验的程序上做修改,在此基础上,只需要把运动控制的部分内容也加进来就行了。
实现步骤:
step1:定义一个发布对象vel_pub,因为这个vel_pub一会我们要在main主函数和回调函数里都要用到,所以这里把它定义为一个全局对象,然后在主函数里对这个vel_pub进行初始化。
回调函数中,我们已经拿到IMU输出的机器人的当前朝向角yaw,我们再定义一个目标朝向角
target_yaw,然后定义一个差值变量diff _angle。再定义一个速度消息包,准备开始进行机器人的运动控制。
step2:编译+运行。
五、IMU航向锁定的python节点
step1:在头文件中加入速度控制消息包Twist。直接在main主函数中声明一个发布者对象。在回调函数中,将这个发布对象声明为全局变量(必须有这一步,否则会将vel_pub变成局部变量)。
step2:保存+运行。