mirror of
https://gitee.com/dlmu-cone/bf_original_balance_chassis
synced 2026-07-25 03:47:47 +08:00
删除了message center的指针传递支持,增加了定位bug的技巧文档
This commit is contained in:
73
如何定位bug.md
73
如何定位bug.md
@@ -85,6 +85,77 @@ long long的范围比float小。无符号和有符号数直接转换可能变成
|
||||
|
||||
**宏只在当前文件生效**,如果宏放在.c那么对其他的文件是不可见的,这也一般称作私有宏。
|
||||
|
||||
|
||||
|
||||
## 典型debug案例
|
||||
|
||||
这是一个结合了软件和硬件且多模块耦合的异常。
|
||||
这是一个结合了软件和硬件且有多模块耦合的异常。该bug发生在调试平衡步兵的底盘过程当中。
|
||||
|
||||
### 引发bug的原因
|
||||
|
||||
1. 指针在强制类型转换中变成了错误的类型,使得指向的内存地址被错误地修改
|
||||
2. CAN总线负载过大导致电机反馈消息丢失
|
||||
|
||||
这里是发生bug的代码片段:
|
||||
|
||||
```c
|
||||
static void LKMotorDecode(CANInstance *_instance)
|
||||
{
|
||||
static LKMotor_Measure_t *measure;
|
||||
static uint8_t *rx_buff;
|
||||
rx_buff = _instance->rx_buff;
|
||||
measure = &((LKMotorInstance *)_instance)->measure; // 通过caninstance保存的id获取对应的motorinstance
|
||||
// 上面一行应为: measure = &(((LKMotorInstance *)_instance->id)->measure);
|
||||
measure->last_ecd = measure->ecd;
|
||||
measure->ecd = ...
|
||||
|
||||
// ....
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
这是问题1的出处。can instance中保存了父指针,即拥有该instance的LKMotorInstance。这里想通过强制类型转换将`void*`类型的`id`转换成电机的instance指针类型并访问其measure成员变量以从CAN反馈的报文中更新量测值。然而却直接将can instance转换成motor instance。
|
||||
|
||||
随后,更新之后的数据被覆写到can instance内部,使得其成员变量改变,包括hcan、txbuf、rxbuf、tx/rxlen等。hcan是HAL定义的can句柄类型,里面保存了指向can状态和控制寄存器的指针以及其他HAL状态信息,然而其值被电机反馈回来的值覆写,之后HAL的接口访问hcan时将引起异常。
|
||||
|
||||
第二个问题则不是显式存在的:
|
||||
|
||||
```c
|
||||
void MotorControlTask()
|
||||
{
|
||||
DJIMotorControl();
|
||||
|
||||
HTMotorControl();
|
||||
|
||||
LKMotorControl();
|
||||
|
||||
ServeoMotorControl();
|
||||
|
||||
StepMotorControl();
|
||||
}
|
||||
```
|
||||
|
||||
这是motortask的内容,此任务将以500hz的频率运行。在发生bug时,我们将4个HT04电机和2个LK MF9025电机全部连接到CAN1上。注意,HT04不支持多电机指令,因此占用的带宽较大。在`LKMotorControl()`完成参考值计算和CAN发送之后立刻会调用`HTMotorControl()`,后者需要连续发送4条报文。而HT和LK电机都会在接收到控制指令之后发送反馈信息报文。由于HT电机的控制在LK电机控制之后立刻执行,导致总线被占据,LK电机发送的反馈数据仲裁失败无法获得总线占有权,使得主机收不到反馈数据。
|
||||
|
||||
|
||||
|
||||
### bug的发现和定位的尝试
|
||||
|
||||
程序的大体情况如下,当时进行轮足式倒立摆机器人的测试,启用了balance.c,在其中注册了4个HT04电机(can1)和2个LK9025电机(can2)。控制报文的发送频率均为500Hz。
|
||||
|
||||
测试时发现,9025电机可以接收到mcu发送的控制指令并响应,但是mcu始终无法获得反馈值,`LKMotorInstance->measure`的所有成员变量一直是零。由于CAN是总线架构,电机能接收到数据说明通信正常。HT04电机也可以正常控制并收到反馈信息。在`LKMotorDecode()`函数中添加断点发现能够成功进入1~2次,随后便引发HardFault。
|
||||
|
||||
此时内心有些动摇,开始检查硬件连线。我们尝试把LK电机也挂载到CAN1总线上。开始单步调试,发现LK电机可以正常接收一次反馈报文,之后就进入`Hardfault_handler()`。HT和DJI电机均无此问题。进一步进行每条指令的调试,发现在成功接收到一次报文之后(接收报文指的是can发生中断并在处理函数中调用LK电机的解码函数,我们并没有查看measure值是否刷新,实际上这时候反馈值仍然为零),进入该电机的控制报文发送时,通过在`Hardfault_handler()`中添加汇编语句`asm("bx lr")`,即跳转到最后一次执行的指令,发现访问`hcan->state`会引起硬件错误。遇到这种情况,说明发生了越界访问或使用了野指针。检查hcan的值,发现是一个非常大的地址。因此怀疑hcan指针被其他的内存访问语句修改。
|
||||
|
||||
有了方向之后,进一步对每一个函数都进行单步进入调试,同时时刻监测hcan1的值。然而,这时候出现即使一开始就单步调试也无法进入LK电机解码函数的问题。于是,怀疑是CAN过滤器的配置问题,使得LK电机反馈报文被过滤,检查LK的接收id无误后,认为可能由于LK电机的发送和接收ID都比较大(0x140和0x280),CAN标准ID放不下。但是查阅CAN specification后发现standar ID可以容纳11位的值,应该不会有问题。于是把过滤器配置为mask模式,让bxCAN控制器接收所有报文(即不进行过滤)。然而还是不奏效,仍然无法收到数据。
|
||||
|
||||
这时候想起HT电机是不支持多电机控制指令的,因此500Hz的控制频率似乎有些过高,相当于2ms内要完成2x4+1+2=11次CAN报文的发送。计算1M波特率下最大通信速率,果然超出了负载。于是降低`MotorTask()`的频率为200Hz,果然能重新接收到数据了。
|
||||
|
||||
继续单步调试,终于发现在`LKMotorDecode()`中,通过强制类型转换获取LKMotorInstance的时候,用错了变量,使得反馈值被写入电机的`CANInstance`内,导致hcan指向随机的地址,最终造成访问时引发hardfault。
|
||||
|
||||
修改之后,将LK电机挂载到CAN2上,控制频率回到500Hz,程序正常运行。
|
||||
|
||||
### 解决方案
|
||||
|
||||
均衡总线负载,调节任务运行时间。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user