
项目名称:摔倒报警监控 ROS 智能小车 来源:第四届 3D 视觉创新应用竞赛 + 吴成威 相机型号:Gemini 2 双目结构光 3D 相机 核心平台:Jetson Nano + Ubuntu 20.04 + ROS Noetic 支持设备:镭神 N10/N10P 激光雷达、科大讯飞 6 通道麦克风阵列语音模块、麦克纳姆轮底盘、超声波模块、SIM 卡串口报警模块 代码参考:https://github.com/3DCVdeveloper/RobotV_Fall-alarm-monitoring
一句话看懂项目
这是一套面向独居老人安全守护的移动式智能监控系统:小车通过 Gemini 2 深度相机和 YOLO 视觉检测识别人体状态,通过激光雷达、超声波与底盘控制完成自主导航和避障;当检测到老人摔倒等异常情况时,可联动 SIM 卡串口模块拨打电话报警,并可扩展语音交互、远程监控和云端通知能力。
它的价值不在于“多装几个传感器”,而在于把视觉感知、空间定位、移动底盘和报警链路整合成一个可巡航、可靠近现场、可主动上报的 ROS 机器人系统。
为什么这个项目值得做?
跌倒已经成为 65 岁以上老年人因伤致死的重要原因之一。独居老人摔倒后,真正危险的不是“摔倒”这个动作本身,而是无人发现、无人响应、救援延迟。
传统固定摄像头有几个明显短板:
- 只能看固定角度,存在卫生间、卧室转角、家具遮挡等盲区。
- 只能记录画面,缺少主动靠近、复核和报警能力。
- 普通 2D 图像很难稳定区分“躺下休息”和“异常倒地”。
这台小车的思路是:让监控从墙上“走下来”。它可以在室内移动巡航,利用深度相机获取空间信息,结合目标检测识别人体位置,再通过 ROS 导航系统靠近异常现场,最终触发报警或远程通知。
项目总体方案
系统组成

| 层级 | 模块 | 作用 |
|---|---|---|
| 计算层 | Jetson Nano | 运行 Ubuntu 20.04、ROS Noetic、YOLO 检测节点、传感器驱动与控制逻辑 |
| 视觉层 | Gemini 2 双目结构光 3D 相机 | 输出 RGB/深度图,支持人体检测、空间距离估计与异常状态分析 |
| 导航层 | 镭神 N10/N10P 激光雷达 | 输出 scan 数据,用于建图、定位、障碍物检测和代价地图更新 |
| 运动层 | STM32 + 麦克纳姆轮底盘 | 接收 ROS 的 cmd_vel 速度指令,驱动底盘全向移动 |
| 安全层 | 超声波模块 | 近距离辅助避障,提高低速靠近人体或家具时的安全性 |
| 交互层 | 科大讯飞 6 通道麦克风阵列 | 可扩展语音唤醒、语音指令、紧急呼叫和智能问答 |
| 报警层 | SIM 卡串口设备 | 通过 AT 指令拨打电话,实现离线可用的紧急报警 |
工作流程:从巡航到报警

关键技术解读:从“看见人”到“发出报警”
这个项目的技术链路可以拆成四个连续问题:
| 问题 | 对应技术 | 解决目标 |
|---|---|---|
| 人在哪里? | YOLO + RGB 图像 | 从画面中检测人体目标 |
| 人离小车多远? | Gemini 2 深度图 | 把 2D 检测框补成 3D 空间信息 |
| 小车如何过去? | ROS Navigation + 雷达代价地图 | 在室内避障、规划路线、靠近现场 |
| 异常如何通知? | SIM 串口报警 | 通过电话链路通知家属或医护人员 |
换句话说,这不是单个算法的展示,而是一个“感知-判断-移动-报警”的机器人闭环。
关键技术一:RGB-D 视觉如何判断“人摔倒了”?
1. 技术目标
普通摄像头只能知道“画面里有一个人”,但很难知道这个人离相机多远、身体是否贴近地面、是否处在家具遮挡后的空间区域。Gemini 2 双目结构光 3D 相机的作用,就是给 YOLO 的 2D 检测结果补上空间距离。
Gemini 2 的核心是“双目结构光”:相机主动投射不可见红外结构光到场景中,再由相机采集反射图案,通过三角测量计算空间深度。资料中给出的关键参数包括:
- 深度图像分辨率:1280 x 800@30fps,640 x 400@60fps
- 测量距离:0.25m 到 7m
- 精度:在 1280 x 800@4m、81% ROI 条件下可达不高于 2%
- 接口:USB Type-C
2. 输入、处理和输出
| 环节 | 数据 |
|---|---|
| 输入 | RGB 图像、深度图、YOLO 人体检测框 |
| 处理 | 判断 person 置信度、计算检测框宽高比、读取框中心或框内区域深度 |
| 输出 | 人体位置、人体距离、疑似摔倒状态、是否触发复核或报警 |
3. 项目中的检测节点逻辑
项目代码中的 YOLO 检测节点订阅了深度图话题,并读取检测结果文件中的类别、置信度和检测框坐标。核心思路如下:
class YoloDetector:
def __init__(self):
self.image_sub = rospy.Subscriber(
"/camera/depth/image_raw",
Image,
self.image_callback
)
self.bridge = CvBridge()
def image_callback(self, msg):
cls_name, conf, x, y, w, h = self.read_detection_results()
if cls_name == "person" and conf > 0.6:
cv_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding="bgr8")
cv2.rectangle(
cv_image,
(int(x - w / 2), int(y - h / 2)),
(int(x + w / 2), int(y + h / 2)),
(0, 255, 0),
2
)
这段逻辑完成了第一步:确认画面中存在高置信度人体,并把检测框画到相机图像上。它解决的是“找到人”的问题。
4. 推荐的深度融合写法
真正用于摔倒判断时,建议不要只取一个中心点深度,因为深度图可能存在空洞、反光噪声或边缘误差。更稳的方式是在检测框中心附近取一个小区域,再做中值滤波:
def estimate_person_depth(depth_image, x, y, box_w, box_h):
cx, cy = int(x), int(y)
radius = max(4, int(min(box_w, box_h) * 0.05))
roi = depth_image[
max(0, cy - radius): cy + radius,
max(0, cx - radius): cx + radius
]
valid_depth = roi[(roi > 0) & (roi < 7000)]
if len(valid_depth) == 0:
return None
return float(np.median(valid_depth)) / 1000.0
5. 摔倒判定可以怎么做?
只看 person 是不够的。更合理的判断应把多个信号组合起来:
def is_fall_like_person(box_w, box_h, depth_m, duration_s):
aspect_ratio = box_w / max(box_h, 1)
body_is_horizontal = aspect_ratio > 1.4
person_is_near_ground = depth_m is not None and depth_m < 5.0
state_is_stable = duration_s >= 3.0
return body_is_horizontal and person_is_near_ground and state_is_stable
这个规则并不是最终模型,而是一个容易理解的工程起点:人体检测负责“看见人”,深度信息负责“确认空间位置”,持续时间负责“避免一闪而过的误报”。

技术重点:摔倒识别不能只看“有没有 person”。更稳的方案应结合目标框宽高比、人体中心高度、地面距离、持续时间和深度变化。也就是说,视觉检测负责“找到人”,深度信息负责“理解空间状态”。
关键技术二:ROS 如何把多个硬件模块组织起来?
1. 技术目标
ROS 不是“软件外壳”,而是系统骨架。它把相机、雷达、底盘、报警模块拆成多个节点,节点之间通过话题、服务或动作通信。这样做的好处是:相机坏了可以单独调相机,雷达数据异常可以单独查雷达,报警逻辑也可以独立测试。
2. 推荐的话题关系
Gemini 2 Camera
-> /camera/color/image_raw
-> /camera/depth/image_raw
YOLO Detector
<- /camera/color/image_raw
<- /camera/depth/image_raw
-> /fall/person_state
Lidar
-> /scan
ROS Navigation
<- /scan
<- /odom
-> /cmd_vel
Wheeltec Chassis Node
<- /cmd_vel
-> /odom
-> /imu
-> /PowerVoltage
Alarm Node
<- /fall/person_state
-> SIM module phone call
3. 最小启动文件示例
项目中已有 YOLO 节点启动文件,后续可以把相机、雷达、底盘和报警节点统一拉起。结构可参考:
<launch>
<include file="$(find astra_camera)/launch/gemini.launch" />
<include file="$(find lslidar_driver)/launch/lslidar.launch" />
<node pkg="turn_on_wheeltec_robot"
type="wheeltec_robot"
name="wheeltec_robot"
output="screen" />
<node pkg="yolov8_track"
type="yolov8_ros_track.py"
name="fall_detector"
output="screen" />
<node pkg="fall_alarm"
type="sim_alarm_node.py"
name="sim_alarm"
output="screen" />
</launch>
4. 控制层应该如何调度?
控制层可以理解为项目的大脑。它不直接处理每个传感器的底层细节,而是订阅各节点输出的状态,再决定下一步动作:
if person_state == "normal":
patrol()
elif person_state == "suspected_fall":
slow_down()
approach_target()
start_recheck_timer()
elif person_state == "confirmed_fall":
stop_robot()
call_family()
upload_event()
技术重点:ROS 的价值在于解耦。上层算法不需要知道电机如何转动,只需要发布
cmd_vel;报警逻辑也不需要知道 YOLO 如何推理,只需要接收“疑似摔倒/确认摔倒”的状态。
关键技术三:小车如何在家里“不撞、不迷路”?
1. 技术目标
小车要在老人家中运行,不能只会识别摔倒,还必须能安全移动。项目中激光雷达和 ROS Navigation 负责这件事。
导航链路可以理解为:

2. 代价地图是什么?
“代价地图”是机器人眼中的室内风险地图。墙体、家具、人和临时障碍物都会被映射成不同代价的区域。规划器不会简单地走直线,而是在可通行、安全距离和底盘运动约束之间寻找可执行路线。
配置文件中可以看到雷达作为障碍物观测源输入 costmap_2d:
obstacle_layer:
enabled: true
observation_sources: scan
scan:
topic: scan
sensor_frame: laser
data_type: LaserScan
clearing: true
marking: true
obstacle_range: 2.5
raytrace_range: 3.0
这里几个参数很关键:
topic: scan表示障碍物来自激光雷达扫描数据。
clearing: true表示雷达可以清除已经变为空闲的区域。
marking: true表示雷达可以把新障碍物写入地图。
obstacle_range控制多远范围内的障碍物会被加入代价地图。
raytrace_range控制机器人向外“清空可见空间”的距离。
3. 路径规划如何输出速度?
项目配置中使用了全局规划器和 TEB 局部规划器:
base_global_planner: "global_planner/GlobalPlanner"
base_local_planner: "teb_local_planner/TebLocalPlannerROS"
controller_frequency: 10.0
planner_frequency: 1.0
全局规划器解决“从当前位置到目标点大致怎么走”,局部规划器解决“下一秒怎么绕开眼前障碍物”。最终输出的是标准 ROS 速度话题 cmd_vel。
4. 底盘节点如何理解cmd_vel?
底盘节点订阅 cmd_vel,把线速度和角速度转换成串口数据帧发送给 STM32。项目代码中可以看到类似这样的处理:
void turn_on_robot::Cmd_Vel_Callback(const geometry_msgs::Twist &twist_aux)
{
short transition;
Send_Data.tx[0] = FRAME_HEADER;
transition = twist_aux.linear.x * 1000;
Send_Data.tx[3] = transition >> 8;
Send_Data.tx[4] = transition;
transition = twist_aux.linear.y * 1000;
Send_Data.tx[5] = transition >> 8;
Send_Data.tx[6] = transition;
transition = twist_aux.angular.z * 1000;
Send_Data.tx[7] = transition >> 8;
Send_Data.tx[8] = transition;
Send_Data.tx[9] = Check_Sum(9, SEND_DATA_CHECK);
Send_Data.tx[10] = FRAME_TAIL;
Stm32_Serial.write(Send_Data.tx, sizeof(Send_Data.tx));
}
这段代码体现了 ROS 机器人常见的分层方式:导航算法只管输出速度,底盘节点负责把速度翻译成硬件能理解的串口帧。

技术重点:麦克纳姆轮支持横向移动,适合室内窄空间调整姿态。但麦轮在地毯、门槛或湿滑地面上可能打滑,因此里程计、IMU 与雷达定位之间的协同非常重要。
关键技术四:报警链路为什么选 SIM 串口?
1. 技术目标
很多智能设备依赖 Wi-Fi 或云服务报警,但养老场景里最怕网络不稳定。SIM 卡串口报警模块的优势是直接、独立、低门槛:Jetson Nano 通过串口连接模块,发送 AT 指令即可拨打电话。
2. 串口拨号的基本流程
项目代码中的报警脚本逻辑包括:
- 打开
/dev/ttyUSB0串口。
- 设置 115200 波特率。
- 发送
ATE0等初始化指令。
- 使用
ATD + 电话号码 + ;发起拨号。
- 根据模块返回值判断是否拨号失败。
- 通话结束后发送
ATH挂断。
核心代码可理解为:
import serial
import time
ser = serial.Serial("/dev/ttyUSB0", 115200, timeout=1)
def initialize_module():
ser.write(b"ATE0rn")
time.sleep(1)
return True
def dial(phone_number):
command = b"ATD" + phone_number.encode() + b";rn"
ser.write(command)
def hang_up():
ser.write(b"ATHrn")
time.sleep(8)
3. 为什么建议封装成 ROS 服务?
如果报警脚本只是一个单独的 Python 文件,控制层调用起来不够优雅。更推荐把它封装成 ROS service,让其他节点用统一接口触发报警:
/fall_alarm/call
request:
phone_number: "151xxxx9692"
message_type: "confirmed_fall"
response:
success: true
detail: "dial command sent"
控制层调用时就会更清楚:
if fall_state == "confirmed":
rospy.wait_for_service("/fall_alarm/call")
call_alarm = rospy.ServiceProxy("/fall_alarm/call", FallAlarm)
result = call_alarm(phone_number, "confirmed_fall")
4. 报警系统需要避免什么问题?
报警链路不仅要“能打电话”,还要尽量减少误报和漏报。比较完整的报警策略应包括:

这条链路看似简单,却是项目落地的关键:当视觉系统判断异常后,报警不能只停留在屏幕弹窗,而要让家属或医护人员真正收到通知。
技术重点:报警系统应具备“触发条件”“复核机制”“失败重试”“联系人优先级”“本地日志”五个要素。当前串口拨号脚本已经打通了最核心的通信路径,后续可继续封装为 ROS service 或 action,方便控制层统一调用。
应用场景

1. 独居老人家庭守护
小车可在客厅、卧室、走廊等区域巡航,实时监测老人活动状态。一旦出现长时间倒地、异常静止或呼救指令,系统可以靠近现场复核并拨打家属电话。
2. 医院病房和康复中心
针对术后康复、行动不便或夜间无人看护场景,小车可辅助护士站进行移动巡检。它不替代医护人员,但可以帮助提前发现风险。
3. 社区养老与公共空间巡逻
在社区活动室、养老驿站、图书馆等公共场所,小车可进行移动监控、异常识别和远程通知,提高场所安全管理效率。
项目亮点
亮点 1:移动式监控,减少固定摄像头盲区
机器人可以主动巡航和靠近现场,解决固定摄像头角度受限的问题。对居家养老来说,这比单点摄像头更贴近真实生活场景。
亮点 2:RGB-D 感知,让摔倒判断更有空间依据
Gemini 2 深度相机不仅提供画面,还提供距离和空间关系。后续如果加入人体姿态估计、地面平面检测、深度滤波,摔倒判断会比单纯图像分类更可靠。
亮点 3:ROS 模块化架构,便于迭代
相机、雷达、底盘、报警、语音交互都可以以节点形式独立开发。未来替换模型、升级雷达、改报警方式,都不必推翻整个系统。
亮点 4:离线报警链路,增强可靠性
SIM 卡串口拨号不完全依赖家庭 Wi-Fi。对于养老安全产品,这种“关键时刻能打出去”的能力很重要。
可继续优化的方向
| 方向 | 优化建议 |
|---|---|
| 摔倒识别 | 在 YOLO 检测基础上加入人体姿态估计、深度高度判断、持续时间判断,降低误报 |
| 深度计算 | 对检测框中心区域做均值/中值滤波,剔除深度空洞与异常点 |
| 控制逻辑 | 将报警脚本封装为 ROS service/action,便于状态机统一调度 |
| 导航安全 | 融合超声波近距离避障,设置靠近人体时的低速安全模式 |
| 人机交互 | 接入 6 通道麦克风阵列,实现呼救词识别、语音确认和情绪陪伴 |
| 远程平台 | 扩展 Web/APP 端,实现实时画面、报警记录、地图位置和远程控制 |
| 隐私保护 | 增加本地化推理、敏感画面脱敏、权限控制和日志追溯 |
最终效果愿景
理想状态下,这台小车不是一个“会动的摄像头”,而是一个居家安全节点:

- 平时,它是巡航监控和语音陪伴设备。
- 出现异常时,它是第一时间发现现场的移动传感器。
- 需要救援时,它是主动拨号、推送位置和提供现场画面的报警终端。
养老机器人真正困难的地方,不是某一个算法单点多炫,而是能否在真实家庭环境里稳定工作。这个项目已经把关键链路搭起来:3D 视觉看见人,ROS 导航让小车动起来,串口报警让异常被通知出去。后续继续增强摔倒判别模型和系统稳定性,它就具备向真实养老看护场景推进的基础。