Gitee
https://gitee.com/WangXi_Chn/RttOs_ModuleLib
开发环境
CubeMX
MDK5 IDE
STM32F407IGH6TR 芯片
大疆开发板 C型
大疆M3508直流无刷电机
大疆C620无刷电机调速器
RT-Thread操作系统
面向对象模块接口设计
硬件条件
- 确保Can线供电电平达到5V(不可仅使用JTAG接口供电3.3V)
- Can线接口连接正确
-
核心思想
将一条Can线上的所有3508电机视为一个电机群
- 最大支持驱动8个不同ID的电机(符合电机电调参数手册)
- 隐藏固定的ID,减少驱动工作量,使能一个电机仅需打开开关,未打开的电机不使能
- 通过掩码思想,标记已打开的电机,并仅驱动打开的电机
- 设计电机工作模式:角度环/速度环,支持切换
- 每个电机绑定两个不同的PID分别控制角度和速度,根据电机模式分别使能
- 模块化思想
源文件
Module_DjiC610620Group.h
```c /*- Copyright (c) 2020 - ~, HIT_HERO Team *
- 2508MOTOR_CAN MODULE HEAD FILE
- Used in RT-Thread Operate System *
- Change Logs:
- Date Author Notes Mail
- 2020-08-08 WangXi first version WangXi_chn@foxmail.com *
- Note:
- DJI 3508 motor and C620 motor controler driver and control framework
- All paramemters shall be subject to the motor rotor control
- And the parameters of the shaft shall be converted by yourself if needed
- The positive direction is clockwise facing the rotor */
ifndef MODULE_DJIC610620GROUP_H
define MODULE_DJIC610620GROUP_H
include
include
include
include “Math_PID.h”
/ Definition —————————————————————————————/ enum DjiC610620ID { DjiC610620ID_1 = 0, DjiC610620ID_2 = 1, DjiC610620ID_3 = 2, DjiC610620ID_4 = 3, DjiC610620ID_5 = 4, DjiC610620ID_6 = 5, DjiC610620ID_7 = 6, DjiC610620ID_8 = 7, };
enum DjiC610620MODE { DjiC610620MODE_SPEED = 0, DjiC610620MODE_ANGLE = 1, };
/ Single motor label —————————————————————————————/ struct _MODULE_DjiC610620 { / Property / rt_uint8_t Enable; rt_uint8_t Mode;
MATH_PID PID_Speed;MATH_PID PID_Angle;/* Value */rt_int16_t Value_motor_AimCurrent;rt_int16_t Value_motor_AimRPM;rt_int16_t Value_motor_AimAngle;rt_int16_t Value_motor_RealCurrent;rt_int16_t Value_motor_RealRPM;rt_int16_t Value_motor_RealAngle;rt_uint8_t Value_motor_Temperature;rt_int8_t Value_motor_InitFlag;rt_int16_t Value_motor_OffsetAngle;rt_int16_t Value_motor_LastAngle;rt_int32_t Value_motor_TotalAngle; /* after the conversion (°) */rt_int16_t Value_motor_AngleCnt;/* Method */void (*Method_Init)(struct _MODULE_DjiC610620 *module);
}; typedef struct _MODULE_DjiC610620 MODULE_DjiC610620;
/ Motor group label —————————————————————————————/ struct _MODULE_DjiC610620GROUP { / Property / char * Property_CanDevName; MODULE_DjiC610620 Value_module_DjiC610620[7];
/* Value */struct rt_can_msg Value_can_msgLow;struct rt_can_msg Value_can_msgHigh;struct rt_can_msg Value_can_mrg;rt_device_t Value_can_dev;rt_uint8_t Value_motorUsedMask;/* Method */void (*Method_Init) (struct _MODULE_DjiC610620GROUP *module);void (*Method_Send) (struct _MODULE_DjiC610620GROUP *module);void (*Method_Feed) (struct _MODULE_DjiC610620GROUP *module);rt_err_t (*Method_Handle) (rt_device_t dev,rt_size_t size);
}; typedef struct _MODULE_DjiC610620GROUP MODULE_DjiC610620GROUP;
/ Glodal Method / rt_err_t Module_DjiC610620Group_Config(MODULE_DjiC610620GROUP *Dev_DjiC610620Group);
endif
/** (C) COPYRIGHT 2020 WANGXI **END OF FILE**/
<a name="bYc1E"></a>## Module_DjiC610620Group.c```c/** Copyright (c) 2020 - ~, HIT_HERO Team** 2508MOTOR_CAN MODULE SOUCE FILE* Used in RT-Thread Operate System** Change Logs:* Date Author Notes Mail* 2020-08-08 WangXi first version WangXi_chn@foxmail.com** Note:* DJI 3508 motor and C620 motor controler driver and control framework* All paramemters shall be subject to the motor rotor control* And the parameters of the shaft shall be converted by yourself if needed* The positive direction is clockwise facing the rotor*/#include "Module_DjiC610620Group.h"/* User Code Begin*//* User Code End *//* Static Method */static void Module_DjiC610620GroupInit(MODULE_DjiC610620GROUP *module);static void Module_DjiC610620GroupSend(MODULE_DjiC610620GROUP *module);static void Module_DjiC610620GroupFeed(MODULE_DjiC610620GROUP *module);static rt_err_t Module_DjiC610620GroupHandle(rt_device_t dev, rt_size_t size);static rt_err_t Module_DjiC610620_Config(MODULE_DjiC610620 *Dev_DjiC610620);static void Module_DjiC610620Init(MODULE_DjiC610620 *module);static struct rt_semaphore can3508Motor_sem;/* Global Method */rt_err_t Module_DjiC610620Group_Config(MODULE_DjiC610620GROUP *Dev_DjiC610620Group){if( Dev_DjiC610620Group->Method_Init ==NULL &&Dev_DjiC610620Group->Method_Feed ==NULL &&Dev_DjiC610620Group->Method_Send ==NULL &&Dev_DjiC610620Group->Method_Handle ==NULL){/* Link the Method */Dev_DjiC610620Group->Method_Init = Module_DjiC610620GroupInit;Dev_DjiC610620Group->Method_Feed = Module_DjiC610620GroupFeed;Dev_DjiC610620Group->Method_Send = Module_DjiC610620GroupSend;Dev_DjiC610620Group->Method_Handle = Module_DjiC610620GroupHandle;}else{rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");return RT_ERROR;}/* Device Init */Dev_DjiC610620Group->Method_Init(Dev_DjiC610620Group);/* Motor Config */for(int i=0;i<8;i++){if(Dev_DjiC610620Group->Value_module_DjiC610620[i].Enable != 0){Dev_DjiC610620Group->Value_motorUsedMask |= 0x01<<i;Module_DjiC610620_Config(&(Dev_DjiC610620Group->Value_module_DjiC610620[i]));}}return RT_EOK;}static void Module_DjiC610620GroupInit(MODULE_DjiC610620GROUP *module){rt_err_t res;/* link can devices */module->Value_can_dev = rt_device_find(module->Property_CanDevName);if (!module->Value_can_dev)rt_kprintf("find %s failed!\n", module->Property_CanDevName);/* init semaphone */rt_sem_init(&can3508Motor_sem, "can3508Motor_sem", 0, RT_IPC_FLAG_FIFO);module->Value_can_msgLow.id = 0x200;module->Value_can_msgLow.ide = RT_CAN_STDID;module->Value_can_msgLow.rtr = RT_CAN_DTR;module->Value_can_msgLow.len = 8;module->Value_can_msgHigh.id = 0x1FF;module->Value_can_msgHigh.ide = RT_CAN_STDID;module->Value_can_msgHigh.rtr = RT_CAN_DTR;module->Value_can_msgHigh.len = 8;module->Value_can_mrg.hdr = -1;res = rt_device_open(module->Value_can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);RT_ASSERT(res == RT_EOK);/* set up can baudrate */rt_device_control(module->Value_can_dev, RT_CAN_CMD_SET_BAUD, (void *)CAN1MBaud);/* link call back function */rt_device_set_rx_indicate(module->Value_can_dev, module->Method_Handle);}rt_err_t Module_DjiC610620_Config(MODULE_DjiC610620 *Dev_DjiC610620){if( Dev_DjiC610620->Method_Init ==NULL){/* Link the Method */Dev_DjiC610620->Method_Init = Module_DjiC610620Init;}else{rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");return RT_ERROR;}/* Device Init */Dev_DjiC610620->Method_Init(Dev_DjiC610620);/* Module PID controler Init */if(Dev_DjiC610620->Mode == DjiC610620MODE_SPEED){Module_PID_Config(&(Dev_DjiC610620->PID_Speed));}else if(Dev_DjiC610620->Mode == DjiC610620MODE_ANGLE){Module_PID_Config(&(Dev_DjiC610620->PID_Speed));Module_PID_Config(&(Dev_DjiC610620->PID_Angle));}return RT_EOK;}/* Static Method */static void Module_DjiC610620Init(MODULE_DjiC610620 *module){module->Value_motor_AimAngle = 0;module->Value_motor_AimCurrent = 0;module->Value_motor_AimRPM = 0;if(module->ENCODER == ROTARYENCODER){module->Encoder_dev = rt_device_find(module->Encoder_DevName);if (module->Encoder_dev == RT_NULL){rt_kprintf("pulse encoder sample run failed! can't find %s device!\n", module->Encoder_DevName);return;}rt_err_t ret = rt_device_open(module->Encoder_dev, RT_DEVICE_OFLAG_RDONLY);if (ret != RT_EOK){rt_kprintf("open %s device failed!\n", module->Encoder_DevName);return;}rt_pin_mode(GET_PIN(D,12), PIN_MODE_INPUT_PULLUP);rt_pin_mode(GET_PIN(D,13), PIN_MODE_INPUT_PULLUP);}}static void Module_DjiC610620GroupSend(MODULE_DjiC610620GROUP *module){rt_size_t size;/* Calculate the final current value of motor */for(int i=0;i<8;i++){if((module->Value_motorUsedMask & (0x01<<i))!=0x00){module->Value_module_DjiC610620[i].Value_motor_AimCurrent =module->Value_module_DjiC610620[i].PID_Speed.Value_output;}}/* make up the all can fram */if((module->Value_motorUsedMask & 0x0F) != 0){for(int i=1;i<=4;i++){module->Value_can_msgLow.data[i*2-1] = module->Value_module_DjiC610620[i-1].Value_motor_AimCurrent & 0xFF;module->Value_can_msgLow.data[i*2-2] = module->Value_module_DjiC610620[i-1].Value_motor_AimCurrent >> 8;}size = rt_device_write(module->Value_can_dev, 0, &(module->Value_can_msgLow), sizeof(module->Value_can_msgLow));if (size == 0)rt_kprintf("can dev write data failed!\n");size = 0;}rt_thread_mdelay(1);if((module->Value_motorUsedMask & 0xF0) != 0){for(int i=5;i<=8;i++){module->Value_can_msgHigh.data[i*2-9] = module->Value_module_DjiC610620[i-1].Value_motor_AimCurrent & 0xFF;module->Value_can_msgHigh.data[i*2-10] = module->Value_module_DjiC610620[i-1].Value_motor_AimCurrent >> 8;}size = rt_device_write(module->Value_can_dev, 0, &(module->Value_can_msgHigh), sizeof(module->Value_can_msgHigh));if (size == 0)rt_kprintf("can dev write data failed!\n");size = 0;}}static rt_err_t Module_DjiC610620GroupHandle(rt_device_t dev, rt_size_t size){rt_sem_release(&can3508Motor_sem);return RT_EOK;}static void Module_DjiC610620GroupFeed(MODULE_DjiC610620GROUP *module){rt_sem_take(&can3508Motor_sem, RT_WAITING_FOREVER);/* Get true value of the motor */rt_uint8_t index = 1;rt_device_read(module->Value_can_dev, 0, &(module->Value_can_mrg), sizeof(module->Value_can_mrg));index = (module->Value_can_mrg.id & 0x00F) - 1;module->Value_module_DjiC610620[index].Value_motor_RealAngle =((module->Value_can_mrg.data[0]<<8) | module->Value_can_mrg.data[1]);module->Value_module_DjiC610620[index].Value_motor_RealRPM =((module->Value_can_mrg.data[2]<<8) | module->Value_can_mrg.data[3]);module->Value_module_DjiC610620[index].Value_motor_RealCurrent =((module->Value_can_mrg.data[4]<<8) | module->Value_can_mrg.data[5]);module->Value_module_DjiC610620[index].Value_motor_Temperature =module->Value_can_mrg.data[6];/* Get the offset angle */if(module->Value_module_DjiC610620[index].Value_motor_InitFlag == 0){module->Value_module_DjiC610620[index].Value_motor_OffsetAngle =module->Value_module_DjiC610620[index].Value_motor_RealAngle;module->Value_module_DjiC610620[index].Value_motor_InitFlag = 1;return;}if(module->Value_module_DjiC610620[index].Mode == DjiC610620MODE_SPEED){/* Update PID output */module->Value_module_DjiC610620[index].PID_Speed.Method_Update(&(module->Value_module_DjiC610620[index].PID_Speed),module->Value_module_DjiC610620[index].Value_motor_AimRPM,module->Value_module_DjiC610620[index].Value_motor_RealRPM);}else if(module->Value_module_DjiC610620[index].Mode == DjiC610620MODE_ANGLE){/* Deal with the data of motor's angle */if(module->Value_module_DjiC610620[index].ENCODER == DjiC610620SELF){/* Use DjiC610/C620 it self encoder */module->Value_module_DjiC610620[index].Value_motor_RealAngle -=module->Value_module_DjiC610620[index].Value_motor_OffsetAngle;if(module->Value_module_DjiC610620[index].Value_motor_RealAngle -module->Value_module_DjiC610620[index].Value_motor_LastAngle > 4096)module->Value_module_DjiC610620[index].Value_motor_AngleCnt --;else if (module->Value_module_DjiC610620[index].Value_motor_RealAngle -module->Value_module_DjiC610620[index].Value_motor_LastAngle < -4096)module->Value_module_DjiC610620[index].Value_motor_AngleCnt ++;module->Value_module_DjiC610620[index].Value_motor_LastAngle =module->Value_module_DjiC610620[index].Value_motor_RealAngle;module->Value_module_DjiC610620[index].Value_motor_TotalAngle =( module->Value_module_DjiC610620[index].Value_motor_AngleCnt * 8192 +module->Value_module_DjiC610620[index].Value_motor_RealAngle)*360/8191;}else if(module->Value_module_DjiC610620[index].ENCODER == ROTARYENCODER){/* Not use DjiC610/C620 it self encoder but use extra rotary encoder*///"module->Value_module_DjiC610620[index].Value_motor_TotalAngle" get from the out side}/* Update PID output */module->Value_module_DjiC610620[index].PID_Angle.Method_Update(&(module->Value_module_DjiC610620[index].PID_Angle),module->Value_module_DjiC610620[index].Value_motor_AimAngle,module->Value_module_DjiC610620[index].Value_motor_TotalAngle);module->Value_module_DjiC610620[index].Value_motor_AimRPM =module->Value_module_DjiC610620[index].PID_Angle.Value_output;module->Value_module_DjiC610620[index].PID_Speed.Method_Update(&(module->Value_module_DjiC610620[index].PID_Speed),module->Value_module_DjiC610620[index].Value_motor_AimRPM,module->Value_module_DjiC610620[index].Value_motor_RealRPM);}}/************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/
Math_PID.h
/** Copyright (c) 2020 - ~, HIT_HERO Team** PID MATH MODULE HEAD FILE* Used in RT-Thread Operate System** Change Logs:* Date Author Notes Mail* 2020-08-05 WangXi first version WangXi_chn@foxmail.com*/#include <rtthread.h>#include <rtdevice.h>#include <board.h>#ifndef _MATH_PID_H_#define _MATH_PID_H_struct _MATH_PID{/* Property */float Property_Kp;float Property_Ki;float Property_Kd;float Property_dt;float Property_integralMax;float Property_integralErrMax;float Property_AimMax;float Property_OutputMax;/* Value */float Value_Aim;float Value_Actual;float Value_err;float Value_err_last;float Value_integral;float Value_output;/* Method */void (*Method_Init)(struct _MATH_PID *module);void (*Method_Update)(struct _MATH_PID *module,float Aim, float Feedback);};typedef struct _MATH_PID MATH_PID;rt_err_t Module_PID_Config(MATH_PID *module);#endif/************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/
Math_PID.c
/** Copyright (c) 2020 - ~, HIT_HERO Team** PID MATH MODULE SOUCE FILE* Used in RT-Thread Operate System** Change Logs:* Date Author Notes Mail* 2020-08-05 WangXi first version WangXi_chn@foxmail.com*/#include "Math_PID.h"#include <math.h>static void Module_PIDInit(MATH_PID *module);static void Module_PIDUpdate(MATH_PID *module,float Aim, float Feedback);/* Global Method */rt_err_t Module_PID_Config(MATH_PID *module){if( module->Method_Init ==NULL &&module->Method_Update ==NULL){/* Link the Method */module->Method_Init = Module_PIDInit;module->Method_Update = Module_PIDUpdate;}else{rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");return RT_ERROR;}/* Device Init */module->Method_Init(module);return RT_EOK;}static void Module_PIDInit(MATH_PID *module){module->Value_Actual = 0;module->Value_Aim = 0;module->Value_err = 0;module->Value_err_last = 0;module->Value_integral = 0;module->Value_output = 0;}static void Module_PIDUpdate(MATH_PID *module,float Aim, float Feedback){float P,I,D;module->Value_Aim = Aim;module->Value_Actual = Feedback;/* Culculate P */if(module->Value_Aim > module->Property_AimMax)module->Value_Aim = module->Property_AimMax;else if(module->Value_Aim < -module->Property_AimMax)module->Value_Aim = -module->Property_AimMax;module->Value_err = module->Value_Aim - module->Value_Actual;P = module->Value_err * module->Property_Kp;/* Culculate I */if(fabs(module->Value_err) < module->Property_integralErrMax){module->Value_integral += module->Value_err * module->Property_Ki * module->Property_dt;if(module->Value_integral > module->Property_integralMax)module->Value_integral = module->Property_integralMax;else if(module->Value_integral < -module->Property_integralMax)module->Value_integral = -module->Property_integralMax;I = module->Value_integral;}/* Culculate D */D = module->Property_Kd * (module->Value_err - module->Value_err_last) / module->Property_dt;/* Culculate Output */module->Value_output = P + I + D;if(module->Value_output > module->Property_OutputMax)module->Value_output = module->Property_OutputMax;else if(module->Value_output < -module->Property_OutputMax)module->Value_output = -module->Property_OutputMax;}/************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/
使用
/** Copyright (c) 2020 - ~, HIT_HERO Team** MAIN SOUCE FILE* Used in RT-Thread Operate System** Change Logs:* Date Author Notes Mail* 2020-08-08 WangXi first version WangXi_chn@foxmail.com* 2020-08-13 WangXi second version WangXi_chn@foxmail.com** Note:* Used for friction gear shot Rugby**/#include <rtthread.h>#include <rtdevice.h>#include <board.h>#include "Module_LED.h"#include "Module_Beep.h"#include "Module_Key.h"#include "Module_DjiC610620Group.h"/* Module param list ---------------------------------------------------------------------------------------- */MODULE_LED dev_led_state ={.pin = GET_PIN(H, 10),.LED_TIME_CYCLE = 4000,.LED_TIME_OUTPUT = 200};MODULE_DjiC610620GROUP dev_DjiC610620group ={.Property_CanDevName = "can1",.Value_module_DjiC610620[DjiC610620ID_1] ={.Enable = 1,.Mode = DjiC610620MODE_SPEED,.ENCODER = DjiC610620SELF,.PID_Speed ={.Property_Kp = 6, .Property_Ki = 2, .Property_Kd = 0, .Property_dt = 0.005,.Property_integralMax = 500, .Property_AimMax = 9000, .Property_OutputMax =16300,.Property_integralErrMax = 500,}},.Value_module_DjiC610620[DjiC610620ID_2] ={.Enable = 1,.Mode = DjiC610620MODE_SPEED,.ENCODER = DjiC610620SELF,.PID_Speed ={.Property_Kp = 6, .Property_Ki = 2, .Property_Kd = 0, .Property_dt = 0.005,.Property_integralMax = 500, .Property_AimMax = 9000, .Property_OutputMax =16300,.Property_integralErrMax = 500,}},.Value_module_DjiC610620[DjiC610620ID_3] ={.Enable = 1,.Mode = DjiC610620MODE_ANGLE,.ENCODER = ROTARYENCODER,.Encoder_DevName = "pulse1",.PID_Speed ={.Property_Kp = 6, .Property_Ki = 1, .Property_Kd = 0, .Property_dt = 0.005,.Property_integralMax = 2000, .Property_AimMax = 9000, .Property_OutputMax =16300,.Property_integralErrMax = 1000,},.PID_Angle ={.Property_Kp = 3, .Property_Ki = 0.5, .Property_Kd = 0, .Property_dt = 0.005,.Property_integralMax = 2000, .Property_AimMax = 60000, .Property_OutputMax =1000,.Property_integralErrMax = 10000,},},};/* thread entry list ---------------------------------------------------------------------------------------- */static void led_shine_entry(void *parameter){while (1){rt_thread_mdelay(1);dev_led_state.Handle(&dev_led_state);}}static void motor_entry(void *parameter){while (1){/* Communicate with motor group */dev_DjiC610620group.Method_Feed(&dev_DjiC610620group);rt_thread_mdelay(1);//dev_DjiC610620group.Method_Send(&dev_DjiC610620group);}}int main(void){/* Config module ---------------------------------------------------------------------------------------- */Module_Led_Config(&dev_led_state);dev_led_state.Set(&dev_led_state,9);Module_DjiC610620Group_Config(&dev_DjiC610620group);/* Enable task thread ---------------------------------------------------------------------------------------- *//* system running shine led thread */rt_thread_t led_thread = rt_thread_create("ledshine", led_shine_entry, RT_NULL,512, RT_THREAD_PRIORITY_MAX - 3, 20);if (led_thread != RT_NULL){rt_thread_startup(led_thread);}/* motor control thread */rt_thread_t motor_thread = rt_thread_create("motor", motor_entry, RT_NULL,1024, RT_THREAD_PRIORITY_MAX - 6, 20);if (motor_thread != RT_NULL){rt_thread_startup(motor_thread);}}/************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/
