Gitee

https://gitee.com/WangXi_Chn/RttOs_ModuleLib

开发环境

CubeMX
MDK5 IDE
STM32F407IGH6TR 芯片
大疆开发板 C型
大疆M3508直流无刷电机
大疆C620无刷电机调速器
RT-Thread操作系统
面向对象模块接口设计

硬件条件

  • 确保Can线供电电平达到5V(不可仅使用JTAG接口供电3.3V)
  • Can线接口连接正确

    添加驱动

    CubuMX

    image.png

  • 使能Can1

  • 配置引脚(使能的自动引脚配置可能错误,需要在右侧引脚单独点击使能)

    Kconfig

    1. menuconfig BSP_USING_CAN
    2. bool "Enable CAN"
    3. default n
    4. select RT_USING_CAN
    5. if BSP_USING_CAN
    6. config BSP_USING_CAN1
    7. bool "using CAN1"
    8. default n
    9. config BSP_USING_CAN2
    10. bool "using CAN2"
    11. default n
    12. endif

    Env

    image.pngimage.png
    image.pngimage.png

  • 使能CAN1驱动

  • SCON命令生成MDK5工程

    修改时钟

  • STM32F407的APB1总线一般是42MHz,但是RT-Thread波特率选项默认为45MHz

  • 需要修改 drv_can.c 文件为如下内容

    1. #elif defined (SOC_SERIES_STM32F4)/* APB1 42MHz(max) */
    2. static const struct stm32_baud_rate_tab can_baud_rate_tab[] =
    3. {
    4. {CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 3)},
    5. {CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_4TQ | 4)},
    6. {CAN500kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 6)},
    7. {CAN250kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 12)},
    8. {CAN125kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 24)},
    9. {CAN100kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 30)},
    10. {CAN50kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 60)},
    11. {CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 150)},
    12. {CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 300)}
    13. };
  • 注意这个位置

image.png

接口函数

查找设备

image.png

打开设备

image.png

控制设备

image.png
image.png
image.png
image.png

发送数据

image.png
image.png

设置接收回调

image.png

接收数据

image.png
image.png

关闭设备

image.png

官方例程

  1. /*
  2. * 程序清单:这是一个 CAN 设备使用例程
  3. * 例程导出了 can_sample 命令到控制终端
  4. * 命令调用格式:can_sample can1
  5. * 命令解释:命令第二个参数是要使用的 CAN 设备名称,为空则使用默认的 CAN 设备
  6. * 程序功能:通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。
  7. */
  8. #include <rtthread.h>
  9. #include "rtdevice.h"
  10. #define CAN_DEV_NAME "can1" /* CAN 设备名称 */
  11. static struct rt_semaphore rx_sem; /* 用于接收消息的信号量 */
  12. static rt_device_t can_dev; /* CAN 设备句柄 */
  13. /* 接收数据回调函数 */
  14. static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
  15. {
  16. /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
  17. rt_sem_release(&rx_sem);
  18. return RT_EOK;
  19. }
  20. static void can_rx_thread(void *parameter)
  21. {
  22. int i;
  23. rt_err_t res;
  24. struct rt_can_msg rxmsg = {0};
  25. /* 设置接收回调函数 */
  26. rt_device_set_rx_indicate(can_dev, can_rx_call);
  27. #ifdef RT_CAN_USING_HDR
  28. struct rt_can_filter_item items[5] =
  29. {
  30. RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 1, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表 */
  31. RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 1, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr 为 - 1 */
  32. RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 1, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr 为 - 1 */
  33. RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL), /* std,match ID:0x486,hdr 为 - 1 */
  34. {0x555, 0, 0, 1, 0x7ff, 7,} /* std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表 */
  35. };
  36. struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有 5 个过滤表 */
  37. /* 设置硬件过滤表 */
  38. res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
  39. RT_ASSERT(res == RT_EOK);
  40. #endif
  41. while (1)
  42. {
  43. /* hdr 值为 - 1,表示直接从 uselist 链表读取数据 */
  44. rxmsg.hdr = -1;
  45. /* 阻塞等待接收信号量 */
  46. rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
  47. /* 从 CAN 读取一帧数据 */
  48. rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
  49. /* 打印数据 ID 及内容 */
  50. rt_kprintf("ID:%x", rxmsg.id);
  51. for (i = 0; i < 8; i++)
  52. {
  53. rt_kprintf("%2x", rxmsg.data[i]);
  54. }
  55. rt_kprintf("\n");
  56. }
  57. }
  58. int can_sample(int argc, char *argv[])
  59. {
  60. struct rt_can_msg msg = {0};
  61. rt_err_t res;
  62. rt_size_t size;
  63. rt_thread_t thread;
  64. char can_name[RT_NAME_MAX];
  65. if (argc == 2)
  66. {
  67. rt_strncpy(can_name, argv[1], RT_NAME_MAX);
  68. }
  69. else
  70. {
  71. rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
  72. }
  73. /* 查找 CAN 设备 */
  74. can_dev = rt_device_find(can_name);
  75. if (!can_dev)
  76. {
  77. rt_kprintf("find %s failed!\n", can_name);
  78. return RT_ERROR;
  79. }
  80. /* 初始化 CAN 接收信号量 */
  81. rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
  82. /* 以中断接收及发送方式打开 CAN 设备 */
  83. res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
  84. RT_ASSERT(res == RT_EOK);
  85. /* 创建数据接收线程 */
  86. thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
  87. if (thread != RT_NULL)
  88. {
  89. rt_thread_startup(thread);
  90. }
  91. else
  92. {
  93. rt_kprintf("create can_rx thread failed!\n");
  94. }
  95. msg.id = 0x78; /* ID 为 0x78 */
  96. msg.ide = RT_CAN_STDID; /* 标准格式 */
  97. msg.rtr = RT_CAN_DTR; /* 数据帧 */
  98. msg.len = 8; /* 数据长度为 8 */
  99. /* 待发送的 8 字节数据 */
  100. msg.data[0] = 0x00;
  101. msg.data[1] = 0x11;
  102. msg.data[2] = 0x22;
  103. msg.data[3] = 0x33;
  104. msg.data[4] = 0x44;
  105. msg.data[5] = 0x55;
  106. msg.data[6] = 0x66;
  107. msg.data[7] = 0x77;
  108. /* 发送一帧 CAN 数据 */
  109. size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
  110. if (size == 0)
  111. {
  112. rt_kprintf("can dev write data failed!\n");
  113. }
  114. return res;
  115. }
  116. /* 导出到 msh 命令列表中 */
  117. MSH_CMD_EXPORT(can_sample, can device sample);

适配模块接口

Module_3508Motor.h

  1. /*
  2. * Copyright (c) 2020 - ~, HIT_HERO Team
  3. *
  4. * 2508MOTOR_CAN MODULE HEAD FILE
  5. * Used in RT-Thread Operate System
  6. *
  7. * Change Logs:
  8. * Date Author Notes Mail
  9. * 2020-08-02 WangXi first version WangXi_chn@foxmail.com
  10. */
  11. #ifndef _MODULE_3508MOTOR_H_
  12. #define _MODULE_3508MOTOR_H_
  13. #include <rtthread.h>
  14. #include <rtdevice.h>
  15. #include <board.h>
  16. #include "Math_PID.h"
  17. struct _MODULE_MOTOR3508
  18. {
  19. /* Property */
  20. char * CanDevName;
  21. rt_uint32_t MOTOR3508ID_HEAD;
  22. rt_uint32_t MOTOR3508ID_NUM;
  23. rt_uint32_t MOTOR3508ID_FEED;
  24. MATH_PID Motor3508_PID;
  25. /* Value */
  26. rt_device_t can_dev;
  27. struct rt_can_msg can_msg;
  28. struct rt_can_msg can_mrg;
  29. rt_int32_t motor_AimCurrent;
  30. rt_int32_t motor_AimAngSpeed;
  31. rt_int32_t motor_AimAngle;
  32. rt_int32_t motor_RealCurrent;
  33. rt_int32_t motor_RealAngSpeed;
  34. rt_int32_t motor_RealAngle;
  35. rt_uint8_t motor_Temperature;
  36. /* Method */
  37. void (*Init)(struct _MODULE_MOTOR3508 *module);
  38. void (*Send)(struct _MODULE_MOTOR3508 *module);
  39. void (*Feed)(struct _MODULE_MOTOR3508 *module);
  40. rt_err_t (*Handle)(rt_device_t dev,rt_size_t size);
  41. };
  42. typedef struct _MODULE_MOTOR3508 MODULE_MOTOR3508;
  43. /* Glodal Method */
  44. rt_err_t Module_Motor3508_Config(MODULE_MOTOR3508 *Dev_Motor3508);
  45. #endif
  46. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/

Module_3508Motor.c

  1. /*
  2. * Copyright (c) 2020 - ~, HIT_HERO Team
  3. *
  4. * 2508MOTOR_CAN MODULE SOUCE FILE
  5. * Used in RT-Thread Operate System
  6. *
  7. * Change Logs:
  8. * Date Author Notes Mail
  9. * 2020-08-02 WangXi first version WangXi_chn@foxmail.com
  10. */
  11. #include "Module_3508Motor.h"
  12. /* User Code Begin*/
  13. /* User Code End */
  14. /* Static Method */
  15. static void Module_Motor3508Init(MODULE_MOTOR3508 *module);
  16. static void Module_Motor3508Send(MODULE_MOTOR3508 *module);
  17. static void Module_Motor3508Feed(MODULE_MOTOR3508 *module);
  18. static rt_err_t Module_Motor3508Handle(rt_device_t dev, rt_size_t size);
  19. static struct rt_semaphore can_sem;
  20. /* Global Method */
  21. rt_err_t Module_Motor3508_Config(MODULE_MOTOR3508 *Dev_Motor3508)
  22. {
  23. if( Dev_Motor3508->Init ==NULL &&
  24. Dev_Motor3508->Handle ==NULL &&
  25. Dev_Motor3508->Send ==NULL &&
  26. Dev_Motor3508->Feed ==NULL
  27. ){
  28. /* Link the Method */
  29. Dev_Motor3508->Init = Module_Motor3508Init;
  30. Dev_Motor3508->Handle = Module_Motor3508Handle;
  31. Dev_Motor3508->Send = Module_Motor3508Send;
  32. Dev_Motor3508->Feed = Module_Motor3508Feed;
  33. }
  34. else{
  35. rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");
  36. return RT_ERROR;
  37. }
  38. /* Device Init */
  39. Dev_Motor3508->Init(Dev_Motor3508);
  40. /* Module PID controler Init */
  41. Module_PID_Config(&(Dev_Motor3508->Motor3508_PID));
  42. return RT_EOK;
  43. }
  44. /* Static Method */
  45. static void Module_Motor3508Init(MODULE_MOTOR3508 *module)
  46. {
  47. rt_err_t res;
  48. /* link can devices */
  49. module->can_dev = rt_device_find(module->CanDevName);
  50. if (!module->can_dev)
  51. rt_kprintf("find %s failed!\n", module->CanDevName);
  52. /* init semaphone */
  53. rt_sem_init(&can_sem, "can_sem", 0, RT_IPC_FLAG_FIFO);
  54. res = rt_device_open(module->can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
  55. RT_ASSERT(res == RT_EOK);
  56. /* set up hardware filter */
  57. struct rt_can_filter_item items[1] =
  58. {
  59. // id ide rtr mode mask hdr
  60. { module->MOTOR3508ID_FEED, 0, 0, 1, 0xFFFF, 1 }
  61. };
  62. struct rt_can_filter_config cfg = {1, 1, items};
  63. res = rt_device_control(module->can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
  64. RT_ASSERT(res == RT_EOK);
  65. /* set up can baudrate */
  66. rt_device_control(module->can_dev, RT_CAN_CMD_SET_BAUD, (void *)CAN1MBaud);
  67. /* send frame preprocess */
  68. module->can_msg.id = module->MOTOR3508ID_HEAD;
  69. module->can_msg.ide = RT_CAN_STDID;
  70. module->can_msg.rtr = RT_CAN_DTR;
  71. module->can_msg.len = 8;
  72. /* feed frame preprocess */
  73. module->can_mrg.hdr = 1;
  74. res = rt_device_control(module->can_dev, RT_CAN_CMD_SET_MODE, (void *)RT_CAN_MODE_NORMAL);
  75. RT_ASSERT(res == RT_EOK);
  76. /* link call back function */
  77. rt_device_set_rx_indicate(module->can_dev, module->Handle);
  78. }
  79. static void Module_Motor3508Send(MODULE_MOTOR3508 *module)
  80. {
  81. rt_size_t size;
  82. module->motor_AimCurrent = module->Motor3508_PID.Value_out;
  83. /* limit output */
  84. module->motor_AimCurrent = module->motor_AimCurrent > 16384? 16384 : module->motor_AimCurrent;
  85. module->motor_AimCurrent = module->motor_AimCurrent < -16384? -16384 : module->motor_AimCurrent;
  86. if(module->MOTOR3508ID_HEAD == 0x200)
  87. {
  88. module->can_msg.data[module->MOTOR3508ID_NUM*2-1]=module->motor_AimCurrent&0XFF;
  89. module->can_msg.data[module->MOTOR3508ID_NUM*2-2]=module->motor_AimCurrent>>8;
  90. }
  91. else if(module->MOTOR3508ID_HEAD == 0x1FF)
  92. {
  93. module->can_msg.data[module->MOTOR3508ID_NUM*2-9]=module->motor_AimCurrent&0XFF;
  94. module->can_msg.data[module->MOTOR3508ID_NUM*2-10]=module->motor_AimCurrent>>8;
  95. }
  96. else
  97. {
  98. rt_kprintf("MOTOR3508ID_HEAD is a wrong number!\n");
  99. }
  100. size = rt_device_write(module->can_dev, 0, &(module->can_msg), sizeof(module->can_msg));
  101. if (size == 0)
  102. rt_kprintf("can dev write data failed!\n");
  103. }
  104. static rt_err_t Module_Motor3508Handle(rt_device_t dev, rt_size_t size)
  105. {
  106. rt_sem_release(&can_sem);
  107. return RT_EOK;
  108. }
  109. static void Module_Motor3508Feed(MODULE_MOTOR3508 *module)
  110. {
  111. rt_sem_take(&can_sem, RT_WAITING_FOREVER);
  112. rt_device_read(module->can_dev, 0, &(module->can_mrg), sizeof(module->can_mrg));
  113. module->motor_RealAngle = ((module->can_mrg.data[0]<<8) + module->can_mrg.data[1])*360/8189; // °
  114. module->motor_RealAngSpeed = ((module->can_mrg.data[2]<<8) + module->can_mrg.data[3])*360/3600; // °/s
  115. module->motor_RealCurrent = ((module->can_mrg.data[4]<<8) + module->can_mrg.data[5]);
  116. module->motor_Temperature = module->can_mrg.data[6];
  117. module->Motor3508_PID.Method_Update( &(module->Motor3508_PID),
  118. module->motor_AimAngSpeed,
  119. module->motor_RealAngSpeed,
  120. 0.5);
  121. }
  122. /************************ (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_Imax;
  23. float Property_outmax;
  24. float Property_IerrorMax; //允许积分的最大偏差值
  25. /* Value */
  26. float Value_dt;
  27. float Value_P;
  28. float Value_I;
  29. float Value_D;
  30. float Value_AntiIFactor; //快速退积分系数
  31. float Value_set;
  32. float Value_feedback;
  33. float Value_Lasterror;
  34. float Value_error;
  35. float Value_derror;
  36. float Value_Lastderror; //滤波用
  37. float Value_out;
  38. /* Method */
  39. void (*Method_Init)(struct _MATH_PID *module);
  40. void (*Method_Update)(struct _MATH_PID *module,float Aim, float Feedback,double Coafficient);
  41. };
  42. typedef struct _MATH_PID MATH_PID;
  43. rt_err_t Module_PID_Config(MATH_PID *module);
  44. #endif
  45. /************************ (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,double Coafficient);
  15. static float constrain_float(float amt, float low, float high);
  16. /* Global Method */
  17. rt_err_t Module_PID_Config(MATH_PID *module)
  18. {
  19. if( module->Method_Init ==NULL &&
  20. module->Method_Update ==NULL
  21. ){
  22. /* Link the Method */
  23. module->Method_Init = Module_PIDInit;
  24. module->Method_Update = Module_PIDUpdate;
  25. }
  26. else{
  27. rt_kprintf("Warning: Module Motor 3508 is Configed twice\n");
  28. return RT_ERROR;
  29. }
  30. /* Device Init */
  31. module->Method_Init(module);
  32. return RT_EOK;
  33. }
  34. static void Module_PIDInit(MATH_PID *module)
  35. {
  36. module->Value_AntiIFactor = 1;
  37. module->Value_Lastderror = 0;
  38. module->Value_P = 0;
  39. module->Value_I = 0;
  40. module->Value_D = 0;
  41. module->Value_error = 0;
  42. module->Value_Lasterror = 0;
  43. module->Value_derror = 0;
  44. module->Value_out = 0;
  45. }
  46. static void Module_PIDUpdate(MATH_PID *module,float Aim, float Feedback,double Coafficient)
  47. {
  48. module->Value_set = Aim;
  49. module->Value_feedback = module->Value_feedback * Coafficient + Feedback * (1 - Coafficient);
  50. module->Value_error= module->Value_set - module->Value_feedback;
  51. module->Value_derror = ((1.0f - Coafficient) * (module->Value_error - module->Value_Lasterror) + Coafficient * (module->Value_Lastderror));
  52. module->Value_Lastderror = module->Value_derror;
  53. module->Value_Lasterror = module->Value_error;
  54. module->Value_P = module->Property_kP * module->Value_error;
  55. if(fabs(module->Value_error) < module->Property_IerrorMax) //如果偏差大于这个,不进行积分
  56. {
  57. if(fabs((float)(module->Value_I + module->Property_kI * module->Value_error + module->Value_P)) < module->Property_outmax)
  58. {
  59. module->Value_I += (float)(module->Property_kI * module->Value_error * module->Value_AntiIFactor);
  60. module->Value_I = constrain_float(module->Value_I, -module->Property_Imax, +module->Property_Imax);
  61. }
  62. }
  63. module->Value_D = module->Property_kD * module->Value_derror;
  64. module->Value_out = module->Value_P + module->Value_I + module->Value_D;
  65. module->Value_out = constrain_float(module->Value_out, -module->Property_outmax, +module->Property_outmax)/100.0f;
  66. }
  67. /**
  68. * @brief 输出限幅
  69. * @param int32_t amt:待输出量
  70. * int32_t low:输出最小值
  71. * int32_t high:输出最大值
  72. * @retval int32_t X:限幅后的输出量
  73. */
  74. static float constrain_float(float amt, float low, float high)
  75. {
  76. return ((amt)<(low)?(low):((amt)>(high)?(high):(amt)));
  77. }
  78. /************************ (C) COPYRIGHT 2020 WANGXI **************END OF FILE****/

使用main.c

  1. #include <rtthread.h>
  2. #include <rtdevice.h>
  3. #include <board.h>
  4. #include "Module_3508Motor.h"
  5. MODULE_MOTOR3508 dev_motor3508_1 =
  6. {
  7. .CanDevName = "can1",
  8. .MOTOR3508ID_HEAD = 0x200,
  9. .MOTOR3508ID_NUM = 1,
  10. .MOTOR3508ID_FEED = 0x201,
  11. .Motor3508_PID =
  12. {
  13. .Property_kP = 15,
  14. .Property_kI = 3,
  15. .Property_kD = 50,
  16. .Property_Imax = 500,
  17. .Property_outmax = 1638400,
  18. .Property_IerrorMax = 5000
  19. }
  20. };
  21. static void motor_entry(void *parameter)
  22. {
  23. while (1)
  24. {
  25. dev_motor3508_1.Feed(&dev_motor3508_1);
  26. rt_thread_mdelay(5);
  27. dev_motor3508_1.Send(&dev_motor3508_1);
  28. }
  29. }
  30. int main(void)
  31. {
  32. Module_Motor3508_Config(&dev_motor3508_1);
  33. dev_motor3508_1.motor_AimAngSpeed = 5;
  34. /* system running motor control */
  35. rt_thread_t motor_thread = rt_thread_create("motor", motor_entry, RT_NULL,
  36. 1024, RT_THREAD_PRIORITY_MAX - 3, 20);
  37. if (led_thread != RT_NULL){
  38. rt_thread_startup(motor_thread);
  39. }
  40. }

部分解释

  • 模块头文件中的Property注释下的变量为属性,是结构体声明时必须定义的数值,否则无法正常工作
  • 模块头文件中的Value注释下的变量为中间变量,是计算过程中的必要数值,可能是输入记录或输出等,可用来调试修改和观察,其初始化赋值在模块的初始化函数中自动进行
  • 模块头文件中的Method注释下的变量为函数指针,是该模块提供的函数方法,可通过结构体变量访问成员直接调用
  • 模块在使用前必须通过提供的全局方法(Global Method)处理,主要作用是绑定方法函数,初始化变量,初始化驱动,使能外设等
  • 目前电机刷入电流、读出数据功能可正常使用,但PID参数和算法还需要调整,慎重使用

    优势

  • 面向对象设计,大大减少全局变量,宏定义等量,近乎没有,移植性强

  • 将PID模块嵌入到电机模块中
    • PID模块暂未得到实际测试,算法和参数正确与否不确定,但代码结构固定
  • Can接收中断仅释放信号量,在线程中处理接收数据,比在中断中处理数据更安全
  • 对模块内的函数static静态保护,实现切实的封装,仅可通过访问结构体变量调用函数
  • 仿C#使用方法,减少使用时的工作量

    存在问题

  • 单电机驱动仅修改电机ID即可

  • 但驱动多个电机时,Can外设会被多次开启,RTT操作系统报错
  • 驱动多电机时,控制帧是一个电机一个电机发送,控制效率低,不符合M3508报文设计
  • 接受多电机返回数据时会发生报文错乱
  • 电机PID控制缺少验证,而且不满足速度闭环角度闭环的需求
  • 以上问题均在下一节中的电机群设计解决