首页 > 其他分享 >ros-slam-microros-发布里程计odom

ros-slam-microros-发布里程计odom

时间:2024-07-03 14:23:30浏览次数:20  
标签:KB 0.0 pose 里程计 0.72 slam microros odom msg

获得了里程计数据后,下一步就是将里程计通过MicroROS话题发布到ROS 2 系统中。

一、了解接口
在 ROS 2 已有的消息接口中:

nav_msgs/msg/Odometry

用于表示里程计数据,该接口内容如下:

 ros2 interface show nav_msgs/msg/Odometry 
 ---
# This represents an estimate of a position and velocity in free space.
# The pose in this message should be specified in the coordinate frame given by header.frame_id
# The twist in this message should be specified in the coordinate frame given by the child_frame_id

# Includes the frame id of the pose parent.
std_msgs/Header header
        builtin_interfaces/Time stamp
                int32 sec
                uint32 nanosec
        string frame_id

# Frame id the pose points to. The twist is in this coordinate frame.
string child_frame_id

# Estimated pose that is typically relative to a fixed world frame.
geometry_msgs/PoseWithCovariance pose
        Pose pose
                Point position
                        float64 x
                        float64 y
                        float64 z
                Quaternion orientation
                        float64 x 0
                        float64 y 0
                        float64 z 0
                        float64 w 1
        float64[36] covariance

# Estimated linear and angular velocity relative to child_frame_id.
geometry_msgs/TwistWithCovariance twist
        Twist twist
                Vector3  linear
                        float64 x
                        float64 y
                        float64 z
                Vector3  angular
                        float64 x
                        float64 y
                        float64 z
        float64[36] covariance

注意看,除了表示位置的 pose 和表示速度的 twist ,还有 child_frame_id 这一参数,它表示里程计子坐标系名称,根据ROS 导航堆栈定义,一般用 base_link 或者 base_footprint 。
接着我们来编写代码。
二、编写代码
如何发布话题在前面的章节中我们已经学习过了,现在我们来编写代码,因为是直接在原来的代码基础上修改的,所以下面展示的代码前如果是+表示新增行,-表示删除行,没有符号表示没有修改。
Kinematics.h
首先是/lib/Kinematics/Kinematics.h,增加四元数定义和欧拉角转四元数函数,这是因为ROS中姿态的表示使用的是四元数。

+typedef struct
+{
+    float w;
+    float x;
+    float y;
+    float z;
+} quaternion_t;
+
 /**
  * @brief 里程计相关信息,根据轮子速度信息和运动模型推算而来
  *
@@ -41,6 +49,7 @@ typedef struct
     float x;                 // 坐标x
     float y;                 // 坐标y
     float yaw;               // yaw
+    quaternion_t quaternion; // 姿态四元数
     float linear_speed;      // 线速度
     float angular_speed;     // 角速度
 } odom_t;
@@ -56,6 +65,7 @@ private:
 public:
     Kinematics(/* args */) = default;
     ~Kinematics() = default;
+    static void Euler2Quaternion(float roll, float pitch, float yaw, quaternion_t &q);
 
     static void TransAngleInPI(float angle,float& out_angle);

Kinematics.cpp
接着是:lib/Kinematics/Kinematics.cpp,增加 Euler2Quaternion 函数实现,在 odom 函数中增加对 Euler2Quaternion 函数的调用。

 #include "Kinematics.h"
 
+// 用于将欧拉角转换为四元数。
+void Kinematics::Euler2Quaternion(float roll, float pitch, float yaw, quaternion_t &q)
+{
+    // 传入机器人的欧拉角 roll、pitch 和 yaw。
+    // 计算欧拉角的 sin 和 cos 值,分别保存在 cr、sr、cy、sy、cp、sp 六个变量中    
+    // https://blog.csdn.net/xiaoma_bk/article/details/79082629
+    double cr = cos(roll * 0.5);
+    double sr = sin(roll * 0.5);
+    double cy = cos(yaw * 0.5);
+    double sy = sin(yaw * 0.5);
+    double cp = cos(pitch * 0.5);
+    double sp = sin(pitch * 0.5);
+    // 计算出四元数的四个分量 q.w、q.x、q.y、q.z
+    q.w = cy * cp * cr + sy * sp * sr;
+    q.x = cy * cp * sr - sy * sp * cr;
+    q.y = sy * cp * sr + cy * sp * cr;
+    q.z = sy * cp * cr - cy * sp * sr;
+}


 odom_t &Kinematics::odom()
 {
+    // 调用 Euler2Quaternion 函数,将机器人的欧拉角 yaw 转换为四元数 quaternion。
+    Kinematics::Euler2Quaternion(0, 0, odom_.yaw, odom_.quaternion);
     return odom_;
 }

main.cpp
接着修改了 /src/main.cpp ,主要添加了一个发布者,接着对时间进行同步,方便发布里程计话题时使用当前的时间。
然后对数据的各项进行设置,最后添加了里程计数据的发布,间隔 50ms 进行发布。

 #include <Esp32McpwmMotor.h>         // 包含使用 ESP32 的 MCPWM 硬件模块控制 DC 电机的 ESP32 MCPWM 电机库
 #include <PidController.h>           // 包含 PID 控制器库,用于实现 PID 控制
 #include <Kinematics.h>              // 运动学相关实现
+#include <nav_msgs/msg/odometry.h>
+#include <micro_ros_utilities/string_utilities.h>
+rcl_publisher_t odom_publisher;   // 用于发布机器人的里程计信息(Odom)
+nav_msgs__msg__Odometry odom_msg; // 机器人的里程计信息
 
 Esp32PcntEncoder encoders[2];      // 创建一个长度为 2 的 ESP32 PCNT 编码器数组
 rclc_executor_t executor;          // 创建一个 RCLC 执行程序对象,用于处理订阅和发布
 
void microros_task(void *param)
 {
+  // 使用 micro_ros_string_utilities_set 函数设置到 odom_msg.header.frame_id 中
+  odom_msg.header.frame_id = micro_ros_string_utilities_set(odom_msg.header.frame_id, "odom");
+  odom_msg.child_frame_id = micro_ros_string_utilities_set(odom_msg.child_frame_id, "base_link");
   // 等待 2 秒,以便网络连接得到建立。
   delay(2000);

+  rclc_publisher_init_best_effort(
+      &odom_publisher,
+      &node,
+      ROSIDL_GET_MSG_TYPE_SUPPORT(nav_msgs, msg, Odometry),
+      "odom");
   // 设置 micro-ROS 执行器,并将订阅添加到其中。
   rclc_executor_init(&executor, &support.context, 1, &allocator);
   rclc_executor_add_subscription(&executor, &subscriber, &sub_msg, &twist_callback, ON_NEW_DATA);

      // 循环运行 micro-ROS 执行器以处理传入的消息。
      while (true)
      {
+       if (!rmw_uros_epoch_synchronized())
+       {
+         rmw_uros_sync_session(1000);
+         // 如果时间同步成功,则将当前时间设置为MicroROS代理的时间,并输出调试信息。
+         delay(10);
+       }
        delay(100);
        rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
      }
  }
 
 unsigned long previousMillis = 0; // 上一次打印的时间
-unsigned long interval = 1000;    // 间隔时间,单位为毫秒
+unsigned long interval = 50;      // 间隔时间,单位为毫秒
 
 void loop()
 {
     previousMillis = currentMillis; // 记录上一次打印的时间
     float linear_speed, angle_speed;
     kinematics.kinematic_forward(kinematics.motor_speed(0), kinematics.motor_speed(1), linear_speed, angle_speed);
-    Serial.printf("[%ld] linear:%f angle:%f\n", currentMillis, linear_speed, angle_speed);                       // 打印当前时间
-    Serial.printf("[%ld] x:%f y:%f yaml:%f\n", currentMillis,kinematics.odom().x, kinematics.odom().y, kinematics.odom().yaw); // 打印当前时间
+    // Serial.printf("[%ld] linear:%f angle:%f\n", currentMillis, linear_speed, angle_speed);                       // 打印当前时间
+    // Serial.printf("[%ld] x:%f y:%f yaml:%f\n", currentMillis,kinematics.odom().x, kinematics.odom().y, kinematics.odom().yaw); // 打印当前时间
+    // 用于获取当前的时间戳,并将其存储在消息的头部中
+    int64_t stamp = rmw_uros_epoch_millis();
+    // 获取机器人的位置和速度信息,并将其存储在一个ROS消息(odom_msg)中
+    odom_t odom = kinematics.odom();
+    odom_msg.header.stamp.sec = static_cast<int32_t>(stamp / 1000); // 秒部分
+    odom_msg.header.stamp.nanosec = static_cast<uint32_t>((stamp % 1000) * 1e6); // 纳秒部分
+    odom_msg.pose.pose.position.x = odom.x;
+    odom_msg.pose.pose.position.y = odom.y;
+    odom_msg.pose.pose.orientation.w = odom.quaternion.w;
+    odom_msg.pose.pose.orientation.x = odom.quaternion.x;
+    odom_msg.pose.pose.orientation.y = odom.quaternion.y;
+    odom_msg.pose.pose.orientation.z = odom.quaternion.z;
+
+    odom_msg.twist.twist.angular.z = odom.angular_speed;
+    odom_msg.twist.twist.linear.x = odom.linear_speed;
+
+    rcl_publish(&odom_publisher, &odom_msg, NULL);
   }
 

这三个文件修改好,接着就可以下载代码进行测试了。
三、下载测试
下载代码,运行agent,点击RST按键。

sudo docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:$ROS_DISTRO udp4 --port 8888 -v6

 看到连接建立表示通信成功,接着用ros2 topic list

ros2 topic list
---
/cmd_vel
/odom
/parameter_events
/rosout

接着我们可以查看里程计数据或其发布频率。

ros2 topic echo /odom --once # 查看数据
---
header:
  stamp:
    sec: 2093
    nanosec: 40
  frame_id: odom
child_frame_id: base_link
pose:
  pose:
    position:
      x: 0.0
      y: 0.0
      z: 0.0
    orientation:
      x: 0.0
      y: 0.0
      z: 0.0
      w: 1.0
  covariance:
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
twist:
  twist:
    linear:
      x: 0.0
      y: 0.0
      z: 0.0
    angular:
      x: 0.0
      y: 0.0
      z: 0.0
  covariance:
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
---

查看数据频率

ros2 topic hz /odom
---
average rate: 19.376
        min: 0.047s max: 0.063s std dev: 0.00326s window: 21
average rate: 19.558
        min: 0.039s max: 0.063s std dev: 0.00338s window: 41
average rate: 19.527
        min: 0.039s max: 0.063s std dev: 0.00307s window: 61
average rate: 19.533
        min: 0.039s max: 0.063s std dev: 0.00301s window: 81

查看数据带宽

ros2 topic bw /odom
---
Subscribed to [/odom]
14.78 KB/s from 20 messages
    Message size mean: 0.72 KB min: 0.72 KB max: 0.72 KB
14.26 KB/s from 39 messages
    Message size mean: 0.72 KB min: 0.72 KB max: 0.72 KB
14.34 KB/s from 59 messages
    Message size mean: 0.72 KB min: 0.72 KB max: 0.72 KB
14.19 KB/s from 78 messages
    Message size mean: 0.72 KB min: 0.72 KB max: 0.72 KB
14.25 KB/s from 98 messages
    Message size mean: 0.72 KB min: 0.72 KB max: 0.72 KB
14.18 KB/s from 100 messages
    Message size mean: 0.72 KB min: 0.72 KB max: 0.72 KB
14.25 KB/s from 100 messages
    Message size mean: 0.72 KB min: 0.72 KB max: 0.72 KB

四、总结
有了控制话题和里程计话题,底盘部分就完成的差不多了,但是对于一个合格的底盘来说,其实还有很多待完善的地方,下一节我们就来说说可以怎么完善,以及完善的后的代码。

标签:KB,0.0,pose,里程计,0.72,slam,microros,odom,msg
From: https://www.cnblogs.com/ai-ldj/p/18281524

相关文章

  • ros - slam - microros - 里程计原理-速度积分
    前面两节中我们完成机器人底盘正逆解的计算,我们通过机器人的运动学逆解完成了机器人实时的角速度和线速度的测量,那我们能不能利用对线速度和角速度的积分,计算机器人当前的位置呢?答案肯定是可以的,那么本节我们就来编写代码实现机器人的里程计。  二、编写代码先修改Kinematics......
  • 【ORB_SLAM的安装报错】—— 使用./build.sh编译ORB_SLAM源码时出现报错:/usr/bin/ld:
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、/usr/bin/ld:找不到-lboost_serialization1.问题描述2.解决(1).下载源码(2).编译安装总结前言Boost库是一组由C++标准库的扩展库组成的集合,旨在为C++开发者提供高质量和功能丰......
  • 【视觉SLAM】 十四讲ch4习题
    概述视觉slam十四讲作为经典书籍,习题解答博客很多,避免重复工作,1~4和8题提供了其它博客连接。5、6、7笔者重新推导一遍并整理一些推导细节。感谢某只郭的誊抄。验证SO(3)、SE(3)和Sim(3)关于乘法成群。验证(R3,R,×)构成李代数。验证so(3)和se(3)满足李代数要求的性质。证明性质......
  • ros - slam - microros - 两轮差速模型运动学 - 运动学逆解
    上一节我们推导并在代码中实现了运动学正解,本节我们来学习下运动学逆解,实现给定线速度和角速度,计算出轮子达到怎样的转速才能达到这个速度。 一、逆解推导我们直接用正解结果进行求逆解即可。 二、编写代码继续在上一节中的代码Kinematics.cpp中完善即可。voidKinematics......
  • ros - slam - microros - 两轮差速模型运动学 - 运动学正解
    上一节了解了两轮差速运动学,本节我们线进一步的了解两轮差速正运动学的推导过程,并利用两轮差速运动学正解,来完成对小车的实时速度计算。 一、正运动学解推导两轮差速机器人是一种常见的移动机器人类型,由两个轮子和一个中心点组成。我们可以通过控制每个轮子的转速来实现移动,并......
  • ros - slam - microros - 两轮差速模型运动学介绍
    本节我们来了解下两轮差速运动学。一、两轮差速运动学模型两轮差速模型指机器人底盘由两个驱动轮和若干支撑轮构成的底盘模型,像turtlebot和开源机器人fishbot都是两轮差速模型。 两轮差速模型通过两个驱动轮可以通过不同转速和转向,使得机器人的达到某个特定的角速度和线速度......
  • ros -slam - microros- PID控制器实现
    上一节我们通过编码器完成了对机器人单个轮子的速度测量,完成了电机速度闭环控制的重要一步-反馈。 有了反馈,接着我们需要设计一个控制器来帮助我们实现这个需求,这个控制器的输入是当前的速度和目标速度,输出是应该给到电机的PWM占空比。一、PID控制器介绍PID控制器是一种广泛应......
  • ros2 - slam - 直流电机-编码器脉冲测量与校准
    这一节我们编写代码来尝试下是否能够读取到电机上编码器的脉冲数,并通过实验测试出小车的输出轴转速和编码器脉冲的比值。一、新建工程并导入开源库新建example25_encoder添加依赖[env:featheresp32];这是一个环境配置标签,指定了代码将运行的硬件平台和框架platform=esp......
  • ros2 - slam - 使用编码器测量轮子最大速度
    新建example26_max_speed_measurement 添加依赖[env:featheresp32];这是一个环境配置标签,指定了代码将运行的硬件平台和框架platform=espressif32;指定了使用的平台为Espressif32board=featheresp32;指定使用的硬件板为FeatherESP32framework=arduino;......
  • ros2 - slam - 编码器测速原理
    上节做完小车,遥控时小车前进时你应该会发现,小车很难走一条直线,但明明我们给到两个电机的PWM占空比都是相同的,原因在于每一个电机的硬件参数并不能完全的保证一致,所以当我们采用开环控制时,即使我们给到每个电机相同的电压,也不能让两个电机保持相同的转速。要解决这个问题我们就要......