1. 项目设计
嘉立创星火计划对此项目的需求如下。

这里因为需要一个人完成软硬件的设计、开发和制作,将项目分为以下部分。
1.1 结构设计
产品设计,结构先行
结构设计软件采用工业上常用的SoildWorks软件进行设计。
综合考虑结构设计水平和开发成本,尽可能简化结构设计并控制3D打印零件数量,经过多次迭代,最终得到的结构外观如下。

结构支撑大多采用铜柱进行支撑,仅在固定摄像头出由外壳进行支撑。
因此,仅需一个3D打印外壳即可完成所有的结构工作,外壳内部效果如下图所示。

1.2 硬件设计
PCB的硬件设计需要结合结构和软件进行考虑,将PCB共设计为两块。
PCB1:小车底盘控制板
处于成本和外壳设计难度考虑,底盘控制板即提供电机支撑,还完成了底盘的控制电路。
- 提供电源:锂电池、电池充电电路、电源转换电路、电源开关;
- 底盘控制:驱动两个N20电机进行旋转,使用常见的TB6612进行驱动;
- MCU控制:此处对性能和资源要求一般,采用最常用的STM32F103C8;
- 其他:LED状态灯、程序烧录口、通信串口。
PCB2:上位机接口扩展板
- 引出端口:将泰山派的通信端口引出,下位机通信串口、雷达通信串口;
- 风扇和雷达电源控制:使用IO通过三极管完成对散热风扇和雷达电源的控制。
原理图设计相对简单,参考原理图即可,开发过程中主要PCB外形和结构配合上走了些弯路,耽误了不少时间。
1.3 软件设计
根据项目需求和PCB设计,软件主要需要包含三个部分:
- 下位机地盘STM32程序:
- 通过串口接收小车电机目标旋转速度;
- PID控制小车电机速度按照目标速度旋转;
- 周期上报小车电机编码器变化数据;
- 长时间为收到上位机命令后停止移动,使用状态灯变化进行提示。
- 泰山派ROS程序:
- 和QT上位机通信,接收目标运行模式(手动控制模式、目标跟随模式、自动导航模式等);
- 根据上位机的不同命令,完成不同算法动作
- 手动控制模式下,接收小车速度话题;
- 目标跟随模式下,获取摄像头画面,识别目标位置,并计算小车所需的跟踪速度;
- 自动导航模式下,接收上位机发送的目标位置,将目标位置发送给导航节点,由导航节点控制小车速度进行移动。
- QT上位机程序:
- 和ROS程序进行通信,显示小车当前状态,并给小车发送目标指令。
这里上位机其实就像是一个低配的Rviz
2. 项目部署
复刻请按照以下步骤进行操作。
2.1 烧录镜像
从官方资料中下载Ubuntu20系统镜像ubuntu20.04_hdmi_20231130_update.img,并按照官方教程烧录。
镜像地址:https://wiki.lckfb.com/zh-hans/tspi-rk3566/download-center.html
烧录完成后,板子上就有Ubuntu系统了。
2.2 内核修改
需要自己编译,比较占电脑空间,开源广场资料有提供编译好的内核。
默认镜像中仅引出一个用户可以使用的串口,上位机需要的端口如下:
- 下位机通信,串口
- 雷达通信,串口
最基础的功能,控制下位机控制、雷达通信还差一个串口。
因此需要修改内核配置:
编译过程参考:https://wiki.lckfb.com/zh-hans/tspi-rk3566/project-case/fat-little-cell-phone/sdk-compile.html
文件需要做的修改如下:
- 调试串口波特率修改(非必须)
找到下面这个文件
1 | tsp/kernel/arch/arm64/boot/dts/rockchip/tspi-rk3566-core-v10.dtsi |
修改下面这段,把调试串口波特率从1500000修改位115200。非必须。
1 | fiq-debugger { |
- 添加一个串口(必须)
板子上引出的排针功能定义如下,选择一个合适的串口使用,此处使用串口5。

引脚定义:https://wiki.lckfb.com/zh-hans/tspi-rk3566/documentation/io-allocation-table.html
找到下面这个文件
1 | tsp/kernel/arch/arm64/boot/dts/rockchip/tspi-rk3566-user-v10-linux.dts |
找到串口3的位置,将其复制一份,然后将3修改为5即可。
1 | //用户串口3 |
然后按照教程中的步骤,只编译内核,生成boot.img文件即可,然后单独将boot.img烧录进板子,烧录方法同样参考官方资料,比较简单。
烧录完成之后,板子上就的串口5就也可以用了,可以先接个串口工具试试能不能使用串口5收发数据。
2.3 空间分配
镜像烧录后,16G的EMMC空间有很大一部分都是空闲的,不能被直接使用,可用的空间还不够安装ROS的,因此需要将空闲的空间重新分配一下。
以下步骤需要将泰山派连接屏幕,下面的图片是最早的时候拍的,如果你按照我的流程生成的镜像,用户名可能不是这个。
在shell窗口中安装分配工具
1 | sudo apt-get install gparted |

使用下面命令启动磁盘分配工具,将磁盘oem和userdata右键取消挂载,再右键删除。
1 | sudo gparted |

将删除掉的空间分配给rootfs,右键选择Resize。

完成之后,即可看到效果,点击对号应用即可。

查看磁盘空间,已分配完成。

2.4 安装SSH
更新包
1 | sudo apt-get update |

安装服务
1 | sudo apt-get install openssh-server |
提示依赖关系不对时,提示需要哪个版本就安装哪个版本。

安装完成之后,将泰山派连接一个WIFI,使用ifconfig命令查看一下板子的IP地址,并记录一下。
1 | ifconfig |
2.5 安装ROS
这里使用小鱼的一键安装,方便省力。
1 | wget http://fishros.com/install -O fishros && bash fishros |
1 | lckfb@MiWiFi-R3GV2-srv:~$ |
等待一段时间后,第一次提示软件包依赖不对,这里先敲回车继续。
1 | ============================================================ |
如果,这里第二次接受方案,然后往下走还是报错了,那就从头来,然后前两次都拒绝,第三次再接受。如果还失败,就再从头来,第四次再接受。
安装完成后,重新起一个终端,输入roscore指令,能看到如下信息,就表示ros安装完成了。
1 | lckfb@MiWiFi-R3GV2-srv:~$ roscore |
2.7 权限设置
2.7.1 串口权限
两个串口/dev/ttyS3和/dev/ttyS5使用普通用户登录默认都是没有操作权限的,在代码里不方便操作。
因此这里永久修改一下权限。
1 | # 创建udev规则文件 |
添加以下内容
1 | KERNEL=="ttyS3", MODE="0666" |
添加完成后重新加载
1 | # 重新加载udev规则 |
查看串口权限,可以看到有读写权限了
1 | lckfb@MiWiFi-R3GV2-srv:~/ros1-car-ws$ ls -l /dev/ttyS5 |
2.7.2 IO引脚
风扇和雷达供电控制引脚上电后默认也是没有操作权限的。
1 | lckfb@MiWiFi-R3GV2-srv:~$ echo 36 > /sys/class/gpio/export |
ubuntu下没找到好的解决办法,创建一个脚本,运行ros程序前执行一下吧。
1 |
|
执行方法为
1 | # 添加执行权限 |
2.7.3 摄像头权限
执行以下命令,重启生效。
1 | # 添加权限 |
重启完成之后,执行以下命令,看到有video输出即表示成功。
1 | lckfb@MiWiFi-R3GV2-srv:~$ groups |
2.8 硬件组装
这里硬件和结构相对来说简单,因此可以在软件编译完成后再进行硬件组装。
组装教程参考B站视频。
组装视频:https://space.bilibili.com/330622220
2.9 软件部署
下载程序
1 | git clone https://gitee.com/imhaozi/TspRosCar.git |
- 切换到Base分支,使用Keil开发,编译后烧录到底盘STM32中;
- 切换到TspWs分支,并将程序复制到泰山派中编译并运行;
- 运行程序前首先执行以下IO权限设置的脚本,否则无法正常打开雷达
- 程序中依赖多个软件包,分别安装即可
- 地图加载和保存:
sudo apt install ros-noetic-map-server - 建图:
sudo apt install ros-noetic-gmapping - 自动探索建图:
sudo apt install ros-noetic-explore-lite - 导航:
sudo apt-get install ros-noetic-navigation - websocket通信:
sudo apt install ros-noetic-rosbridge-suite
- 地图加载和保存:
- 运行命令如下
roslaunch launch_pkg all.launch
- 切换到App分支,使用QT打开并运行(也可以直接运行打包好的上位机);
泰山派和运行上位机的电脑需要在一个网络下运行。
3. 开发笔记
以下内容为学习过程中的一些记录罢了。
3.1 创建项目
创建一个工作空间文件夹(就是一个工程文件夹)
- 工作空间中可以有多个软件包
- 软件包中又可以又多个节点
步骤1:创建工作空间
比如这里想创建一个小车项目,就可以创建下面的文件目录
- Ros1CarWs
- src:存放代码,源代码、功能包等
创建一个Ros1CarWs目录作为本项目的工作空间。
1 | haozi@computer:~/develop$ mkdir Ros1CarWs |
步骤2:创建软件包
在工作空间的src目录下可以有多个软件包。
因此需要在src目录下进行创建,切换到工作空间的src目录下,执行如下格式指令:
1 | catkin_create_pkg 包名 <依赖项1> <依赖项2> ... |
比如,创建一个名叫test_pkg的包,指令如下:
1 | haozi@computer:~/develop/Ros1CarWs/src$ catkin_create_pkg test_pkg rospy roscpp std_msgs |
执行完成后,在src目录下就会多出一个新的目录test_pkg,该目录就是一个包了,包里面又包含了多个文件。
1 | haozi@computer:~/develop/Ros1CarWs/src$ ls |
步骤3:添加节点代码
在软件包的src目录下创建代码文件main.cpp
1 |
|
在这个包的CMakeLists.txt文件中,build部分,找到对应的注释的位置,添加如下两条(没注释掉的是添加的,注释掉的是原有的)。
1 | ## Declare a C++ executable |
其中:
- add_executable:表示需要编译可执行文件
- target_link_libraries:表示需要链接ros库
步骤4:编译代码
在工作空间目录Ros1CarWs下执行编译命令
1 | haozi@computer:~/develop/Ros1CarWs$ pwd |
编译完成后,工作空间下就会多出来两个文件夹,build、devel
1 | haozi@computer:~/develop/Ros1CarWs$ ls |
- build:编译文件
- devel:执行文件,执行前需要在这里添加源
步骤5:执行
启动一个新的终端,启动ros
1 | roscore |
添加代码源(注意相对目录或者绝对目录)
1 | haozi@computer:~/develop/Ros1CarWs$ source devel/setup.bash |
执行代码
1 | # 命令格式:rosrun 包名 节点名 |
到这里,创建一个ros软件包并执行的流程就完成了。
还可以继续重复步骤2-5,就可以创建多个不同的软件包了。
步骤6:优化
每次打开终端总要source一下,可以修改配置,打开终端时自动source。
执行如下指令
1 | haozi@computer:~$ gedit ~/.bashrc |
在弹出的编辑器中,最后一行添加如下内容。
1 | source ~/Ros1CarWs/devel/setup.bash |
这样每次打开终端,就会自动执行这一行命令了。
不过这里我还是不用了。
3.2 电脑端可视化
开发过程中,需要调试时,小车主控不具有可视化能力,需要借用电脑来进行可视化操作。
步骤1:
虚拟机网络设置为桥接模式(这样开发板和虚拟机才可以在一个网段下)
步骤2:
将电脑和开发板连接同一个wifi
步骤3:
查看电脑端和开发板IP地址和设备名
1 | hostname |
结果:
- 虚拟机
- 主机名:computer
- IP:192.168.31.28
- 开发板
- 主机名:MiWiFi-R3GV2-srv
- IP:192.168.31.35
步骤4:
编辑/etc/hosts文件,添加一行,添加对方的IP和主机名
开发板端
1 | 192.168.31.28 computer |
电脑端
1 | 192.168.31.35 MiWiFi-R3GV2-srv |
设置完成之后,分别ping对方的ip和主机名,应该都是可以ping通的。
步骤5:
这里将开发板作为ROS主机使用。编辑~/.bashrc文件,添加几行。
开发板端
1 | # ROS网络配置 |
电脑端
1 | # ROS网络配置 |
然后在开发板端运行roscore及其他服务,在电脑端就可以使用相关命令看到状态了。
也可以直接将上面两行写入到这个文件,就不用每次打开终端都需要重新导入了。
3.3 常用命令
软件包
1 | # 创建软件包 |
节点相关
1 | # 查看节点图关系 |
话题相关
1 | # 查看当前存在的话题 |
工具节点
1 | # 运行速度控制器 |
里程计数据可视化

雷达数据可视化

建图可视化

3.4 TF系统
使用以下命令查看TF树
1 | rosrun rqt_tf_tree rqt_tf_tree |
效果如下

TF(TransForm,坐标变换系),主要搞清楚几个坐标系之间的关系。
地图坐标系
地图坐标系/map,最根本的坐标系,坐标系原点从建图开始就固定不动了。
- 原点:在机器人建图时候的初始位置
- 方向:遵循右手法则,正前方为X,正左方为Y,正上方为Z
机器人坐标系
机器人坐标系base_footprint,坐标系原点永远跟随机器人移动。
- 原点:在机器人地面投影的正中心
- 方向:遵循右手法则,机器人的正前方为X,机器人正左方为Y,机器人正上方为Z
为了描述机器人在地图中的位置,把地图坐标系作为父坐标系,机器人坐标系作为子坐标系。
只需要六个值就可以表示机器人在地图中的位置:
- 机器人坐标系在地图坐标系中,xyz三个方向上距离的偏差
- 机器人坐标系在地图坐标系中,xyz三个方向上角度的偏差
对于小车来说,不可能在空中,所以z方向距离永远为0,不会向前或者向后倒,所以xy方向的角度永远为0。
有了这两个坐标系,就可以使用雷达进行建图了,雷达建图使用的就是这两个坐标系之间的转换关系。
3.5 地图保存和加载
当建图完成之后,需要把这个地图保存起来,下次启动直接调用即可。
3.5.1 地图保存
软件包安装命令如下。会报某些软件包依赖不对的错误,根据提示补充相关依赖即可。
1 | sudo apt install ros-noetic-map-server |
安装完成后,先使用建图软件包完成建图,保持建图程序不要关闭。
运行地图保存程序
1 | rosrun map_server map_saver -f <文件名> |
如果只有一个文件名就是当前终端的路径,这里使用绝对路径
需要先创建/home/lckfb/TspRosCar/RosCarWs/src/map_config/home这个文件夹,否则会保存失败
1 | rosrun map_server map_saver -f /home/lckfb/TspRosCar/RosCarWs/src/map_config/home/home_map |
运行结果如下
1 | lckfb@MiWiFi-R3GV2-srv:~/TspRosCar/RosCarWs$ rosrun map_server map_saver -f /home/lckfb/TspRosCar/RosCarWs/src/map_config/home/home_map |
得到两个文件,两个文件共同组成了一个地图数据。
- home_map.pgm:一张图片的格式
- home_map.yaml:描述了这个图片的信息,比如每个像素点对应的实际大小、起始点等信息
3.5.2 地图加载
地图加载完成后,关闭建图节点,只运行一个roscore即可。
运行之后,查看当前ros存在的话题是找不到/map的
1 | rostopic list |
然后运行以下命令加载地图(只需要yaml文件即可,文件中有对应的地图图片的名字)
1 | rosrun map_server map_server <地图名.yaml> |
同样的这里使用绝对路径
1 | rosrun map_server map_server /home/lckfb/TspRosCar/RosCarWs/src/map_config/home/home_map.yaml |
加载完成之后就有地图话题了,在rviz中可以看到发布的地图。
3.6 通信支持包
我们的上位机中肯定是无法直接运行ros来和小车进行通信的,可以使用网络通信获取ros中的消息内容。
在小车中需要一个将Ros消息和网络消息转换的东西(有现成的)。
将ROS环境的运行信息进行上报需要软件包rosbridge_server,安装命令如下
1 | sudo apt install ros-noetic-rosbridge-suite |
和其他的软件包一样,最后把这个软件包也启动起来即可。
1 | roslaunch rosbridge_server rosbridge_websocket.launch |