ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

智能车竞赛国一方案:轮腿机器人室外视觉感知与平衡控制实战

智能车竞赛国一方案:轮腿机器人室外视觉感知与平衡控制实战 从备赛到站上领奖台前后差不多一年时间。那段时间里我一直在捣鼓一套和主流方案不太一样的“轮腿车 室外视觉”组合。最后的结果还算幸运在 21 届全国大学生智能车竞赛中拿了国一整个过程也让我对嵌入式视觉、底盘控制、比赛工程化有了比课堂更深的理解。这篇文章我会完整复盘这套方案为什么会选择“猎奇”的技术路线整体架构怎么搭室外视觉为什么难、又是怎么解决的以及调试阶段最容易被忽视的坑。文末还会讲一下开源仓库的组织方式方便想复现、想继续改进的同学直接上手。如果你是准备参加智能车竞赛的学生或者对轮腿机器人、室外视觉感知、嵌入式控制感兴趣的开发者这篇文章应该能给你一份比较完整的参考。1. 背景为什么选轮腿为什么做室外视觉1.1 智能车轮腿组的本质是什么全国大学生智能车竞赛是国内规模很大的嵌入式竞赛之一每年都会吸引大量高校队伍参加。不同组别有不同侧重点有的偏向高速循迹有的偏向硬件传感器融合而轮腿组更看重“机械结构 运动控制 感知算法”的协同能力。轮腿车可以简单理解为在传统轮式底盘上增加了可活动的腿部结构。这种结构让它既能保持轮式车的高速和平顺又能通过抬腿动作越过障碍、上下台阶动作比普通小车灵活很多。但灵活也带来了麻烦重心更高平衡更难控制。腿部执行器增加了机械误差和控制延迟。运动过程中摄像头视野会波动图像稳定性较差。所以轮腿组从底层就是一个工程权衡问题——你不能只把视觉做得很强也不能只把底盘调得很稳必须让两者配合。1.2 室外视觉难在哪里传统室内智能车通常面对的是固定光照、固定色温、相对干净的背景视觉算法只要把赛道边缘提取出来就能稳定输出偏差。室外完全不一样光照强度随时间和天气变化极大早晨、正午、傍晚的曝光完全不同。地面材质复杂有沥青、砖块、水泥、草地边缘颜色纹理都很杂。太阳角度变化会让阴影方向不断漂移影子边缘很容易被误判成赛道边界。反光、积水、落叶、随机行人都会成为干扰。这就意味着如果直接把室内那套“摄像头固定参数 固定阈值分割 简单边缘提取”搬到室外大概率会出现画面过曝、丢失赛道、频繁误判的情况。我的方案核心思路是不追求在极端复杂环境中做到完美感知而是通过硬件安装角度、摄像头参数设置、动态阈值、状态机决策把“室外视觉”问题简化成若干个可控的小问题。1.3 为什么说这是一套“猎奇方案”所谓“猎奇”不是说方案猎奇到不可复现而是指它和大多数队伍选择了不一样的技术组合。当时主流方案有几个方向使用更大算力的平台跑深度学习分割模型。使用多传感器融合比如摄像头 激光雷达。在室内视觉方案基础上加一堆强假设强行迁移到室外。我选的路线相对“克制”不依赖大算力平台视觉模块用轻量级方案处理。不搞多个传感器堆叠而是把所有信息尽量统一到“图像”这一个维度。不在前端做复杂语义理解而是设计一个清晰的状态机用连续帧验证替代单帧强判断。这套路线在逻辑上很“朴素”但好处是调试成本低、可复现性强、比赛现场稳定。这也是为什么最后它能拿到国一——竞赛比的不是谁的模型更酷而是谁在真实赛道上跑得更稳。2. 系统总体架构设计2.1 硬件整体框架先聊硬件因为很多参赛选手容易忽略一个问题视觉能不能跑好一半取决于摄像头装得好不好另一半才取决于算法。我的硬件架构大致如下模块作用说明轮毂电机 / 直流电机提供驱动和运动控制能力舵机或直线舵机控制腿部抬升与姿态调整MCU 主控板负责底盘控制、平衡算法、执行电机指令高性能视觉模块负责采集图像、运行视觉算法、输出赛道偏差摄像头固定在车体前上方角度可调电源系统分路供电避免舵机波动影响主控这里想提醒一下具体型号和主控芯片不重要每个学校、每支队伍手头资源不一样完全可以用手边已有的板子。关键是要理解每个模块之间的接口关系。我在方案里把“视觉模块”和“MCU 主控”分开而不是把图像处理也放在 MCU 上。这样做的好处是图像处理占用大量算力单独用高性能模块不会拖慢底盘实时控制。底盘控制需要确定的实时性中断延迟越小越好。调试时可以分别处理视觉模块独立跑底盘单独调问题隔离。2.2 软件分层架构软件我分成三层感知层负责采集图像、预处理、提取赛道特征。决策层根据感知结果维护状态机计算出目标速度和转向量。执行层把目标值转换成电机 PWM、舵机角度等底层控制信号。这里最核心的设计原则是层与层之间只通过稳定接口通信不要跨层依赖。比如决策层不需要知道图像是 RGB 还是灰度它只需要一个“赛道中心偏差值”执行层不需要知道当前是哪个赛道元素它只需要一个“目标速度”。这样做让整个系统很容易调试——视觉出问题只查视觉控制出问题只查控制不会互相牵扯。2.3 数据流与控制流整个系统工作流程可以这样描述摄像头采集图像 ↓ 视觉模块做颜色分割 / 边缘提取 ↓ 输出当前帧赛道中心偏差 error 与元素标志 ↓ 决策状态机根据误差和标志更新运动模式 ↓ 输出目标速度与转向角度 ↓ MCU 执行平衡控制与速度闭环在通信上视觉模块和 MCU 之间我使用串口通信通信频率在 50Hz 左右。帧格式尽量简单包含帧头、数据长度、赛道偏差、元素标志、校验位即可。3. 环境准备与开发工具链3.1 开发环境说明由于不同队伍的板子和视觉平台差异较大我这里只给一套通用环境建议重点说明配置思路具体版本请你根据自己的项目调整。视觉算法开发环境Ubuntu 20.04/22.04使用 C 和 OpenCV便于部署到嵌入式 Linux 平台。底盘开发环境Windows 或 Linux 都可以使用 Keil / VSCode GCC编写 MCU 固件。调试工具串口调试助手、可视化图像回放程序、逻辑分析仪。版本管理建议从第一天开始就使用 Git 管理代码避免“最终版最终版2最终版3”的惨剧。说明一下如果你用 Python 快速验证视觉算法效率会更高。建议先拿 Python 脚本在录制的视频上跑通逻辑再移植成 C 的嵌入式版本。我的习惯是“双轨开发”Python 做原型验证C 做最终部署。3.2 项目目录结构规划开源项目最重要的是让别人一看就能找到入口。我的代码仓库目录是这样设计的smartcar-wheelleg/ ├── README.md # 项目说明与快速上手 ├── docs/ │ ├── hardware-design.md # 机械结构说明 │ ├── algorithm-design.md # 算法设计文档 │ └── competition-summary.md # 比赛经验总结 ├── firmware/ # MCU 主控固件 │ ├── control/ │ ├── balance/ │ └── driver/ ├── vision/ # 视觉算法模块 │ ├── capture/ │ ├── processing/ │ ├── recognition/ │ └── inference/ ├── configs/ # 所有参数配置文件 │ ├── vision_config.yaml │ ├── pid_config.yaml │ └── track_config.yaml └── tools/ ├── image_replay.py # 图像视频回放工具 └── serial_debug.py # 串口调试工具目录结构不建议过度设计但必须让新人知道“代码放哪、配置放哪、文档放哪”。竞赛项目更迭快代码可读性直接影响团队协作效率。3.3 参数配置文件示例我强烈建议把经常需要调整的参数全部抽出来放到配置文件里而不是写死在代码中。比如视觉阈值、PID 参数、目标速度、转向限幅。下面是一份简化的视觉参数配置示例# 文件路径configs/vision_config.yaml camera: width: 320 height: 240 exposure_mode: auto brightness: 50 contrast: 60 track: # 以深色赛道线为例HSV 范围按实际调试结果调整 lower_hsv: [0, 0, 0] upper_hsv: [180, 255, 90] roi: # 感兴趣区域只处理画面下方区域减少远处干扰 start_row: 80 end_row: 240 start_col: 20 end_col: 300 morph: open_size: 3 close_size: 9配置文件集中管理的价值等到现场调试的时候才会真正体现。比赛现场时间紧张若因为改一个亮度阈值就要重新编译一次固件那会浪费大量时间。4. 核心模块实现与原理4.1 轮腿底盘的直立与平衡控制轮腿车与普通四轮车的最大区别在平衡。如果车身重心较高腿部结构又存在弹性车在加速和转向时会明显晃动这会直接恶化摄像头采集图像的质量。我的平衡控制采用经典的“直立环 速度环”串级结构直立环负责让车体保持竖直使用 PD 控制。速度环负责调整目标速度使用 PI 控制。两个环路嵌套直立环在内、速度环在外速度环输出作为直立环的目标角度修正。简单理解直立环让车不摔速度环让车往前走且不冲过头。一个基础的直立环控制循环用 C 可以这样写// 文件路径firmware/control/balance_controller.cpp // 示意代码具体参数需要根据实际传感器和机械结构调试 class BalanceController { public: void init(float kp, float kd, float ki) { kp_ kp; kd_ kd; ki_ ki; integral_ 0.0f; last_error_ 0.0f; } // pitch_angle 为当前车身倾角target_speed 为速度环输出的目标速度 float update(float pitch_angle, float target_speed) { // 目标角速度会根据目标速度做适量前倾补偿 float target_angle 0.0f kp_speed_ * target_speed; float error target_angle - pitch_angle; integral_ error; integral_ clamp(integral_, -100.0f, 100.0f); float differential error - last_error_; last_error_ error; // 直立 PD 速度积分项 float output kp_ * error kd_ * differential ki_ * integral_; return clamp(output, -1000.0f, 1000.0f); } private: float clamp(float v, float min_v, float max_v) { if (v min_v) return min_v; if (v max_v) return max_v; return v; } float kp_, kd_, ki_; float kp_speed_ 0.02f; float integral_ 0.0f; float last_error_ 0.0f; };这里要特别提醒PID 参数没有一劳永逸的固定值每个机械结构都不一样。正确做法是先只调直立环P 从很小开始加到车体能“硬起来”再一点点加 D 抑制抖动。直立环稳定后再加速度环观察匀速行驶时有没有来回震荡。最后再调转向因为转向会引入横向扰动容易暴露直立环刚度不足的问题。4.2 室外视觉信息提取室外视觉是我投入时间最多的部分。传统的边缘提取在室外很容易被阴影干扰所以我选择了“基于颜色空间的赛道线分割 形态学处理 轮廓中心提取”。为什么用 HSV 而不是 RGB因为 RGB 受亮度影响非常大同一个颜色在阳光直射和阴影下的 RGB 值可能差很多。而 HSV 把色相 H、饱和度 S、亮度 V 分开在光照剧烈变化时H 分量相对稳定更适合做室外颜色分割。下面是一段用 Python OpenCV 验证的视觉处理核心流程示意# 文件路径tools/vision_demo.py # 用于离线视频验证视觉算法的 Python 原型 import cv2 import numpy as np def process_frame(frame): # 1. 裁剪感兴趣区域减少远处天空和景物干扰 roi frame[100:240, 20:300] # 2. 转为 HSV 颜色空间 hsv cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) # 3. 根据配置的阈值提取赛道线 lower np.array([0, 0, 0]) upper np.array([180, 255, 90]) mask cv2.inRange(hsv, lower, upper) # 4. 形态学操作先开运算去噪再闭运算连接断裂区域 kernel_open cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) kernel_close cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9)) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel_open) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel_close) # 5. 提取轮廓并计算赛道中心 contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if len(contours) 0: return mask, None, 1.0 # 丢失赛道标志 largest_contour max(contours, keycv2.contourArea) M cv2.moments(largest_contour) if M[m00] 0: return mask, None, 1.0 center_x int(M[m10] / M[m00]) # 偏差正值偏右负值偏左 frame_width roi.shape[1] error (center_x - frame_width / 2) / (frame_width / 2) return mask, error, 0.0这里最关键的两点形态学操作很重要。室外图像小噪点很多不做开运算会一堆假轮廓赛道线如果有断裂不做闭运算会把一条线分割成多段导致中心计算不稳定。轮廓面积过滤也值得加。把小于一定像素面积的目标直接忽略避免把远处一个水坑或落叶当成赛道线。由于室外光照变化非常快我额外加了“动态阈值校准”机制每隔一段时间取画面中央部分的亮度中位数动态微调 V 通道的阈值范围。这个操作很简单但在实际调试中效果显著。4.3 元素识别与决策状态机室外赛道不可能永远是简单直线转弯、上下坡、特殊元素等场景如果都用同一组 PID 参数很难做到最优。我的做法是用“有限状态机”来管理不同的运动模式。核心思想是不依赖单帧图像直接判断当前是哪个元素而是维护一个状态只有连续多帧满足切换条件时才切换状态。这样可以过滤掉单帧抖动带来的误判。一个简化的状态机逻辑如下// 文件路径vision/recognition/track_state_machine.cpp // 示意代码展示状态机切换思路 enum class TrackState { STRAIGHT, LEFT_TURN, RIGHT_TURN, ELEMENT_A, ELEMENT_B, LOST }; const char* stateName(TrackState s) { switch (s) { case TrackState::STRAIGHT: return STRAIGHT; case TrackState::LEFT_TURN: return LEFT_TURN; case TrackState::RIGHT_TURN: return RIGHT_TURN; case TrackState::ELEMENT_A: return ELEMENT_A; case TrackState::ELEMENT_B: return ELEMENT_B; case TrackState::LOST: return LOST; } return UNKNOWN; } class StateMachine { public: void reset() { state_ TrackState::STRAIGHT; frame_count_ 0; } void update(float error, int flagA, int flagB) { TrackState next state_; if (flagA) next TrackState::ELEMENT_A; else if (flagB) next TrackState::ELEMENT_B; else if (error 0.2f) next TrackState::RIGHT_TURN; else if (error -0.2f) next TrackState::LEFT_TURN; else next TrackState::STRAIGHT; if (next state_) { frame_count_ 0; } else { frame_count_; } // 连续超过 3 帧才允许切换状态 if (frame_count_ 3) { state_ next; frame_count_ 0; } } TrackState getState() const { return state_; } private: TrackState state_; int frame_count_ 0; };为什么要用连续帧确认因为视觉单帧误判很难完全避免。如果镜头正好拍到阴影边缘可能一个直线状态就变成了转弯状态。把“单帧可能出错”作为前提设计算法系统稳定性会高很多。另外状态机切到 LOST 时不要立刻刹车。更稳妥的做法是保留上一个有效状态用稍低的速度继续运行同时提高搜索范围阈值尝试找回赛道。如果超过限定时间仍未找回再执行停车保护。4.4 速度规划与转向输出感知和状态机解决了“车在哪、赛道长什么样”的问题接下来要让车动起来。速度规划我采用“曲率感知 分段限速”策略直道允许较高速度。大弯道降低目标速度同时增大转向比例系数。特殊元素前提前减速通过后再恢复。转向输出本质上是一个 PD 控制器输入为赛道中心偏差 error输出为转向角度或差速比。这里我加了一个“非线性死区”处理当偏差很小时输出为 0 或很小避免频繁抖动。当偏差中等时按固定比例输出转向。当偏差很大时输出限幅到最大值同时降低目标速度。转向控制的简化示意如下// 文件路径firmware/control/steering_controller.cpp // 计算转向输出输出范围 -1.0 ~ 1.0负值左转正值右转 float computeSteering(float error, float kp_steer, float kd_steer, float last_error) { float output kp_steer * error kd_steer * (error - last_error); // 死区处理 if (abs(output) 0.08f) { output 0.0f; } // 输出限幅 if (output 1.0f) output 1.0f; if (output -1.0f) output -1.0f; return output; }速度规划和转向是一体的。如果车入弯速度太快转向再强也容易冲出赛道。所以我在程序中做了这样一条硬规则当转向绝对值超过某个阈值时目标速度必须线性下降。这个规则用代码写非常简单但实际效果立竿见影——弯道不再甩尾直道也能尽量跑满。5. 调试方法论与工程经验5.1 先跑起来再调精度很多人一开始就追求完美视觉要达到多少帧率平衡要多久不倒。我的建议恰好相反——第一版代码怎么简陋怎么来。先让车能简单直行、能识别最基本的赛道线哪怕速度只有 0.2m/s 都可以。拿到一个“能跑的最简系统”后再一步步加功能、加约束。这样做有三个好处每一个新改动都能立刻在真车上验证不会积压大量错误。任何一步出问题都知道是最近这次改动引起的排查范围很小。心理压力小很多不会因为系统一直跑不起来而焦虑。5.2 视觉调参数记录、回放、再调参室外视觉最大的困难不是算法不先进而是你很难在调试现场复现同一个环境。太阳角度变了、云飘过来了画面就完全不一样。所以我花了很多时间做了一个“图像记录与回放工具”# 文件路径tools/image_replay.py # 从视频中抽帧方便离线反复调整视觉参数 import cv2 video_path track_20240601_16_30.avi cap cv2.VideoCapture(video_path) save_dir frames_output/ frame_id 0 while True: ret, frame cap.read() if not ret: break if frame_id % 5 0: cv2.imwrite(save_dir fframe_{frame_id:05d}.jpg, frame) frame_id 1 cap.release() print(done)有了录制好的真实赛道视频后我可以在宿舍里慢慢调 HSV 阈值、形态学核大小、ROI 区域不需要带队去室外一遍遍跑。这样效率提高非常多。同时我也养成了保存参数版本的习惯。“今天上午曝光强参数一套下午阴天参数另一套”每套参数都记下日期、天气和效果。这个习惯在比赛现场临时遇到天气变化时救了我很多次。5.3 底盘调参从平衡环到速度环底盘调试的核心顺序我前面提到过但这里再细化一下第一步把车架起来轮子悬空调直立环输出方向。注意方向弄反车会瞬间飞出去所以第一版代码务必先看电机响应方向对不对。第二步让车接触地面并尝试平衡。最开始手扶着一点一点增加 P。第三步平衡稳定后加入速度环。观察车在均匀速度下是否出现周期性的“前冲—后仰”震荡。第四步加转向。先低速转大弯再逐步提高速度和弯道难度。另外电机供电非常关键。舵机、电机、主控不要共用一路电源否则舵机启动瞬间电压跌落会导致 MCU 复位表现就是车跑着跑着突然重启极难排查。5.4 现场比赛的系统性检查清单比赛前最后一周我不怎么改算法而是反复做整机检查。这里分享一份我的检查清单电池电压是否充足备用电池是否提前充满。所有螺丝是否紧固尤其是轮腿连接件和摄像头支架。摄像头有没有松动镜头是否有污渍。串口通信线是否插紧引脚有没有虚焊。配置文件参数和当前赛道类型是否匹配。代码仓库是否提交是否能一键构建出最新固件。无线调试功能是否正常紧急遥控停车是否可用。6. 常见问题与排查思路室外轮腿视觉车的调试过程本质上是在不断“踩坑—定位—修复”中前进。下面整理了我遇到的高频问题供大家排查时参考。问题现象常见原因解决思路车体无法直立直接倒向一边平衡环输出方向反了先悬空验证电机响应方向处理好方向再调参数直立时车身来回抖动P 过大或 D 过小降低 P逐步增大 D观察震荡幅度变化匀速行驶时出现周期性前后摇摆速度环积分过大减小 Ki或限制积分累计上限画面过曝赛道线完全看不清曝光参数不适合当前室外光照将曝光模式改为自动或根据 ROI 亮度动态调曝光赛道线提取出现大量碎块阈值不合适或形态学核太小调整 HSV 范围增大闭运算核尺寸弯道入弯不降速冲出赛道速度规划和转向未联动转向输出大时强制降低目标速度舵机动作卡顿偶尔无响应供电不足或堵转独立供电检查机械结构是否存在卡死视觉和底盘通信丢帧串口波特率太高或抗干扰不足降低波特率加帧头帧尾和校验使用屏蔽线典型的两个问题我再展开讲一下。问题一画面过曝怎么办室外阳光下自动曝光很可能会被天空或远处亮部影响导致近处赛道变暗或发白。我把曝光参考区域限制在图像下方的 ROI 内让摄像头主要参考“赛道区域”的平均亮度。这样即使天空很亮也不会影响近处赛道的曝光。问题二状态机误触发怎么办某一帧突然识别到元素标志马上切换状态结果发现是误判。解决方式就是前面代码中已经体现的“连续帧确认”。这里要强调确认帧数不能设得太大否则车辆已经开过元素状态还没切换。一般 3 到 5 帧是合理的平衡点。7. 开源仓库组织与发布建议7.1 为什么要把方案开源拿完国一之后代码一直放在本地其实也是一种选择。但我觉得这套方案最大的价值不只是那一张证书而是整个调试过程中沉淀下来的方法论和避坑经验。开源可以让更多学弟学妹少走弯路也能通过社区反馈发现自己设计中的不足。从另一个角度讲开源过程本身就强迫你把代码整理清楚、把文档补完整是一次很好的工程训练。7.2 开源仓库里应该包含什么我建议不只是放代码。智能车项目是“机械 硬件 软件 算法”的综合体只放代码别人很难复现。推荐开源仓库包含以下内容README.md项目简介、整体架构图、快速开始教程。源码视觉模块、控制模块、通信模块。参数配置所有可调参数的默认配置。机械结构文件三维模型或外壳图纸。调试文档PID 调试记录、视觉调参记录。比赛总结哪些方案有效、哪些方案被淘汰以及原因。7.3 README 快速开始示例一份好的 README 应该让新人在 10 分钟内搞明白“这个项目怎么跑起来”。下面是一个简化模板# smartcar-wheelleg 第21届全国大学生智能车竞赛 轮腿组国一方案。 本仓库包含完整的室外视觉感知、轮腿平衡控制、状态机决策代码。 采用轻量级视觉方案不依赖高算力平台适合复现和二次开发。 ## 快速开始 ### 1. 克隆仓库 git clone https://gitee.com/your_name/smartcar-wheelleg.git cd smartcar-wheelleg ### 2. 安装依赖 - OpenCV 4.5 - CMake 3.16 - C 编译器 ### 3. 构建视觉模块 cd vision mkdir build cd build cmake .. make ### 4. 运行图像回放工具 python3 tools/image_replay.py --video track.avi ## 目录说明 - firmware/ : MCU 主控固件负责平衡与电机控制 - vision/ : 室外视觉感知与赛道识别 - configs/ : 视觉阈值、PID 参数、赛道配置 ## 相关文档 - [算法设计文档](docs/algorithm-design.md) - [硬件结构说明](docs/hardware-design.md) - [比赛经验总结](docs/competition-summary.md)国内队伍考虑到下载速度可以选择托管在 Gitee 上如果你自己经常使用 GitHub也可以上传一份到 GitHub并在 README 里互相跳转。不需要额外引入复杂的协作工具Git 本身就足够支撑一支 2 到 4 人的竞赛队伍了。8. 学习路线与工程建议8.1 给智能车新手的学习路径如果你还是一名刚接触智能车竞赛的本科生建议按下面顺序推进先让车“动起来”。不管用什么电机、什么板子搞定驱动让轮子能转。做一个最简单的循迹。一根红外对管或一个灰度传感器都行先理解反馈闭环。再把视觉加上。从离线图片开始把颜色分割、边缘提取、中心计算的流程跑通。在真车上闭环调试。先直道再弯道再特殊元素。最后才是优化和比赛冲刺。优化永远建立在稳定系统之上而不是反过来。不要一开始就陷进“哪个模型更强”“哪个架构更先进”的讨论里。对竞赛来说能稳定复现的方法才是好方法。8.2 从比赛到工程思维的转变竞赛和做企业项目有一个共同点不确定性永远存在。室外视觉不会因为你换了一个更好的摄像头就突然不抖了状态机也不会因为你多写了一个分支就自动变稳。真正的进步来自系统化的调试、数据驱动的决策、团队分工和代码规范。比赛结束后我最大的收获并不是某一套算法而是养成了一套处理复杂系统的工作习惯先拆解再隔离再验证最后整体联调。这套习惯在任何嵌入式项目、任何软件系统开发中都适用。8.3 写在最后智能车竞赛不是一个“比谁代码炫”的比赛而是一个“比谁在真实物理世界里更稳”的比赛。轮腿 室外视觉的方案给了我很深的体验——越是看起来复杂的系统越需要你用简单可靠的方式去化解复杂度。我的这套“猎奇方案”已经开源配置、代码、文档都在仓库里。如果你也想做轮腿车或者对室外视觉感知感兴趣可以直接从仓库拉一份代码先跑通再改成你自己的版本。祝每一位认真调车的朋友都能在赛场上跑出自己的节奏。
返回列表