zl程序教程

您现在的位置是:首页 >  工具

当前栏目

RT-Thread GCC VSCode等开源工具链 在智能小车制作中的应用

VSCode应用工具开源智能 制作 thread gcc
2023-09-11 14:15:18 时间

学 校: 山东大学(威海)
队伍名称: 海韵五队
参赛队员: 崔海勤、刘子晖、赵润萌
带队教师: 王小利

简 介: 社会的不断进步与发展,伴随的是对自动化技术需求的不断增加,同时自动化程序也呈现出任务复杂化和性能要求高的特点。由此而产生的智能汽车比赛,可以很好的将工程实践带入到学习中,帮助大学生快速掌握实践中的技巧。

为防止克隆车老爷车的出现,同时也为了竞赛趣味性,大赛组委会不断新增和调整赛题任务,使得当前的智能车比赛中小车需要完成的任务不断变多,且内容也变得更加复杂。面对这种问题,将工程思想、方案和前沿的科技带入到小车制作中是刻不容缓的。

RT-Thread 提供的多线程支持,及其配套的内存管理,数据同步,控制台等功能,可以有效的拆分程序代码,提升代码可维护性,并且提升重要任务的执行性能,降低开发复杂性。

出于对版权的尊重和对开源软件的热爱,以及对现实情况的妥协。我们采用了几乎全套的开源方案。基于逐飞科技提供的 RT-Thread 库,我们对其进行了 GCC 编译器适配调优,同时做了 VSCode 整合,使得不使用任何商业软件进行开发成为可能。该方案曾提交到智能车相关的公开博客,供全体参赛队伍参考,且代码已经在 GitHub 上开源。

本文针对该方案的具体实现以及其在我们团队的智能车制作中的实际使用情况与相应的改进方式作出论述。

关键词 智能车比赛RT-ThreadGCCVSCode

 

§01 RT-Thread调试应用


1.1 解决显示屏显示影响小车性能问题

在实际调车中,会发现,如果关闭显示屏的输出,车辆的响应性能,即每秒处理的图像帧数会有明显的提升。这是因为,单片机与显示屏通信需要占据大量的时间。但又由于显示屏有其重要的调试作用,并不可以简单粗暴的禁用它。故最好的解决方式是降低显示屏刷新输出的频率,即让图像处理与显示屏刷新的次数不一致。

传统大循环的方式,实现这种任务需要在主循环里写复杂的代码,如每两个周期调用一次显示屏刷新函数。但该方式仍然存在瞬卡的问题,即两次图像处理间隙过长,因为显示刷新的过程为一个整体,中间不可中断(不使用定时器)。

RT-Thread 通过 SysTick 和栈切换实现的线程切换很好的解决了这个问题,图像处理间的时间空隙是可预期的,更可通过设置线程优先级的方式保障高优先级任务在指定的时间内可以执行完毕,体现出实时操作系统在解决这种问题时的重要作用。

1.2 拆分功能代码

实践中,随着功能不断变多,需要对代码进行合理的组织。使用 RT-Thread 的线程功能,可以将不同功能的代码拆分开来,提升内聚度,降低代码耦合度。

我们将代码拆分为如下几个模块,并分别对其建立线程:

  • main 线程(RT-Thread 自带),初始化各个硬件模块,并且初始化线程
  • finsh 线程(RT-Thread 自带)
  • autopilot 线程,负责方向控制,执行图像算法(由于我们队伍的小车是纯视觉车,没有电磁相关处理),从图像中获取赛道当前曲率,并控制主舵机的角度。
  • engine 线程,负责速度控制,主要运行 PID 算法,从编码器中获取速度数据,并且根据当前打角曲率,更新双电机 PWM 参数
  • 其他辅助线程(screen beep 等)

与此同时,善用 RT-Thread 提供的锁,可以很好的同步线程数据,避免出现数据不同步导致的 bug。我们曾经遇到过一个线程同步相关的问题,加锁后成功解决。

图为使用 RT-Thread 后的代码,整洁干净,避免了原来不同代码拧在一起的混沌情况。

1.3 使用控制台加速调试过程

调车中经常遇到需要频繁修改车辆运行参数以达到最好的车辆运行状态,面对这种情况,传统方式是在板上设置按钮同时设计图形或文字界面,调整参数时使用按钮进行。但是这种方式缺乏灵活性,功能较为单一,并且操作复杂。我们小车的电路板采用紧凑型设计,故在板子小小的空间内挤入过多的按钮并不现实。

RT-Thread 自带一个很好用的控制台——FinSH,提供了类 Unix Shell 的体验。在其上操作如同操作交换机等设备。搭配上无线模块,通过命令行传递需要修改的参数,简单快速、直观高效。还可通过自制 Web 上位机实现图形化调参。

图为我们队伍用于修改参数的代码截图、实际运行情况、和图形化调参界面。


 

§02 植问题


2.1 修改启动文件使 RT-Thread 启动

RT-Thread 要求通过设置 -eentry 到编译参数,使 main 函数运行前,先运行 entry 函数以初始化 RT-Thread。(Libraries/rttherad_libraries/src/
components.c:157 objdump -d 可反汇编)

如果在 startup_MIMXRT1064.s 中使用 GCC 自带的 _start (来自 GCC 自带的 crt0.o),_start 在初始化 c 运行环境之后,会直接进入 main 函数,不会经过 entry 函数。故需要在启动文件中,手动初始化 c 运行环境(初始化 bss 段,调用 __libc_init_array 函数),并跳入 entry 函数。

3.2 解决 context_gcc.S 中的编译错误

在 Libraries/rttherad_libraries/libcpu/arm/cortex-m7/context_gcc.S 中有错误:
Error: thumb conditional instruction should be in IT block – `vstmdbeq r1!,{d8-d15}’
解决方案:在 flags.cmake 增加 -mimplicit-it=thumb flag

3.3 解决符号冲突导致的编译错误

C 标准库里和 RT-Thread 库中有重复定义,需要配置 RT-Thread 以让出符号。
解决方案:添加了 Libraries/rttherad_libraries/bsp/cconfig.h 文件(来自 Github),添加到了 files.cmake 中的头文件搜索目录,在 flags.cmake 中添加了 HAVE_CCONFIG_H flag

3.4 解决一些链接错误

增加了 .rti_fn (用于 RT-Thread 自动初始化) .FSymTab .VSymTab (用于 FinSH)段的配置。
在 .heap(底)和 .stack(顶)间配置了 heap_start heap_end 作为 RT-Thread 的堆内存(用于分配线程栈等)。

3.5 解决线程不切换的问题

如默认项目里的 rt_thread_mdelay(100); ,在 100ms 后 LED 并没有切换状态。
发现是由于 Libraries/nxp_libraries/middleware/sdmmc/port/usdhc/polling/
fsl_sdmmc_event.c 里的 SysTick_Handler 覆盖掉了 Libraries/seekfree_libraries/
board/board.c 文件中的 SysTick_Handler,其中 board.c 负责配置 SysTick 并且在 SysTick 定时结束时调用 RT-Thread 继续线程(初始化板子)。

解决方案:在 files.cmake 里注释掉 Libraries/nxp_libraries/middleware/sdmmc/
port/usdhc/polling/fsl_sdmmc_event.c (该错误解决后我根据 IAR 的配置继续注释掉了其他不需要的文件)

Tips:修改 Libraries/rttherad_libraries/include/rtdebug.h 可以开启内核功能调试输出

 

§03


RT-Thread 是一个很优秀的实时操作系统,在工程实践中,可以很大程度上降低代码编写复杂度,提升代码可维护性,在开发、调试、运行过程中,都可发挥其重要的作用。尤其是在智能车比赛中,RT-Thread 可以合理分配任务运行,降低开发负担,提升开发速度。

参考文献

  • 崔海勤. 2021. hilookas/SeekFree_RT1064_Library_GCC_Porting. GitHub. [联机] 2021年. https://github.com/hilookas/SeekFree_RT1064_Library_GCC_Porting.
  • 逐飞 RT1064 RT-Thread 库 GCC (VSCode) 移植踩坑. lookas. [联机] 2021年5月19日. https://lookas2001.com/%e9%80%90%e9%a3%9e-rt1064-rt-thread-%e5%ba%93-gcc-vscode-%e7%a7%bb%e6%a4%8d%e8%b8%a9%e5%9d%91/.