便携式远程监控摄像头机器人系统
组件与材料
| 组件 | 数量 |
|---|---|
| SparkFun Arduino Pro Mini 328 - 5V/16MHz | 1 |
| 轮胎 + 减速直流电机 + 固定支架 | 1 套 |
| SparkFun 双 H 桥驱动板 L298 | 1 |
| Raspberry Pi 3 Model B | 1 |
| Raspberry Pi Camera Module | 1 |
所需工具
- USB 转串口 FTDI 适配器 (FT232RL)
- Arduino IDE
- 电钻
- 细齿锯
- 螺丝刀套装
- 电烙铁
- 剥线钳
项目简介
这是一个集机械制造、嵌入式开发、Linux 系统配置、Android App 开发、网络通信于一体的综合项目。虽然复杂,但拆解学习每个模块极具价值。
核心技术栈:
- 开发平台:Arduino、Raspberry Pi、Android
- 电子电路:H 桥驱动、三极管驱动大功率负载、红外避障
- Linux:Docker、Docker Compose、systemd 服务管理、视频流
- 编程:Android (Java/Kotlin)、Python、Arduino C++、串口通信、MQTT
步骤 1:材料清单


结构件:亚克力/有机玻璃板、塑料板、胶水、轮胎+减速电机+支架、螺母螺栓、六角铜柱、万向轮×2、小型 LED 手电筒(改装前照灯)、PCB 板、NPN 三极管(驱动前照灯)、L7805CV 5V 稳压、L298 H桥、220Ω 电阻、USB 公头、Micro USB 公头、各色导线、3.3V 稳压(Pi-Arduino 通讯)、公母排针、开关、XT60 母头、2S 1300mAh LiPo 电池、5V 移动电源、Pi 3、Pi 存储卡、Pi 外壳、Pi 摄像头。
步骤 2:机械平台搭建
设计目标:前轮双电机差速转向(原地旋转)、后轮万向轮、顶部前照灯、内部容纳电池/电路/Pi 箱、底盘离地几厘米。
底盘:18×13cm 底板,电机用金属支架固定,H桥装底板朝下,后轮用 2cm 六角铜柱(一公一母)固定,底板预留大孔穿线。
上层:两块 L 型板(12×13cm 和 6.5×13cm)胶合,提供电子仓盖、前照灯座、Pi 箱支撑,用 6cm 六角铜柱与底盘连接。

























步骤 3:电子电路制作

























Arduino 引脚分配
- 前照灯:D3
- 左电机:PWM D5, EN1 A4, EN2 A5
- 右电机:PWM D6, EN1 A3, EN2 A2
- 红外避障:前 A0, 后 A1
- Pi 通讯:TX D11, RX D10 (软串口)
PCB 组装要点
- 底盘底部已装 H桥,另装前/后红外传感器(用 L 型金属片固定)。
- 前照灯:拆解 5V LED 手电筒仅保留灯头,焊线穿孔至上层板,接 2P 母座。
- Pi 箱组装:装入 Pi、摄像头、存储卡(已烧录 Raspbian)、摄像头排线。
- 主控 PCB 焊接顺序:排母座 → KF301-2P 端子 → NPN 三极管+基极电阻 → L7805CV → 3.3V 稳压(Arduino TX 线) → Arduino Pro Mini 公排针 → 信号线(红/黑/白) → 前照灯公排针。
- 连接器制作:
① 5V 移动电源 → USB A 公头 + Micro USB 公头 双头供电 Pi 与 Arduino。
② LiPo 电池 → XT60 母头 + 开关 → KF301-2P 供电 H桥/电机。
③ 红外传感器、H桥、电机、主电源按对应排针连接。 - 上电前务必放大镜检查焊点、万用表测通断短路。
步骤 4:Arduino 固件
为什么要中间层 Arduino?
- 模块化:可脱离 Pi 独立复用。
- 安全:烧坏 3 美元 Pro Mini 远好过 35 美元 Pi。
- 实时性:裸机轮询传感器、PWM 控制电机,不受 OS 抢占。
- 看门狗可靠:Python 脚本挂起可能导致电机失控,Arduino 看门狗更可靠。
- 解耦调试:分层排查更容易。
固件功能:
- 串口接收指令控制电机/灯光。协议示例:
M:-25:16;左转 25 功率 16 → 左电机 17% 右电机 32% 前进M:44:19;右转 44 功率 19 → 左 38% 右 5% 前进L:1;灯亮L:0灯灭 - 定时轮询前/后红外传感器,串口上报距离数据:
F=3:B=0;
依赖库 TextMotorCommandsInterpretter (GitHub)。完整代码:
// source: https://github.com/danionescu0/arduino/tree/master/libraries/TextMotorCommandsInterpretter
#include <SoftwareSerial.h>
#include <TextMotorCommandsInterpretter.h>
const char MOTOR_COMMAND = 'M';
const char LIGHT_COMMAND = 'L';
const long maxDurationForMottorCommand = 300; // ms
const byte maxPwmValue = 230;
const long transmitingInterval = 500;
const int maxObstacleDetection = 1000;
const int minObstacleDetection = 500;
const byte FLASH_PIN = 3;
const byte RIGHT_MOTOR_PWM_PIN = 5;
const byte RIGHT_MOTOR_EN1_PIN = A4;
const byte RIGHT_MOTOR_EN2_PIN = A5;
const byte LEFT_MOTOR_PWM_PIN = 6;
const byte LEFT_MOTOR_EN1_PIN = A3;
const byte LEFT_MOTOR_EN2_PIN = A2;
const byte FRONT_DISTANCE_SENSOR = A0;
const byte BACK_DISTANCE_SENSOR = A1;
SoftwareSerial masterComm(11, 10); // RX, TX
TextMotorCommandsInterpretter motorCommandsInterpretter(-50, 50, -50, 50);
String currentCommand;
long lastCheckedTime;
long lastTransmitTime;
boolean inMotion = false;
void setup() {
Serial.begin(9600);
masterComm.begin(9600);
masterComm.setTimeout(10);
pinMode(FLASH_PIN, OUTPUT);
pinMode(LEFT_MOTOR_PWM_PIN, OUTPUT);
pinMode(LEFT_MOTOR_EN1_PIN, OUTPUT);
pinMode(LEFT_MOTOR_EN2_PIN, OUTPUT);
pinMode(RIGHT_MOTOR_PWM_PIN, OUTPUT);
pinMode(RIGHT_MOTOR_EN1_PIN, OUTPUT);
pinMode(RIGHT_MOTOR_EN2_PIN, OUTPUT);
lastCheckedTime = millis();
lastTransmitTime = millis();
}
void loop() {
if (masterComm.available() > 0) {
currentCommand = masterComm.readString();
processCommand();
}
if (inMotion && millis() - lastCheckedTime > maxDurationForMottorCommand) {
stopMotors();
}
if (millis() - lastTransmitTime > transmitingInterval) {
lastTransmitTime = millis();
masterComm.print(getObstacleData());
Serial.print(analogRead(BACK_DISTANCE_SENSOR)); Serial.print("---");
Serial.println(getObstacleData());
}
}
String getObstacleData() {
int frontDistance = analogRead(FRONT_DISTANCE_SENSOR);
int backDistace = analogRead(BACK_DISTANCE_SENSOR);
frontDistance = map(frontDistance, maxObstacleDetection, minObstacleDetection, 0, 10);
backDistace = map(backDistace, maxObstacleDetection, minObstacleDetection, 0, 10);
return String("F=" + String(frontDistance) + ":B=" + String(backDistace) + ";");
}
void processCommand() {
switch (currentCommand.charAt(0)) {
case MOTOR_COMMAND: steerCar(); break;
case LIGHT_COMMAND: toggleLight(currentCommand.charAt(2)); break;
}
}
void steerCar() {
motorCommandsInterpretter.analizeText(currentCommand);
float percentLeftMotor = motorCommandsInterpretter.getPercentLeft();
float percentRightMotor = motorCommandsInterpretter.getPercentRight();
Serial.write("Left="); Serial.println(percentLeftMotor);
Serial.write("Right="); Serial.println(percentRightMotor);
setMotorsDirection(motorCommandsInterpretter.getDirection());
analogWrite(LEFT_MOTOR_PWM_PIN, percentLeftMotor * maxPwmValue);
analogWrite(RIGHT_MOTOR_PWM_PIN, percentRightMotor * maxPwmValue);
inMotion = true;
lastCheckedTime = millis();
}
void setMotorsDirection(boolean forward) {
if (forward) {
digitalWrite(LEFT_MOTOR_EN1_PIN, HIGH);
digitalWrite(LEFT_MOTOR_EN2_PIN, LOW);
digitalWrite(RIGHT_MOTOR_EN1_PIN, HIGH);
digitalWrite(RIGHT_MOTOR_EN2_PIN, LOW);
} else {
digitalWrite(LEFT_MOTOR_EN1_PIN, LOW);
digitalWrite(LEFT_MOTOR_EN2_PIN, HIGH);
digitalWrite(RIGHT_MOTOR_EN1_PIN, LOW);
digitalWrite(RIGHT_MOTOR_EN2_PIN, HIGH);
}
}
void stopMotors() {
Serial.println("Stopping motors");
analogWrite(LEFT_MOTOR_PWM_PIN, 0);
analogWrite(RIGHT_MOTOR_PWM_PIN, 0);
inMotion = false;
}
void toggleLight(char command) {
Serial.println("Toggle light");
if (command == '1') digitalWrite(FLASH_PIN, HIGH);
else digitalWrite(FLASH_PIN, LOW);
}
用 FTDI 适配器烧录。调试可接蓝牙模块(HC-05)发送串口指令测试。
步骤 5:树莓派端部署
架构概览:

- Android App 在 WebView 中显示 uv4l 视频流 (Pi 端采集摄像头推流)。
- App 控制指令 → MQTT Broker (Mosquitto)。
- Docker 容器中 Python 服务订阅 MQTT,经串口转发给 Arduino。
- Arduino 串口上报避障距离 → Python → MQTT → App 显示。
前置条件
- Pi 烧录最新 Raspbian,摄像头硬件连接并启用 (参考 官方文档)。
- 配置 SSH 远程管理。
- 如需外网访问,路由器端口映射:9090 (uv4l)、1883 (Mosquitto)。
安装步骤
git clone https://github.com/danionescu0/robot-camera-platform.git(目录固定为/home/pi/robot-camera-platform,如改动需同步修改docker-compose.yml)。- 禁用 Pi 串口控制台 (参考 官方指南)。
- 安装 uv4l:
chmod +x uv4l/install.sh uv4l/start.sh && sh ./uv4l/install.sh
编辑uv4l/start.sh配置密码、端口、帧率、分辨率、旋转等。
测试:sh ./uv4l/start.sh→ 浏览器访问https://<Pi_IP>:9090/stream→sudo pkill uv4l停止。 - 配置
config.py(MQTT 密码、串口设备/波特率) 和docker-container/mosquitto/Dockerfile(设置 Mosquitto 用户密码)。 - 安装 Docker & Docker Compose (参考 树莓派官方博客)。
- 配置 systemd 自启动:
sudo cp systemctl/* /etc/systemd/system/sudo systemctl enable robot-camera.service robot-camera-video.service
重启验证:sudo systemctl status robot-camera.servicesudo systemctl status robot-camera-video.service
步骤 6:Android App 配置与构建
git clone https://github.com/danionescu0/android-robot-camera- 开启手机开发者选项 & USB 调试。
- 安装 Android Studio,导入项目。
- 编辑
app/src/main/res/values/passwords.xml填入 MQTT 服务器地址/端口、流媒体地址/端口。 - 连接手机运行/安装 APK。
步骤 7:使用与调试



App 操作
- 左侧显示视频流,右侧虚拟方向盘控制移动,下方按钮切换前照灯。
- 右上角状态栏:
- Batt Connected。
第一字符:-无障碍,↑前方障碍,↓后方障碍。Batt电量状态(未实现)。Connected/DisconnectedMQTT 连接状态。
多层级调试
- Arduino 层:FTDI 接第二串口(Pro Mini D11/D10)发指令测试电机/灯光;检查电机反转则对调两线;核对 H桥接线。
- Pi 层:
docker ps确认两容器运行;netstat -nltp检查 9090/1883 端口;ls -l /dev/ttyS0确认串口设备;停止 Docker 后用picocom -b 9600 /dev/ttyS0直连 Arduino 测试;确认串口控制台已禁用;外部机器测试 MQTT/流媒体可达性。 - App 层:检查
passwords.xml配置;验证流媒体/MQTT 外部可达;观察右上角 “Connected”;Android Studio Logcat 查报错。
步骤 8:扩展应用 — 颜色物体跟踪
机器人可跟随特定颜色/大小物体。需 pip3 install -r navigation/requirements.txt (较慢)。修改 navigation/config_navigation.py 中 HSV 阈值 hsv_bounds 和尺寸阈值 object_size_threshold。安装 VNC 查看桌面,运行 python3 object_tracking.py colored-object --show-video 实时查看检测框。
更多创意:人脸跟随、巡逻报警、3G/4G 远程探索危险区域等。项目复杂难免疏漏,欢迎评论区提问交流。喜欢请订阅作者 YouTube 频道支持更多作品。
代码仓库
- Android App:https://github.com/danionescu0/android-robot-camera
- 主仓库 (Arduino/Python/Docker) :https://github.com/danionescu0/robot-camera-platform
原理图
制造工艺
- 现代相机的演变与设计
- 深度解析相机镜头:设计原理、发展历史与未来创新
- MrRobot:Ubuntu移动端控制Rapiro机器人,支持语音、触控与摇晃交互
- Roomberry:用树莓派 Zero W 将 Roomba 改装为监控机器人
- 蓝牙控制 Arduino 电动相机滑轨:打造丝滑电影级运镜
- 互动陀螺仪 LED 显示:NeoPixel Ring + Arduino Pro Mini
- 基于 Arduino、1Sheeld 与红外控制的万能安卓遥控器
- DIY Arduino USB 游戏手柄 — 自制高性能游戏手柄
- Pixie:基于 Arduino Pro Mini 的 NeoPixel 智能腕表 - 极简 DIY LED 时钟
- 在 Arduino Due 上实现语音识别与语音合成 - BitVoicer Server 方案
- Arduino PowerPoint 指针:无缝无线演示控制器
- 智能手语手套:柔性传感器 + 加速度计 + 蓝牙将手势转文字/语音