跳转至

触摸屏与Web界面

概述

当机器人需要丰富的交互功能时,触摸屏GUI和Web界面是两种主要方案。触摸屏适合本地交互(如服务机器人面板),Web界面适合远程监控和控制。

触摸屏集成

电容触摸屏

参数 电容触摸 电阻触摸
触摸方式 手指/导电笔 任何物体/手套
精度
多点触摸 支持 不支持
耐久性 中(表面层磨损)
成本 稍高
推荐 室内机器人 工业/手套操作

常见触摸屏模块

模块 尺寸 分辨率 接口 触摸IC 适用平台
RPi官方7" 7" 800×480 DSI FT5406 树莓派
Waveshare 7" 7" 1024×600 HDMI+USB GT911 通用
Waveshare 5" 5" 800×480 HDMI+USB 通用
Nextion NX 2.4-7" 各种 UART 内置 MCU

嵌入式GUI框架

LVGL(嵌入式最佳选择)

LVGL适合在MCU或低资源SBC上构建触摸界面:

// LVGL 创建状态面板
void create_status_panel(void) {
    // 电池电量条
    lv_obj_t *bar = lv_bar_create(lv_scr_act());
    lv_bar_set_value(bar, 85, LV_ANIM_ON);
    lv_obj_set_size(bar, 200, 20);
    lv_obj_align(bar, LV_ALIGN_TOP_MID, 0, 20);

    // 电量标签
    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Battery: 85%");
    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 50);

    // 模式切换按钮
    lv_obj_t *btn_auto = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn_auto, 120, 50);
    lv_obj_align(btn_auto, LV_ALIGN_CENTER, -70, 0);
    lv_obj_t *lbl1 = lv_label_create(btn_auto);
    lv_label_set_text(lbl1, "AUTO");
    lv_obj_center(lbl1);

    lv_obj_t *btn_manual = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn_manual, 120, 50);
    lv_obj_align(btn_manual, LV_ALIGN_CENTER, 70, 0);
    lv_obj_t *lbl2 = lv_label_create(btn_manual);
    lv_label_set_text(lbl2, "MANUAL");
    lv_obj_center(lbl2);
}

支持平台:ESP32、STM32、RPi、Linux framebuffer

PyQt5 / PySide6(SBC上的桌面GUI)

在树莓派或Jetson上使用Python桌面GUI框架:

import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, 
                              QVBoxLayout, QHBoxLayout, QPushButton,
                              QLabel, QProgressBar)
from PyQt5.QtCore import QTimer

class RobotControlPanel(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Robot Control Panel")
        self.setGeometry(0, 0, 800, 480)

        central = QWidget()
        self.setCentralWidget(central)
        layout = QVBoxLayout(central)

        # 状态标签
        self.status_label = QLabel("Status: Ready")
        self.status_label.setStyleSheet("font-size: 24px; color: green;")
        layout.addWidget(self.status_label)

        # 电量条
        self.battery_bar = QProgressBar()
        self.battery_bar.setValue(85)
        layout.addWidget(self.battery_bar)

        # 控制按钮
        btn_layout = QHBoxLayout()
        self.btn_start = QPushButton("START")
        self.btn_start.setStyleSheet("font-size: 20px; padding: 15px;")
        self.btn_start.clicked.connect(self.on_start)
        btn_layout.addWidget(self.btn_start)

        self.btn_stop = QPushButton("STOP")
        self.btn_stop.setStyleSheet(
            "font-size: 20px; padding: 15px; background: red; color: white;")
        self.btn_stop.clicked.connect(self.on_stop)
        btn_layout.addWidget(self.btn_stop)

        layout.addLayout(btn_layout)

    def on_start(self):
        self.status_label.setText("Status: Running")
        self.status_label.setStyleSheet("font-size: 24px; color: blue;")

    def on_stop(self):
        self.status_label.setText("Status: Stopped")
        self.status_label.setStyleSheet("font-size: 24px; color: red;")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = RobotControlPanel()
    window.showFullScreen()
    sys.exit(app.exec_())

Tkinter(轻量替代)

import tkinter as tk

root = tk.Tk()
root.title("Robot Control")
root.geometry("800x480")

status = tk.Label(root, text="Ready", font=("Arial", 24), fg="green")
status.pack(pady=20)

def start_robot():
    status.config(text="Running", fg="blue")

def stop_robot():
    status.config(text="Stopped", fg="red")

tk.Button(root, text="START", font=("Arial", 18), 
          command=start_robot).pack(side=tk.LEFT, expand=True, padx=20)
tk.Button(root, text="STOP", font=("Arial", 18), bg="red", fg="white",
          command=stop_robot).pack(side=tk.RIGHT, expand=True, padx=20)

root.mainloop()

Web界面控制

Web界面允许通过浏览器远程控制和监控机器人,无需安装任何软件。

Flask + WebSocket

from flask import Flask, render_template
from flask_socketio import SocketIO, emit
import threading
import time

app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*")

robot_state = {
    "battery": 85,
    "mode": "idle",
    "speed": 0.0,
    "position": {"x": 0, "y": 0, "theta": 0}
}

@app.route('/')
def index():
    return render_template('robot_control.html')

@socketio.on('command')
def handle_command(data):
    cmd = data.get('cmd')
    if cmd == 'forward':
        robot_state['mode'] = 'moving'
        robot_state['speed'] = 0.5
    elif cmd == 'stop':
        robot_state['mode'] = 'idle'
        robot_state['speed'] = 0.0
    emit('state_update', robot_state, broadcast=True)

def broadcast_state():
    """定期广播机器人状态"""
    while True:
        socketio.emit('state_update', robot_state)
        time.sleep(0.1)

if __name__ == '__main__':
    thread = threading.Thread(target=broadcast_state, daemon=True)
    thread.start()
    socketio.run(app, host='0.0.0.0', port=5000)

Gradio(快速原型)

Gradio是一个Python库,可以快速创建Web交互界面:

import gradio as gr

def control_robot(command, speed):
    return f"Executing: {command} at speed {speed}"

def get_camera_frame():
    # 返回摄像头图像
    import cv2
    cap = cv2.VideoCapture(0)
    ret, frame = cap.read()
    cap.release()
    return frame if ret else None

demo = gr.Interface(
    fn=control_robot,
    inputs=[
        gr.Radio(["Forward", "Backward", "Left", "Right", "Stop"]),
        gr.Slider(0, 1, 0.5, label="Speed")
    ],
    outputs="text",
    title="Robot Control Panel"
)

demo.launch(server_name="0.0.0.0", server_port=7860)

ROS2 Web Bridge

rosbridge_server 提供WebSocket接口来访问ROS2话题和服务:

# 安装
sudo apt install ros-humble-rosbridge-server

# 启动
ros2 launch rosbridge_server rosbridge_websocket_launch.xml

前端使用 roslibjs

<script src="https://cdn.jsdelivr.net/npm/roslib/build/roslib.min.js"></script>
<script>
var ros = new ROSLIB.Ros({ url: 'ws://192.168.1.100:9090' });

// 订阅话题
var listener = new ROSLIB.Topic({
    ros: ros,
    name: '/robot_status',
    messageType: 'std_msgs/String'
});

listener.subscribe(function(message) {
    document.getElementById('status').innerHTML = message.data;
});

// 发布速度指令
var cmdVel = new ROSLIB.Topic({
    ros: ros,
    name: '/cmd_vel',
    messageType: 'geometry_msgs/Twist'
});

function moveForward() {
    var twist = new ROSLIB.Message({
        linear: { x: 0.5, y: 0, z: 0 },
        angular: { x: 0, y: 0, z: 0 }
    });
    cmdVel.publish(twist);
}
</script>

Foxglove Studio

Foxglove Studio 是ROS2生态中最强大的可视化和调试工具:

特性 说明
平台 桌面应用 / Web版
数据源 ROS1/ROS2/自定义WebSocket
面板 3D视图、图表、图像、日志、地图等
布局 可自定义面板布局
录放 支持MCAP/ROS bag回放
价格 基础版免费

连接ROS2

# 安装 Foxglove Bridge
sudo apt install ros-humble-foxglove-bridge

# 启动
ros2 launch foxglove_bridge foxglove_bridge_launch.xml

# Foxglove Studio 连接: ws://robot_ip:8765

常用面板

  • 3D Panel:显示点云、TF、机器人模型
  • Image Panel:显示摄像头画面
  • Plot Panel:实时绘制数值曲线
  • Map Panel:2D栅格地图
  • Log Panel:ROS日志
  • Teleop Panel:虚拟摇杆控制

移动APP控制

方案对比

方案 开发难度 跨平台 实时性 适用
原生APP (Swift/Kotlin) 商用产品
Flutter/React Native 中型项目
Web APP (PWA) 快速原型
蓝牙串口APP 简单控制

推荐方案

对于机器人项目,Web APP(PWA) 是最佳平衡:

  • 手机浏览器直接访问,无需安装
  • 使用Flask/FastAPI后端 + 响应式前端
  • WebSocket实现实时通信
  • 可添加到手机主屏幕(PWA)

方案选型总结

需求 推荐方案 理由
MCU + 触摸屏 LVGL + SPI LCD 最适合嵌入式
SBC本地GUI PyQt5 + DSI屏 功能丰富
远程监控 Flask + WebSocket 简单灵活
快速演示 Gradio 一行代码出界面
ROS2可视化 Foxglove Studio 功能最强
ROS2 Web控制 rosbridge + roslibjs ROS原生
手机控制 PWA Web App 跨平台、免安装

参考资源


评论 #