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;

  1. MATH_PID PID_Speed;
  2. MATH_PID PID_Angle;
  3. /* Value */
  4. rt_int16_t Value_motor_AimCurrent;
  5. rt_int16_t Value_motor_AimRPM;
  6. rt_int16_t Value_motor_AimAngle;
  7. rt_int16_t Value_motor_RealCurrent;
  8. rt_int16_t Value_motor_RealRPM;
  9. rt_int16_t Value_motor_RealAngle;
  10. rt_uint8_t Value_motor_Temperature;
  11. rt_int8_t Value_motor_InitFlag;
  12. rt_int16_t Value_motor_OffsetAngle;
  13. rt_int16_t Value_motor_LastAngle;
  14. rt_int32_t Value_motor_TotalAngle; /* after the conversion (°) */
  15. rt_int16_t Value_motor_AngleCnt;
  16. /* Method */
  17. 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];

  1. /* Value */
  2. struct rt_can_msg Value_can_msgLow;
  3. struct rt_can_msg Value_can_msgHigh;
  4. struct rt_can_msg Value_can_mrg;
  5. rt_device_t Value_can_dev;
  6. rt_uint8_t Value_motorUsedMask;
  7. /* Method */
  8. void (*Method_Init) (struct _MODULE_DjiC610620GROUP *module);
  9. void (*Method_Send) (struct _MODULE_DjiC610620GROUP *module);
  10. void (*Method_Feed) (struct _MODULE_DjiC610620GROUP *module);
  11. 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**/

  1. <a name="bYc1E"></a>
  2. ## Module_DjiC610620Group.c
  3. ```c
  4. /*
  5. * Copyright (c) 2020 - ~, HIT_HERO Team
  6. *
  7. * 2508MOTOR_CAN MODULE SOUCE FILE
  8. * Used in RT-Thread Operate System
  9. *
  10. * Change Logs:
  11. * Date Author Notes Mail
  12. * 2020-08-08 WangXi first version WangXi_chn@foxmail.com
  13. *
  14. * Note:
  15. * DJI 3508 motor and C620 motor controler driver and control framework
  16. * All paramemters shall be subject to the motor rotor control
  17. * And the parameters of the shaft shall be converted by yourself if needed
  18. * The positive direction is clockwise facing the rotor
  19. */
  20. #include "Module_DjiC610620Group.h"
  21. /* User Code Begin*/
  22. /* User Code End */
  23. /* Static Method */
  24. static void Module_DjiC610620GroupInit(MODULE_DjiC610620GROUP *module);
  25. static void Module_DjiC610620GroupSend(MODULE_DjiC610620GROUP *module);
  26. static void Module_DjiC610620GroupFeed(MODULE_DjiC610620GROUP *module);
  27. static rt_err_t Module_DjiC610620GroupHandle(rt_device_t dev, rt_size_t size);
  28. static rt_err_t Module_DjiC610620_Config(MODULE_DjiC610620 *Dev_DjiC610620);
  29. static void Module_DjiC610620Init(MODULE_DjiC610620 *module);
  30. static struct rt_semaphore can3508Motor_sem;
  31. /* Global Method */
  32. rt_err_t Module_DjiC610620Group_Config(MODULE_DjiC610620GROUP *Dev_DjiC610620Group)
  33. {
  34. if( Dev_DjiC610620Group->Method_Init ==NULL &&
  35. Dev_DjiC610620Group->Method_Feed ==NULL &&
  36. Dev_DjiC610620Group->Method_Send ==NULL &&
  37. Dev_DjiC610620Group->Method_Handle ==NULL
  38. ){
  39. /* Link the Method */
  40. Dev_DjiC610620Group->Method_Init = Module_DjiC610620GroupInit;
  41. Dev_DjiC610620Group->Method_Feed = Module_DjiC610620GroupFeed;
  42. Dev_DjiC610620Group->Method_Send = Module_DjiC610620GroupSend;
  43. Dev_DjiC610620Group->Method_Handle = Module_DjiC610620GroupHandle;
  44. }
  45. else{
  46. rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");
  47. return RT_ERROR;
  48. }
  49. /* Device Init */
  50. Dev_DjiC610620Group->Method_Init(Dev_DjiC610620Group);
  51. /* Motor Config */
  52. for(int i=0;i<8;i++)
  53. {
  54. if(Dev_DjiC610620Group->Value_module_DjiC610620[i].Enable != 0)
  55. {
  56. Dev_DjiC610620Group->Value_motorUsedMask |= 0x01<<i;
  57. Module_DjiC610620_Config(&(Dev_DjiC610620Group->Value_module_DjiC610620[i]));
  58. }
  59. }
  60. return RT_EOK;
  61. }
  62. static void Module_DjiC610620GroupInit(MODULE_DjiC610620GROUP *module)
  63. {
  64. rt_err_t res;
  65. /* link can devices */
  66. module->Value_can_dev = rt_device_find(module->Property_CanDevName);
  67. if (!module->Value_can_dev)
  68. rt_kprintf("find %s failed!\n", module->Property_CanDevName);
  69. /* init semaphone */
  70. rt_sem_init(&can3508Motor_sem, "can3508Motor_sem", 0, RT_IPC_FLAG_FIFO);
  71. module->Value_can_msgLow.id = 0x200;
  72. module->Value_can_msgLow.ide = RT_CAN_STDID;
  73. module->Value_can_msgLow.rtr = RT_CAN_DTR;
  74. module->Value_can_msgLow.len = 8;
  75. module->Value_can_msgHigh.id = 0x1FF;
  76. module->Value_can_msgHigh.ide = RT_CAN_STDID;
  77. module->Value_can_msgHigh.rtr = RT_CAN_DTR;
  78. module->Value_can_msgHigh.len = 8;
  79. module->Value_can_mrg.hdr = -1;
  80. res = rt_device_open(module->Value_can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
  81. RT_ASSERT(res == RT_EOK);
  82. /* set up can baudrate */
  83. rt_device_control(module->Value_can_dev, RT_CAN_CMD_SET_BAUD, (void *)CAN1MBaud);
  84. /* link call back function */
  85. rt_device_set_rx_indicate(module->Value_can_dev, module->Method_Handle);
  86. }
  87. rt_err_t Module_DjiC610620_Config(MODULE_DjiC610620 *Dev_DjiC610620)
  88. {
  89. if( Dev_DjiC610620->Method_Init ==NULL
  90. ){
  91. /* Link the Method */
  92. Dev_DjiC610620->Method_Init = Module_DjiC610620Init;
  93. }
  94. else{
  95. rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");
  96. return RT_ERROR;
  97. }
  98. /* Device Init */
  99. Dev_DjiC610620->Method_Init(Dev_DjiC610620);
  100. /* Module PID controler Init */
  101. if(Dev_DjiC610620->Mode == DjiC610620MODE_SPEED)
  102. {
  103. Module_PID_Config(&(Dev_DjiC610620->PID_Speed));
  104. }
  105. else if(Dev_DjiC610620->Mode == DjiC610620MODE_ANGLE)
  106. {
  107. Module_PID_Config(&(Dev_DjiC610620->PID_Speed));
  108. Module_PID_Config(&(Dev_DjiC610620->PID_Angle));
  109. }
  110. return RT_EOK;
  111. }
  112. /* Static Method */
  113. static void Module_DjiC610620Init(MODULE_DjiC610620 *module)
  114. {
  115. module->Value_motor_AimAngle = 0;
  116. module->Value_motor_AimCurrent = 0;
  117. module->Value_motor_AimRPM = 0;
  118. if(module->ENCODER == ROTARYENCODER)
  119. {
  120. module->Encoder_dev = rt_device_find(module->Encoder_DevName);
  121. if (module->Encoder_dev == RT_NULL){
  122. rt_kprintf("pulse encoder sample run failed! can't find %s device!\n", module->Encoder_DevName);
  123. return;
  124. }
  125. rt_err_t ret = rt_device_open(module->Encoder_dev, RT_DEVICE_OFLAG_RDONLY);
  126. if (ret != RT_EOK){
  127. rt_kprintf("open %s device failed!\n", module->Encoder_DevName);
  128. return;
  129. }
  130. rt_pin_mode(GET_PIN(D,12), PIN_MODE_INPUT_PULLUP);
  131. rt_pin_mode(GET_PIN(D,13), PIN_MODE_INPUT_PULLUP);
  132. }
  133. }
  134. static void Module_DjiC610620GroupSend(MODULE_DjiC610620GROUP *module)
  135. {
  136. rt_size_t size;
  137. /* Calculate the final current value of motor */
  138. for(int i=0;i<8;i++)
  139. {
  140. if((module->Value_motorUsedMask & (0x01<<i))!=0x00)
  141. {
  142. module->Value_module_DjiC610620[i].Value_motor_AimCurrent =
  143. module->Value_module_DjiC610620[i].PID_Speed.Value_output;
  144. }
  145. }
  146. /* make up the all can fram */
  147. if((module->Value_motorUsedMask & 0x0F) != 0)
  148. {
  149. for(int i=1;i<=4;i++)
  150. {
  151. module->Value_can_msgLow.data[i*2-1] = module->Value_module_DjiC610620[i-1].Value_motor_AimCurrent & 0xFF;
  152. module->Value_can_msgLow.data[i*2-2] = module->Value_module_DjiC610620[i-1].Value_motor_AimCurrent >> 8;
  153. }
  154. size = rt_device_write(module->Value_can_dev, 0, &(module->Value_can_msgLow), sizeof(module->Value_can_msgLow));
  155. if (size == 0)
  156. rt_kprintf("can dev write data failed!\n");
  157. size = 0;
  158. }
  159. rt_thread_mdelay(1);
  160. if((module->Value_motorUsedMask & 0xF0) != 0)
  161. {
  162. for(int i=5;i<=8;i++)
  163. {
  164. module->Value_can_msgHigh.data[i*2-9] = module->Value_module_DjiC610620[i-1].Value_motor_AimCurrent & 0xFF;
  165. module->Value_can_msgHigh.data[i*2-10] = module->Value_module_DjiC610620[i-1].Value_motor_AimCurrent >> 8;
  166. }
  167. size = rt_device_write(module->Value_can_dev, 0, &(module->Value_can_msgHigh), sizeof(module->Value_can_msgHigh));
  168. if (size == 0)
  169. rt_kprintf("can dev write data failed!\n");
  170. size = 0;
  171. }
  172. }
  173. static rt_err_t Module_DjiC610620GroupHandle(rt_device_t dev, rt_size_t size)
  174. {
  175. rt_sem_release(&can3508Motor_sem);
  176. return RT_EOK;
  177. }
  178. static void Module_DjiC610620GroupFeed(MODULE_DjiC610620GROUP *module)
  179. {
  180. rt_sem_take(&can3508Motor_sem, RT_WAITING_FOREVER);
  181. /* Get true value of the motor */
  182. rt_uint8_t index = 1;
  183. rt_device_read(module->Value_can_dev, 0, &(module->Value_can_mrg), sizeof(module->Value_can_mrg));
  184. index = (module->Value_can_mrg.id & 0x00F) - 1;
  185. module->Value_module_DjiC610620[index].Value_motor_RealAngle =
  186. ((module->Value_can_mrg.data[0]<<8) | module->Value_can_mrg.data[1]);
  187. module->Value_module_DjiC610620[index].Value_motor_RealRPM =
  188. ((module->Value_can_mrg.data[2]<<8) | module->Value_can_mrg.data[3]);
  189. module->Value_module_DjiC610620[index].Value_motor_RealCurrent =
  190. ((module->Value_can_mrg.data[4]<<8) | module->Value_can_mrg.data[5]);
  191. module->Value_module_DjiC610620[index].Value_motor_Temperature =
  192. module->Value_can_mrg.data[6];
  193. /* Get the offset angle */
  194. if(module->Value_module_DjiC610620[index].Value_motor_InitFlag == 0)
  195. {
  196. module->Value_module_DjiC610620[index].Value_motor_OffsetAngle =
  197. module->Value_module_DjiC610620[index].Value_motor_RealAngle;
  198. module->Value_module_DjiC610620[index].Value_motor_InitFlag = 1;
  199. return;
  200. }
  201. if(module->Value_module_DjiC610620[index].Mode == DjiC610620MODE_SPEED)
  202. {
  203. /* Update PID output */
  204. module->Value_module_DjiC610620[index].PID_Speed.Method_Update(
  205. &(module->Value_module_DjiC610620[index].PID_Speed),
  206. module->Value_module_DjiC610620[index].Value_motor_AimRPM,
  207. module->Value_module_DjiC610620[index].Value_motor_RealRPM);
  208. }
  209. else if(module->Value_module_DjiC610620[index].Mode == DjiC610620MODE_ANGLE)
  210. {
  211. /* Deal with the data of motor's angle */
  212. if(module->Value_module_DjiC610620[index].ENCODER == DjiC610620SELF)
  213. {
  214. /* Use DjiC610/C620 it self encoder */
  215. module->Value_module_DjiC610620[index].Value_motor_RealAngle -=
  216. module->Value_module_DjiC610620[index].Value_motor_OffsetAngle;
  217. if(module->Value_module_DjiC610620[index].Value_motor_RealAngle -
  218. module->Value_module_DjiC610620[index].Value_motor_LastAngle > 4096)
  219. module->Value_module_DjiC610620[index].Value_motor_AngleCnt --;
  220. else if (module->Value_module_DjiC610620[index].Value_motor_RealAngle -
  221. module->Value_module_DjiC610620[index].Value_motor_LastAngle < -4096)
  222. module->Value_module_DjiC610620[index].Value_motor_AngleCnt ++;
  223. module->Value_module_DjiC610620[index].Value_motor_LastAngle =
  224. module->Value_module_DjiC610620[index].Value_motor_RealAngle;
  225. module->Value_module_DjiC610620[index].Value_motor_TotalAngle =
  226. ( module->Value_module_DjiC610620[index].Value_motor_AngleCnt * 8192 +
  227. module->Value_module_DjiC610620[index].Value_motor_RealAngle)*360/8191;
  228. }
  229. else if(module->Value_module_DjiC610620[index].ENCODER == ROTARYENCODER)
  230. {
  231. /* Not use DjiC610/C620 it self encoder but use extra rotary encoder*/
  232. //"module->Value_module_DjiC610620[index].Value_motor_TotalAngle" get from the out side
  233. }
  234. /* Update PID output */
  235. module->Value_module_DjiC610620[index].PID_Angle.Method_Update(
  236. &(module->Value_module_DjiC610620[index].PID_Angle),
  237. module->Value_module_DjiC610620[index].Value_motor_AimAngle,
  238. module->Value_module_DjiC610620[index].Value_motor_TotalAngle);
  239. module->Value_module_DjiC610620[index].Value_motor_AimRPM =
  240. module->Value_module_DjiC610620[index].PID_Angle.Value_output;
  241. module->Value_module_DjiC610620[index].PID_Speed.Method_Update(
  242. &(module->Value_module_DjiC610620[index].PID_Speed),
  243. module->Value_module_DjiC610620[index].Value_motor_AimRPM,
  244. module->Value_module_DjiC610620[index].Value_motor_RealRPM);
  245. }
  246. }
  247. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/

Math_PID.h

  1. /*
  2. * Copyright (c) 2020 - ~, HIT_HERO Team
  3. *
  4. * PID MATH MODULE HEAD FILE
  5. * Used in RT-Thread Operate System
  6. *
  7. * Change Logs:
  8. * Date Author Notes Mail
  9. * 2020-08-05 WangXi first version WangXi_chn@foxmail.com
  10. */
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include <board.h>
  14. #ifndef _MATH_PID_H_
  15. #define _MATH_PID_H_
  16. struct _MATH_PID
  17. {
  18. /* Property */
  19. float Property_Kp;
  20. float Property_Ki;
  21. float Property_Kd;
  22. float Property_dt;
  23. float Property_integralMax;
  24. float Property_integralErrMax;
  25. float Property_AimMax;
  26. float Property_OutputMax;
  27. /* Value */
  28. float Value_Aim;
  29. float Value_Actual;
  30. float Value_err;
  31. float Value_err_last;
  32. float Value_integral;
  33. float Value_output;
  34. /* Method */
  35. void (*Method_Init)(struct _MATH_PID *module);
  36. void (*Method_Update)(struct _MATH_PID *module,float Aim, float Feedback);
  37. };
  38. typedef struct _MATH_PID MATH_PID;
  39. rt_err_t Module_PID_Config(MATH_PID *module);
  40. #endif
  41. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/

Math_PID.c

  1. /*
  2. * Copyright (c) 2020 - ~, HIT_HERO Team
  3. *
  4. * PID MATH MODULE SOUCE FILE
  5. * Used in RT-Thread Operate System
  6. *
  7. * Change Logs:
  8. * Date Author Notes Mail
  9. * 2020-08-05 WangXi first version WangXi_chn@foxmail.com
  10. */
  11. #include "Math_PID.h"
  12. #include <math.h>
  13. static void Module_PIDInit(MATH_PID *module);
  14. static void Module_PIDUpdate(MATH_PID *module,float Aim, float Feedback);
  15. /* Global Method */
  16. rt_err_t Module_PID_Config(MATH_PID *module)
  17. {
  18. if( module->Method_Init ==NULL &&
  19. module->Method_Update ==NULL
  20. ){
  21. /* Link the Method */
  22. module->Method_Init = Module_PIDInit;
  23. module->Method_Update = Module_PIDUpdate;
  24. }
  25. else{
  26. rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");
  27. return RT_ERROR;
  28. }
  29. /* Device Init */
  30. module->Method_Init(module);
  31. return RT_EOK;
  32. }
  33. static void Module_PIDInit(MATH_PID *module)
  34. {
  35. module->Value_Actual = 0;
  36. module->Value_Aim = 0;
  37. module->Value_err = 0;
  38. module->Value_err_last = 0;
  39. module->Value_integral = 0;
  40. module->Value_output = 0;
  41. }
  42. static void Module_PIDUpdate(MATH_PID *module,float Aim, float Feedback)
  43. {
  44. float P,I,D;
  45. module->Value_Aim = Aim;
  46. module->Value_Actual = Feedback;
  47. /* Culculate P */
  48. if(module->Value_Aim > module->Property_AimMax)
  49. module->Value_Aim = module->Property_AimMax;
  50. else if(module->Value_Aim < -module->Property_AimMax)
  51. module->Value_Aim = -module->Property_AimMax;
  52. module->Value_err = module->Value_Aim - module->Value_Actual;
  53. P = module->Value_err * module->Property_Kp;
  54. /* Culculate I */
  55. if(fabs(module->Value_err) < module->Property_integralErrMax)
  56. {
  57. module->Value_integral += module->Value_err * module->Property_Ki * module->Property_dt;
  58. if(module->Value_integral > module->Property_integralMax)
  59. module->Value_integral = module->Property_integralMax;
  60. else if(module->Value_integral < -module->Property_integralMax)
  61. module->Value_integral = -module->Property_integralMax;
  62. I = module->Value_integral;
  63. }
  64. /* Culculate D */
  65. D = module->Property_Kd * (module->Value_err - module->Value_err_last) / module->Property_dt;
  66. /* Culculate Output */
  67. module->Value_output = P + I + D;
  68. if(module->Value_output > module->Property_OutputMax)
  69. module->Value_output = module->Property_OutputMax;
  70. else if(module->Value_output < -module->Property_OutputMax)
  71. module->Value_output = -module->Property_OutputMax;
  72. }
  73. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/

使用

  1. /*
  2. * Copyright (c) 2020 - ~, HIT_HERO Team
  3. *
  4. * MAIN SOUCE FILE
  5. * Used in RT-Thread Operate System
  6. *
  7. * Change Logs:
  8. * Date Author Notes Mail
  9. * 2020-08-08 WangXi first version WangXi_chn@foxmail.com
  10. * 2020-08-13 WangXi second version WangXi_chn@foxmail.com
  11. *
  12. * Note:
  13. * Used for friction gear shot Rugby
  14. *
  15. */
  16. #include <rtthread.h>
  17. #include <rtdevice.h>
  18. #include <board.h>
  19. #include "Module_LED.h"
  20. #include "Module_Beep.h"
  21. #include "Module_Key.h"
  22. #include "Module_DjiC610620Group.h"
  23. /* Module param list ---------------------------------------------------------------------------------------- */
  24. MODULE_LED dev_led_state =
  25. {
  26. .pin = GET_PIN(H, 10),
  27. .LED_TIME_CYCLE = 4000,
  28. .LED_TIME_OUTPUT = 200
  29. };
  30. MODULE_DjiC610620GROUP dev_DjiC610620group =
  31. {
  32. .Property_CanDevName = "can1",
  33. .Value_module_DjiC610620[DjiC610620ID_1] =
  34. {
  35. .Enable = 1,
  36. .Mode = DjiC610620MODE_SPEED,
  37. .ENCODER = DjiC610620SELF,
  38. .PID_Speed =
  39. {
  40. .Property_Kp = 6, .Property_Ki = 2, .Property_Kd = 0, .Property_dt = 0.005,
  41. .Property_integralMax = 500, .Property_AimMax = 9000, .Property_OutputMax =16300,
  42. .Property_integralErrMax = 500,
  43. }
  44. },
  45. .Value_module_DjiC610620[DjiC610620ID_2] =
  46. {
  47. .Enable = 1,
  48. .Mode = DjiC610620MODE_SPEED,
  49. .ENCODER = DjiC610620SELF,
  50. .PID_Speed =
  51. {
  52. .Property_Kp = 6, .Property_Ki = 2, .Property_Kd = 0, .Property_dt = 0.005,
  53. .Property_integralMax = 500, .Property_AimMax = 9000, .Property_OutputMax =16300,
  54. .Property_integralErrMax = 500,
  55. }
  56. },
  57. .Value_module_DjiC610620[DjiC610620ID_3] =
  58. {
  59. .Enable = 1,
  60. .Mode = DjiC610620MODE_ANGLE,
  61. .ENCODER = ROTARYENCODER,
  62. .Encoder_DevName = "pulse1",
  63. .PID_Speed =
  64. {
  65. .Property_Kp = 6, .Property_Ki = 1, .Property_Kd = 0, .Property_dt = 0.005,
  66. .Property_integralMax = 2000, .Property_AimMax = 9000, .Property_OutputMax =16300,
  67. .Property_integralErrMax = 1000,
  68. },
  69. .PID_Angle =
  70. {
  71. .Property_Kp = 3, .Property_Ki = 0.5, .Property_Kd = 0, .Property_dt = 0.005,
  72. .Property_integralMax = 2000, .Property_AimMax = 60000, .Property_OutputMax =1000,
  73. .Property_integralErrMax = 10000,
  74. },
  75. },
  76. };
  77. /* thread entry list ---------------------------------------------------------------------------------------- */
  78. static void led_shine_entry(void *parameter)
  79. {
  80. while (1)
  81. {
  82. rt_thread_mdelay(1);
  83. dev_led_state.Handle(&dev_led_state);
  84. }
  85. }
  86. static void motor_entry(void *parameter)
  87. {
  88. while (1)
  89. {
  90. /* Communicate with motor group */
  91. dev_DjiC610620group.Method_Feed(&dev_DjiC610620group);
  92. rt_thread_mdelay(1);
  93. //dev_DjiC610620group.Method_Send(&dev_DjiC610620group);
  94. }
  95. }
  96. int main(void)
  97. {
  98. /* Config module ---------------------------------------------------------------------------------------- */
  99. Module_Led_Config(&dev_led_state);
  100. dev_led_state.Set(&dev_led_state,9);
  101. Module_DjiC610620Group_Config(&dev_DjiC610620group);
  102. /* Enable task thread ---------------------------------------------------------------------------------------- */
  103. /* system running shine led thread */
  104. rt_thread_t led_thread = rt_thread_create("ledshine", led_shine_entry, RT_NULL,
  105. 512, RT_THREAD_PRIORITY_MAX - 3, 20);
  106. if (led_thread != RT_NULL){
  107. rt_thread_startup(led_thread);
  108. }
  109. /* motor control thread */
  110. rt_thread_t motor_thread = rt_thread_create("motor", motor_entry, RT_NULL,
  111. 1024, RT_THREAD_PRIORITY_MAX - 6, 20);
  112. if (motor_thread != RT_NULL){
  113. rt_thread_startup(motor_thread);
  114. }
  115. }
  116. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/

测试结果

  • 可以大大减少驱动压力,仅需关注调节PID参数和控制方式
  • 灵活性强,添加一个电机仅需为结构体成员赋值即可
  • PID控制已验证,逻辑正确

    注意事项

  • 读取电机总转角,实现电机位置控制时,在高速运动情况下,会出现距离(圈数)误差

  • 原因是电机返回的是电机的转子的位置(0~360°)是否转过了一圈需要程序确定
  • 当电机转速较快,(减速齿轮约为19:1)转子位置采样会出现丢圈的可能
  • 建议仅使用3508或2006于速度控制,或较低速的位置控制,或对位置不严格要求的场合
  • 如果需要用3508或2006电机实现精准的位置控制,建议配合编码器使用