面灵AI→

原力灵机机器人软件工程一二面:ROS 2 通信机制与真机排查

轮次
一面+二面
结果
一、二面已过,等终面
时间
2026-10
来源
牛客网

《面试题目》

一面(约 50 分钟)

  1. 请做一下自我介绍(2 分钟左右)。
  2. 挑一个你参与最深的项目,画架构图讲清楚:背景、整体架构、你负责哪一块、遇到过什么问题、最后怎么解决。
  3. 机器人上的节点是怎么划分的?底盘和机械臂之间为什么用 ROS 2 通信?
  4. Topic、Service、Action 有什么区别?项目里分别用在哪?
  5. 抓取这类长任务为什么不能用 Service 一直阻塞等?
  6. Action 底层是怎么实现的?
  7. QoS 了解吗?雷达、相机这类传感器话题应该怎么配?
  8. 订阅者掉线一段时间,消息要不要补?(durability)
  9. ROS 2 相比 ROS 1 最大的变化是什么?DDS 在里面起什么作用?
  10. launch 和参数是怎么组织的?
  11. 指针和引用有什么区别?
  12. shared_ptr 的原理是什么?引用计数线程安全吗?循环引用怎么办?
  13. 虚函数和多态是怎么实现的?析构函数为什么建议写成 virtual?
  14. 多线程:互斥锁怎么用?死锁的四个必要条件是什么?生产者消费者怎么写?
  15. 程序在机器人上偶发崩溃,怎么查?
  16. CPU 占用突然飙高,怎么定位?
  17. 串口、CAN 收数据怎么保证不丢?
  18. 反问环节。

二面(约 70 分钟)

  1. 真机联调时踩过最大的坑是什么?
  2. 机器人跑着跑着,一个机械臂突然不动了,怎么查?
  3. 怎么确认指令已经发出去了?录下来的包怎么和现场时间对上?
  4. 相机丢帧、不出图怎么排查?
  5. 通信出现周期性卡顿,怀疑是哪里?
  6. EtherCAT 的状态机和 PDO/SDO 了解吗?WKC 是什么?
  7. CAN 的 bus-off 怎么恢复?平时怎么抓包?
  8. STM32:中断和轮询怎么选?HardFault 怎么定位?串口怎么用 DMA 加空闲中断收不定长数据?
  9. 雷达和相机怎么做时间同步?多个传感器的坐标系怎么管理?
  10. 代码怎么合入、怎么交叉编译出包、现场怎么部署升级?机器人长时间跑怎么保证不出事?
  11. 反问环节。

《参考解析》

ROS 2 通信三件套:按消息的生命周期选

Topic 是单向、异步、多对多的数据流,适合高频且「新值覆盖旧值」的数据,比如底盘速度指令、雷达与相机话题;Service 是请求-应答,一次性、同步,适合「取一次配置、查一次状态」这种短操作;Action 是给长任务准备的,有 goal、feedback、result,可取消、可查询进度,抓取这类要跑几秒到几十秒的任务用它才不会把调用方卡死。为什么不能拿 Service 一直阻塞等?因为服务端在处理这个请求期间无法响应同一回调组里的其它回调,客户端也在同步等待,整条链路实质上被冻住;一旦任务耗时不可控(抓取失败重试、目标丢失),超时与取消都无从谈起。Action 底层确实就是 Service 加 Topic 拼出来的:发送目标、取消目标走 Service,反馈、状态、结果走 Topic——被追问「底层怎么实现」时答出这一点,比只背三个概念高一个层次。

QoS 与 DDS:ROS 2 真正的分水岭

QoS 是 ROS 2 相对 ROS 1 最本质的变化,它把「可靠性」交还给使用者配置。传感器话题的典型配法是 reliability 选 best_effort、history 选 keep_last 并给一个较小的 depth:丢一帧点云或图像无关紧要,反过来用 reliable 会在网络抖动时积压重传,延迟越滚越大。控制指令与静态参数则相反,用 reliable 甚至 transient_local 的 durability,这样后加入的订阅者也能拿到最后一次发布的参数。面试官会顺着 durability 追问「订阅者掉线一段时间回来要不要补历史消息」——volatile 不补、transient_local 补,判据是这条数据是不是「最新值即全部」。DDS 是 ROS 2 的通信底座:它负责服务发现(不再需要 roscore 那样的中心 master)、提供发布订阅与 QoS 协商,因此节点可以分布式自发现,也能往实时与安全(SROS2)方向扩展。ROS 2 的其它差异顺手带上:launch 变成 Python 脚本、生命周期节点、跨平台与实时内核配置。

真机排查:先定位「哪一层断了」,再谈原因

二面几乎全是场景题,套路是把链路分层——上层指令有没有发出、通信有没有到、从站有没有执行、机械有没有被急停或保护掐断,然后逐层取证。机械臂突然不动:先看急停与电源、驱动器指示灯与报错,再看总线状态(EtherCAT 的从站状态、CAN 的错误计数与 bus-off),然后确认指令是否真的发出——用 ros2 topic hz 与 ros2 topic echo 看话题频率与内容,必要时录包回放。录包与现场时间对齐靠的是 bag 中每条消息的接收时间戳加统一时钟:上位机与控制器走 PTP/NTP,或者把急停、日志行连同时间戳一起记下来做交叉比对,否则事后只能靠猜。相机丢帧、不出图按物理层到应用层排:线缆与供电、USB 或网口带宽是否被别的设备占满、dmesg 看驱动报错、话题频率是否掉、图像时间戳是否连续。周期性卡顿优先怀疑调度而不是带宽:控制线程优先级够不够、有没有被高负载线程抢占、总线错误计数是否在涨;用 top -H 把 CPU 占用拆到线程粒度、再用 perf 看热点,能很快区分「算不过来」和「被打断」。

总线与嵌入式:答得上细节的都是真做过

EtherCAT 的状态机是 Init → Pre-Operational → Safe-Operational → Operational,每往上一级开放的能力不同:到 Pre-Op 才能走邮箱通信配参数,进 Safe-Op 后从站开始收过程数据但输出仍被屏蔽,Op 才真正生效。PDO 是每个周期都传的过程数据(位置、状态字),SDO 是邮箱式的参数读写,非周期、可以长包;WKC(Working Counter)是每个从站处理过帧之后累加的计数,主站拿它和期望值比对,就能判断有没有从站掉队——比逐个读寄存器快得多,是现场定位掉站的第一手信号。CAN 这边,bus-off 是发送错误计数累计超过阈值后节点主动退出总线的保护动作,恢复有自动与手动重启控制器两种,真正常见的根因是终端电阻缺失、波特率不一致、线缆过长或共地不良;用 candump 抓包配合 ip -details link show can0 看 TEC/REC 与状态字,比盲猜快。STM32 的几问全是实战:中断与轮询按实时性要求、触发频率、处理耗时来选,高频且要确定响应的用中断,慢速批量的用轮询,中断里只做搬运、重活交给线程或 DMA;HardFault 定位看 SCB 里的 CFSR/HFSR 与压栈的 PC、LR,再回 .map 反查函数;不定长串口帧的标准写法是 DMA 接收加 IDLE 空闲中断,用空闲线判定一帧结束,既不必逐字节中断也不怕帧长变化。

时间同步、坐标管理与工程化:把「能跑」做成「能长期跑」

多传感器融合的前提是同一时间基准:雷达和相机要么硬件同步(同一个触发源给相机曝光脉冲、与雷达共时钟),要么走 PTP(IEEE 1588,亚微秒级)而不是 NTP;软件打时间戳要减掉传输与驱动缓冲带来的固定延迟,并标成「采样时刻」而不是「收到时刻」,否则标定与融合会系统性偏移。坐标系交给 tf2:静态外参用 static_transform_publisher 发布,动态关系(里程计、定位)由对应节点发布,查询时给 timeout 容忍坐标树短暂未就绪,同时注意时间戳一致——用 bag 回放时要开 use_sim_time,否则 tf 会因为「未来数据」报错。工程化那组问题(代码怎么合入、怎么交叉编译出包、现场怎么部署升级、长时间运行怎么不出事)面试官只要求讲清流程:分支与评审、用交叉工具链加 sysroot 打平台包、现场灰度升级与回滚、看门狗与日志回传保证出问题可查。

C++ 与 Linux 调试:八股都挂在项目上

指针与引用:指针可以为空、可以重指向,引用必须初始化且绑定后不可改;接口里表示「一定存在」用引用,表示「可能没有」用指针或 optional。shared_ptr 的引用计数在控制块里是原子操作,多线程拷贝同一个 shared_ptr 是安全的,但它保护的是「谁持有」,不保护被指向对象的内容——对象自身的读写仍要自己加锁,这是最常见的追问陷阱。循环引用(父持子 shared、子持父 shared)会让计数永远不归零,标准解法是一端改 weak_ptr,典型场景是观察者、缓存与定时器回调只持弱引用。虚析构的必要性在于通过基类指针 delete 派生对象时,只有虚函数表才能找到派生类析构,否则派生类的资源不释放,是实打实的泄漏。死锁四个必要条件(互斥、持有并等待、不可剥夺、循环等待)背下来只是起点,工程上真正管用的是统一加锁顺序、用 std::scoped_lock 一次锁多个互斥量、给等待加超时兜底。Linux 两题的答法固定:偶发崩溃先开 core dump,用 gdb 看 backtrace 与寄存器,再结合业务日志还原时序;CPU 飙高用 top -H 找到线程,再用 perf top/record 定位热点函数。串口与 CAN 不丢数据的原则是「缓冲加及时搬走」:环形缓冲、单生产者单消费者,把处理逻辑挪出中断。