diff --git a/.vscode/launch.json b/.vscode/launch.json index b7051ea..56720ef 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,24 +1,25 @@ { "version": "0.2.0", "configurations": [ - { + { // 使用dap-link(如无线调试器时的参考配置) "name": "Debug-dap", "cwd": "${workspaceRoot}", - "executable": "${workspaceRoot}\\build\\basic_framework.elf", + "executable": "${workspaceRoot}\\build\\basic_framework.elf", // 要下载到调试器的文件 "request": "launch", "type": "cortex-debug", - "device":"STM32F407IG", //使用J-link GDB Server时必须;其他GBD Server时可选(有可能帮助自动选择SVD文件)。支持的设备见 https://www.segger.com/downloads/supported-devices.php - "svdFile": ".\\STM32F407.svd", //svd文件,有这个文件才能查看寄存器的值,每个单片机都不同。可以在以下地址找到 https://github.com/posborne/cmsis-svd - "servertype": "openocd", //使用的GDB Server - "configFiles":[ - ".\\openocd.cfg", + "device": "STM32F407IG", //使用J-link GDB Server时必须;其他GBD Server时可选(有可能帮助自动选择SVD文件)。支持的设备见 https://www.segger.com/downloads/supported-devices.php + "svdFile": ".\\STM32F407.svd", //svd文件,有这个文件才能查看寄存器的值,每个单片机都不同。可以在以下地址找到 https://github.com/posborne/cmsis-svd + // 该项目的根目录已经提供了C型开发板使用的外设svd文件 + "servertype": "openocd", //使用的GDB Server + "configFiles": [ + ".\\openocd.cfg", // 配置文件已经在根目录提供,若要修改以此类推 ], - // path to your gcc-arm-none-eabi/bin + // path to your gcc-arm-none-eabi/bin,如果在cortex-debug的设置中写入了全局路径,这里不需要再写 "armToolchainPath": "D:\\gcc-arm-none-eabi\\bin", - // path to your gcc-arm-none-eabi/arm-none-eabi-gdb.exe - "gdbPath": "D:\\gcc-arm-none-eabi\\bin\\arm-none-eabi-gdb.exe" + // path to your gcc-arm-none-eabi/arm-none-eabi-gdb.exe,如果在cortex-debug的设置中写入了全局路径,这里不需要再写 + "gdbPath": "D:\\gcc-arm-none-eabi\\bin\\arm-none-eabi-gdb.exe" }, - { + { // 使用j-link时的参考配置 "name": "Debug-jlink", "cwd": "${workspaceFolder}", "executable": "${workspaceRoot}\\build\\basic_framework.elf", @@ -29,8 +30,10 @@ "showDevDebugOutput": "none", "servertype": "jlink", "interface": "swd", + //如果在cortex-debug的设置中写入了全局路径,这里不需要再写 "armToolchainPath": "D:\\gcc-arm-none-eabi\\bin", - "gdbPath": "D:\\gcc-arm-none-eabi\\bin\\arm-none-eabi-gdb.exe" + //如果在cortex-debug的设置中写入了全局路径,这里不需要再写 + "gdbPath": "D:\\gcc-arm-none-eabi\\bin\\arm-none-eabi-gdb.exe" } ] } \ No newline at end of file diff --git a/Makefile b/Makefile index d0213b7..6b76ffb 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,7 @@ bsp/bsp_can.c \ bsp/bsp_buzzer.c \ bsp/bsp_usart.c \ bsp/bsp_log.c \ +bsp/bsp_init.c \ \ \ modules/algorithm/controller.c \ modules/algorithm/kalman_filter.c \ @@ -117,6 +118,7 @@ modules/master_machine/master_process.c \ modules/motor/dji_motor.c \ modules/motor/HT04.c \ modules/motor/LK9025.c \ +modules/mode/step_motor.c \ modules/motor/motor_task.c \ modules/referee/referee.c \ modules/referee/referee_UI.c \ @@ -125,7 +127,8 @@ modules/remote/remote_control.c \ modules/super_cap/super_cap.c \ modules/master_machine/seasky_protocol.c \ modules/algorithm/crc8.c \ -modules/algorithm/crc16.c +modules/algorithm/crc16.c \ +modules/can_comm/can_comm.c # ASM sources diff --git a/README.md b/README.md index cb2fafb..57259e9 100644 --- a/README.md +++ b/README.md @@ -100,10 +100,11 @@ Module层主要存放的是类型定义和实例指针数组,在该层没有 ## 文件树 +板级支持包的每个组件,每个moduel,每个app都有对应的说明文档. ```shell ROOT:. │ .gitignore # git版本管理忽略文件 -│ .mxproject # CubeMX项目文件 +│ .mxproject # CubeMX项目文件 │ basic_framework.ioc # CubeMX初始化配置文件 │ Makefile # 编译管理文件,为make命令的目标 │ openocd.cfg # 用于OpenOCD调试使用的配置文件 @@ -111,39 +112,50 @@ ROOT:. │ startup_stm32f407xx.s # F407汇编启动文件 │ STM32F407.svd # F407外设地址映射文件,用于调试 │ STM32F407IGHx_FLASH.ld # F407IGH(C板使用的MCU)的文件目标FLASH地址,用于烧录和调试 -│ +│ VSCode+Ozone使用方法.md # 开发环境配置 +| ├─.vscode │ launch.json # 用于VSCode插件CORTEX-DEBUG调试的配置文件 │ ├─application # 应用层,包括底盘控制,云台控制和发射控制 │ chassis.c │ chassis.h +│ chassis.md │ gimbal.c │ gimbal.h +│ gimbal.md │ shoot.c │ shoot.h +│ shoot.md │ ├─bsp # 板级支持包,提供对硬件的封装,将接口暴露给module层 +│ bsp.md │ bsp_buzzer.c │ bsp_buzzer.h │ bsp_can.c │ bsp_can.h +│ bsp_can.md │ bsp_dwt.c │ bsp_dwt.h +│ bsp_init.c +│ bsp_init.h │ bsp_led.c │ bsp_led.h │ bsp_log.c │ bsp_log.h +│ bsp_log.md │ bsp_temperature.c │ bsp_temperature.h │ bsp_usart.c │ bsp_usart.h +│ bsp_usart.md │ struct_typedef.h │ ├─HAL_N_Middlewares # HAL库对寄存器操作的封装,以及FreeRTOS等中间件 | └─modules # 模块层,使用BSP提供的接口构建对应的功能模块,将模块实例提供给应用层 ├─algorithm # 算法 + │ algorithm.md │ controller.c # 控制器 │ controller.h │ crc16.c # 循环冗余校验 @@ -159,6 +171,11 @@ ROOT:. │ user_lib.c # 多个模块都会使用到的函数 │ user_lib.h │ + ├─can_comm # 双板CAN通信组件 + │ can_comm.c + │ can_comm.h + │ can_comm.md + | ├─imu # 考虑到使用SPI的设备较少,这里没有对SPI提供bsp支持,直接于此实现 │ BMI088driver.c │ BMI088driver.h @@ -173,10 +190,12 @@ ROOT:. │ led_task.h │ ├─master_machine # 和上位机(视觉PC)通信的模块 - │ master_process.c + │ master_process.c │ master_process.h - │ seasky_protocol.c # 视觉通信协议 + │ master_process.md + │ seasky_protocol.c │ seasky_protocol.h + │ 湖南大学RoboMaster电控组通信协议.md │ ├─motor # 电机模块 │ dji_motor.c # DJI智能电机 @@ -193,7 +212,8 @@ ROOT:. │ referee.c # 接收裁判系统信息 │ referee.h │ referee_UI.c # UI绘制(发送) - │ + │ referee_communication.c # 多机通信 + | ├─remote # 遥控器模块 │ remote_control.c │ remote_control.h diff --git a/VSCode+Ozone使用方法.md b/VSCode+Ozone使用方法.md index 92ee851..bfcb4f6 100644 --- a/VSCode+Ozone使用方法.md +++ b/VSCode+Ozone使用方法.md @@ -1,2 +1,199 @@ -# VSCode+Ozone使用方法 +# VSCode+Ozone开发STM32的方法 + +
neozng1@hnu.edu.cn
+ +> TODO: +> +> 1. 实现麦轮和全向轮的速度解算 +> 2. 实现LQR +> 3. 实现一些通用的滤波器,如指数平均,窗平均,低通等 +> 4. 实现系统辨识 + +## 总览和使用 + +module层的algorithm提供了一些供其他模块以及app的应用层使用的算法,包括: + +1. PID控制器`controller.h` +2. crc8 crc16循环冗余校验 +3. 卡尔曼滤波器`kalman_filter.h`,可以通过用户自定义函数配置为扩展卡尔曼滤波 +4. `LQR.h`,线性二次型调节器 +5. `QuaterninoEKF.h`,用于`ins_task`的四元数姿态解算和扩展卡尔曼滤波融合 +6. `user_lib.h`,一些通用的函数,包括限幅、数据类型转换、角度弧度转换、快速符号判断以及优化开方等功能。多个模块都会使用的、不好区分的函数可以放置于此 + +## 代码结构 + +.c 为算法的实现,.h为算法对外接口的头文件 + + + +在编写应用的时候,你基本不会使用这里的函数,或是修改其实现。 + +若发现bug或需要增加功能,联系组长讨论。 + diff --git a/modules/algorithm/user_lib.c b/modules/algorithm/user_lib.c index f1754b7..a2d0a92 100644 --- a/modules/algorithm/user_lib.c +++ b/modules/algorithm/user_lib.c @@ -2,7 +2,8 @@ ****************************************************************************** * @file user_lib.c * @author Wang Hongxi - * @version V1.0.0 + * @author modified by neozng + * @version 0.2 beta * @date 2021/2/18 * @brief ****************************************************************************** @@ -24,7 +25,7 @@ uint8_t GlobalDebugMode = 7; -//快速开方 +// 快速开方 float Sqrt(float x) { float y; @@ -51,29 +52,7 @@ float Sqrt(float x) return y; } -/** - * @brief 斜波函数计算,根据输入的值进行叠加, 输入单位为 /s 即一秒后增加输入的值 - * @author RM - * @param[in] 斜波函数结构体 - * @param[in] 输入值 - * @retval 返回空 - */ -float ramp_calc(ramp_function_source_t *ramp_source_type, float input) -{ - ramp_source_type->input = input; - ramp_source_type->out += ramp_source_type->input * ramp_source_type->frame_period; - if (ramp_source_type->out > ramp_source_type->max_value) - { - ramp_source_type->out = ramp_source_type->max_value; - } - else if (ramp_source_type->out < ramp_source_type->min_value) - { - ramp_source_type->out = ramp_source_type->min_value; - } - return ramp_source_type->out; -} - -//绝对值限制 +// 绝对值限制 float abs_limit(float num, float Limit) { if (num > Limit) @@ -87,7 +66,7 @@ float abs_limit(float num, float Limit) return num; } -//判断符号位 +// 判断符号位 float sign(float value) { if (value >= 0.0f) @@ -100,7 +79,7 @@ float sign(float value) } } -//浮点死区 +// 浮点死区 float float_deadband(float Value, float minValue, float maxValue) { if (Value < maxValue && Value > minValue) @@ -120,7 +99,7 @@ int16_t int16_deadline(int16_t Value, int16_t minValue, int16_t maxValue) return Value; } -//限幅函数 +// 限幅函数 float float_constrain(float Value, float minValue, float maxValue) { if (Value < minValue) @@ -131,7 +110,7 @@ float float_constrain(float Value, float minValue, float maxValue) return Value; } -//限幅函数 +// 限幅函数 int16_t int16_constrain(int16_t Value, int16_t minValue, int16_t maxValue) { if (Value < minValue) @@ -142,7 +121,7 @@ int16_t int16_constrain(int16_t Value, int16_t minValue, int16_t maxValue) return Value; } -//循环限幅函数 +// 循环限幅函数 float loop_float_constrain(float Input, float minValue, float maxValue) { if (maxValue < minValue) @@ -169,9 +148,9 @@ float loop_float_constrain(float Input, float minValue, float maxValue) return Input; } -//弧度格式化为-PI~PI +// 弧度格式化为-PI~PI -//角度格式化为-180~180 +// 角度格式化为-180~180 float theta_format(float Ang) { return loop_float_constrain(Ang, -180.0f, 180.0f); diff --git a/modules/algorithm/user_lib.h b/modules/algorithm/user_lib.h index 56f7ca8..d223225 100644 --- a/modules/algorithm/user_lib.h +++ b/modules/algorithm/user_lib.h @@ -87,39 +87,9 @@ extern uint8_t GlobalDebugMode; #define VAL_MIN(a, b) ((a) < (b) ? (a) : (b)) #define VAL_MAX(a, b) ((a) > (b) ? (a) : (b)) -typedef struct -{ - float input; //�������� - float out; //������� - float min_value; //����Сֵ - float max_value; //�����ֵ - float frame_period; //ʱ���� -} ramp_function_source_t; - -typedef struct -{ - uint16_t Order; - uint32_t Count; - - float *x; - float *y; - - float k; - float b; - - float StandardDeviation; - - float t[4]; -} Ordinary_Least_Squares_t; //���ٿ��� float Sqrt(float x); - -//б��������ʼ�� -void ramp_init(ramp_function_source_t *ramp_source_type, float frame_period, float max, float min); -//б���������� -float ramp_calc(ramp_function_source_t *ramp_source_type, float input); - //�������� float abs_limit(float num, float Limit); //�жϷ���λ diff --git a/modules/can_comm/can_comm.c b/modules/can_comm/can_comm.c new file mode 100644 index 0000000..e69de29 diff --git a/modules/can_comm/can_comm.h b/modules/can_comm/can_comm.h new file mode 100644 index 0000000..e69de29 diff --git a/modules/can_comm/can_comm.md b/modules/can_comm/can_comm.md new file mode 100644 index 0000000..b9bea44 --- /dev/null +++ b/modules/can_comm/can_comm.md @@ -0,0 +1,3 @@ +can_comm + +双板CAN通信 \ No newline at end of file diff --git a/modules/led_light/led.md b/modules/led_light/led.md new file mode 100644 index 0000000..c99ee17 --- /dev/null +++ b/modules/led_light/led.md @@ -0,0 +1,6 @@ +# led_task +neozng1@hnu.edu.cn
+ +> TODO: +> 1. 预计添加不同错误标志,将错误类型和灯的闪烁频率或颜色等对应起来,方便调试 + diff --git a/modules/master_machine/master_process.c b/modules/master_machine/master_process.c index 4a9f933..db1bef8 100644 --- a/modules/master_machine/master_process.c +++ b/modules/master_machine/master_process.c @@ -12,11 +12,14 @@ /* use usart1 as vision communication*/ static Vision_Recv_s recv_data; +// @todo:由于后续需要进行IMU-Cam的硬件触发采集控制,因此可能需要将发送设置为定时任务,或由IMU采集完成产生的中断唤醒的任务, +// 使得时间戳对齐. 因此,在send_data中设定其他的标志位数据,让ins_task填充姿态值. +// static Vision_Send_s send_data; static usart_instance vision_usart_instance; /** * @brief 接收解包回调函数,将在bsp_usart.c中被usart rx callback调用 - * @todo 1.提高可读性,将get_protocol_info的第四个参数增加一个float buffer + * @todo 1.提高可读性,将get_protocol_info的第四个参数增加一个float类型buffer * 2.添加标志位解码 */ static void DecodeVision() @@ -38,8 +41,10 @@ Vision_Recv_s* VisionInit(UART_HandleTypeDef *handle) /** * @brief 发送函数 - * @todo 1.提高可读性,将get_protocol_info的第四个参数增加一个float buffer + * @todo 1.提高可读性,将get_protocol_send_data的第6个参数增加一个float buffer * 2.添加标志位解码 + * 3.由于后续需要进行IMU-Cam的硬件触发采集控制,因此可能需要将发送设置为定时任务 + * 或由IMU采集完成产生的中断唤醒的任务,使得时间戳对齐. * * @param send 待发送数据 */ @@ -53,3 +58,9 @@ void VisionSend(Vision_Send_s *send) get_protocol_send_data(0x02, flag_register, &send->yaw, 3, send_buff, &tx_len); USARTSend(&vision_usart_instance, send_buff, tx_len); } + + +Vision_Recv_s* VisionGetcmd() +{ + return &recv_data; +} \ No newline at end of file diff --git a/modules/master_machine/master_process.h b/modules/master_machine/master_process.h index 4e79552..8338a40 100644 --- a/modules/master_machine/master_process.h +++ b/modules/master_machine/master_process.h @@ -22,4 +22,11 @@ Vision_Recv_s *VisionInit(UART_HandleTypeDef *handle); */ void VisionSend(Vision_Send_s *send); +/** + * @brief 返回所需的上位机数据 + * + * @return Vision_Recv_s* 数据结构体指针 + */ +Vision_Recv_s* VisionGetcmd(); + #endif // !MASTER_PROCESS_H \ No newline at end of file diff --git a/modules/master_machine/seasky_protocol.h b/modules/master_machine/seasky_protocol.h index bc3369a..2bdc180 100644 --- a/modules/master_machine/seasky_protocol.h +++ b/modules/master_machine/seasky_protocol.h @@ -6,7 +6,7 @@ #define PROTOCOL_CMD_ID 0XA5 -#define OFFSET_BYTE 8 //出数据段外,其他部分所占字节数 +#define OFFSET_BYTE 8 // 出数据段外,其他部分所占字节数 typedef enum { @@ -77,7 +77,7 @@ typedef struct float pitch; float roll; - // uint32_t time_stamp; + // uint32_t time_stamp; // @todo 用于和相机的时间戳对齐 } Vision_Send_s; typedef struct @@ -86,23 +86,23 @@ typedef struct { uint8_t sof; uint16_t data_length; - uint8_t crc_check; //帧头CRC校验 - } header; //数据帧头 - uint16_t cmd_id; //数据ID - uint16_t frame_tail; //帧尾CRC校验 + uint8_t crc_check; // 帧头CRC校验 + } header; // 数据帧头 + uint16_t cmd_id; // 数据ID + uint16_t frame_tail; // 帧尾CRC校验 } protocol_rm_struct; /*更新发送数据帧,并计算发送数据帧长度*/ -void get_protocol_send_data(uint16_t send_id, //信号id +void get_protocol_send_data(uint16_t send_id, // 信号id uint16_t flags_register, // 16位寄存器 - float *tx_data, //待发送的float数据 + float *tx_data, // 待发送的float数据 uint8_t float_length, // float的数据长度 - uint8_t *tx_buf, //待发送的数据帧 - uint16_t *tx_buf_len); //待发送的数据帧长度 + uint8_t *tx_buf, // 待发送的数据帧 + uint16_t *tx_buf_len); // 待发送的数据帧长度 /*接收数据处理*/ -uint16_t get_protocol_info(uint8_t *rx_buf, //接收到的原始数据 - uint16_t *flags_register, //接收数据的16位寄存器地址 - float *rx_data); //接收的float数据存储地址 +uint16_t get_protocol_info(uint8_t *rx_buf, // 接收到的原始数据 + uint16_t *flags_register, // 接收数据的16位寄存器地址 + float *rx_data); // 接收的float数据存储地址 #endif diff --git a/modules/motor/dji_motor.h b/modules/motor/dji_motor.h index cf4b3e8..ddd515a 100644 --- a/modules/motor/dji_motor.h +++ b/modules/motor/dji_motor.h @@ -2,13 +2,11 @@ * @file dji_motor.h * @author neozng * @brief DJI智能电机头文件 - * @version 0.1 + * @version 0.2 * @date 2022-11-01 * * @todo 1. 给不同的电机设置不同的低通滤波器惯性系数而不是统一使用宏 - 2. 当前电机初始化函数`DJIMotorInit()`稍显凌乱, - 应设置一个`dji_motor_init_config_s`结构体用于电机初始化,使得风格统一,提高可读性 - 3. 为M2006和M3508增加开环的零位校准函数 + 2. 为M2006和M3508增加开环的零位校准函数 * @copyright Copyright (c) 2022 HNU YueLu EC all rights reserved * @@ -28,13 +26,13 @@ /* DJI电机CAN反馈信息*/ typedef struct { - uint16_t ecd; + uint16_t ecd; // 0-8192 uint16_t last_ecd; - int16_t speed_rpm; - int16_t given_current; + int16_t speed_rpm; // rounds per minute + int16_t given_current; // 实际电流 uint8_t temperate; - int16_t total_round; - int32_t total_angle; + int16_t total_round; // 总圈数,注意方向 + int32_t total_angle; // 总角度,注意方向 } dji_motor_measure; /** @@ -66,19 +64,18 @@ typedef struct /** * @brief 调用此函数注册一个DJI智能电机,需要传递较多的初始化参数,请在application初始化的时候调用此函数 * 推荐传参时像标准库一样构造initStructure然后传入此函数. - * recommend: type xxxinitStructure = { - * .member1=xx, - * .member2=xx, - * ....}; + * recommend: type xxxinitStructure = {.member1=xx, + * .member2=xx, + * ....}; * 请注意不要在一条总线上挂载过多的电机(超过6个),若一定要这么做,请降低每个电机的反馈频率(设为500Hz), * 并减小DJIMotorControl()任务的运行频率. * * @attention M3508和M2006的反馈报文都是0x200+id,而GM6020的反馈是0x204+id,请注意前两者和后者的id不要冲突. * 如果产生冲突,在初始化电机的时候会进入IDcrash_Handler(),可以通过debug来判断是否出现冲突. - * + * * @param config 电机初始化结构体,包含了电机控制设置,电机PID参数设置,电机类型以及电机挂载的CAN设置 - * - * @return dji_motor_instance* + * + * @return dji_motor_instance* */ dji_motor_instance *DJIMotorInit(Motor_Init_Config_s config); diff --git a/modules/motor/dji_motor.md b/modules/motor/dji_motor.md index a931ce8..97c5a46 100644 --- a/modules/motor/dji_motor.md +++ b/modules/motor/dji_motor.md @@ -5,8 +5,7 @@ > TODO: > > 1. 给不同的电机设置不同的低通滤波器惯性系数而不是统一使用宏 -> 2. 当前电机初始化函数`DJIMotorInit()`稍显凌乱,应设置一个`dji_motor_init_config_s`结构体用于电机初始化,使得风格统一,提高可读性 -> 3. 为M2006和M3508增加开环的零位校准函数 +> 2. 为M2006和M3508增加开环的零位校准函数 diff --git a/modules/motor/step_motor.c b/modules/motor/step_motor.c new file mode 100644 index 0000000..e69de29 diff --git a/modules/motor/step_motor.h b/modules/motor/step_motor.h new file mode 100644 index 0000000..e69de29 diff --git a/modules/referee/referee.md b/modules/referee/referee.md new file mode 100644 index 0000000..e69de29 diff --git a/modules/remote/remote.md b/modules/remote/remote.md new file mode 100644 index 0000000..e69de29 diff --git a/modules/super_cap/super_cap.md b/modules/super_cap/super_cap.md new file mode 100644 index 0000000..e69de29