19f06d383258c.png

项目名称:摔倒报警监控 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 导航系统靠近异常现场,最终触发报警或远程通知。

项目总体方案

系统组成

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

工作流程:从巡航到报警

19f06d703dfe1.png

关键技术解读:从“看见人”到“发出报警”

这个项目的技术链路可以拆成四个连续问题:

问题 对应技术 解决目标
人在哪里? 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

这个规则并不是最终模型,而是一个容易理解的工程起点:人体检测负责“看见人”,深度信息负责“确认空间位置”,持续时间负责“避免一闪而过的误报”。

19f06d91e138c.png

技术重点:摔倒识别不能只看“有没有 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 负责这件事。

导航链路可以理解为:

19f0d5f929a91.png

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 机器人常见的分层方式:导航算法只管输出速度,底盘节点负责把速度翻译成硬件能理解的串口帧。

19f06db0f237a.png

技术重点:麦克纳姆轮支持横向移动,适合室内窄空间调整姿态。但麦轮在地毯、门槛或湿滑地面上可能打滑,因此里程计、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. 报警系统需要避免什么问题?

报警链路不仅要“能打电话”,还要尽量减少误报和漏报。比较完整的报警策略应包括:

19f0d641cf1c4.png

这条链路看似简单,却是项目落地的关键:当视觉系统判断异常后,报警不能只停留在屏幕弹窗,而要让家属或医护人员真正收到通知。

技术重点:报警系统应具备“触发条件”“复核机制”“失败重试”“联系人优先级”“本地日志”五个要素。当前串口拨号脚本已经打通了最核心的通信路径,后续可继续封装为 ROS service 或 action,方便控制层统一调用。

应用场景

19f06dddd4a48.png

1. 独居老人家庭守护

小车可在客厅、卧室、走廊等区域巡航,实时监测老人活动状态。一旦出现长时间倒地、异常静止或呼救指令,系统可以靠近现场复核并拨打家属电话。

2. 医院病房和康复中心

针对术后康复、行动不便或夜间无人看护场景,小车可辅助护士站进行移动巡检。它不替代医护人员,但可以帮助提前发现风险。

3. 社区养老与公共空间巡逻

在社区活动室、养老驿站、图书馆等公共场所,小车可进行移动监控、异常识别和远程通知,提高场所安全管理效率。

项目亮点

亮点 1:移动式监控,减少固定摄像头盲区

机器人可以主动巡航和靠近现场,解决固定摄像头角度受限的问题。对居家养老来说,这比单点摄像头更贴近真实生活场景。

亮点 2:RGB-D 感知,让摔倒判断更有空间依据

Gemini 2 深度相机不仅提供画面,还提供距离和空间关系。后续如果加入人体姿态估计、地面平面检测、深度滤波,摔倒判断会比单纯图像分类更可靠。

亮点 3:ROS 模块化架构,便于迭代

相机、雷达、底盘、报警、语音交互都可以以节点形式独立开发。未来替换模型、升级雷达、改报警方式,都不必推翻整个系统。

亮点 4:离线报警链路,增强可靠性

SIM 卡串口拨号不完全依赖家庭 Wi-Fi。对于养老安全产品,这种“关键时刻能打出去”的能力很重要。

可继续优化的方向

方向 优化建议
摔倒识别 在 YOLO 检测基础上加入人体姿态估计、深度高度判断、持续时间判断,降低误报
深度计算 对检测框中心区域做均值/中值滤波,剔除深度空洞与异常点
控制逻辑 将报警脚本封装为 ROS service/action,便于状态机统一调度
导航安全 融合超声波近距离避障,设置靠近人体时的低速安全模式
人机交互 接入 6 通道麦克风阵列,实现呼救词识别、语音确认和情绪陪伴
远程平台 扩展 Web/APP 端,实现实时画面、报警记录、地图位置和远程控制
隐私保护 增加本地化推理、敏感画面脱敏、权限控制和日志追溯

最终效果愿景

理想状态下,这台小车不是一个“会动的摄像头”,而是一个居家安全节点:

19f06dedbd0aa.png
  • 平时,它是巡航监控和语音陪伴设备。
  • 出现异常时,它是第一时间发现现场的移动传感器。
  • 需要救援时,它是主动拨号、推送位置和提供现场画面的报警终端。

养老机器人真正困难的地方,不是某一个算法单点多炫,而是能否在真实家庭环境里稳定工作。这个项目已经把关键链路搭起来:3D 视觉看见人,ROS 导航让小车动起来,串口报警让异常被通知出去。后续继续增强摔倒判别模型和系统稳定性,它就具备向真实养老看护场景推进的基础。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注