0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

学会面向对象编程封装IMU驱动

CHANBAEK 来源:鱼香ROS 作者:小鱼 2023-07-13 14:55 次阅读

上一节我们成功读取到了IMU的数据,其中角度用欧拉角的方式表示的,在我们机器人世界里姿态的表示往往使用四元数表示(如果不清楚他们之间的关系可以回看第六章机器人学篇),所以我们需要将欧拉角转换成四元数。除此之外我们还需要将其坐标系矫正到右手坐标系。

所以本节我们将通过面向对象的方式将IMU驱动进行封装,并为其添加坐标系转换以及四元数转换函数。

教程所使用硬件平台为MicroROS学习板V1.0.0,可点击阅读原文购买及查看详情

图片

一、理论介绍

1.1.欧拉角转四元数

欧拉角转四元数的公式我们在第六章入门篇第三节有介绍,这里回顾一下

图片

根据公式我们可以写出代码

typedef struct
{
    float w;
    float x;
    float y;
    float z;
} quaternion_t;

Euler2Quaternion(float roll, float pitch, float yaw, quaternion_t &q)
{
    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 = 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;
}

1.2 坐标系校准

我们采用右手坐标系,接着我们依次来校准角度数据的方向。

打开终端,点击RST,查看IMU数据。

首先是X轴,我们让开发板上爱神丘比特的剑头指向自己,然后从右侧往左侧倾斜。

可以看到此时X轴为正值,符合右手坐标系法则。

接着是Y轴,平放,将箭头朝向自己的胸口,接着抬高板子,让箭头指向自己的头部,观察Y轴的变化。

Y轴为负值,不符合右手坐标系法则,所以Y的值应该取一次负,使其为正。

接着是Z轴,平放,将箭头朝向自己的胸口,然后逆时针旋转板子,观察数值变化。

图片

值为正,表示符合右手坐标系法则。

你可能会问小鱼怎么确认怎样旋转是正,怎样旋转是负,首先要确认轴向,我们开发板的Z轴朝上,X轴朝前,此时Y轴应该朝左。接着摊开右手手掌,用大拇指朝向轴的方向,比如朝向X轴,然后握起手掌,那么你握的方向就是正方向。

二、开始写代码

新建工程example07_mpu6050_oop

图片

接着为其添加依赖

修改platformio.ini

[env:featheresp32]
platform = espressif32
board = featheresp32
framework = arduino
lib_deps = 
    https://ghproxy.com/https://github.com/rfetick/MPU6050_light.git

接着在lib下新建IMU文件夹,并在文件夹下新建IMU.hIMU.cpp

图片

IMU.h

#ifndef __IMU_H__
#define __IMU_H__
#include "Wire.h"
#include "MPU6050_light.h"

typedef struct
{
    float w;
    float x;
    float y;
    float z;
} quaternion_t; // 四元数结构体

typedef struct
{
    float x;
    float y;
    float z;
} vector_3d_t; // 通用3D点结构体

typedef struct
{
    quaternion_t orientation;
    vector_3d_t angle_euler;
    vector_3d_t angular_velocity;
    vector_3d_t linear_acceleration;
} imu_t; // IMU数据结构体

class IMU
{
private:
    MPU6050 *mpu_; // mpu6050指针

public:
    /**
     * @brief 同u哦NPU6050构造一个新的IMU对象
     *
     * @param mpu
     */
    IMU(MPU6050 &mpu);
    
    ~IMU() = default;
    /**
     * @brief 初始化函数
     *
     * @param sda 引脚编号
     * @param scl 引脚编号
     * @return true
     * @return false
     */
    bool begin(int sda, int scl);
    /**
     * @brief 欧拉角转四元数
     *
     * @param roll 输入X
     * @param pitch 输入y
     * @param yaw 输入Z
     * @param q  返回的四元数引用
     */
    static void Euler2Quaternion(float roll, float pitch, float yaw, quaternion_t &q);
    /**
     * @brief 获取IMU数据函数
     *
     * @param imu
     */
    void getImuData(imu_t &imu);
    /**
     * @brief 更新IMU数据,同上一节中的mou.update
     *
     */
    void update();
};

#endif // __IMU_H__

IMU.cpp

#include "IMU.h"

IMU::IMU(MPU6050 &mpu)
{
    mpu_ = &mpu;
};

bool IMU::begin(int sda, int scl)
{
    Wire.begin(sda, scl);
    byte status = mpu_- >begin();
    Serial.print(F("MPU6050 status: "));
    Serial.println(status);
    if (status != 0)
    {
        return false;
    } // stop everything if could not connect to MPU6050

    Serial.println(F("Calculating offsets, do not move MPU6050"));
    delay(1000);
    // mpu.upsideDownMounting = true; // uncomment this line if the MPU6050 is mounted upside-down
    mpu_- >calcOffsets(); // gyro and accelero
    Serial.println("Done!n");
    return true;
}

void IMU::Euler2Quaternion(float roll, float pitch, float yaw, quaternion_t &q)
{
    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 = 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;
}

void IMU::getImuData(imu_t &imu)
{
    imu.angle_euler.x = mpu_- >getAngleX();
    imu.angle_euler.y = -mpu_- >getAngleY();
    imu.angle_euler.z = mpu_- >getAngleZ();

    imu.angular_velocity.x = mpu_- >getAccAngleX();
    imu.angular_velocity.y = -mpu_- >getAccAngleY();
    imu.angular_velocity.z = mpu_- >getGyroZ();

    imu.linear_acceleration.x = mpu_- >getAccX();
    imu.linear_acceleration.y = mpu_- >getAccY();
    imu.linear_acceleration.z = mpu_- >getAccZ();

    IMU::Euler2Quaternion(imu.angle_euler.x, imu.angle_euler.y, imu.angle_euler.z,
                          imu.orientation);
}

void IMU::update()
{
    mpu_- >update();
}

main.cpp

#include < Arduino.h >
#include "IMU.h"

MPU6050 mpu(Wire); // 初始化MPU6050对象
IMU imu(mpu);      // 初始化IMU对象

imu_t imu_data;
unsigned long timer = 0;

void setup()
{
  Serial.begin(115200);
  imu.begin(18, 19); // 初始化IMU,使用18,19引脚
}

void loop()
{
  imu.update();
  if ((millis() - timer) > 100)
  {
    imu.getImuData(imu_data); // 获取IMU数据结构体
    Serial.printf("imu:teuler(%f,%f,%f)n",
                  imu_data.angle_euler.x, imu_data.angle_euler.y, imu_data.angle_euler.z);
    Serial.printf("imu:torientation(%f,%f,%f,%f)n",
                  imu_data.orientation.w, imu_data.orientation.x, imu_data.orientation.y, imu_data.orientation.z);
    timer = millis();
  }
}

对于代码的解释已经放到了注释之中。

编译下载后,你将看到

图片

三、总结

本节我们通过对MPU6050驱动的封装,学习了如何在嵌入式上使用面向对象编程的方法,下一节我们继续尝试使用开源库来驱动OLED模块,让我们的显示器亮起来。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5056

    文章

    18950

    浏览量

    301479
  • 封装
    +关注

    关注

    126

    文章

    7709

    浏览量

    142549
  • 面向对象
    +关注

    关注

    0

    文章

    64

    浏览量

    9971
  • 学习板
    +关注

    关注

    0

    文章

    42

    浏览量

    12147
  • IMU
    IMU
    +关注

    关注

    6

    文章

    295

    浏览量

    45631
收藏 人收藏

    评论

    相关推荐

    Python的面向对象编程详解

    一般编程可分为面向过程编程,和面向对象编程。Python的
    发表于 09-04 16:35 496次阅读
    Python的<b class='flag-5'>面向</b><b class='flag-5'>对象</b><b class='flag-5'>编程</b>详解

    labview面向对象编程

    点击学习>>《龙哥手把手教你学LabVIEW视觉设计》视频教程使用LabVIEW面向对象编程方法,对于大型测试应用程序来讲,面向对象相对于
    发表于 11-24 11:01

    labview面向对象编程

    有没有大神在labview中用面向对象编程的?请教一下怎样做?书上的对这方面的知识很少,无从下手,急急急急急急!
    发表于 08-08 14:26

    如何用C语言实现面向对象编程

    1 用C语言实现面向对象编程GOF的《设计模式》一书的副标题叫做“可复用面向对象软件的基础”,从标题就能看出
    发表于 07-12 07:24

    面向对象编程及其三大特性 精选资料分享

    Oriented)是一种以过程为中心的编程思想。这些都是以什么正在发生为 目标进行编程,不同于面向对象的是谁在受影响。与面向
    发表于 07-21 08:38

    基于面向对象的LabVIEW编程有哪些优势

    基于面向对象的LabVIEW编程有哪些优势?如何去学习基于面向对象的LabVIEW编程
    发表于 08-24 07:22

    谈谈面向对象编程

    在工业自动化领域,梯形图逻辑仍然是最常用的编程语言之一,但对于更加复杂的控制对象面向对象编程不失为一种高效率的方式。下面先来谈谈
    发表于 09-08 07:47

    面向对象编程语言的特点

    在工业自动化领域,梯形图逻辑仍然是最常用的编程语言之一,但对于更加复杂的控制对象面向对象编程不失为一种高效率的方式。下面先来谈谈
    发表于 09-08 07:44

    面向对象编程介绍

    目录一、面向对象编程介绍1.面向过程编程2.函数式编程3.
    发表于 12-13 07:22

    如何在嵌入式上使用面向对象编程呢?

    代码的解释已经放到了注释之中。  编译下载后,你将看到  三、总结  本节我们通过对MPU6050驱动封装,学习了如何在嵌入式上使用面向对象编程
    发表于 03-28 14:55

    面向对象编程练习

    实验 3 面向对象编程练习 一、实验目的     通过编程和上机实验理解 Java 语言是如何体现面向
    发表于 09-23 18:57 3030次阅读

    plc面向对象编程架构与实现

    面向对象编程是计算机高级语言的一种先进的编程模式,在工业控制系统的PLC程序中也可以采用这种设计思想,虽然我们无法实现面向
    发表于 01-31 15:00 4217次阅读
    plc<b class='flag-5'>面向</b><b class='flag-5'>对象</b><b class='flag-5'>编程</b>架构与实现

    面向对象方法实现IIC驱动封装以及AT24CXX存储器的封装

    使用面向对象编程思想封装IIC驱动,将IIC的属性和操作封装成一个库,在需要创建一个IIC设备
    的头像 发表于 09-16 09:22 1398次阅读

    西门子PLC面向对象编程

    面向对象编程是计算机高级语言的一种高级编程模式,这种设计思想也可以应用于工业控制系统的plc程序中。虽然我们 无法实现面向
    发表于 04-17 11:41 4次下载
    西门子PLC<b class='flag-5'>面向</b><b class='flag-5'>对象</b><b class='flag-5'>编程</b>

    什么是面向对象编程(OOP)?面向对象的程序设计

    编程领域,面向对象编程 (OOP) 是一种强大的范例,使开发人员能够构建复杂且可扩展的应用程序。
    的头像 发表于 07-19 14:57 1148次阅读