一、 项目背景:被井道噪声逼疯的弱电工程师
在上个月的一个智慧园区项目中,我们需要让物流AGV自主上下楼。由于电梯太老没有网络接口,我们采用了一款通用的非侵入式机器人梯控 网关设备。思路很简单:在轿顶外挂光电传感器,检测井道内的隔光板,以此来推算电梯当前所在的楼层。
原本以为把传感器往上一挂,GPIO读取个高低电平就完事了。但实操时发现,电磁与机械运行环境十分复杂。变频器启动时的电磁辐射、电梯高速运行时的机械震动,导致传感器传回来的信号充满了毛刺(Glitch)。小车经常误以为电梯到了,结果门还没开就往前冲。
为了解决这个问题,我们在网关侧进行了一系列硬件检查与软件滤波调校,这里把详细的踩坑记录分享给大家。

二、 硬件实施调校:从源头干掉机械抖动
1. 物理位置的"三维对齐"
一开始,现场实施师傅只是随便用轧带把探头绑在钢丝绳支架旁。电梯一跑,探头自身跟着晃,导致感应距离时远时近(临界震荡)。
我们重新进行了调校:
-
X/Y轴: 使用定制的L型角铁,利用原厂感应器支架的孔位进行螺丝硬连接。
-
Z轴(间隙): 用塞尺测量光电探头槽与隔光板的距离,确保探头两侧间隙均等(通常保持在5mm左右的居中位置),防止电梯在水平晃动时刮擦探头。
2. 强弱电隔离布线
我们发现网关的输入端子经常收到莫名其妙的脉冲。排查后发现,传感器的信号线和轿厢照明的220V交流电绑在了一起。必须将24V的弱电信号线单独穿管,或者使用带屏蔽网的线缆,并将屏蔽层单端接地接到轿顶的金属梁上。
三、 软件滤波实战:用代码手撕电磁干扰
光有硬件对齐还不够,网关接收到的GPIO信号仍然需要经过严格的软件防抖(Debounce)处理。我们不能一检测到电平跳变就认为楼层变了,必须引入时间窗口和状态机机制。
以下是我们针对该非侵入式架构,在网关内编写的一段简化的传感器信号滤波与楼层计数逻辑(基于C语言/伪代码演示):
C
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#define DEBOUNCE_TIME_MS 150 // 防抖阈值:持续150ms才认为是有效平层信号
#define FLOOR_MAX 10
// 模拟读取GPIO状态 (1: 经过感应板, 0: 未经过)
extern bool read_sensor_gpio(void);
extern uint32_t get_system_tick_ms(void);
typedef struct {
bool current_state;
bool last_state;
uint32_t last_debounce_time;
int current_floor;
int direction; // 1: up, -1: down
} ElevatorState;
ElevatorState elevator = {false, false, 0, 1, 1};
void update_elevator_status() {
bool reading = read_sensor_gpio();
// 如果读到的状态和上次不同,说明发生了电平跳变(可能是真实信号,也可能是毛刺)
if (reading != elevator.last_state) {
elevator.last_debounce_time = get_system_tick_ms(); // 重置计时器
}
// 如果当前状态保持的时间超过了设定的防抖阈值
if ((get_system_tick_ms() - elevator.last_debounce_time) > DEBOUNCE_TIME_MS) {
// 如果确认状态发生了实质性改变
if (reading != elevator.current_state) {
elevator.current_state = reading;
// 当状态从 0 变 1 时,意味着进入了平层区
if (elevator.current_state == true) {
// 根据运行方向更新楼层
elevator.current_floor += elevator.direction;
// 边界保护
if(elevator.current_floor > FLOOR_MAX) elevator.current_floor = FLOOR_MAX;
if(elevator.current_floor < 1) elevator.current_floor = 1;
printf("[状态机] 电梯平层信号确认!当前计算楼层: %d\n", elevator.current_floor);
// 此处可触发MQTT消息上报给调度系统...
}
}
}
// 保存本次读取的状态,供下一次循环比对
elevator.last_state = reading;
}
// 主循环
int main() {
while(1) {
update_elevator_status();
// 适当休眠让出CPU
// sleep(10);
}
return 0;
}
[DBG] 10:20:01.102 -> GPIO_IN_01 HIGH (Floor 5 Arrived), Debounce 150ms passed.
四、 状态机逻辑的进阶思考
在实际的非侵入式机器人梯控 项目中,仅仅计算楼层是不够的,还需要结合"上行/下行继电器状态"以及"开门到位传感器"组成一个复合状态机。
例如,只有当 current_floor == target_floor 且 door_open_sensor == true 时,网关才会向小车下发"允许驶入"的指令。

五、 交付总结
实施这种非侵入式方案,本质上是在用传统的工业控制思维解决现代IT问题。对于实施工程师和开发者而言,不要过度迷信上层算法,回归底层的物理隔离与电气滤波,踏踏实实地把传感器的位置调好、把防抖代码写健壮,才是项目快速交付、减少半夜报修的最优解。