基于RT-Thread的RoboMaster电控框架设计

发布者:EnigmaticSoul最新更新时间:2024-05-08 来源: elecfans关键字:RT-Thread  RoboMaster 手机看文章 扫描二维码
随时随地手机看文章

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


背景
Robomaster 机器人比赛包含多个兵种,为了提高研发效率,模块化尤为重要,使用 RT-Thread 有助于面对对象思想开发;通过配备的 Kconfig,Scons 等工具可以实现工程的灵活配置;软件定时器可用作各电机等模块监控,RingBuffer 可以实现传感器信息的高效处理 …….


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

电机模块开发
使用电机和电调均为大疆官方出品,如 2006,3508,6020 等,采用 CAN 通讯方式。

构建对象
首先我们根据使用的电机特性,构建一个通用的电机对象

/**

@brief DJI intelligent motor typedef
/
typedef struct dji_motor_object
{
rt_device_t can_dev; // 电机CAN实例
dji_motor_measure_t measure; // 电机测量值
uint32_t tx_id; // 发送id(主发)
uint32_t rx_id; // 接收id(主收)
/ 分组发送设置 /
uint8_t send_group; // 同一帧报文分组
uint8_t message_num; // 一帧报文中位置
motor_type_e motor_type; // 电机类型
motor_working_type_e stop_flag; // 启停标志
/ 监控线程相关 /
rt_timer_t timer; // 电机监控定时器
/ 电机控制相关 */
void *controller; // 电机控制器
int16_t (*control)(dji_motor_measure_t measure); // 控制电机的接口 用户可以自定义,返回值为16位的电压或电流值
} dji_motor_object_t;
因为这些电机我们均使用 CAN 方式进行驱动,是 CAN 设备的延申,于是将 rt_device_t can_dev 父类结构体对象内嵌。

dji_motor_measure_t 结构体中为,电机控制时需要用到的一些反馈值,包括电调直接反馈的数据以及进一步解算的得出的:

/**

@brief DJI motor feedback
/
typedef struct
{
/ 以下是处理得出的数据 /
float angle_single_round; // 单圈角度
float speed_aps; // 角速度,单位为:度/秒
float total_angle; // 总角度,注意方向
int32_t total_round; // 总圈数,注意方向
float target; // 目标值(输出轴扭矩矩/速度/角度(单位度))
/ 以下是电调直接回传的数据 */
uint16_t ecd; // 0-8191
uint16_t last_ecd; // 上一次读取的编码器值
int16_t speed_rpm; //电机的转速值
int16_t real_current; // 实际转矩电流
uint8_t temperature; // Celsius
} dji_motor_measure_t;
注册实例
通过 dji_motor_object_t *dji_motor_register(motor_config_t *config, void *controller) 注册对应的电机实例,用户通过 motor_config_t *config 对实例进行灵活配置:

/**
@brief 电机初始化,返回一个电机实例

@param config 电机配置
@return dji_motor_object_t* 电机实例指针
*/
dji_motor_object_t *dji_motor_register(motor_config_t *config, void *controller)
{
dji_motor_object_t *object = (dji_motor_object_t )rt_malloc(sizeof(dji_motor_object_t));
rt_memset(object, 0, sizeof(dji_motor_object_t));
// 对接用户配置的 motor_config
object->motor_type = config->motor_type; // 6020 or 2006 or 3508
object->rx_id = config->rx_id; // 电机接收报文的ID
object->control = controller; // 电机控制器
/ 查找 CAN 设备 /
object->can_dev = rt_device_find(config->can_name);
// 电机分组,因为至多4个电机可以共用一帧CAN控制报文
motor_send_grouping(object, config);
// 电机离线检测定时器相关
object->timer = rt_timer_create('motor1',
motor_lost_callback,
object, 20,
RT_TIMER_FLAG_PERIODIC);
rt_timer_start(object->timer);
dji_motor_enable(object);
dji_motor_obj[idx++] = object;
return object;
}
/ 电机配置结构体 */
typedef struct
{
motor_type_e motor_type;
const char *can_name;
uint32_t tx_id; // 发送id(主发)
uint32_t rx_id; // 接收id(主收)
void *controller; // 电机控制器
} motor_config_t;
motor_config_t 结构体中的 void *controller 为电机所使用到的控制器集合,是一个控制器类型为其成员的结构体变量,如下:

static struct chassis_controller_t{
pid_object_t *speed_pid;
}chassis_controller;
static struct gimbal_controller_t{
pid_object_t *speed_pid;
pid_object_t *angle_pid;
}gimbal_controlelr;
调用 dji_motor_object_t *dji_motor_register 时传入的 void *controller 为电机对应的控制器具体实现,如进行 pid 计算,滤波等,会赋值给电机对象对应的函数指针,在进行电机控制计算时被执行,如下:

rt_int16_t chassis_control(dji_motor_measure_t measure){
static rt_int16_t set = 0;
set = pid_calculate(chassis_controller.speed_pid, measure.speed_rpm, 1000);
return set;
}
数据处理
电机对象离不开对数据稳定快速的收发和解析计算,接下来展开讨论使用 RT-Thread 的 CAN 设备驱动收发数据的思路。

首先是数据的接收,stm32f4 拥有 2 个 CAN 外设,所有电机和使用 CAN 总线的设备都挂载在这两条总线上,但 RT-Thread 的每个 CAN 总线只能通过 rt_device_set_rx_indicate(can_dev, can_rx_call); 注册一个对应的接收回调函数。但不同类型电机,不同 CAN 设备的数据解析处理都是不一样的,我这里的解决思路是:首先创建了一个 usr_callback 文件,用于统一管理 CAN、串口等设备可能用到的用户接收对调函数;将一个大的设备类型回调函数注册到对应 CAN 设备,其中再细分各挂载设备的数据解析,实现如下:

#ifdef BSP_USING_CAN
rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
{
struct rt_can_msg rxmsg = {0};
uint8_t rxbuff = rxmsg.data;
/ 从 CAN 读取一帧数据 /
rt_device_read(dev, 0, &rxmsg, sizeof(rxmsg));
/ CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 /
#ifdef BSP_USING_DJI_MOTOR
dji_motot_rx_callback(rxmsg.id, rxbuff);
#endif / BSP_USING_DJI_MOTOR /
return RT_EOK;
}
#endif / BSP_USING_CAN */
但是这其中也有一点问题,rt_err_t can_rx_call(rt_device_t dev, rt_size_t size) 传入的参数无法判断具体的 CAN 设备来源,因此所有使用到的 CAN 外设数据处理函数都会被调用,但目前问题不大,因为同一条总线上不会挂载相同 ID 的设备,这也是一开始就应该避免的错误。

接下来是 CAN 报文的发送,调用 rt_device_write 发送填充好的 CAN 报文帧即可。

离线检测
这里使用 RT-Thread 的软件定时器对电机进行离线检测,当超过定时间没有接收到对应电机反馈报文,则进入超时回调,并输出警告日志:

/**

@brief 电机定时器超时回调函数
@param motor_ptr
*/
static void motor_lost_callback(void *motor_ptr)
{
dji_motor_object_t *motor = (dji_motor_object_t *)motor_ptr;
// dji_motor_stop(motor);
LOG_W('[dji_motor] Motor lost, can bus [%s] , id 0x[%x]', motor->can_dev->parent.name, motor->rx_id);
}
使用实例
封装完成的电机模块使用示例如下:

static struct chassis_controller_t{
pid_object_t *speed_pid;
}chassis_controller;
static struct gimbal_controller_t{
pid_object_t *speed_pid;
pid_object_t *angle_pid;
}gimbal_controlelr;
static dji_motor_object_t *chassis_motor;
static dji_motor_object_t *gimbal_motor;
rt_int16_t chassis_control(dji_motor_measure_t measure){
static rt_int16_t set = 0;
set = pid_calculate(chassis_controller.speed_pid, measure.speed_rpm, 1000);
return set;
}
rt_int16_t gimbal_control(dji_motor_measure_t measure){
static rt_int16_t set = 0;
set = pid_calculate(gimbal_controlelr.speed_pid, measure.speed_rpm, 0);
return set;
}
static void example_init()
{
pid_config_t chassis_speed_config = {
.Kp = 10, // 4.5
.Ki = 0, // 0
.Kd = 0, // 0
.IntegralLimit = 3000,
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement,
.MaxOut = 12000,
};
pid_config_t gimbal_speed_config = {
.Kp = 50, // 50
.Ki = 200, // 200
.Kd = 0,
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement,
.IntegralLimit = 3000,
.MaxOut = 20000,
};
chassis_controller.speed_pid = pid_register(&chassis_speed_config);
gimbal_controlelr.speed_pid = pid_register(&gimbal_speed_config);
motor_config_t chassis_motor_config = {
.motor_type = M3508,
.can_name = CAN_CHASSIS,
.rx_id = 0x201,
.controller = &chassis_controller,
};
motor_config_t gimbal_motor_config = {
.motor_type = GM6020,
.can_name = CAN_GIMBAL,
.rx_id = 0x206,
.controller = &gimbal_controlelr,
};
chassis_motor = dji_motor_register(&chassis_motor_config, chassis_control);
gimbal_motor = dji_motor_register(&gimbal_motor_config, gimbal_control);
}
到此就可以方便且灵活的配置和使用电机模块啦。

存在问题及优化方向
目前 rt-thread 下 stm32 can驱动似乎仅支持 FIFO0 ,但 stm32f4 系列 can 具备两个 FIFO,如能同时使能所有 FIFO,应该能有效提高性能和稳定性。
电机的离线回调可以增加相应的声光报警。
后续考虑能不能也优化为,read,write,control 等形式。


关键字:RT-Thread  RoboMaster 引用地址:基于RT-Thread的RoboMaster电控框架设计

上一篇:bldc可以做伺服电机吗 bldc电机和fpa直驱电机哪个好
下一篇:变频器运行的两个条件

推荐阅读最新更新时间:2024-11-13 18:20

基于STM32F107与RT-Thread的数据采集器方案设计与解析
设计了基于STM32F107设计的数据采集器,实现多种数据(串口、CAN口)采集处理后通过 GPRS模块 无线上传。重点编写了CAN设备驱动; 使用设备方式实现GPRS模块串口数据的上传下载;最后提出了使用线程过程中出现的一些问题。 一、 功能分析 系统功能如图1 所示,不算太复杂。由于下级传感器模块的上报的数据内容很多,导致编写处理程序内容较多。 二、CAN驱动编写 为了模块化地处理传感器的主动上报数据,CAN设备不再用以前的中断处理,而是采用了RTT的设备框架,重新编写了device的驱动。研究RTT里的CAN总线收发设备: 发现只有框架,没有内容。就仿着串口写一个candevice。研究组件使用 中的串口驱动:
[单片机]
基于STM32F107与<font color='red'>RT-Thread</font>的数据采集器方案设计与解析
大疆连续举办四届RoboMaster4,是为了寻找下一个汪滔吗?
当年还是香港科技大学学生的汪滔带着Robocon(亚太大学生机器人大赛)获奖的飞控系统研究,在深圳一间不足20平米的仓库开始了创业历程。 也许主办的RoboMasr是在寻找下一个汪滔,而下一个“汪滔”们将会组成下一个行业独角兽。 RoboMaster 机甲大师,是由DJI大疆创新发起并承办的面向大学生的机器人比赛。参赛选手需要独立研发制作工程、步兵、英雄等多种地面和空中机器人,操作手通过第一视角操控机器人发射弹丸攻击敌方以及防御。 从2015年起,RoboMaster已连续举办四届,如果RoboMaster是一所大学的话,那么今年这所学校也已经迎来了第一届毕业生。4年近3个亿的投入,第一届毕业生不足20人进入大疆
[机器人]
基于RT-Thread的智能车载温湿度监测系统设计方案
摘要 目前市场上的中低端家用轿车普遍采用手动空调方案。这种方案要求驾乘人员根据车内外的温差和个人的体感温度通过档位开关控制空调功率。然而,由于人体感知的滞后性,这种方式存在一定的问题。通常情况下,驾乘者会在感觉到热时将空调开到最大,而在感觉到冷时才减小空调功率。特别是在夏天,容易出现空调过冷导致驾乘者不适甚至引发空调病、感冒等严重后果。 因此,针对这种需求,我们采用星火一号开发板与板载外设提供了一个准确可靠、成本低廉的解决方案。简言之,相较于传统手动空调系统,我们的方案具备准确的温度感知和调控能力,能够根据实际温度情况自动调整空调功率。这样,驾乘者就能够享受到更加舒适和合理的车内温度,无需手动操作空调档位。我们的系统还增添电子
[嵌入式]
基于<font color='red'>RT-Thread</font>的智能车载温湿度监测系统设计方案
RT-Thread带来4.0版本,让工程师的设计如此简单
随着国内物联网环境的快速成熟,各类终端厂商、芯片,以及IP厂商也在进行多种市场布局。在此背景下, RT-Thread 深入产业合作,吸引越来越多的物联网厂商采用自己物联网操作系统。近期,RT-Thread发布了RT-Thread4.0物联网操作系统,从多方面进行了产品升级,方便了开发者使用,整合了生态资源,优化设计环境。   RT-Thread4.0发布会现场 在本次发布会上,RT-Thread创始人兼 睿赛德电子科技 总经理熊谱翔在RT-Thread3.0的基础上带大家回顾了RT-Thread的发展历程,尤其是针对软件包的生态建设,经过一年多的发展软件包数量已经增加到100多个,成为厂商、开发者进行模块化开发及设计的最佳选
[嵌入式]
RT-Thread商业支持车规级多核安全处理器
国内领先国产核心软件厂商 睿赛德科技 宣布,RT-Thread商业支持英飞凌科技车规级32位AURIX™ TriCore™多核控制器,可以让客户更容易且无缝地使用TriCore™处理器,充分利用多核的强大性能,提供给用户易用的操作系统开发环境及OTA,CAN/CANFD/LIN等能力;结合即将获得的ISO26262 ASIL-D功能安全认证,RT-Thread Auto for MCU为汽车领域众多应用场景提供了一个可选择的高安全性、高性价比的商用OS解决方案。 图片来源网络 RT-Thread 是一个集实时操作系统(RTOS)内核、中间件组件和开发者社区于一体的技术平台,由熊谱翔先生带领并集合中国开源社区力量
[汽车电子]
<font color='red'>RT-Thread</font>商业支持车规级多核安全处理器
小广播
最新嵌入式文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved