以下是系统设计的详细方案:
1. 系统架构
+-----------------+ +------------------------+ +---------------------+ +--------------------+
| 用户浏览器 | ---->| 前端应用 (SPA) | ---> | Spring Boot 后端 | ---> | ROS Master(s) |
| (Login, Bind, | | (React/Vue/Angular) | | (API, ROS Sub, Logic)| | (在机器人或网络上) |
| View Data) | +------------------------+ +----------+----------+ +----------^---------+
+-----------------+ | | |
| | | ROS Topics
+---------------------+ | | | (Sensor Data)
| 关系型数据库 | <-----+ +---------------------> (订阅)
| (用户, 机器人, 绑定) | |
| (PostgreSQL/MySQL) | |
+---------------------+ | +---------------------+
+->| 时序数据库 (TSDB) |
| (传感器数据存储) |
| (InfluxDB/TimescaleDB)|
+---------------------+
2. 技术选型
-
后端框架: Spring Boot (Java) - 强大的生态,快速开发,易于集成。
-
ROS Java库:
-
ROS 1: rosjava_core (官方提供,相对成熟但可能有些复杂)。
-
ROS 2: rcljava (ROS 2的官方Java客户端库)。你需要根据你的机器人使用的ROS版本选择。
-
-
时序数据库 (TSDB):
-
InfluxDB: 专门为时间序列数据设计,性能优异,查询语言(Flux/InfluxQL)强大,有良好的Java客户端。
-
TimescaleDB: PostgreSQL的扩展,将PostgreSQL变成一个功能齐全的时序数据库。可以使用标准SQL查询,与Spring Data JPA/JDBC集成更自然。
-
选择建议: 如果对SQL熟悉且希望利用关系型数据库特性,选TimescaleDB。如果追求极致的时序性能和专用工具链,选InfluxDB。
-
-
关系型数据库: PostgreSQL / MySQL / MariaDB - 用于存储用户信息、机器人元数据(ID、名称、ROS Master URI等)、用户与机器人的绑定关系。Spring Data JPA可以很好地支持。
-
前端框架: React / Vue / Angular (或其他现代前端框架) - 用于构建单页应用(SPA),提供动态和交互式用户体验。
-
API通信: RESTful API (通过Spring Web)
-
认证/授权: Spring Security + JWT (JSON Web Tokens) - 标准且安全的方案。
3. 后端设计 (Spring Boot Application)
-
pom.xml / build.gradle:
-
Spring Boot Starters (Web, Security, Data JPA, AOP).
-
ROS Java库依赖 (rosjava_core 或 rcljava).
-
时序数据库Java客户端依赖 (e.g., influxdb-java, postgresql JDBC driver for TimescaleDB).
-
关系型数据库JDBC驱动.
-
Lombok (简化代码).
-
-
核心组件:
-
UserController (@RestController):
-
POST /api/auth/login: 处理用户登录请求,验证成功后返回JWT。
-
POST /api/auth/register: (可选)处理用户注册请求。
-
GET /api/user/me: 获取当前用户信息。
-
-
RobotController (@RestController):
-
GET /api/robots: 获取当前用户绑定的机器人列表。
-
POST /api/robots/bind: 用户绑定机器人(需要提供机器人标识,如ID或名称,以及ROS Master URI)。
-
POST /api/robots/{robotId}/unbind: 用户解绑机器人。
-
-
DataController (@RestController):
-
GET /api/data/{robotId}: 获取指定机器人的传感器数据。
-
查询参数: startTime, endTime, sensorType (可选), topicName (可选), granularity (可选,用于数据聚合)。
-
返回格式化的时序数据(适合图表展示)。
-
-
-
UserService (@Service): 处理用户相关的业务逻辑(登录验证、密码加密、用户信息管理)。
-
RobotService (@Service): 处理机器人相关的业务逻辑(绑定、解绑、查询用户机器人列表、验证机器人所有权)。
-
RosSubscriberService (@Service):
-
关键服务: 负责管理与ROS Master的连接和主题订阅。
-
连接管理: 当机器人被绑定且系统需要接收数据时,根据存储的ROS Master URI建立与对应ROS Master的连接。
-
动态订阅: 维护一个订阅列表。当机器人绑定/解绑时,相应地添加/移除订阅。
-
消息处理: 实现MessageListener接口(或类似机制),接收来自ROS主题的消息。
-
数据转换与存储: 解析接收到的ROS消息(如sensor_msgs/Imu, sensor_msgs/LaserScan, nav_msgs/Odometry等),提取关键数据,添加robotId和时间戳,然后调用DataService存储到TSDB。
-
错误处理: 处理连接失败、消息解析错误等。
-
线程管理: ROS Java库的监听器通常在单独的线程中运行,需要妥善管理。
-
-
DataService (@Service):
-
提供将处理好的传感器数据写入TSDB的接口。
-
提供根据时间范围、机器人ID、传感器类型等条件从TSDB查询数据的接口。
-
-
-
数据模型 (JPA Entities for Relational DB):
-
User: id, username, password (hashed), roles.
-
Robot: id, robotIdentifier (唯一标识), name, rosMasterUri.
-
UserRobotBinding: userId, robotId (复合主键或单独ID + 外键)。
-
-
时序数据模型 (TSDB Schema - e.g., InfluxDB):
-
Measurement: sensor_data (或其他按传感器类型划分的measurement, e.g., imu, lidar).
-
Tags (用于索引和过滤): robotId, topicName, sensorType.
-
Fields (实际数值): 根据传感器类型变化,如 linear_acceleration_x, angular_velocity_z, range_min, range_max, pose_x, pose_y, orientation_w 等。
-
Timestamp: 数据点的时间戳 (由ROS消息头提供或在接收时生成)。
-
-
配置 (application.properties / application.yml):
-
数据库连接信息 (关系型和时序型)。
-
JWT密钥和过期时间。
-
ROS相关配置(可选,如默认订阅主题列表)。
-
-
安全 (SecurityConfig):
-
配置Spring Security。
-
定义哪些API需要认证。
-
配置密码编码器。
-
配置JWT过滤器用于验证请求中的Token。
-
4. 前端设计 (SPA)
-
页面:
-
登录页 (/login): 输入用户名、密码,调用后端登录API。成功后存储JWT,并重定向到主页。
-
主页/仪表盘 (/ or /dashboard):
-
显示欢迎信息。
-
机器人列表: 调用 GET /api/robots 获取并展示用户绑定的机器人。
-
绑定机器人按钮/表单: 触发一个模态框或跳转到绑定页面,输入机器人信息,调用 POST /api/robots/bind。
-
解绑按钮: 在机器人列表中,为每个机器人提供解绑选项,调用 POST /api/robots/{robotId}/unbind。
-
查看数据链接: 点击后跳转到数据查看页面,并带上robotId。
-
-
数据查看页 (/data/{robotId}):
-
显示当前查看的机器人信息。
-
时间范围选择器: 允许用户选择开始和结束时间。
-
(可选) 传感器类型/主题选择器: 允许用户筛选特定数据。
-
图表区域: 使用图表库(如 Chart.js, Plotly.js, ECharts)根据选择的条件调用 GET /api/data/{robotId} 获取数据并进行可视化展示(折线图、散点图等)。
-
数据刷新机制: 可以有手动刷新按钮,或设置定时自动刷新。
-
-
-
状态管理: 使用前端框架自带的状态管理(如Vuex, Redux)或简单的组件状态来管理用户信息、机器人列表、当前查看的数据等。
-
API调用: 使用 axios 或 fetch 与后端API交互。需要设置请求头携带JWT进行认证。
5. ROS集成细节 (RosSubscriberService)
-
初始化: 服务启动时,可以查询数据库中所有已绑定的机器人,并尝试为它们建立ROS连接和订阅。
-
连接: 使用rosjava_core的DefaultNodeMainExecutor和NodeConfiguration来连接到指定的ROS Master URI。每个机器人可能需要一个独立的NodeMain实例或类似的管理机制。
-
订阅: 使用NodeMain实例创建Subscriber对象,指定要订阅的topicName和消息类型(如sensor_msgs.Imu)。
-
消息监听: 在Subscriber的回调函数(onNewMessage)中接收原始ROS消息。
-
数据持久化: 在回调中,提取所需字段,创建数据点对象(包含robotId, timestamp, tags, fields),然后通过DataService异步或同步写入TSDB。注意处理背压和批量写入以提高性能。
-
健壮性: 需要处理ROS Master不可达、网络中断、节点关闭等情况。实现重连逻辑。
6. 部署注意事项
-
网络: 后端服务器必须能够访问所有已绑定机器人的ROS Master URI。这可能需要配置VPN、防火墙规则或确保它们在同一局域网内。
-
资源: 后端服务会持续监听ROS消息,可能会消耗一定的CPU和内存,尤其是在机器人数量多或数据频率高的情况下。TSDB也需要足够的存储和I/O能力。
-
容器化 (Docker): 将后端应用、前端应用、关系型数据库、时序数据库分别打包成Docker镜像,使用Docker Compose进行本地开发和部署,或使用Kubernetes进行生产环境部署。
7. 潜在挑战与扩展
-
ROS Java库的复杂性: rosjava 可能学习曲线较陡峭,文档和社区支持相对Python/C++较少。rcljava (ROS 2)相对更新。
-
性能: 大量机器人或高频数据可能对后端处理能力和TSDB写入/查询性能带来压力。需要考虑异步处理、批量写入、数据聚合、数据库调优。
-
实时性: 如果需要近乎实时的数据展示,前端可能需要使用WebSocket与后端建立连接,由后端在收到新数据时主动推送给前端。
-
错误处理和监控: 需要健壮的错误处理机制(网络、ROS连接、数据解析、数据库写入)和监控系统来跟踪服务状态和性能。
-
数据量: 时序数据增长很快,需要考虑数据保留策略(Data Retention Policies)和存储扩展性。
-
安全性: 除了用户认证,还需要考虑ROS通信本身的安全性(如果需要跨公网通信)。