Lan Tian @ Blog

I'm starting to provide Chinese / English versions of some articles, switch with the Language menu above. 我开始提供部分文章的中文、英文翻译,请使用顶部语言菜单切换。

RoboMaster 开发踩坑日记(2018-05-28 更新)

学校组建了一支 RoboMaster 队伍,准备参加今年的比赛。因为是新校区新学生,因此我们完全没有之前的参考资料,只能自己一个个踩坑。

以下是我们在软件开发中遇到的一些坑。

硬件版本:RoboMaster 官方开发板(信仰板)
芯片型号:STM32F427IIHx
软件系统:ChibiOS 18.2.0

信仰板 HSE 时钟频率为 12MHz 而非常见的 8MHz

最坑的是信仰板的说明书和硬件原理图上完全没有提到这事。

这个问题导致我们用 STM32CubeMX 等软件算出的时钟频率远高于额定频率,并导致了如下后果:

  • 莫名其妙的频率设置失败(设置了在合理范围内的频率,但是板子不响应了,只能短接某个电阻 Reset)
  • USART 时序错误(明明两端波特率一样,但是收发的数据就是乱码,遥控器无法使用)
  • CAN 数据无法应答(明明板子和电机电调都在发数据,示波器能解码出来,但是双方就是不 ACK)

以上问题在重新调整时钟频率后全部解决。

while(true); 发送 CAN 报文必须加延时

这是一个小问题。CAN 通信时所有设备都在一条总线上,同时只能有一台设备发送信息。如果 while(true); 发送信息不加延时,会导致其它设备没有机会发送信息,开发板自然就收不到它们的回复了。

加个 chThdSleepMilliseconds(100); 就能解决这个问题。

STM32 不能同时使用 CAN 和 USB

因为信仰板上的 UART 接口不是裸露的针,是某种接口,而我们没有线,因此我们尝试使用 ChibiOS 的 Serial over USB 功能,即通过 USB 接口模拟串口进行调试。

在尝试两个小时未果后仔细搜寻资料,发现 CAN 和 USB 不能同时使用,CAN 优先级高于 USB。

而我们必须使用 CAN 和各种电机通信,因此……我们只能继续闪灯调试了。

主线程 while(true); 堵死子线程

队友把主要逻辑(判断按键,驱动电机等)都写在另一个线程,主线程初始化完后就启动那个线程然后 while(true); 什么都不干。然后队友发现必须把逻辑线程的优先级提升到正常优先级 +2 才能正常执行,否则不运行。

我简单研究后得出结论:ChibiOS 主线程优先级是正常 +1,并且 while(true); 也在消耗 CPU,并且堵死了同等优先级或者更低优先级的其它线程。解决方法是把主线程改成 while(true) chThdSleepMilliseconds(1000);,让它去 sleep,让 ChibiOS 调度其它任务就能解决问题。

大疆文档里某几个键顺序写反

Q、E、Shift、Ctrl 四个键,以 4 个 bit 一一对应的形式传给开发板,文档的顺序是高位到低位 Q、E、Shift、Ctrl,但实测是 Ctrl、Shift、E、Q。(差点被车撞飞)

谜之数据类型转换

队友写了机器人底盘的 PID 调速,然后发现只要轮子一动,无论哪个方向,都会全速向电机反转方向加速。

经过两个小时的调试,发现队友有类似下图的代码:

uint8_t x = 0xff; // 电机返回数据示例
uint8_t y = 0x8f; // 返回的数据分成了两个 uint8_t
int a = (x << 8 | y); // 队友的代码

此处 int 为 int32_t。

我们希望得到的值是 0xffffff8f,即 -113;运行上述代码,实际上 C 在前面补了 0,得到的 a 是 0x0000ff8f,即 65423。因此 PID 认为电机以非常快的速度在运行,并作出了诡异的调节。

C 这么做是因为 x << 8 这一步生成了一个 4 byte 的变量:

int c = sizeof(x << 8); // c = 4

然后或操作的实际对象是 0x0000ff00 和 0x8f,得 0x0000ff8f。

另外,拼接 uint16_t 时不会出现这样的现象:

uint16_t x = 0xffff;
uint16_t y = 0xff8f;
int64_t a = (x << 16 | y); // a = -113

因为 x << 16 = 0xffff0000,所以 a = 0xffffff8f = -113。

对于原来的问题,修改方法就是把 int 替换成 int16_t:

int16_t a = (x << 8 | y);

此时 a 为 0xff8f,即 -113,符合预期。

NAT64 服务器搭建
下一篇文章 »