基于 RT-Thread 的 RoboMaster 电控框架(二)

基于 RT-Thread 的 RoboMaster 电控框架(二)

由于 RT-Thread 稳定高效的内核,丰富的文档教程,积极活跃的社区氛围,以及设备驱动框架、Kconfig、Scons、日志系统、海量的软件包…很难不选择 RT-Thread 进行项目开发。但也正是因为这些优点的覆盖面较广,很多初学者会觉得无从下手,但只要步入 RT-Thread 的大门,你就发现她的美好。这系列文档将作为本人基于 RT-Thread 开发 RoboMaster 电控框架的记录与分享,希望能帮助到更多初识 RT-Thread 的小伙伴,也欢迎大家交流分享,指正不足,共同进步。

背景

使用的开发板为大疆的 RoboMaster-C 型开发板,基础工程为 rt-thread>bsp>stm32f407-robomaster-c

ist8310磁力计模块开发

ist8310 为 robomaster-c 开发板上集成的三轴磁力计,使用 I2C 通讯,驱动主要参考 Firmament Autopilot Embedded System 该飞控开源项目中的驱动程序在此基础上进行调整。

添加 I2C 读写 API

首先将飞控程序中针对 RT-Thread 的 I2C 设备驱动封装的 I2C 读写函数借鉴过来:

rt_err_t i2c_read_reg(struct rt_i2c_bus_device *bus, uint16_t slave_addr, uint8_t reg, uint8_t* buffer)
{
    rt_size_t ret;
    struct rt_i2c_msg msgs[2];

    msgs[0].addr = slave_addr;
    msgs[0].flags = RT_I2C_WR | bus->flags;
    msgs[0].buf = ®
    msgs[0].len = 1;

    msgs[1].addr = slave_addr;
    msgs[1].flags = RT_I2C_RD | bus->flags;
    msgs[1].buf = buffer;
    msgs[1].len = 1;

    ret = rt_i2c_transfer(bus, msgs, 2);

    return ret == 2 ? RT_EOK : RT_ERROR;
}

rt_err_t i2c_write_reg(struct rt_i2c_bus_device *bus, uint16_t slave_addr, uint8_t reg, uint8_t val)
{
    rt_size_t ret;
    rt_uint8_t buffer[2];
    struct rt_i2c_msg msgs;

    buffer[0] = reg;
    buffer[1] = val;

    msgs.addr = slave_addr;
    msgs.flags = RT_I2C_WR | bus->flags;
    msgs.buf = buffer;
    msgs.len = 2;

    ret = rt_i2c_transfer(bus, &msgs, 1);

    return ret == 1 ? RT_EOK : RT_ERROR;
}

rt_err_t i2c_read_regs(struct rt_i2c_bus_device *bus, uint16_t slave_addr, uint8_t reg, uint8_t* buffer, uint16_t count)
{
    rt_size_t ret;
    struct rt_i2c_msg msgs[2];

    msgs[0].addr = slave_addr;
    msgs[0].flags = RT_I2C_WR | bus->flags;
    msgs[0].buf = ®
    msgs[0].len = 1;

    msgs[1].addr = slave_addr;
    msgs[1].flags = RT_I2C_RD | bus->flags;
    msgs[1].buf = buffer;
    msgs[1].len = count;

    ret = rt_i2c_transfer(bus, msgs, 2);

    return ret == 2 ? RT_EOK : RT_ERROR;
}

rt_err_t i2c_write_regs(struct rt_i2c_bus_device *bus, uint16_t slave_addr, uint8_t reg, uint8_t* vals, uint16_t count)
{
    rt_size_t ret;
    struct rt_i2c_msg msgs[2];

    msgs[0].addr = slave_addr;
    msgs[0].flags = RT_I2C_WR | bus->flags;
    msgs[0].buf = ®
    msgs[0].len = 1;

    msgs[1].addr = slave_addr;
    msgs[1].flags = RT_I2C_WR | bus->flags;
    msgs[1].buf = vals;
    msgs[1].len = count;

    ret = rt_i2c_transfer(bus, msgs, 2);

    return ret == 2 ? RT_EOK : RT_ERROR;
}

BSP 中 STM32 I2C 设备驱动使用的是软件 I2C,于是进入到 menuconfig 中对 I2C 引脚进行配置:

/* Notice: PA8 --> 8; PC9 --> 41 */
#define BSP_I2C1_SCL_PIN 8
#define BSP_I2C1_SDA_PIN 41

IST8310 驱动

主要就是先对 IST8310 进行初始化,设置相关采样参数,之后就可以读取磁力计的信息了

static rt_err_t mag_raw_measure(int16_t mag[3])
{
    uint8_t buffer[6];

    i2c_read_regs(i2c_bus, IST8310_ADDRESS, REG_DATA_OUT_X_L, buffer, sizeof(buffer));

    /* swap the data */
    mag[0] = ((int16_t)buffer[1] << 8) | (int16_t)buffer[0];
    mag[1] = ((int16_t)buffer[3] << 8) | (int16_t)buffer[2];
    mag[2] = ((int16_t)buffer[5] << 8) | (int16_t)buffer[4];
    /* start next measurement */
    // i2c_write_reg(i2c_bus, IST8310_ADDRESS, REG_CTRL1, CTRL1_ODR_SINGLE));

    return RT_EOK;
}

static rt_err_t mag_measure(float mag[3])
{
    int16_t raw[3];

    mag_raw_measure(raw);

    mag[0] = _range_scale * raw[0];
    mag[1] = _range_scale * raw[1];
    mag[2] = _range_scale * raw[2];

    ist8310_rotate_to_frd(mag);

    if (ist8310_user_calibrate != RT_NULL) {
        /* do user defined calibration */
        ist8310_user_calibrate(mag);
    }

    return RT_EOK;
}

其中 ist8310_user_calibrateist8310_rotate_to_frd 为预留的虚函数,用户可根据校准及转化需求,自行定义实现。

__attribute__((weak)) void ist8310_user_calibrate(float data[3]);

/* Re-implement this function to define customized rotation */
__attribute__((weak)) void ist8310_rotate_to_frd(float* data);

抽象设备

为提高程序的模块化,选用不同传感器时的灵活性,将 ist8310 抽象为 mag 一类设备,抽象出 mag_init 和 mag_read 两个操作方法。

struct mag_ops{
    rt_err_t (*mag_init)(const char* i2c_bus_name);
    rt_err_t (*mag_read)(float data[3]);
};

项目选用不同的磁力计传感器时,对接这两个接口即可,以 ist8310 为例:

/**
 * @brief 调用此函数初始化 ist8310
 *
 * @param i2c_bus_name ist8310 所挂载的总线名称
 *
 * @return RT_EOK
 */
static rt_err_t drv_ist8310_init(const char* i2c_bus_name);

/**
 * @brief 调用此函数读取 ist8310 数据
 *
 * @param data[3] 存储读取数据的数组
 *
 * @return 读取成功 RT_EOK ; 读取失败 -RT_ERROR
 */
static rt_err_t ist8310_read(float data[3]);

struct mag_ops mag = {
    .mag_init = drv_ist8310_init,
    .mag_read = ist8310_read,
};

应用层需要使用磁力计时,调用 mag_ops 中的操作方法即可:

static float read_data[3];
mag.mag_init("i2c1");      // 初始化 mag 设备
mag.mag_read(read_data);  // 将设备数据读取到 read_data 中

到此就可以方便的使用磁力计模块啦

仓库地址放这里了 HNU_RM_SHARK_C ,觉得不错可以点个 Star !

感谢阿木实验室开源的基于 RT-Thread 的飞控程序!

存在问题及优化方向

  1. 目前为了提高性能,mag设备的注册对接形式是比较简陋的。
  2. 后续考虑能不能也优化为,read,write,control 等形式。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值