前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于RT-THREAD nano的平衡车--下位机软件

基于RT-THREAD nano的平衡车--下位机软件

作者头像
Rice加饭
发布2022-05-10 17:44:50
4080
发布2022-05-10 17:44:50
举报
文章被收录于专栏:Rice嵌入式

简要

  • 平衡车文章分为4篇进行说明:
    1. 《平衡车 - 硬件》:讲解平衡车的硬件设计。
    2. 《平衡车 - 软件》:讲解平衡车的软件设计,算法。
    3. 《平衡车 - 上位机》:讲解调参上位机的设计
    4. 《平衡车 - 微信小程序》:讲解微信小程序作为遥控器的实现。
  • github连接:https://github.com/RiceChen/Balance_Car.git

软件设计

代码结构

  • 平衡车的代码设计,该平衡车是基于RT-THREAD NANO上进行设计,主要分为3层,driver-device-controler。
    1. driver层:主要对接STM32的HAL层。这部分的代码,模仿了rt-thread完整版的设备驱动框架。
    2. device层:主要实现平衡车各种外设的驱动。
    3. controler层:主要实现平衡车的算法,控制,显示,通信等功能。
driver层:
  • 主要包含如下驱动:| 驱动 | 功能 | |------|------| | drv_adc | 测量电压,提供原始数据 | | drv_flash | 保存平衡车参数,提供操作flash接口 | | drv_gpio | 通用GPIO的,效仿RTT完整版接口 | | drv_pulse_encoder | 脉冲解码器,提供读取编码器数值 | | drv_pwm | 提供电机驱动底层接口 | | drv_soft_i2c | 提供软件I2C接口,可任意扩展 | | drv_uart | 驱动串口接口,可任意扩展 |
  • 以上的驱动都是根据rt-thread完整版的思想,进行简化,为上层提供统一的接口。
  • 以采集ADC 驱动为例:
  1. 将名字和ADC1实例绑定:
代码语言:javascript
复制
#ifdef RT_USING_ADC1
#define ADC1_CONFIG                                               \
    {                                                             \
        .name = "adc1",                                           \
        .Instance = ADC1,                                         \
    }
#endif

#ifdef RT_USING_ADC2
#define ADC2_CONFIG                                               \
    {                                                             \
        .name = "adc2",                                           \
        .Instance = ADC2,                                         \
    }
#endif
  1. 为上层提供统一的API,通过rt_find_adc()接口找到相对应的实例句柄,然后通过rt_adc_enabled()接口使能对应的实例,通过rt_get_adc_value()接口读取对应的通道的ADC值。
代码语言:javascript
复制
struct rt_adc_drv *rt_find_adc(char *name);
rt_err_t rt_adc_enabled(struct rt_adc_drv *obj, rt_bool_t enabled);
rt_err_t rt_get_adc_value(struct rt_adc_drv *obj, rt_uint32_t channel, rt_uint32_t *value);
device层:
  • device层主要提供传感器的原始数据,设备控制接口。设备驱动如下:| 设备 | 功能 | |------|------| | dev_ble | 提供BLE的发送与接收接口,对接drv_uart | | dev_buzzer | 提供控制蜂鸣器接口,对接drv_gpio | | dev_encoder | 提供读取编码器数值接口,对接drv_pulse_encoder | | dev_key | 提供读取按键值接口,对接drv_gpio | | dev_motor | 通过控制电机接口,对接drv_pwm | | dev_mpu6050 | 提供陀螺仪读取数值接口,对接drv_soft_i2c | | dev_oled | 提供陀控制oled接口,对接drv_soft_i2c | | dev_voltage | 通过读取电压接口,对接drv_adc |
  • 以采集ADC 驱动为例:
  1. 获取对应实例的句柄,以及使能对应实例:
代码语言:javascript
复制
int rt_voltage_dev_init(void)
{
    voltage_adc_drv = rt_find_adc("adc1");
    if(voltage_adc_drv == RT_NULL)
    {
        rt_kprintf("find adc1 fail\n");
        return RT_ERROR;
    }

    rt_adc_enabled(voltage_adc_drv, RT_TRUE);

    return RT_EOK;
}
  1. 获取电压, 上层只需要调用此接口,即可完成电压读取:
代码语言:javascript
复制
rt_uint32_t rt_get_voltage(void)
{
    rt_uint32_t vol = 0;
    rt_uint32_t value = 0;
    rt_get_adc_value(voltage_adc_drv, VOLTAGE_ADC_CHANNEL, &value);

    vol = (value * REFER_VOLTAGE / CONVERT_BITS) * 11;

    rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);

    return value;
}
controler层:
  1. ble_ctrl: 提供BLE与上位机/微信小程序的控制逻辑
  • 串口一个数据发送线程。
  • 注册BLE接受数据回调函数,接受上位机/微信小程序的控制逻辑。因为采用中断以及为了分层,所以采用回调的形式。
  1. show_menu: oled显示,参数设置,参数显示等控制逻辑
  • 初始化启动了一个线程,用于运行时参数数据实时显示。
  • 每次重新启动都会进入此功能,通过按键和oled,可进行PID,速度等参数整定。
  1. sds:这是一款虚拟示波器,通过串口输入,在我这个平衡车中,我采用BLE转发
  • 方便在整定参数的时候使用。
  1. controler:控制层的总入口,角度计算,平衡PID算法,速度计算,速度PID,方向PID。
  • 创建一个线程,然后每运行一次延时5ms。线程执行内容:
代码语言:javascript
复制
static void ctrl_thread_entry(void *parameter)
{
    for(;;)
    {
        ctrl_get_angle();   //获取角度
        ctrl_balance_pid(); //平衡PID计算
        ctrl_get_speed();   //获取当前速度
        ctrl_speed_pid();   //速度PID计算
        ctrl_turn_pid();    //转向PID计算
        ctrl_set_speed();   //控制速度

        rt_thread_delay(5);
    }
}
  • 角度计算,我直接采用三角函数进行计算,没有采用四元数:
代码语言:javascript
复制
    turn_parm.turn_gyor = gyro.z / 16.384;
    angle_parm.balance_gyor = gyro.y / 16.384;
    angle_parm.angle = atan2(accel.x, accel.z) * 180 / PI;
    angle_parm.angle_increment = angle_parm.out_angle - (gyro.y / 16.384) * 0.005;
    angle_parm.out_angle = K1 * angle_parm.angle + (1 - K1)*(angle_parm.angle_increment);
  • 平衡PID算法,采用PD控制算法:
代码语言:javascript
复制
int ctrl_balance_pid(void)
{
    float bias_val = 0.0;

    bias_val = (car_parm.blc_angle - 0.5) - angle_parm.out_angle;

    speed_parm.balance_pwm = car_parm.blc_Kp * bias_val + car_parm.blc_Kd * angle_parm.balance_gyor;

    return speed_parm.balance_pwm;
}
  • 速度计算,直接获取左右编码器的值
  • 速度PID,采用PI控制算法:
代码语言:javascript
复制
void ctrl_speed_pid(void)
{
    float current_bias = 0;

    current_bias = (speed_parm.get_left_speed + speed_parm.get_right_speed) - car_parm.speed;

    current_bias = speed_parm.last_bias * 0.3 + current_bias * 0.7;
    speed_parm.integral_bias += current_bias;

    speed_parm.speed_pwm = (int)(car_parm.speed_Kp * current_bias +
                         car_parm.speed_Ki * speed_parm.integral_bias);

    speed_parm.last_bias = current_bias;
}
  • 速度PID,我这里是没有太关乎的,只有P值.
  • 速度设置,将平衡PID、速度PID、转向PID计算出来的整合既是最终速度的值。

效果:

http://mpvideo.qpic.cn/0bf2maaaaaaa2yac3ryqlzqfaygdabqaaaaa.f10002.mp4?dis_k=b09a68cde9e9da40d677c12c747eaad0&dis_t=1652175861&vid=wxv_1712630676849491971&format_id=10002&support_redirect=0&mmversion=false

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rice 嵌入式开发技术分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简要
  • 软件设计
    • 代码结构
      • driver层:
      • device层:
      • controler层:
  • 效果:
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档