diff --git a/HAL_N_Middlewares/Src/stm32f4xx_it.c b/HAL_N_Middlewares/Src/stm32f4xx_it.c index 4678211..be8484d 100644 --- a/HAL_N_Middlewares/Src/stm32f4xx_it.c +++ b/HAL_N_Middlewares/Src/stm32f4xx_it.c @@ -112,6 +112,7 @@ void HardFault_Handler(void) /* USER CODE END HardFault_IRQn 0 */ while (1) { + asm("bx lr"); /* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */ } diff --git a/README.md b/README.md index af19f8a..9204efe 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ VSCode可通过Cortex-Debug利用OpenOCD进行调试,jlink/stlink/dap-link都支持,具体的使用方法和环境配置教程在[VSCode+Ozone使用方法](./VSCode+Ozone使用方法.md)中。**请使用UTF-8编码查看\&编辑此项目**。 - - **分层**: 本框架主要代码分为**BSP、Module、APP**三层。三层的代码分别存放在同名的三个文件夹中,这三个文件夹存放在根目录下。开发过程中主要编写APP层代码,Module层与BSP层不建议修改。如需添加module(如oled屏幕、其他传感器和外设等),请按照规范编写并联系组长提交commit到dev分支或对应的功能名分支,完善后合并至主分支。在配置git的时候,将自己的`user.name`配置成英文缩写或易懂的nick name。 @@ -104,8 +103,6 @@ } CANInstance; ``` - - ## BSP层(Board Sopport Package) - TODO: @@ -165,21 +162,20 @@ Module层主要存放的是类型定义和实例指针数组,在该层没有 ## APP层(application) - - 功能:实现机器人的控制,对机器人**控制**结构进行抽象。 +- 功能:实现机器人的控制,对机器人**控制**结构进行抽象。 在完成BSP层和Module层后,如果在APP层没有控制代码,则代码并无实际功能。换言之,BSP层与Module层的存在是为了APP层更简单、更合理、更易于扩展和移植。本框架的初始目标即是实现:在APP层仅需思考逻辑并用无关硬件的C语言代码实现即可完成整个机器人的控制。所有需要使用的模块和算法都在Module层提供,硬件的抽象在bsp层完成。**所有使用到的模块都在APP层初始化**,因此不需要module自行初始化。 - - APP层按照机械设计结构(如云台、发射、底盘)建立对应的子文件夹,在其中完成初始化和相关逻辑功能的编写。还有用于发布指令的云台指令应用和底盘指令应用,前者应该包含一个遥控器模块和一个视觉通信模块,后者包含裁判系统模块。它们包含的模块都会处理一些指令和控制信息,因此将这两个应用从云台和底盘应用中隔离出来。这样还可以方便兼容双板。 +- APP层按照机械设计结构(如云台、发射、底盘)建立对应的子文件夹,在其中完成初始化和相关逻辑功能的编写。还有用于发布指令的云台指令应用和底盘指令应用,前者应该包含一个遥控器模块和一个视觉通信模块,后者包含裁判系统模块。它们包含的模块都会处理一些指令和控制信息,因此将这两个应用从云台和底盘应用中隔离出来。这样还可以方便兼容双板。 - - 单双板切换在application的`robot_def.h`中进行,**修改宏定义可以切换开发板的设定模式**。当设定为单板的时候,在`robot.c`中会对gimbal,chassis,shoot,gimbal_cmd,chassis_cmd五个应用都进行初始化。对于双板的情况,需要将上板配置为gimbal board,下板配置为chassis board,它们会分别初始化gimbal/shoot/gimbal_cmd和chassis/chassis_cmd。 +- 单双板切换在application的`robot_def.h`中进行,**修改宏定义可以切换开发板的设定模式**。当设定为单板的时候,在`robot.c`中会对gimbal,chassis,shoot,gimbal_cmd,chassis_cmd五个应用都进行初始化。对于双板的情况,需要将上板配置为gimbal board,下板配置为chassis board,它们会分别初始化gimbal/shoot/gimbal_cmd和chassis/chassis_cmd。 - - 对于单板的情况,所有应用之间的信息交互通过message center完成。而使用双板时,需要通过板间通信传递控制信息(默认遥控器接收机和pc在云台板,裁判系统在底盘板,因此需要互发信息)。当前通过**条件编译**来控制信息的去向(发往message center/接收,还是通过can comm发送/接收),后续考虑将双板通信纳入message center的实现中,根据`robot_def.h`的开发板定义自动处理通信,降低应用层级的逻辑复杂度。 - - +- 对于单板的情况,所有应用之间的信息交互通过message center完成。而使用双板时,需要通过板间通信传递控制信息(默认遥控器接收机和pc在云台板,裁判系统在底盘板,因此需要互发信息)。当前通过**条件编译**来控制信息的去向(发往message center/接收,还是通过can comm发送/接收),后续考虑将双板通信纳入message center的实现中,根据`robot_def.h`的开发板定义自动处理通信,降低应用层级的逻辑复杂度。 ## 文件树 板级支持包的每个组件,每个moduel,以及每个app都有对应的说明文档. + ```shell ROOT:. │ .gitignore # git版本管理忽略文件 @@ -394,14 +390,10 @@ ROOT:. vofa.h ``` - - ## BSP/Module/Application介绍 在对应应用、模块和板级支持包文件夹下。每个.c文件或完整的功能模块都有说明文档。在编写新代码时注意按照规范编写说明文档。 - - ## 整体架构 ### 软件分层 @@ -424,4 +416,3 @@ HAL库初始化 --> BSP初始化 --> Application初始化 --> app调用其拥有 APP会调用其所有的模块的初始化函数(注册函数),这是因为本框架的设计思想是任何模块在被注册(构造/初始化)之前,都是不存在的,当且仅当定义了一个模块结构体(也称实例)的时候,才有一个实体的概念。 main函数唯一需要的函数是app层的`robot.c`中的`RobotInit()`函数,它首先会调用BSP初始化,然后进行所有应用的初始化;每个应用会调用对应模块的初始化;一些依赖通信外设的模块会将通信支持相关的bsp进行初始化。初始化结束之后实时系统启动。 - diff --git a/TODO.md b/TODO.md index 131efdd..33e5fe7 100644 --- a/TODO.md +++ b/TODO.md @@ -89,7 +89,7 @@ #### LQR -- [ ] 通用的LQR控制器 +- [ ] 通用的LQR控制器(矩阵运算) @@ -183,8 +183,7 @@ #### ==robot_cmd== -- [ ] 键盘控制 -- [ ] 鼠标控制 +- [ ] 键鼠控制 - [x] 双板兼容(待测试) #### ==chassis== diff --git a/VSCode+Ozone使用方法.md b/VSCode+Ozone使用方法.md index adfd154..ac7531a 100644 --- a/VSCode+Ozone使用方法.md +++ b/VSCode+Ozone使用方法.md @@ -267,7 +267,7 @@ typedef struct > **如果你使用basic_framework,不需要重新生成代码。** - +- **建议将ozone和jlink的目录一同加入环境变量,方便我们后续的一键下载和一键调试配置** ## VSCode编译和调试配置 @@ -483,18 +483,20 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 2. Hex Editor,在查看汇编代码和机器代码的时候,提供2、10、16进制转换,并且可以以16进制或2进制的格式编辑文件。 -3. GitLens,提供强大的可视化Git支持 +3. GitLens和git graph,提供强大的可视化commit记录和UI支持 -4. Blockman - Highlight Nested Code Blocks 此插件会高亮嵌套的代码块(即花括号包围的部分或for/while/ifelse代码块) +4. Blockman - Highlight Nested Code Blocks 此插件会高亮嵌套的代码块(即花括号包围的部分或for/while/ifelse代码块),对于多层条件和循环嵌套效果非常炸裂 -5. bookmark提供代码中插入书签的功能,从而快速在页面间跳转。 +5. bookmark 提供代码中插入书签的功能,从而快速在页面间跳转。 6. Code Issue Manager,为团队提供issues和todo管理,方便协同开发 -7. github copilot:超强,超快,需要一些小钱 +7. github copilot:超强,超快,需要一些小钱(10块用一年!你也可以在github上申请student pack,需要学信网认证和学生卡,但有一定概率无法通过) 在插件中你也可以找到一些免费的copilot替代品。 8. `ctrl+k ctrl+s`配置属于你的快捷键,提高效率! +9. live share,和你的小伙伴一起结对编程 + @@ -575,7 +577,7 @@ Project.SetOSPlugin(“plugin_name”) ![image-20221119174445067](assets/image-20221119174445067.png) -我们的项目是F4的板子,内核时Cortex-M4(CM4),因此选用`FreeRTOSPlugin_CM4.js`(输入的时候js后缀不用输)。 +我们的项目是F4的板子,内核时Cortex-M4(CM4),因此选用`FreeRTOSPlugin_CM4.js`(输入的时候js后缀不用输)。 ozone默认输入的命令似乎有误,需要手动修改(这好像和ozone的版本有关,请留意) ### 常用调试窗口和功能 @@ -672,6 +674,14 @@ CPU选项卡可以查看CPU的寄存器。 | 右键+break on change | 当变量发生变化的时候进入此断点 | | ctrl+H | 展示调用图,会列出该函数调用的所有函数(内部调用栈) | +如果你使用拥有多个按键的鼠标,推荐将侧键前设置为ctrl+点击以查看声明/定义,侧键后设置为添加到watch(debug),侧滚轮设置为前进后退(历史) + +你还可以按ctrl+K ctrl+S进入快捷键设置页面,将tab设置为下一个提示,用enter接受intelliSense建议,这样不需要将手移出主键盘区域. 将ctrl+;设置为移动到行尾,同时打开c/c++的函数括号不全,这样不需要手动敲击括号. + +将alt+k设置为左移,alt+l设置为右移,这样不需要方向键. + +选择最适合自己的配置! + ### 保存调试项目 退出时可以将调试项目保存在项目的根目录下,方便下次调试使用,不需要重新设置。可以为jlink和daplink分别保存一套调试配置。 @@ -883,6 +893,7 @@ $(BUILD_DIR): # 如果makefile所处的文件目录下没有build文件夹,这 ####################################### clean: rm -r $(BUILD_DIR) +# 你的makefile可能会使用cmd而不是powershell来调用内核,而cmd不支持rm命令,因此可能要修改为rd (remove directory),cmd传入参数的方式为 /x ,x为要传入的参数 ####################################### diff --git a/bsp/can/bsp_can.c b/bsp/can/bsp_can.c index 62a7edf..50f28ed 100644 --- a/bsp/can/bsp_can.c +++ b/bsp/can/bsp_can.c @@ -92,9 +92,13 @@ CANInstance *CANRegister(CAN_Init_Config_s *config) uint8_t CANTransmit(CANInstance *_instance,uint8_t timeout) { float dwt_start = DWT_GetTimeline_ms(); - while (HAL_CAN_GetTxMailboxesFreeLevel(_instance->can_handle) == 0) // 等待邮箱空闲 + while (HAL_CAN_GetTxMailboxesFreeLevel(_instance->can_handle) == 0);// 等待邮箱空闲 + { if (DWT_GetTimeline_ms() - dwt_start > timeout) // 超时 + { return 0; + } + } // tx_mailbox会保存实际填入了这一帧消息的邮箱,但是知道是哪个邮箱发的似乎也没啥用 HAL_CAN_AddTxMessage(_instance->can_handle, &_instance->txconf, _instance->tx_buff, &_instance->tx_mailbox); return 1; // 发送成功 diff --git a/bsp/usb/bsp_usb.h b/bsp/usb/bsp_usb.h index 4ee7af2..16dd758 100644 --- a/bsp/usb/bsp_usb.h +++ b/bsp/usb/bsp_usb.h @@ -10,7 +10,7 @@ * @copyright Copyright (c) 2023 * */ - +#pragma once #include "usb_device.h" #include "usbd_cdc.h" #include "usbd_conf.h" @@ -22,4 +22,4 @@ uint8_t *USBInit(); // bsp初始化时调用会重新枚举设备 -void USBTransmit(uint8_t *buffer, uint16_t len); // 通过usb发送数据 +void USBTransmit(uint8_t *buffer, uint16_t len); // 通过usb发送数据 \ No newline at end of file diff --git a/modules/encoder/encoder.md b/modules/encoder/encoder.md new file mode 100644 index 0000000..65a08e8 --- /dev/null +++ b/modules/encoder/encoder.md @@ -0,0 +1,6 @@ +# encoder + +提供对光电和霍尔磁编码器的支持. + +可能需要新增bsp_tim以提供period lapse和tim编码器计数的功能. + diff --git a/modules/motor/DJImotor/dji_motor.h b/modules/motor/DJImotor/dji_motor.h index 8fc0c6c..03c64d7 100644 --- a/modules/motor/DJImotor/dji_motor.h +++ b/modules/motor/DJImotor/dji_motor.h @@ -6,7 +6,8 @@ * @date 2022-11-01 * * @todo 1. 给不同的电机设置不同的低通滤波器惯性系数而不是统一使用宏 - 2. 为M2006和M3508增加开环的零位校准函数 + 2. 为M2006和M3508增加开环的零位校准函数,并在初始化时调用(根据用户配置决定是否调用) + 3. 完成前馈功能(已经添加了前馈数据指针) * @copyright Copyright (c) 2022 HNU YueLu EC all rights reserved * diff --git a/modules/motor/DJImotor/dji_motor.md b/modules/motor/DJImotor/dji_motor.md index b383020..49dff38 100644 --- a/modules/motor/DJImotor/dji_motor.md +++ b/modules/motor/DJImotor/dji_motor.md @@ -177,7 +177,7 @@ void DJIMotorChangeFeed(dji_motor_instance *motor, Feedback_Source_e type); ``` -调用第一个并传入设定值,它会自动根据你设定的PID参数进行动作。 +调用第一个并传入设定值,它会自动根据你设定的PID参数进行动作。 如果对不同闭环都有参考输入,则设置最外层的闭环(通过此函数)并将剩下的参考输入通过前馈数据指针进行设定 调用第二个并设定要修改的反馈环节和反馈类型,它会将反馈数据指针切换到你设定好的变量(需要在初始化的时候设置反馈指针)。 diff --git a/modules/motor/HTmotor/HT04.c b/modules/motor/HTmotor/HT04.c index 5272b04..c07934a 100644 --- a/modules/motor/HTmotor/HT04.c +++ b/modules/motor/HTmotor/HT04.c @@ -6,17 +6,17 @@ static uint8_t idx; HTMotorInstance *ht_motor_instance[HT_MOTOR_CNT]; /** - * @brief + * @brief 设置电机模式,报文内容[0xff,0xff,0xff,0xff,0xff,0xff,0xff,cmd] * * @param cmd * @param motor */ static void HTMotorSetMode(HTMotor_Mode_t cmd, HTMotorInstance *motor) -{ - static uint8_t buf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; - buf[7] = (uint8_t)cmd; - memcpy(motor->motor_can_instace->tx_buff, buf, sizeof(buf)); - CANTransmit(motor->motor_can_instace,1); +{ + memset(motor->motor_can_instace->tx_buff, 0xff, 7); // 发送电机指令的时候前面7bytes都是0xff + motor->motor_can_instace->tx_buff[7] = (uint8_t)cmd; // 最后一位是命令id + CANTransmit(motor->motor_can_instace, 1); + memset(motor->motor_can_instace->tx_buff, 0, 6); // 发送控制指令的时候前面6bytes都是0 } /* 两个用于将uint值和float值进行映射的函数,在设定发送值和解析反馈值时使用 */ @@ -53,7 +53,7 @@ static void HTMotorDecode(CANInstance *motor_can) measure->total_angle = RAD_2_ANGLE * uint_to_float(tmp, P_MIN, P_MAX, 16); tmp = (uint16_t)((rxbuff[3] << 4) | (rxbuff[4] >> 4)); - measure->speed_aps = RAD_2_ANGLE * SPEED_SMOOTH_COEF * uint_to_float(tmp, V_MIN, V_MAX, 12) + + measure->speed_aps = SPEED_SMOOTH_COEF * uint_to_float(tmp, V_MIN, V_MAX, 12) + (1 - SPEED_SMOOTH_COEF) * measure->speed_aps; tmp = (uint16_t)(((rxbuff[4] & 0x0f) << 8) | rxbuff[5]); @@ -102,7 +102,7 @@ void HTMotorControl() motor = ht_motor_instance[i]; measure = &motor->motor_measure; setting = &motor->motor_settings; - motor_can = motor_can; + motor_can = motor->motor_can_instace; pid_ref = motor->pid_ref; if ((setting->close_loop_type & ANGLE_LOOP) && setting->outer_loop_type == ANGLE_LOOP) @@ -111,8 +111,8 @@ void HTMotorControl() pid_measure = *motor->other_angle_feedback_ptr; else pid_measure = measure->real_current; - - pid_ref = PID_Calculate(&motor->angle_PID, pid_measure, pid_ref); + // measure单位是rad,ref是角度,统一到angle下计算,方便建模 + pid_ref = PID_Calculate(&motor->angle_PID, pid_measure*RAD_2_ANGLE, pid_ref); } if ((setting->close_loop_type & SPEED_LOOP) && setting->outer_loop_type & (ANGLE_LOOP | SPEED_LOOP)) @@ -124,8 +124,8 @@ void HTMotorControl() pid_measure = *motor->other_speed_feedback_ptr; else pid_measure = measure->speed_aps; - - pid_ref = PID_Calculate(&motor->angle_PID, pid_measure, pid_ref); + // measure单位是rad / s ,ref是angle per sec,统一到angle下计算 + pid_ref = PID_Calculate(&motor->speed_PID, pid_measure*RAD_2_ANGLE, pid_ref); } if (setting->close_loop_type & CURRENT_LOOP) @@ -140,26 +140,29 @@ void HTMotorControl() if (setting->reverse_flag == MOTOR_DIRECTION_REVERSE) set *= -1; - tmp = float_to_uint(set, T_MIN, T_MAX, 12); - motor_can->tx_buff[6] = tmp >> 8; + LIMIT_MIN_MAX(set, T_MIN, T_MAX); // 限幅,实际上这似乎和pid输出限幅重复了 + tmp = float_to_uint(set, T_MIN, T_MAX, 12); // 数值最后在 -12~+12之间 + motor_can->tx_buff[6] = (tmp >> 8); motor_can->tx_buff[7] = tmp & 0xff; if (motor->stop_flag == MOTOR_STOP) { // 若该电机处于停止状态,直接将发送buff置零 memset(motor_can->tx_buff + 6, 0, sizeof(uint16_t)); } - CANTransmit(motor_can,1); + CANTransmit(motor_can, 1); } } void HTMotorStop(HTMotorInstance *motor) { HTMotorSetMode(CMD_RESET_MODE, motor); + motor->stop_flag = MOTOR_STOP; } void HTMotorEnable(HTMotorInstance *motor) { HTMotorSetMode(CMD_MOTOR_MODE, motor); + motor->stop_flag = MOTOR_ENALBED; } void HTMotorCalibEncoder(HTMotorInstance *motor) diff --git a/modules/motor/HTmotor/HT04.h b/modules/motor/HTmotor/HT04.h index 4279771..ed5b061 100644 --- a/modules/motor/HTmotor/HT04.h +++ b/modules/motor/HTmotor/HT04.h @@ -18,9 +18,9 @@ #define T_MAX 18.0f typedef struct // HT04 -{ // 角度为多圈角度,范围是-95.5~95.5,单位为rad - float last_angle; - float total_angle; +{ + float last_angle; + float total_angle; // 角度为多圈角度,范围是-95.5~95.5,单位为rad float speed_aps; float real_current; } HTMotor_Measure_t; diff --git a/modules/motor/motor_task.c b/modules/motor/motor_task.c index 1431d9c..91f0034 100644 --- a/modules/motor/motor_task.c +++ b/modules/motor/motor_task.c @@ -11,14 +11,14 @@ void MotorControlTask() // static uint8_t cnt = 0; 设定任务频率 // if(cnt%5==0) //200hz // if(cnt%10==0) //100hz - DJIMotorControl(); - //LKMotorControl(); + /* 如果有对应的电机则取消注释,可以加入条件编译或者register对应的idx判断是否注册了电机 */ + LKMotorControl(); - //HTMotorControl(); + HTMotorControl(); - //ServeoMotorControl(); + ServeoMotorControl(); //StepMotorControl(); } diff --git a/modules/motor/motor_task.h b/modules/motor/motor_task.h index 94bdf77..214d3c1 100644 --- a/modules/motor/motor_task.h +++ b/modules/motor/motor_task.h @@ -16,6 +16,8 @@ * @brief 电机控制闭环任务,在RTOS中应该设定为1Khz运行 * 舵机控制任务的频率设定为20Hz或更低 * + * @note 好无语,就一个函数罢了,干脆全部放到头文件里好了. + * */ void MotorControlTask(); diff --git a/modules/motor/servo_motor/servo_motor.c b/modules/motor/servo_motor/servo_motor.c index 5efded4..41145d0 100644 --- a/modules/motor/servo_motor/servo_motor.c +++ b/modules/motor/servo_motor/servo_motor.c @@ -80,7 +80,7 @@ void Servo_Motor_Type_Select(ServoInstance *Servo_Motor, int16_t mode) * @brief 舵机输出控制 * */ -void Servo_Motor_Control() +void ServeoMotorControl() { static ServoInstance *Servo_Motor; diff --git a/modules/motor/servo_motor/servo_motor.h b/modules/motor/servo_motor/servo_motor.h index d64180c..319161d 100644 --- a/modules/motor/servo_motor/servo_motor.h +++ b/modules/motor/servo_motor/servo_motor.h @@ -86,5 +86,5 @@ typedef struct ServoInstance *ServoInit(Servo_Init_Config_s *Servo_Init_Config); void Servo_Motor_FreeAngle_Set(ServoInstance *Servo_Motor, int16_t S_angle); void Servo_Motor_Type_Select(ServoInstance *Servo_Motor,int16_t mode); -void Servo_Motor_Control(); +void ServeoMotorControl(); #endif // SERVO_MOTOR_H \ No newline at end of file diff --git a/modules/motor/servo_motor/servo_motor.md b/modules/motor/servo_motor/servo_motor.md index 303277a..12d1079 100644 --- a/modules/motor/servo_motor/servo_motor.md +++ b/modules/motor/servo_motor/servo_motor.md @@ -1,6 +1,10 @@ ##舵机的使用 +

panrui@hnu.edu.cn

+ +> todo: 由于新增了bsp_pwm的支持,舵机模块需要部分重构 ### 舵机基础知识 + 已最常见的SG90舵机为例,SG90舵机要求工作在频率为50HZ——周期为20ms的PWM波,且对应信号的高低电平在0.5ms - 2.5ms之间,对应的舵机转动角度如下表所示(当然也可以按照这个线性的对应关系去达到转动自己想要的角度,如想要转动60°,则高电平脉宽为大概为1.2ms,具体能不能转到特定的角度还和舵机的精度有关) >0.5ms-------------0度; 2.5% diff --git a/task.ps1 b/task.ps1 index 210daeb..13eee81 100644 --- a/task.ps1 +++ b/task.ps1 @@ -1,3 +1,5 @@ +# 推荐安装powershell7 以获得更好的shell体验! + JLinkGDBServer: $(Q)JLinkGDBServer -select USB -device $(CHIP) \ diff --git a/必须做&禁止做.md b/必须做&禁止做.md index ba8458a..d40c81a 100644 --- a/必须做&禁止做.md +++ b/必须做&禁止做.md @@ -1,3 +1,9 @@ -# 禁止在临界区使用延时,这会导致因中断关闭定时器无法进入中断更新时间,进而卡死系统 +# 禁止在临界区使用延时,这会导致因中断关闭使得定时器无法进入中断更新时间,进而卡死系统 + +除非你使用的是基于计数寄存器差值的延时方法,或阻塞式的for延时 # 禁止摸鱼 + +提供工作效率! + +# \ No newline at end of file