一、项目背景与目标
robot_pc_project 是一个基于 Linux操作系统 开发的机器人控制与状态上报项目。
整体采用 PC 客户端 + 机器人服务端 的架构,围绕“网络通信、状态管理、多线程并发、传感器仿真、避障联动、ARM 移植部署”逐步完成开发。
项目最终目标包括:
- 实现里程计、IMU、激光雷达、视觉识别、避障等传感器仿真
- 实现 Ubuntu 主机编译与 ARM 开发板部署运行
二、项目最终架构
项目最终形成了两个可执行程序:
1. robot_server
机器人端服务程序,主要负责:
2. pc_client
PC 控制端程序,主要负责:
三、项目目录结构与模块划分
项目整体结构如下:
robot_pc_project├── include│ ├── common│ │ ├── log.h│ │ ├── msg_queue.h│ │ ├── net.h│ │ └── protocol.h│ ├── pc│ │ └── pc_client.h│ └── robot│ ├── client_manager.h│ ├── robot_dispatcher.h│ ├── robot_server.h│ ├── robot_sensors.h│ └── robot_state.h├── src│ ├── common│ │ ├── log.c│ │ ├── msg_queue.c│ │ ├── net.c│ │ └── protocol.c│ ├── pc│ │ ├── main_pc.c│ │ └── pc_client.c│ └── robot│ ├── client_manager.c│ ├── main_robot.c│ ├── robot_dispatcher.c│ ├── robot_server.c│ ├── robot_sensors.c│ └── robot_state.c└── Makefile
模块职责
common 公共模块
robot 机器人端模块
robot_dispatcher:命令分发与业务处理
pc 客户端模块
pc_client:连接、命令发送、接收处理、心跳
四、项目开发全过程知识点复盘
4.1 工程迁移与开发环境搭建
1. Windows 到 Ubuntu 传输工程
项目最初开发在 Windows 环境下,后续需要转移到 Ubuntu 编译运行。
用到的知识点
典型问题
使用相对路径或中文目录时,scp 报:
No such file or directory
解决方法
使用绝对路径加引号进行传输:
scp -r "D:\robot_pc_project" root@192.168.1.111:/home/robot_demo/
沉淀
- Windows 向 Linux 传工程时,优先使用绝对路径
- 工程迁移阶段优先保证“文件正确到位”,不要一开始就纠结代码问题
4.2 Makefile 编译系统问题与修复
1. Makefile 基础知识
Makefile 是 Linux C 工程的核心构建脚本,负责:
2. 遇到的经典问题
问题一:遗漏分隔符
报错:
*** 遗漏分隔符 (null)
根因
典型错误写法
COMMON_SRCS = \ # 注释
$(CC) ...
3. 正确经验
4. CRLF 换行问题
从 Windows 传到 Ubuntu 后,Makefile 可能带有 Windows 换行符,影响解析。
沉淀
- Makefile 最常见的问题不是逻辑错,而是格式错
- 嵌入式/ Linux 项目里,构建系统是第一道门槛
4.3 C 语言工程化开发知识
1. 头文件与源文件必须严格一致
项目中多次出现以下问题:
implicit declaration of function
根因
核心原则
典型示例
例如日志函数、协议结构体、机器人状态接口等,必须统一命名和参数。
沉淀
4.4 Linux Socket 网络编程知识
1. TCP 服务端开发流程
服务端实现了:
socket()setsockopt()bind()listen()accept()recv()/send()close()
2. TCP 客户端开发流程
客户端实现了:
socket()connect()send()/recv()close()
3. 用到的核心知识点
4. 网络错误处理
客户端后续优化为:
沉淀
- Linux 网络编程的本质是“文件描述符 + 协议 + 阻塞/非阻塞”
4.5 应用层协议设计知识
TCP 是字节流,不保证消息边界,因此需要自己设计协议。
1. 协议头设计
项目设计了:
2. 协议结构
3. 协议功能
4. 学到的本质
- TCP 不懂“消息”,应用程序必须自己定义“消息”
4.6 多线程并发编程知识
项目最后是一个典型多线程系统。
1. 服务端线程模型
client_recv_thread:每客户端接收线程heartbeat_check_thread:心跳检测线程dispatcher_thread:业务消息分发线程
2. 客户端线程模型
3. 用到的线程知识点
4. 共享数据保护
使用了 pthread_mutex_t 保护:
5. 条件变量
在消息队列/分发队列中使用了:
实现生产者-消费者模型。
沉淀
- 多线程程序的关键不是“线程越多越好”,而是职责划分清晰
4.7 机器人状态管理与状态机设计
1. robot_state_t 的作用
机器人状态不再只是一个“速度值”,而是完整的状态模型,包含:
2. 命令驱动状态变化
移动命令
会联动更新:
停止命令
会联动更新:
3. 状态广播
状态变化后,服务端可以主动广播给客户端。
沉淀
4.8 客户端登录、心跳与权限控制
1. 登录机制
项目实现了:
2. 心跳机制
客户端定期发送心跳,服务端收到后更新活跃状态。
3. 连接断开清理
客户端断开时,服务端会:
沉淀
4.9 命令分发与解耦设计
1. 为什么要分发线程
如果收包线程直接做业务处理,会导致:
2. 最终方案
3. 价值
沉淀
4.10 传感器仿真设计知识
这是项目后期最重要的亮点之一。
1. 传感器仿真模块包含
2. 里程计仿真
通过速度、方向、时间步长计算:
涉及知识点:
3. IMU 仿真
根据速度变化和转向行为估算:
4. 激光雷达仿真
根据当前运动状态动态调整前方障碍距离:
5. 视觉识别仿真
识别结果在以下内容中轮换:
6. 避障状态分级
沉淀
4.11 自动避障联动设计
1. 从“打印状态”到“控制联动”
项目最初只是打印激光雷达与避障提示,后续升级为真正控制:
2. 急停联动逻辑
满足条件时:
3. 防止重复触发
使用 emergency_stop_active 标记,避免每个周期重复触发急停。
4. 客户端状态同步
后续在急停逻辑中补上:
robot_dispatcher_broadcast_status();
从而实现:
沉淀
- 状态变化后必须及时同步到客户端,否则会出现视图不一致
4.12 客户端交互体验优化
1. 中文/英文双命令支持
最终支持:
2. 参数合法性检查
3. 优雅退出
客户端支持 Ctrl+C 安全退出:
沉淀
4.13 日志系统设计与中文化
1. 自定义日志模块
日志模块实现了:
涉及知识点:
2. 中文日志输出
项目后期将核心日志从英文改为中文,例如:
3. 多线程日志交错问题
由于多个线程同时 printf,曾出现日志重叠现象。
沉淀
- 日志系统不仅是调试工具,也是系统行为的可观测性基础
- 多线程日志如需进一步优化,应考虑在日志模块中加全局锁
4.14 ARM 交叉编译与开发板部署
1. 为什么不能直接把 Ubuntu 程序拷到 ARM 板
Ubuntu 主机编译出的程序默认是 x86_64 架构,而开发板是 ARM 架构,因此必须交叉编译。
2. 交叉编译器
项目使用:
arm-linux-gnueabihf-gcc
完成 ARM 32 位交叉编译。
3. Makefile 双模式
Makefile 最终支持:
4. 用 file 验证目标架构
通过:
file robot_serverfile pc_client
确认输出为 ARM ELF 文件。
5. 板端运行时报 not found
虽然程序文件存在,但执行时报:
./robot_server: not found
根因
ARM 交叉编译的动态链接程序依赖:
/lib/ld-linux-armhf.so.3
而开发板使用的是 musl 体系,只有:
ld-musl-armhf.so.1
6. 静态链接解决库不匹配问题
将:
LDFLAGS = -lm
改为:
LDFLAGS = -lm -static
重新编译后,程序不再依赖开发板上的动态加载器,最终成功运行。
7. ADB 推送部署
使用:
adb push robot_server pc_client /root/
将程序推送到开发板运行。
沉淀
“not found” 不一定是文件不存在,也可能是加载器找不到
4.15 开发板时间同步与北京时间设置
1. 问题
开发板日志时间最初显示为:
1970-01-01 ...
说明系统时间未同步。
2. 北京时间设置
最终通过:
echo"CST-8" > /etc/TZexport TZ=CST-8
使系统切换到北京时间。
3. 联网 NTP 校时
开发板存在 ntpd,最终通过:
ntpd -n -q -p ntp.aliyun.com
完成时间同步。
4. 最终结果
日志时间成功显示为北京时间。
沉淀
嵌入式系统时区配置方式可能不同于 PC Linux
五、项目开发中形成的方法论闭环
整个项目的开发过程,本质上形成了一个完整的方法论闭环:
1. 先打通环境
2. 再打通构建
3. 再打通运行
4. 再打通业务
5. 再打通仿真
6. 再打通联动
7. 再打通部署
8. 再打通系统保障
六、项目中沉淀出来的核心能力
通过本项目,最终沉淀出了以下综合能力:
1. Linux C 工程能力
2. Linux 网络编程能力
3. 并发编程能力
4. 业务架构能力
5. 机器人仿真能力
6. 嵌入式移植能力
7. 系统运行保障能力
七、项目最终复盘结论
robot_pc_project 项目最终完成了从“基础 socket 通信练习”到“机器人仿真控制系统”的完整升级,形成了一个覆盖:
完整知识闭环。
这个项目最重要的意义不只是“写出了两个程序”,而是经历了一个完整的工程实践过程:
从 Windows 传工程、Ubuntu 编译、修 Makefile、修接口、打通网络、打通业务、加入仿真、实现联动、适配中文日志、再到 ARM 开发板静态部署与时间同步,最终真正把一个项目“做活、做通、做上板”。
八、项目一句话总复盘
robot_pc_project 的开发过程,本质上是一次完整的 Linux C 网络控制系统 + 机器人状态仿真 + ARM 嵌入式部署 的工程闭环实践。
九、项目运行效果
客户端
root@Linux:~/robot_pc_project$ ./pc_client[2026-03-28 21:10:55][INFO] PC客户端初始化完成,服务器IP=127.0.0.1,端口=9000[2026-03-28 21:10:55][INFO] 已连接到服务端:IP=127.0.0.1,端口=9000[2026-03-28 21:10:55][INFO] PC客户端启动成功可用命令: 登录 / login -> 登录机器人服务端 移动 <方向> <速度> / move <方向> <速度> -> 发送移动命令 停止 / stop -> 发送停止命令 查询 / query -> 查询机器人状态 编号 / id -> 查看当前客户端ID 帮助 / help -> 显示帮助信息 退出 / quit -> 退出客户端方向说明:1=前进,2=后退,3=左转,4=右转客户端> [状态信息] 电量=100%;速度=0.00;方向=无;运行状态=已停止;温度=25.0℃;模式=待机login[登录响应] 客户端ID=4,内容=登录成功,客户端ID=4客户端> move 3 100客户端> [确认消息] 客户端ID=4,内容=移动成功[状态信息] 电量=94%;速度=100.00;方向=左转;运行状态=运行中;温度=27.0℃;模式=移动^C收到退出信号,正在安全退出客户端...[2026-03-28 21:11:27][INFO] PC客户端接收线程退出[2026-03-28 21:11:28][INFO] PC客户端心跳线程退出[2026-03-28 21:11:28][INFO] PC客户端已停止[2026-03-28 21:11:28][INFO] PC客户端进程退出
服务端
root@Linux:~/robot_pc_project$ ./robot_server[2026-03-28 21:10:50][INFO] 机器人分发器初始化成功[2026-03-28 21:10:50][INFO] 机器人传感器仿真模块初始化成功[2026-03-28 21:10:50][INFO] 机器人服务端初始化完成,IP=0.0.0.0,端口=9000[2026-03-28 21:10:50][INFO] 服务端开始监听:IP=0.0.0.0,端口=9000[2026-03-28 21:10:50][INFO] 机器人分发器启动成功[2026-03-28 21:10:50][INFO] 机器人服务端启动成功[2026-03-28 21:10:50][INFO] 机器人传感器仿真线程启动成功[2026-03-28 21:10:50][INFO] 机器人主循环开始运行[2026-03-28 21:10:50][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:10:50][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:10:50][INFO] 【激光雷达】前方最近障碍距离=1.56 m,方向=无[2026-03-28 21:10:50][INFO] 【视觉识别】未识别到目标[2026-03-28 21:10:50][INFO] 【避障状态】避障正常[2026-03-28 21:10:52][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:10:52][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:10:52][INFO] 【激光雷达】前方最近障碍距离=1.56 m,方向=无[2026-03-28 21:10:52][INFO] 【视觉识别】未识别到目标[2026-03-28 21:10:52][INFO] 【避障状态】避障正常[2026-03-28 21:10:54][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:10:54][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:10:54][INFO] 【激光雷达】前方最近障碍距离=1.60 m,方向=无[2026-03-28 21:10:54][INFO] 【视觉识别】识别到行人[2026-03-28 21:10:54][INFO] 【避障状态】避障正常[2026-03-28 21:10:55][INFO] 新客户端接入:连接fd=4,客户端ID=4[2026-03-28 21:10:55][INFO] 客户端接收线程启动:连接fd=4,客户端ID=4[2026-03-28 21:10:55][INFO] 广播机器人状态:电量=100%;速度=0.00;方向=无;运行状态=已停止;温度=25.0℃;模式=待机[2026-03-28 21:10:56][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:10:56][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:10:56][INFO] 【激光雷达】前方最近障碍距离=1.68 m,方向=无[2026-03-28 21:10:56][INFO] 【视觉识别】识别到行人[2026-03-28 21:10:56][INFO] 【避障状态】避障正常[2026-03-28 21:10:58][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:10:58][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:10:58][INFO] 【激光雷达】前方最近障碍距离=1.80 m,方向=无[2026-03-28 21:10:58][INFO] 【视觉识别】识别到行人[2026-03-28 21:10:58][INFO] 【避障状态】避障正常[2026-03-28 21:11:00][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:11:00][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:11:00][INFO] 【激光雷达】前方最近障碍距离=1.72 m,方向=无[2026-03-28 21:11:00][INFO] 【视觉识别】识别到箱子[2026-03-28 21:11:00][INFO] 【避障状态】避障正常[2026-03-28 21:11:02][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:11:02][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:11:02][INFO] 【激光雷达】前方最近障碍距离=1.68 m,方向=无[2026-03-28 21:11:02][INFO] 【视觉识别】识别到箱子[2026-03-28 21:11:02][INFO] 【避障状态】避障正常[2026-03-28 21:11:02][INFO] 处理登录请求:连接fd=4,客户端ID=4[2026-03-28 21:11:04][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:11:04][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:11:04][INFO] 【激光雷达】前方最近障碍距离=1.68 m,方向=无[2026-03-28 21:11:04][INFO] 【视觉识别】识别到箱子[2026-03-28 21:11:04][INFO] 【避障状态】避障正常[2026-03-28 21:11:04][INFO] 收到心跳:客户端ID=4[2026-03-28 21:11:06][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:11:10][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:11:10][INFO] 【激光雷达】前方最近障碍距离=1.92 m,方向=无[2026-03-28 21:11:10][INFO] 【视觉识别】识别到路标[2026-03-28 21:11:10][INFO] 【避障状态】避障正常[2026-03-28 21:11:10][INFO] 收到心跳:客户端ID=4[2026-03-28 21:11:12][INFO] 【里程计】X=0.00 m,Y=0.00 m,航向=0.0°,累计里程=0.00 m[2026-03-28 21:11:12][INFO] 【IMU】加速度(ax=0.00, ay=0.00) m/s²,角速度(gz=0.00) °/s[2026-03-28 21:11:12][INFO] 【激光雷达】前方最近障碍距离=1.84 m,方向=无[2026-03-28 21:11:12][INFO] 【视觉识别】识别到台阶边缘[2026-03-28 21:11:12][INFO] 【避障状态】避障正常[2026-03-28 21:11:12][INFO] 收到移动命令:客户端ID=4,方向=3,速度=100.00,模式=移动[2026-03-28 21:11:12][INFO] 广播机器人状态:电量=94%;速度=100.00;方向=左转;运行状态=运行中;温度=27.0℃;模式=移动[2026-03-28 21:11:13][INFO] 收到心跳:客户端ID=4[2026-03-28 21:11:14][INFO] 【里程计】X=0.67 m,Y=0.17 m,航向=14.0°,累计里程=0.69 m^C[2026-03-28 21:11:36][INFO] 机器人传感器仿真线程退出[2026-03-28 21:11:36][INFO] 机器人传感器仿真模块已停止[2026-03-28 21:11:36][INFO] accept 线程退出[2026-03-28 21:11:36][INFO] 分发线程退出[2026-03-28 21:11:36][INFO] 机器人分发器已停止[2026-03-28 21:11:36][INFO] 机器人服务端已停止[2026-03-28 21:11:36][INFO] 机器人进程退出