← 返回首页
← 返回上一页
📑 目录
1. 项目概述
📌 小布米简介
| 身高 | 94cm |
| 体重 | 12kg |
| 自由度 | 21个 |
| 价格 | ¥9998 |
| 公司 | 北京松延动力 (Noetix Robotics) |
🎯 可实现场景
- 远程监控 + AI 对话 - 远程查看家中情况,语音聊天
- 舵机控制开关 - 物理按压墙壁开关
- 红外控制家电 - 控制空调、电视、风扇
- 智能插座控制 - 控制台灯、风扇等
2. 硬件清单
| 场景 | 配件 | 数量 | 价格 | 难度 |
|---|---|---|---|---|
| 场景1 | 小布米自带(摄像头/麦克风/扬声器) | 1 | ¥0 | 简单 |
| 场景2 | 舵机 MG996R | 4 | ¥60 | 困难 |
| PCA9685 I2C控制板 | 1 | ¥15 | ||
| 3D打印手指支架 | 1 | ¥30 | ||
| 杜邦线+电源 | 1 | ¥20 | ||
| 场景3 | 红外发射管 + 38KHz模块 | 1 | ¥20 | 中等 |
| 场景4 | WiFi智能插座 | 若干 | ¥30-50/个 | 简单 |
| 总计(全部场景) | 约 ¥145-200 | |||
3. 场景一:远程监控 + AI 对话
🎯 目标
通过 QQ/微信/Telegram 远程查看小布米摄像头画面,并进行 AI 对话
3.1 部署服务(小布米端)
在有小布米上安装 Python 环境并创建服务:
mkdir -p ~/xiaoao-robot && cd ~/xiaoao-robot
pip install flask flask-cors opencv-python numpy pyaudio gTTS
创建主服务文件 ~/xiaoao-robot/main.py:
#!/usr/bin/env python3
"""小布米机器人控制服务 - 远程监控+AI对话"""
from flask import Flask, request, jsonify, send_file
from flask_cors import CORS
import cv2
import numpy as np
import threading
import base64
import io
from gtts import gTTS
import os
import time
app = Flask(__name__)
CORS(app)
# 全局变量
camera = None
audio_buffer = []
current_frame = None
def init_camera():
"""初始化摄像头"""
global camera
camera = cv2.VideoCapture(0)
camera.set(3, 640) # 宽度
camera.set(4, 480) # 高度
def generate_frames():
"""生成视频流"""
global current_frame
while True:
if camera is not None:
success, frame = camera.read()
if success:
current_frame = frame
# 压缩为 JPEG
ret, buffer = cv2.imencode('.jpg', frame)
if ret:
frame_bytes = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
time.sleep(0.03) # 约30fps
@app.route('/camera/stream')
def stream_camera():
"""视频流端点"""
return Response(generate_frames(),
mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/camera/snapshot')
def snapshot():
"""拍照端点"""
global current_frame
if current_frame is not None:
_, buffer = cv2.imencode('.jpg', current_frame)
return send_file(io.BytesIO(buffer), mimetype='image/jpeg')
return jsonify({'error': 'No frame available'}), 400
@app.route('/camera/snapshot/base64')
def snapshot_base64():
"""返回 Base64 编码的图片(用于发送给 OpenClaw)"""
global current_frame
if current_frame is not None:
_, buffer = cv2.imencode('.jpg', current_frame)
img_base64 = base64.b64encode(buffer).decode('utf-8')
return jsonify({'image': f'data:image/jpeg;base64,{img_base64}'})
return jsonify({'error': 'No frame available'}), 400
@app.route('/tts/speak', methods=['POST'])
def speak():
"""文字转语音端点"""
data = request.json
text = data.get('text', '')
lang = data.get('lang', 'zh-CN')
if not text:
return jsonify({'error': 'No text provided'}), 400
# 生成语音
tts = gTTS(text=text, lang=lang)
audio_file = io.BytesIO()
tts.write_to_fp(audio_file)
audio_file.seek(0)
return send_file(audio_file, mimetype='audio/mp3')
@app.route('/status')
def status():
"""服务状态"""
return jsonify({
'status': 'running',
'camera': camera is not None,
'timestamp': time.time()
})
if __name__ == '__main__':
init_camera()
print("🚀 小布米服务启动: http://0.0.0.0:5000")
app.run(host='0.0.0.0', port=5000, debug=False)
3.2 后台运行
# 使用 screen 或 nohup 后台运行
cd ~/xiaoao-robot
nohup python3 main.py > robot.log 2>&1 &
# 或使用 systemd(推荐)
sudo tee /etc/systemd/system/xiaoao-robot.service > /dev/null <
3.3 API 端点总结
端点 方法 说明
/camera/stream GET 视频流 (MJPEG)
/camera/snapshot GET 拍照 (JPEG)
/camera/snapshot/base64 GET Base64 图片 (JSON)
/tts/speak POST 文字转语音
/status GET 服务状态
⚠️ 注意事项
- 确保小布米和小布米在同一局域网
- 如需外网访问,需配置端口转发或 VPN
- 如需 https,使用 nginx 反向代理
4. 场景二:舵机控制开关
🎯 目标
通过 OpenClaw 控制舵机,物理按压墙壁开关
4.1 硬件接线
PCA9685 引脚连接: ├── SCL → 小布米 I2C SCL ├── SDA → 小布米 I2C SDA ├── VCC → 5V 电源正极 └── GND → GND 舵机连接: ├── 舵机0 → PCA9685 通道0 (客厅灯) ├── 舵机1 → PCA9685 通道1 (卧室灯) ├── 舵机2 → PCA9685 通道2 (厨房灯) └── 舵机3 → PCA9685 通道3 (卫生间灯)
4.2 安装依赖
sudo apt-get install -y python3-pip i2c-tools
pip3 install adafruit-circuitpython-servokit smbus2
# 开启 I2C 接口
sudo raspi-config
# 选择 Interface Options → I2C → Enable
4.3 舵机控制服务
#!/usr/bin/env python3
"""舵机控制服务 - 控制开关"""
from flask import Flask, request, jsonify
from adafruit_servokit import ServoKit
import time
app = Flask(__name__)
# 初始化 PCA9685 (16通道)
kit = ServoKit(channels=16)
# 开关位置映射
SWITCH_MAP = {
'客厅灯': {'servo': 0, 'angle_press': 90, 'angle_reset': 0},
'卧室灯': {'servo': 1, 'angle_press': 90, 'angle_reset': 0},
'厨房灯': {'servo': 2, 'angle_press': 90, 'angle_reset': 0},
'卫生间灯': {'servo': 3, 'angle_press': 90, 'angle_reset': 0},
}
def press_switch(servo_id, press_angle=90, reset_angle=0, hold_time=0.5):
"""按压开关"""
try:
servo = kit.servo[servo_id]
# 按下
servo.angle = press_angle
time.sleep(hold_time)
# 复位
servo.angle = reset_angle
return True
except Exception as e:
print(f"Error: {e}")
return False
@app.route('/switch/', methods=['POST'])
def control_switch(device):
"""控制开关"""
data = request.json or {}
action = data.get('action', 'toggle') # toggle, on, off
if device not in SWITCH_MAP:
return jsonify({'error': f'Unknown device: {device}'}), 404
config = SWITCH_MAP[device]
success = press_switch(config['servo'],
config['angle_press'],
config['angle_reset'])
return jsonify({
'device': device,
'action': action,
'success': success
})
@app.route('/switches')
def list_switches():
"""列出所有开关"""
return jsonify({
'devices': list(SWITCH_MAP.keys()),
'map': SWITCH_MAP
})
@app.route('/calibrate', methods=['POST'])
def calibrate():
"""校准舵机"""
data = request.json
servo_id = data.get('servo', 0)
angle = data.get('angle', 90)
kit.servo[servo_id].angle = angle
return jsonify({'servo': servo_id, 'angle': angle})
if __name__ == '__main__':
print("🎮 舵机服务启动: http://0.0.0.0:5001")
app.run(host='0.0.0.0', port=5001, debug=False)
4.4 校准步骤
- 运行服务后,通过 API 调整舵机角度
- 找到手指对准开关的角度
- 更新 SWITCH_MAP 中的 angle_press 值
- 测试开关是否正常
⚠️ 难点提醒
- 3D 打印手指支架需要精确设计
- 不同开关位置需要单独校准
- 建议添加限位开关防止舵机过转
5. 场景三:红外控制家电
🎯 目标
通过红外发射控制空调、电视、风扇等红外设备
5.1 硬件
| 红外发射管 | VS1838B 或 通用 38KHz 模块 |
| 连接 | GPIO 18 (BCM) 或任意 PWM 引脚 |
5.2 安装 LIRC
sudo apt-get install -y lirc
# 编辑 /boot/config.txt 添加:
# dtoverlay=lirc-rpi,gpio_in_pin=18,gpio_out_pin=17
# 编辑 /etc/lirc/lircd.conf.d/ 添加强制码
5.3 红外控制服务
#!/usr/bin/env python3
"""红外控制服务"""
from flask import Flask, request, jsonify
import subprocess
import time
app = Flask(__name__)
# 红外命令映射(需要先用 irw 录制)
COMMANDS = {
'空调开': 'KEY_POWERON',
'空调关': 'KEY_POWEROFF',
'空调升温': 'KEY_TEMPUP',
'空调降温': 'KEY_TEMPDOWN',
'电视开': 'KEY_POWER',
'电视音量加': 'KEY_VOLUMEUP',
'电视音量减': 'KEY_VOLUMEDOWN',
}
def send_ir(command):
"""发送红外命令"""
try:
subprocess.run(['irsend', 'SEND_ONCE', 'ac_remote', command],
check=True, capture_output=True)
return True
except Exception as e:
print(f"IR Error: {e}")
return False
@app.route('/ir/', methods=['POST'])
def ir_control(command):
"""发送红外命令"""
if command not in COMMANDS:
return jsonify({'error': 'Unknown command'}), 404
success = send_ir(COMMANDS[command])
return jsonify({'command': command, 'success': success})
@app.route('/ir/list')
def list_commands():
"""列出可用命令"""
return jsonify({'commands': list(COMMANDS.keys())})
if __name__ == '__main__':
print("📡 红外服务启动: http://0.0.0.0:5002")
app.run(host='0.0.0.0', port=5002, debug=False)
5.4 录制红外码
# 1. 停止 LIRC
sudo systemctl stop lircd
# 2. 录制遥控器按键
mode2 -d /dev/lirc0 | irrecord -d /dev/lirc0 my_remote.conf
# 3. 复制配置
sudo cp my_remote.conf /etc/lirc/lircd.conf.d/
# 4. 重启 LIRC
sudo systemctl start lircd
# 5. 测试
irsend LIST ac_remote ""
irsend SEND_ONCE ac_remote KEY_POWERON
6. 场景四:智能插座控制
🎯 目标
通过 WiFi 智能插座控制普通电器(台灯、风扇等)
6.1 推荐硬件
| 型号 | 协议 | 价格 | 备注 |
|---|---|---|---|
| 小米米家插座 | 米家/小米 | ¥50 | 需米家APP |
| TP-Link Kasa | Kasa | ¥40 | 支持 API |
| 涂鸦智能插座 | Tuya | ¥30 | 需配网 |
| ESP01S 继电器 | 自建 | ¥15 | 需要动手 |
6.2 涂鸦智能插座方案
#!/usr/bin/env python3
"""智能插座控制服务 (Tuya)"""
from flask import Flask, request, jsonify
import tinytuya
app = Flask(__name__)
# 插座配置(从 涂鸦APP 获取)
DEVICES = {
'客厅台灯': {'id': 'bf1234567890abcdef', 'key': '你的设备key', 'ip': '192.168.1.xxx'},
'卧室风扇': {'id': 'bf1234567890abcdef', 'key': '你的设备key', 'ip': '192.168.1.xxx'},
}
def get_device(name):
"""获取设备"""
if name not in DEVICES:
return None
cfg = DEVICES[name]
d = tinytuya.OutletDevice(cfg['id'], cfg['ip'], cfg['key'])
d.set_version(3.3)
return d
@app.route('/plug//on', methods=['POST'])
def plug_on(name):
"""打开插座"""
d = get_device(name)
if d:
d.turn_on()
return jsonify({'device': name, 'state': 'on'})
return jsonify({'error': 'Device not found'}), 404
@app.route('/plug//off', methods=['POST'])
def plug_off(name):
"""关闭插座"""
d = get_device(name)
if d:
d.turn_off()
return jsonify({'device': name, 'state': 'off'})
return jsonify({'error': 'Device not found'}), 404
@app.route('/plug//status', methods=['GET'])
def plug_status(name):
"""查询状态"""
d = get_device(name)
if d:
status = d.status()
return jsonify({'device': name, 'status': status})
return jsonify({'error': 'Device not found'}), 404
@app.route('/plugs')
def list_plugs():
"""列出所有插座"""
return jsonify({'devices': list(DEVICES.keys())})
if __name__ == '__main__':
print("🔌 智能插座服务: http://0.0.0.0:5003")
app.run(host='0.0.0.0', port=5003, debug=False)
💡 小技巧
推荐使用 ESP01S + 继电器 方案,可以自己焊接,成本最低 ¥15
7. OpenClaw 集成
🎯 目标
让 OpenClaw 能够调用小布米的各种能力
7.1 创建 Skill
在 OpenClaw workspace 创建 skill 目录:
mkdir -p ~/.openclaw/skills/xiaoao-robot
cd ~/.openclaw/skills/xiaoao-robot
# 创建 skill 配置
cat > SKILL.md << 'EOF'
# 小布米机器人 Skill
## 能力
- 摄像头监控
- 语音对话
- 控制开关
- 家电控制
## API 端点
- 摄像头: http://小布米IP:5000/
- 舵机: http://小布米IP:5001/
- 红外: http://小布米IP:5002/
- 插座: http://小布米IP:5003/
EOF
# 创建工具脚本
mkdir -p tools
cat > tools/camera.py << 'EOF'
#!/usr/bin/env python3
import requests
import sys
ip = sys.argv[1] if len(sys.argv) > 1 else "192.168.1.100"
resp = requests.get(f"http://{ip}:5000/camera/snapshot/base64")
data = resp.json()
print(data.get('image', ''))
EOF
chmod +x tools/*.py
7.2 配置 OpenClaw
# 在 OpenClaw 控制台或配置文件中添加工具
# openclaw.json 示例配置:
{
"skills": {
"xiaoao-robot": {
"enabled": true,
"tools": ["camera", "servo", "ir", "plug"]
}
},
"agents": {
"defaults": {
"model": "qwen3.5-plus"
}
}
}
7.3 使用示例
用户: "帮我看看家里现在什么样"
OpenClaw → 调用摄像头API → 返回画面 → 发送给用户
用户: "帮我打开客厅灯"
OpenClaw → 调用舵机API → 小布米伸手按开关 → 确认完成
用户: "好热啊,开下空调"
OpenClaw → 调用红外API → 发送空调开启指令
用户: "帮我关掉台灯"
OpenClaw → 调用插座API → 关闭对应插座
7.4 完整 Skill 目录结构
~/.openclaw/skills/xiaoao-robot/
├── SKILL.md # Skill 描述
├── tools/
│ ├── __init__.py
│ ├── camera.py # 摄像头工具
│ ├── servo.py # 舵机工具
│ ├── ir.py # 红外工具
│ └── plug.py # 插座工具
└── config.yaml # 配置文件
8. 常见问题
Q1: 小布米是什么系统?
小布米基于 Android 系统,可以通过 ADB 连接或安装 Termux 来运行 Python 服务。
Q2: 如何连接小布米?
- 开启开发者模式:设置 → 关于手机 → 连续点击版本号7次
- 开启 USB 调试:开发者选项 → USB 调试
- 通过 ADB 连接:adb connect 小布米IP:5555
Q3: 没有智能家居能实现控制吗?
可以!通过方案2(舵机按开关)或方案3(红外控制)可以在不更换现有设备的情况下实现控制。
Q4: 舵机力度不够怎么办?
选择扭矩更大的舵机(如 MG996R 扭矩约 2.5kg/cm),或使用金属齿轮舵机。
Q5: 如何实现外网控制?
方案:1) 配置 VPN 连接家庭网络;2) 使用内网穿透(如 frp、ngrok);3) 部署到有公网IP的服务器。
📐 整体架构图
用户 (QQ/微信/Telegram/Discord)
│
▼
┌─────────────────────────┐
│ OpenClaw Gateway │
│ (AI Agent) │
└───────────┬─────────────┘
│
┌───────────┴─────────────┐
│ Skill: xiaoao-robot │
│ (工具调用) │
└───────────┬─────────────┘
│
┌───────────┴─────────────┐
│ 小布米控制服务 │
│ (Flask API Server) │
└───────────┬─────────────┘
│
┌───────────┼─────────────┐
│ │ │
▼ ▼ ▼
摄像头 舵机控制 红外/插座
│ │
▼ ▼
手指按开关 设备开关