Gitee

https://gitee.com/WangXi_Chn/RttOs_ModuleLib

开发环境

CubeMX
MDK5 IDE
STM32F407IGH6TR 芯片
大疆开发板 C型
冯哈伯 3863 直流电机 带减速箱(38:2)
RoboModule直流伺服电机驱动器 RMDS-303
RoboModule电机配置上位机
RT-Thread操作系统
面向对象模块接口设计

硬件条件

  • 需要一根RS232转USB线,电脑上位机配置电调
  • 电机与Robomodule连接正确
  • 单片机通过Can线与Robomodule连接

    配置电机

  • Robomodule内部集成电机控制算法,仅需通过上位机配置电机的PID参数等

  • 单片机仅需根据协议发送指令即可驱动电机

Robomodule配置电机教程
http://www.robomodule.net/download.html

核心思想

  • 同3508电机思路一样,视挂载在同一条Can线上的所有Robomodule电机为一个电机群
  • 根据结构体成员的赋值实现电机使能
  • 因为实际使用中,用到的3863电机不会超过8个,因此注释掉了多余的ID选项(可自行扩展)
  • Can报文协议也遵循最多8电机编写(组号为0,电机号为1~8)(格式参照Robomodule教程)

    Module_RobomoduleGroup.h

    ```c /*
    • Copyright (c) 2020 - ~, HIT_HERO Team *
    • ROBOMODULE MODULE HEAD FILE
    • Used in RT-Thread Operate System *
    • Change Logs:
    • Date Author Notes Mail
    • 2020-08-22 WangXi first version WangXi_chn@foxmail.com
    • Note:
    • */

include

include

include

enum ROBOMODULE_GROUPID { ROBOMODULE_GROUPID_0 = 0, // ROBOMODULE_GROUPID_1 = 1, // ROBOMODULE_GROUPID_2 = 2, // ROBOMODULE_GROUPID_3 = 3, // ROBOMODULE_GROUPID_4 = 4, // ROBOMODULE_GROUPID_5 = 5, // ROBOMODULE_GROUPID_6 = 6, // ROBOMODULE_GROUPID_7 = 7, };

enum ROBOMODULE_NUMID { ROBOMODULE_NUMID_1 = 0, ROBOMODULE_NUMID_2 = 1, ROBOMODULE_NUMID_3 = 2, ROBOMODULE_NUMID_4 = 3, ROBOMODULE_NUMID_5 = 4, ROBOMODULE_NUMID_6 = 5, ROBOMODULE_NUMID_7 = 6, ROBOMODULE_NUMID_8 = 7, // ROBOMODULE_NUMID_9 = 9, // ROBOMODULE_NUMID_10 = 10, // ROBOMODULE_NUMID_11 = 11, // ROBOMODULE_NUMID_12 = 12, // ROBOMODULE_NUMID_13 = 13, // ROBOMODULE_NUMID_14 = 14, // ROBOMODULE_NUMID_15 = 15, };

enum ROBOMODULE_MODE { ROBOMODULE_MODE_OPENLOOP = 1, ROBOMODULE_MODE_CURRENT = 2, ROBOMODULE_MODE_SPEED = 3, ROBOMODULE_MODE_LOCATION = 4, ROBOMODULE_MODE_SPEEDLOCATION = 5, ROBOMODULE_MODE_CURRENTSPEED = 6, ROBOMODULE_MODE_CURRENLOCATION = 7, ROBOMODULE_MODE_CURRENSPEEDLOCATION = 8, };

/ Single module label —————————————————————————————/ struct _MODULE_ROBOMODULE { / Property / rt_uint8_t Property_Enable; enum ROBOMODULE_GROUPID Property_GroupID; enum ROBOMODULE_NUMID Property_NumID; enum ROBOMODULE_MODE Property_Mode;

  1. /* Value */
  2. rt_device_t Value_can_dev;
  3. struct rt_can_msg Value_can_msg;
  4. struct rt_can_msg Value_can_mrg;
  5. rt_int16_t Value_motor_AimCurrent;
  6. rt_int16_t Value_motor_AimRPM;
  7. rt_int32_t Value_motor_AimAngle;
  8. rt_int16_t Value_motor_RealCurrent;
  9. rt_int16_t Value_motor_RealRPM;
  10. rt_int32_t Value_motor_RealAngle;
  11. /* Method */
  12. void (*Method_Init)(struct _MODULE_ROBOMODULE *module);

}; typedef struct _MODULE_ROBOMODULE MODULE_ROBOMODULE;

/ Motor group label —————————————————————————————/ struct _MODULE_ROBOMODULEGROUP { / Property / char * Property_CanDevName;

  1. /* Value */
  2. MODULE_ROBOMODULE Value_robomodule[8];
  3. rt_device_t Value_can_dev;
  4. struct rt_can_msg Value_can_msg;
  5. struct rt_can_msg Value_can_mrg;
  6. rt_uint8_t Value_moduleUsedMask;
  7. /* Method */
  8. void (*Method_Init) (struct _MODULE_ROBOMODULEGROUP *module);
  9. void (*Method_Send) (struct _MODULE_ROBOMODULEGROUP *module);
  10. void (*Method_Feed) (struct _MODULE_ROBOMODULEGROUP *module);
  11. rt_err_t (*Method_Handle) (rt_device_t dev,rt_size_t size);

}; typedef struct _MODULE_ROBOMODULEGROUP MODULE_ROBOMODULEGROUP;

/ Glodal Method / rt_err_t Module_RobomoduleGroup_Config(MODULE_ROBOMODULEGROUP *module);

  1. <a name="nlcHm"></a>
  2. ## Module_RobomoduleGroup.c
  3. ```c
  4. /*
  5. * Copyright (c) 2020 - ~, HIT_HERO Team
  6. *
  7. * ROBOMODULE MODULE SOUCE FILE
  8. * Used in RT-Thread Operate System
  9. *
  10. * Change Logs:
  11. * Date Author Notes Mail
  12. * 2020-08-22 WangXi first version WangXi_chn@foxmail.com
  13. *
  14. * Note:
  15. *
  16. */
  17. #include "Module_RobomoduleGroup.h"
  18. /* User Code Begin*/
  19. /* User Code End */
  20. /* Static Method */
  21. static void Module_RobomoduleGroupInit(MODULE_ROBOMODULEGROUP *module);
  22. static void Module_RobomoduleGroupSend(MODULE_ROBOMODULEGROUP *module);
  23. static void Module_RobomoduleGroupFeed(MODULE_ROBOMODULEGROUP *module);
  24. static rt_err_t Module_RobomoduleGroupHandle(rt_device_t dev, rt_size_t size);
  25. static rt_err_t Module_Robomodule_Config(MODULE_ROBOMODULE *module);
  26. static void Module_RobomoduleInit(MODULE_ROBOMODULE *module);
  27. static struct rt_semaphore canRobomodule_sem;
  28. /* Global Method */
  29. rt_err_t Module_RobomoduleGroup_Config(MODULE_ROBOMODULEGROUP *module)
  30. {
  31. if( module->Method_Init ==NULL &&
  32. module->Method_Feed ==NULL &&
  33. module->Method_Send ==NULL &&
  34. module->Method_Handle ==NULL
  35. ){
  36. /* Link the Method */
  37. module->Method_Init = Module_RobomoduleGroupInit;
  38. module->Method_Feed = Module_RobomoduleGroupFeed;
  39. module->Method_Send = Module_RobomoduleGroupSend;
  40. module->Method_Handle = Module_RobomoduleGroupHandle;
  41. }
  42. else{
  43. rt_kprintf("Warning: Module Robomodule is Configed twice\n");
  44. return RT_ERROR;
  45. }
  46. /* Device Init */
  47. module->Method_Init(module);
  48. /* Motor Config */
  49. for(int i=0;i<8;i++)
  50. {
  51. if(module->Value_robomodule[i].Property_Enable!= 0)
  52. {
  53. module->Value_moduleUsedMask |= 0x01<<i;
  54. module->Value_robomodule[i].Value_can_dev = module->Value_can_dev;
  55. Module_Robomodule_Config(&(module->Value_robomodule[i]));
  56. }
  57. }
  58. return RT_EOK;
  59. }
  60. static void Module_RobomoduleGroupInit(MODULE_ROBOMODULEGROUP *module)
  61. {
  62. rt_err_t res;
  63. /* link can devices */
  64. module->Value_can_dev = rt_device_find(module->Property_CanDevName);
  65. if (!module->Value_can_dev)
  66. rt_kprintf("find %s failed!\n", module->Property_CanDevName);
  67. /* init semaphone */
  68. rt_sem_init(&canRobomodule_sem, "canRobomodule_sem", 0, RT_IPC_FLAG_FIFO);
  69. res = rt_device_open(module->Value_can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
  70. RT_ASSERT(res == RT_EOK);
  71. /* set up can baudrate */
  72. rt_device_control(module->Value_can_dev, RT_CAN_CMD_SET_BAUD, (void *)CAN1MBaud);
  73. /* link call back function */
  74. rt_device_set_rx_indicate(module->Value_can_dev, module->Method_Handle);
  75. }
  76. rt_err_t Module_Robomodule_Config(MODULE_ROBOMODULE *module)
  77. {
  78. if( module->Method_Init ==NULL
  79. ){
  80. /* Link the Method */
  81. module->Method_Init = Module_RobomoduleInit;
  82. }
  83. else{
  84. rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");
  85. return RT_ERROR;
  86. }
  87. /* Device Init */
  88. module->Method_Init(module);
  89. return RT_EOK;
  90. }
  91. /* Static Method */
  92. static void Module_RobomoduleInit(MODULE_ROBOMODULE *module)
  93. {
  94. /* Reset the motor */
  95. module->Value_can_msg.id = (module->Property_GroupID<<8)|((module->Property_NumID+1)<<4);
  96. module->Value_can_msg.id += 0x000;
  97. module->Value_can_msg.ide = RT_CAN_STDID;
  98. module->Value_can_msg.rtr = RT_CAN_DTR;
  99. module->Value_can_msg.len = 8;
  100. for(int i=0;i<8;i++)
  101. module->Value_can_msg.data[i]=0x55;
  102. rt_size_t size = rt_device_write(module->Value_can_dev, 0, &(module->Value_can_msg), sizeof(module->Value_can_msg));
  103. if (size == 0)
  104. rt_kprintf("can dev write data failed!\n");
  105. rt_thread_mdelay(500);
  106. /* Set the motor mode*/
  107. module->Value_can_msg.id = (module->Property_GroupID<<8)|((module->Property_NumID+1)<<4);
  108. module->Value_can_msg.id += 0x001;
  109. module->Value_can_msg.ide = RT_CAN_STDID;
  110. module->Value_can_msg.rtr = RT_CAN_DTR;
  111. module->Value_can_msg.len = 8;
  112. module->Value_can_msg.data[0]=module->Property_Mode;
  113. for(int i=1;i<8;i++)
  114. module->Value_can_msg.data[i]=0x55;
  115. size = rt_device_write(module->Value_can_dev, 0, &(module->Value_can_msg), sizeof(module->Value_can_msg));
  116. if (size == 0)
  117. rt_kprintf("can dev write data failed!\n");
  118. rt_thread_mdelay(500);
  119. module->Value_motor_AimAngle = 0;
  120. module->Value_motor_AimCurrent = 0;
  121. module->Value_motor_AimRPM = 0;
  122. }
  123. static void Module_RobomoduleGroupSend(MODULE_ROBOMODULEGROUP *module)
  124. {
  125. rt_size_t size;
  126. /* Send motor data */
  127. for(int i=0;i<8;i++)
  128. {
  129. if((module->Value_moduleUsedMask & (0x01<<i))!=0x00)
  130. {
  131. switch(module->Value_robomodule[i].Property_Mode)
  132. {
  133. case ROBOMODULE_MODE_OPENLOOP:
  134. break;
  135. case ROBOMODULE_MODE_CURRENT:
  136. break;
  137. case ROBOMODULE_MODE_SPEED:
  138. break;
  139. case ROBOMODULE_MODE_LOCATION:
  140. module->Value_can_msg.id
  141. =(module->Value_robomodule[i].Property_GroupID<<8)
  142. |((module->Value_robomodule[i].Property_NumID+1)<<4);
  143. module->Value_can_msg.id += 0x005;
  144. module->Value_can_msg.ide = RT_CAN_STDID;
  145. module->Value_can_msg.rtr = RT_CAN_DTR;
  146. module->Value_can_msg.len = 8;
  147. module->Value_can_msg.data[0]= (unsigned char)(5000>>8)&0xFF;
  148. module->Value_can_msg.data[1]= (unsigned char)(5000)&0xFF;
  149. module->Value_can_msg.data[2]=0x55;
  150. module->Value_can_msg.data[3]=0x55;
  151. module->Value_can_msg.data[4]=
  152. (unsigned char)((module->Value_robomodule[i].Value_motor_AimAngle>>24)&0xff);
  153. module->Value_can_msg.data[5]=
  154. (unsigned char)((module->Value_robomodule[i].Value_motor_AimAngle>>16)&0xff);
  155. module->Value_can_msg.data[6]=
  156. (unsigned char)((module->Value_robomodule[i].Value_motor_AimAngle>>8)&0xff);
  157. module->Value_can_msg.data[7]=
  158. (unsigned char)(module->Value_robomodule[i].Value_motor_AimAngle&0xff);
  159. size = rt_device_write(module->Value_can_dev, 0,
  160. &(module->Value_can_msg), sizeof(module->Value_can_msg));
  161. if (size == 0)
  162. rt_kprintf("robomodule can dev write data failed!\n");
  163. break;
  164. case ROBOMODULE_MODE_SPEEDLOCATION:
  165. break;
  166. case ROBOMODULE_MODE_CURRENTSPEED:
  167. break;
  168. case ROBOMODULE_MODE_CURRENLOCATION:
  169. break;
  170. case ROBOMODULE_MODE_CURRENSPEEDLOCATION:
  171. break;
  172. }
  173. }
  174. }
  175. }
  176. static rt_err_t Module_RobomoduleGroupHandle(rt_device_t dev, rt_size_t size)
  177. {
  178. rt_sem_release(&canRobomodule_sem);
  179. return RT_EOK;
  180. }
  181. static void Module_RobomoduleGroupFeed(MODULE_ROBOMODULEGROUP *module)
  182. {
  183. rt_sem_take(&canRobomodule_sem, RT_WAITING_FOREVER);
  184. /* Get true value of the motor */
  185. rt_device_read(module->Value_can_dev, 0, &(module->Value_can_mrg), sizeof(module->Value_can_mrg));
  186. }
  187. /************************ (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_BlueToothHC06.h"
  21. #include "Module_RobomoduleGroup.h"
  22. /* Module param list ---------------------------------------------------------------------------------------- */
  23. MODULE_LED dev_led_state =
  24. {
  25. .pin = GET_PIN(H, 10),
  26. .LED_TIME_CYCLE = 4000,
  27. .LED_TIME_OUTPUT = 200
  28. };
  29. MODULE_BLUETOOTHHC06 dev_communicate =
  30. {
  31. .Property_UartDevName = "uart6",
  32. };
  33. MODULE_ROBOMODULEGROUP dev_robomoduleGroup =
  34. {
  35. .Property_CanDevName = "can1",
  36. .Value_robomodule[ROBOMODULE_NUMID_1] =
  37. {
  38. .Property_Enable = 1,
  39. .Property_GroupID = ROBOMODULE_GROUPID_0,
  40. .Property_NumID = ROBOMODULE_NUMID_1,
  41. .Property_Mode = ROBOMODULE_MODE_LOCATION,
  42. },
  43. .Value_robomodule[ROBOMODULE_NUMID_2] =
  44. {
  45. .Property_Enable = 1,
  46. .Property_GroupID = ROBOMODULE_GROUPID_0,
  47. .Property_NumID = ROBOMODULE_NUMID_2,
  48. .Property_Mode = ROBOMODULE_MODE_LOCATION,
  49. },
  50. };
  51. /* thread entry list ---------------------------------------------------------------------------------------- */
  52. static void led_shine_entry(void *parameter)
  53. {
  54. while (1)
  55. {
  56. rt_thread_mdelay(1);
  57. dev_led_state.Handle(&dev_led_state);
  58. }
  59. }
  60. static void motor_entry(void *parameter)
  61. {
  62. while (1)
  63. {
  64. rt_thread_mdelay(1);
  65. dev_robomoduleGroup.Method_Send(&dev_robomoduleGroup);
  66. }
  67. }
  68. static void bluetupdata_entry(void *parameter)
  69. {
  70. dev_communicate.Method_Feed(&dev_communicate);
  71. }
  72. static void bluetcontrol_entry(void *parameter)
  73. {
  74. static rt_uint32_t time_1000m = 0;
  75. while(1)
  76. {
  77. rt_thread_mdelay(1);
  78. time_1000m++;
  79. switch(dev_communicate.Value_keyMask)
  80. {
  81. case (0x0001<<0):
  82. dev_robomoduleGroup.Value_robomodule[ROBOMODULE_NUMID_1].Value_motor_AimAngle= 27500; //360°
  83. dev_robomoduleGroup.Value_robomodule[ROBOMODULE_NUMID_2].Value_motor_AimAngle= -27500;
  84. break;
  85. case (0x0001<<1):
  86. dev_robomoduleGroup.Value_robomodule[ROBOMODULE_NUMID_1].Value_motor_AimAngle=0;
  87. dev_robomoduleGroup.Value_robomodule[ROBOMODULE_NUMID_2].Value_motor_AimAngle=0;
  88. break;
  89. case (0x0001<<2):
  90. break;
  91. case (0x0001<<3):
  92. break;
  93. case (0x0001<<4):
  94. break;
  95. case (0x0001<<5):
  96. break;
  97. case (0x0001<<6):
  98. break;
  99. case (0x0001<<7):
  100. break;
  101. case (0x0001<<8):
  102. break;
  103. case (0x0001<<9):
  104. break;
  105. case (0x0001<<10):
  106. break;
  107. case (0x0001<<11):
  108. break;
  109. }
  110. dev_communicate.Value_keyMask = 0x0000;
  111. if(time_1000m >= 1000)
  112. {
  113. time_1000m = 0;
  114. rt_int16_t temp = dev_robomoduleGroup.Value_robomodule[ROBOMODULE_NUMID_1].Value_motor_AimAngle*360/27500;
  115. dev_communicate.Method_Send(&dev_communicate,PARAM_SHOW_1,
  116. temp);
  117. }
  118. }
  119. }
  120. int main(void)
  121. {
  122. /* Config module ---------------------------------------------------------------------------------------- */
  123. Module_Led_Config(&dev_led_state);
  124. dev_led_state.Set(&dev_led_state,9);
  125. Module_RobomoduleGroup_Config(&dev_robomoduleGroup);
  126. Module_BlueToothHC06_Config(&dev_communicate);
  127. /* Enable task thread ---------------------------------------------------------------------------------------- */
  128. /* system running shine led thread */
  129. rt_thread_t led_thread = rt_thread_create("ledshine", led_shine_entry, RT_NULL,
  130. 512, RT_THREAD_PRIORITY_MAX - 3, 20);
  131. if (led_thread != RT_NULL){
  132. rt_thread_startup(led_thread);
  133. }
  134. /* motor control thread */
  135. rt_thread_t motor_thread = rt_thread_create("motor", motor_entry, RT_NULL,
  136. 1024, RT_THREAD_PRIORITY_MAX - 2, 20);
  137. if (motor_thread != RT_NULL){
  138. rt_thread_startup(motor_thread);
  139. }
  140. /* blue tooth updata thread */
  141. rt_thread_t bluetupdata_thread = rt_thread_create("bluetupdata", bluetupdata_entry, RT_NULL,
  142. 512, RT_THREAD_PRIORITY_MAX - 5, 20);
  143. if (bluetupdata_thread != RT_NULL){
  144. rt_thread_startup(bluetupdata_thread);
  145. }
  146. /* blue tooth updata thread */
  147. rt_thread_t bluetcontrol_thread = rt_thread_create("bluetcontrol", bluetcontrol_entry, RT_NULL,
  148. 512, RT_THREAD_PRIORITY_MAX - 5, 20);
  149. if (bluetcontrol_thread != RT_NULL){
  150. rt_thread_startup(bluetcontrol_thread);
  151. }
  152. }
  153. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/

补充说明

  • 目前模块支持电机的多种模式设置,但由于仅用到了位置模式,所以填充的发送位置模式报文的地方
  • 如果需要其他模式,在结构体成员赋值时,配置模式,并填充对应分支即可
  • 模块的初始化大致分为两步
    • 电机群初始化:完成Can线的驱动,根据电机使能标记,选择性初始化电机
    • 电机初始化:完成电机复位指令发送,电机模式选择指令发送
  • 目前还未解读报文返回信息,仅是放置在了缓冲区内,用一个信号量指示接收到了报文
  • 后期可根据需求解析报文
  • 使用上与前面的3508电机群模块使用基本一致
    • 声明结构体变量,并赋值,使能电机,设置模式,设置ID
    • 在主函数完成电机群模块的初始化
    • 在电机控制线程中调用电机群的发送报文方法
    • 然后在任何一个位置中均可以设置电机群中某一个电机的转角

注意:如果需要同其他类型的Can设备(如3508电机群)公用同一Can线,注意会出现RTT的Can设备被多次初始化而被报错的情况,建议同种协议的设备唯一占用一趟Cans线,比如3508电机和2006电机使用Can1,Robomodule使用Can2即可避免该问题