机器人工程本科毕设入门指南:从选题到原型开发的完整技术路径
摘要:很多机器人工程本科生在毕设初期都会陷入“选题模糊、技术栈混乱、软硬件协同困难”的三连坑。本文面向零项目经验的新手,把毕设拆成“选题→技术栈→MVP→仿真→实机→避坑”六步,给出可直接落地的工具链与代码模板,帮你高效做出能跑、能避障、能写论文的差速小车。
1. 毕设常见痛点:为什么总卡在 30 % 进度条
- 目标不清:老师一句“做个移动机器人”就散会,需求颗粒度堪比“做个淘宝”。
- 软硬脱节:算法同学只管 MATLAB 仿真,硬件同学只焊板子,最后联调发现 ROS 话题对不上。
- 调试困难:实机一出问题就抓瞎,没有分块验证,只能“全量祈祷法”。
- 时间失控:把“买零件”排在第 7 周,快递一延误,毕业直接变延期。
一句话总结:把毕设当工程做,而不是当实验做。
2. 主流技术栈 5 分钟速览
| 维度 | 方案 A | 方案 B | 方案 C | 怎么选 |
|---|---|---|---|---|
| 中间件 | ROS 1 (Melodic/Noetic) | ROS 2 (Humble) | 裸 Socket | 新手直接 ROS 1,资料多;想长生命周期再迁 ROS 2 |
| 主控 | Arduino UNO | STM32F4 | Raspberry Pi 4 | 需要浮点+ROS 节点→树莓派;只收编码器→STM32 |
| 仿真 | Gazebo 11 | Webots R2023b | PyBullet | Gazebo 与 ROS 1 无缝,插件现成;Webots 界面友好 |
| 语言 | C++11 | Python 3 | 图形化 | 实时性要求>100 Hz 用 C++;快速验证用 Python |
经验:先让系统跑通,再谈“优雅”。别一上来就 ROS 2 + micro-ROS,配置能吃掉你两周。
3. MVP 案例:10 周做出“会避障的差速小车”
3.1 系统架构图
- 高层拆 4 块:感知→决策→控制→执行。
- 每一块先在仿真里跑通,再换真车,降低“未知变量”数量。
3.2 最小硬件清单(淘宝可一键下单)
- 小车底盘 + 电机编码器 ×2
- 树莓派 4B(4 GB)+ 32 GB 卡
- RPLIDAR A1(360° 激光雷达)
- TB6612 电机驱动板
- 12 V 锂电池 3 Ah + 降压 5 V 模块
- 跳线、支架、螺丝若干
预算 ≈ 1 200 元,可复用实验室旧车更省。
3.3 软件包结构(catkin_ws 内)
racecar/racecar_description/URDF + 仿真插件racecar_gazebo/launch + 世界文件racecar_bringup/真机参数、udev 规则racecar_nav/避障节点(C++)racecar_utils/Python 工具脚本
3.4 核心节点:lidar_based_avoidance.cpp
/* * 订阅 /scan (sensor_msgs/LaserScan) * 发布 /cmd_vel (geometry_msgs/Twist) * 算法:最小安全距离 + 右手规则 * 实时性:10 ms 定时器,约 100 Hz */ #include <ros/ros.h> #include <sensor_msgs/LaserScan.h> #include <geometry_msgs/Twist.h> class LidarAvoid { public: LidarAvoid() : nh_("~") { scan_sub_ = nh_.subscribe("/scan", 1, &LidarAvoid::scanCB, this); vel_pub_ = nh_.advertise<geometry_msgs::Twist>("/cmd_vel", 1); timer_ = nh_.createTimerimer(ros::Duration(0.01), &LidarAvoid::update, this); safe_dist_ = 0.35; // m max_speed_ = 0.25; // m/s } private: void scanCB(const sensor_msgs::LaserScan::ConstPtr& msg) { scan_ = *msg; // 缓存最新数据 } void update(const ros::TimerEvent&) { if (scan_.ranges.empty()) return; geometry_msgs::Twist cmd; // 1. 找最小距离 float min_dist = scan_.range_max; int min_idx = -1; const int center = scan_.ranges.size() / 2; const int view = 90 / (scan_.angle_increment * 180/M_PI); // ±45° for (int i = center - view; i < center + view; ++i) { if (std::isfinite(scan_.ranges[i]) && scan_.ranges[i] < min_dist) { min_dist = scan_.ranges[i]; min_idx = i; } } // 2. 决策 if (min_dist < safe_dist_) { cmd.linear.x = 0; cmd.angular.z = (min_idx < center) ? 0.3 : -0.3; // 右转/左转 } else { cmd.linear.x = max_speed_; cmd.angular.z = 0; } vel_pub_.publish(cmd); } ros::NodeHandle nh_; ros::Subscriber scan_sub_; ros::Publisher vel_pub_; ros::Timer timer_; sensor_msgs::LaserScan scan_; double safe_dist_, max_speed_; }; int main(int argc, char** argv) { ros::init(argc, argv, "lidar_avoid"); LidarAvoid core; ros::spin(); return 0; }代码要点:
- 类封装,职责单一;
- 魔法数放构造函数参数,可动态重载;
- 10 ms 定时器保证实时性,避免 ROS spinOnce 漂移。
3.5 编译与运行
- 把代码放到
racecar_nav/src/ catkin_make -DCMAKE_EXPORT_COMPILE_COMMANDS=1roslaunch racecar_gazebo racecar_lidar.launch
仿真里插入障碍物,小车应自动绕开。- 真机端
roslaunch racecar_bringup robot.launch
同一节点零修改直接跑,验证“仿真-实机”一致性。
4. 仿真→实机:性能与实时性 checklist
- 计算负载:树莓派 4 跑 100 Hz 激光避障 CPU < 15 %,余量留给后续视觉。
- 通信延迟:
rostopic delay /cmd_vel应 < 5 ms;若超标,把tcpNoDelay打开。 - 时钟同步:真机用
ntp对时,避免tf跳变。 - 控制频率:电机空载 5 ms 响应,带载 10 ms,与算法周期匹配,杜绝“命令丢帧”。
- 数据落盘:用
rosbag记录/scan + /cmd_vel + /odom,回实验室再复现,调参不用二次搬车。
5. 生产环境避坑指南
串口权限
udev 规则新增SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", MODE="0666",避免每次sudo chmod。节点启动顺序
雷达上电慢于树莓派,launch 里加<node pkg="racecar_utils" type="wait_for_lidar.py" />>,防止空指针。电源管理
电机启动电流可达 2 A,电池加 470 μF 电解电容,防止瞬间压降重启树莓派。TF 漂移
若用机器人自带轮速里程计,把odom->base_link发布频率固定在 50 Hz,低于 20 Hz 时amp 会累积漂移。Git 大文件
URDF 的 STL 贴图易超 100 MB,用git-lfs或单独models/目录,避免仓库克隆龟速。
6. 把 MVP 扩展成论文的 3 条路线
- 局部路径规划:把“固定转角”换成 DWA 或 TEB,跑通后对比轨迹平滑度,可出图、有数据。
- 视觉增强:加装单目,跑 ORB-SLAM2,与激光避障做融合,定位精度提升 30 % 就有故事。
- 多机协同:同门再做一辆,跑 ROS 多机通信,实验“谁当主机”“如何分布式避障”,直接蹭“群体智能”热点。
7. 结语:先跑起来,再完美
把上面的小车从零到能避障,大约 10 周,每周 10 h 左右,足够写论文+拍演示视频。别急着堆功能,先让车每天稳定跑 100 圈不出错,你的信心、日志、数据自然就来。后续想加视觉、抓夹、甚至 Ros-OpenCV 深度学习,都在同一框架下插件式升级。代码记得推到 GitHub,开源才是毕业设计最好的“致谢”。祝你毕设一遍过,答辩不烧脑。