13.Dreamview模块详解

第十三部分:Dreamview Plus模块详解

免责声明

本文档仅供学习和技术研究使用,内容基于 Apollo 开源项目的公开资料和代码分析整理而成。文档中的技术实现细节、架构设计等内容可能随 Apollo 项目更新而变化。使用本文档所述技术方案时,请以 Apollo 官方最新文档为准。

声明事项:

  • 本文档不构成任何商业使用建议
  • 涉及自动驾驶技术的应用需遵守当地法律法规
  • 作者不对因使用本文档内容产生的任何后果承担责任
  • Apollo 为百度公司注册商标,本文档为非官方技术解析

1. Dreamview模块概述

1.1 模块定位

Dreamview Plus是Apollo 10.0的新一代可视化人机交互平台,提供了全方位的自动驾驶开发、调试和监控能力。

复制代码
┌────────────────────────────────────────────────────────────┐
│                   Dreamview Plus 平台                      │
│  ┌──────────────────────────────────────────────────────┐  │
│  │          Web Frontend (React + TypeScript)           │  │
│  │  ┌─────────┐ ┌────────┐ ┌─────────┐ ┌──────────┐    │  │
│  │  │  地图   │ │ 感知  │ │  规划   │ │   HMI   │    │  │
│  │  │ 可视化  │ │ 可视化│ │  可视化 │ │  控制台  │    │  │
│  │  └─────────┘ └────────┘ └─────────┘ └──────────┘    │  │
│  └─────────────────────┬────────────────────────────────┘  │
│                        │ WebSocket                          │
│  ┌─────────────────────┴────────────────────────────────┐  │
│  │       Backend Server (C++ + CivetWeb)                │  │
│  │  ┌──────────┐ ┌──────────┐ ┌────────────────────┐   │  │
│  │  │Socket    │ │ Plugin   │ │    Updater         │   │  │
│  │  │Manager   │ │ Manager  │ │    Manager         │   │  │
│  │  └──────────┘ └──────────┘ └────────────────────┘   │  │
│  └─────────────────────┬────────────────────────────────┘  │
│                        │ CyberRT Topics                     │
└────────────────────────┴────────────────────────────────────┘
                         │
       ┌─────────────────┼─────────────────┐
       │                 │                 │
       ▼                 ▼                 ▼
  ┌─────────┐      ┌──────────┐     ┌──────────┐
  │Planning │      │Perception│     │  Canbus  │
  │ Module  │      │  Module  │     │  Module  │
  └─────────┘      └──────────┘     └──────────┘

1.2 核心功能

功能分类 具体功能 说明
可视化 3D地图渲染 高精地图、道路网络、车道线可视化
车辆状态显示 实时位置、速度、加速度、转向角
障碍物显示 检测到的车辆、行人、障碍物
规划轨迹显示 规划路径、决策信息、速度曲线
感知结果显示 相机图像、点云、融合结果
控制 模块启停控制 启动/停止各功能模块
驾驶模式切换 手动/自动驾驶模式切换
仿真控制 仿真车辆控制、场景重放
路由设置 起点终点设置、路径规划
调试 数据录制回放 录制bag文件、回放分析
实时监控 模块状态、系统性能监控
参数调节 在线调整算法参数
日志查看 实时查看系统日志
扩展 插件系统 自定义插件扩展
多车管理 支持多车辆管理

1.3 技术栈

后端:

  • C++17: 核心业务逻辑
  • CyberRT: Apollo通信框架
  • CivetWeb: 轻量级HTTP/WebSocket服务器
  • Protocol Buffers: 数据序列化
  • nlohmann/json: JSON处理

前端:

  • React 18: UI框架
  • TypeScript: 类型安全
  • Three.js: 3D渲染引擎
  • WebSocket: 实时通信
  • Ant Design: UI组件库
  • Lerna: Monorepo管理

2. 系统架构设计

2.1 整体架构

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     Dreamview Plus                          │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              Frontend Layer (前端层)                    │ │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐             │ │
│  │  │   UI     │  │  3D视图  │  │   HMI    │             │ │
│  │  │ 组件库   │  │  渲染器  │  │  控制台  │             │ │
│  │  └──────────┘  └──────────┘  └──────────┘             │ │
│  │  ┌──────────────────────────────────────────┐          │ │
│  │  │      WebSocket Client Manager             │          │ │
│  │  │  (多WebSocket连接池管理)                  │          │ │
│  │  └──────────────────────────────────────────┘          │ │
│  └────────────────────────────────────────────────────────┘ │
│                           │                                  │
│                           │ WebSocket (多通道)               │
│                           │                                  │
│  ┌────────────────────────────────────────────────────────┐ │
│  │            Communication Layer (通信层)                 │ │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐             │ │
│  │  │/websocket│  │  /map    │  │ /plugin  │   ... 9个    │ │
│  │  │WebSocket │  │WebSocket │  │WebSocket │   WebSocket  │ │
│  │  │ Handler  │  │ Handler  │  │ Handler  │   通道       │ │
│  │  └──────────┘  └──────────┘  └──────────┘             │ │
│  │  ┌──────────────────────────────────────────┐          │ │
│  │  │          CivetWeb Server                  │          │ │
│  │  │  HTTP静态文件服务 + WebSocket服务        │          │ │
│  │  └──────────────────────────────────────────┘          │ │
│  └────────────────────────────────────────────────────────┘ │
│                           │                                  │
│  ┌────────────────────────────────────────────────────────┐ │
│  │             Business Logic Layer (业务层)               │ │
│  │  ┌──────────────┐  ┌────────────────┐                 │ │
│  │  │SocketManager │  │ PluginManager  │                 │ │
│  │  │(WebSocket    │  │(插件管理)       │                 │ │
│  │  │ 路由管理)    │  │                │                 │ │
│  │  └──────────────┘  └────────────────┘                 │ │
│  │  ┌──────────────┐  ┌────────────────┐                 │ │
│  │  │UpdaterManager│  │   HMI Worker   │                 │ │
│  │  │(更新器管理)  │  │(人机交互逻辑)   │                 │ │
│  │  └──────────────┘  └────────────────┘                 │ │
│  └────────────────────────────────────────────────────────┘ │
│                           │                                  │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              Data Processing Layer (数据层)             │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌─────────────┐  │ │
│  │  │SimulationWorld│  │ MapUpdater  │  │ObstacleUpdater│ │ │
│  │  │   Updater    │  │             │  │              │  │ │
│  │  └──────────────┘  └──────────────┘  └─────────────┘  │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌─────────────┐  │ │
│  │  │PointCloud    │  │CameraUpdater│  │ChannelsUpdater│ │ │
│  │  │   Updater    │  │             │  │              │  │ │
│  │  └──────────────┘  └──────────────┘  └─────────────┘  │ │
│  └────────────────────────────────────────────────────────┘ │
│                           │                                  │
│  ┌────────────────────────────────────────────────────────┐ │
│  │                CyberRT Integration Layer                │ │
│  │              (CyberRT消息订阅与发布)                     │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────┬───────────────────────────────────┘
                          │ CyberRT Topics
        ┌─────────────────┼─────────────────┐
        ▼                 ▼                 ▼
  /apollo/planning  /apollo/perception  /apollo/chassis

2.2 9个WebSocket通道

Dreamview Plus使用9个独立的WebSocket通道来实现不同数据的并发传输:

通道名称 URL路径 功能 数据类型 频率
MainWebSocket /websocket 主通道,通用消息 JSON 按需
MapWebSocket /map 地图数据传输 JSON/Binary 按需
PointCloudWS /pointcloud 点云数据传输 Binary 10Hz
CameraWS /camera 相机图像传输 JPEG/Binary 10Hz
PluginWS /plugin 插件消息传输 JSON 按需
SimWorldWS /simworld 仿真世界状态 JSON 10-30Hz
HMI_WS /hmi 人机交互控制 JSON 按需
SocketManagerWS /socketmanager Socket管理 JSON 按需
ObstacleWS /obstacle 障碍物信息 JSON 10Hz
ChannelsInfoWS /channelsinfo 通道信息 JSON 1Hz

通道分离的优势:

  • 并发传输: 不同类型数据互不阻塞
  • 优先级控制: 高优先级数据独立通道
  • 带宽优化: 大数据量独立通道(点云、图像)
  • 解耦设计: 模块间松耦合

2.3 核心组件关系

cpp 复制代码
// 文件: modules/dreamview_plus/backend/dreamview.h:54-102

class Dreamview {
 public:
  ~Dreamview();

  apollo::common::Status Init();
  apollo::common::Status Start();
  void Stop();
  void RegisterUpdaters();

 private:
  // ========== Web服务器 ==========
  std::unique_ptr<CivetServer> server_;  // HTTP/WebSocket服务器

  // ========== 9个WebSocket处理器 ==========
  std::unique_ptr<WebSocketHandler> websocket_;        // 主通道
  std::unique_ptr<WebSocketHandler> map_ws_;           // 地图
  std::unique_ptr<WebSocketHandler> point_cloud_ws_;   // 点云
  std::unique_ptr<WebSocketHandler> camera_ws_;        // 相机
  std::unique_ptr<WebSocketHandler> plugin_ws_;        // 插件
  std::unique_ptr<WebSocketHandler> sim_world_ws_;     // 仿真世界
  std::unique_ptr<WebSocketHandler> obstacle_ws_;      // 障碍物
  std::unique_ptr<WebSocketHandler> hmi_ws_;           // HMI
  std::unique_ptr<WebSocketHandler> socket_manager_ws_;// Socket管理
  std::unique_ptr<WebSocketHandler> channels_info_ws_; // 通道信息

  // ========== 核心服务 ==========
  std::unique_ptr<MapService> map_service_;              // 地图服务
  std::unique_ptr<HMI> hmi_;                             // 人机交互
  std::unique_ptr<SocketManager> socket_manager_;        // Socket管理
  std::unique_ptr<DvPluginManager> dv_plugin_manager_;   // 插件管理
  std::unique_ptr<UpdaterManager> updater_manager_;      // 更新器管理
  std::unique_ptr<PluginManager> plugin_manager_;        // 旧插件管理

  // ========== 数据更新器 ==========
  std::unique_ptr<SimulationWorldUpdater> sim_world_updater_;       // 仿真世界
  std::unique_ptr<MapUpdater> map_updater_;                         // 地图
  std::unique_ptr<ObstacleUpdater> obstacle_updater_;               // 障碍物
  std::unique_ptr<PerceptionCameraUpdater> perception_camera_updater_; // 相机
  std::unique_ptr<PointCloudUpdater> point_cloud_updater_;          // 点云
  std::unique_ptr<ChannelsUpdater> channels_info_updater_;          // 通道信息

  // ========== HTTP处理器 ==========
  std::unique_ptr<ImageHandler> image_;          // 图片HTTP接口
  std::unique_ptr<ProtoHandler> proto_handler_;  // Protobuf HTTP接口
};

3. 后端架构详解

3.1 主入口程序

cpp 复制代码
// 文件: modules/dreamview_plus/main.cc:27-81

int main(int argc, char* argv[]) {
  // 1. 设置工作目录
  const char* apollo_runtime_path = std::getenv("APOLLO_RUNTIME_PATH");
  if (apollo_runtime_path != nullptr) {
    std::filesystem::current_path(apollo_runtime_path);
  }

  google::ParseCommandLineFlags(&argc, &argv, true);

  // 2. 性能分析支持 (可选)
  std::signal(SIGTERM, [](int sig) {
    apollo::cyber::OnShutdown(sig);
    if (FLAGS_dv_cpu_profile) {
      ProfilerStop();  // 停止CPU性能分析
    }
    if (FLAGS_dv_heap_profile) {
      HeapProfilerDump("Befor shutdown");  // 转储堆内存分析
      HeapProfilerStop();
    }
  });

  // 启动性能分析
  if (FLAGS_dv_cpu_profile) {
    auto base_name_cpu = std::string(argv[0]) + "_cpu.prof";
    ProfilerStart(base_name_cpu.c_str());
  }
  if (FLAGS_dv_heap_profile) {
    auto base_name_heap = std::string(argv[0]) + "_heap.prof";
    HeapProfilerStart(base_name_heap.c_str());
  }

  // 3. 初始化CyberRT
  apollo::cyber::GlobalData::Instance()->SetProcessGroup("dreamview_sched");
  apollo::cyber::Init(argv[0]);

  // 4. 创建并启动Dreamview
  apollo::dreamview::Dreamview dreamview;
  const bool init_success = dreamview.Init().ok() && dreamview.Start().ok();
  if (!init_success) {
    AERROR << "Failed to initialize dreamview server";
    return -1;
  }

  // 5. 等待shutdown信号
  apollo::cyber::WaitForShutdown();
  return 0;
}

启动流程:

  1. 设置工作目录为$APOLLO_RUNTIME_PATH
  2. 注册信号处理器(SIGTERM/SIGINT)
  3. 可选启动性能分析(CPU/Heap)
  4. 初始化CyberRT框架
  5. 创建Dreamview实例并初始化
  6. 启动所有服务
  7. 等待shutdown信号

3.2 Dreamview::Init() 初始化流程

cpp 复制代码
// 文件: modules/dreamview_plus/backend/dreamview.cc:57-141

Status Dreamview::Init() {
  // 1. 初始化车辆配置
  VehicleConfigHelper::Init();

  // 2. 配置profiling模式 (可选)
  if (FLAGS_dreamview_profiling_mode &&
      FLAGS_dreamview_profiling_duration > 0.0) {
    exit_timer_.reset(new cyber::Timer(
        FLAGS_dreamview_profiling_duration,
        [this]() { this->TerminateProfilingMode(); }, false));
    exit_timer_->Start();
  }

  // 3. 初始化HTTP/WebSocket服务器
  std::vector<std::string> options = {
      "document_root",         FLAGS_static_file_dir,     // 静态文件目录
      "listening_ports",       FLAGS_server_ports,        // 监听端口(默认8888)
      "websocket_timeout_ms",  FLAGS_websocket_timeout_ms, // WebSocket超时
      "request_timeout_ms",    FLAGS_request_timeout_ms,   // HTTP超时
      "enable_keep_alive",     "yes",                      // 保持连接
      "tcp_nodelay",           "1",                        // TCP_NODELAY
      "keep_alive_timeout_ms", "500"                       // Keep-Alive超时
  };

  // SSL证书 (HTTPS支持)
  if (PathExists(FLAGS_ssl_certificate)) {
    options.push_back("ssl_certificate");
    options.push_back(FLAGS_ssl_certificate);
  }

  server_.reset(new CivetServer(options));

  // 4. 创建9个WebSocket处理器
  websocket_.reset(new WebSocketHandler("websocket"));
  map_ws_.reset(new WebSocketHandler("Map"));
  point_cloud_ws_.reset(new WebSocketHandler("PointCloud"));
  camera_ws_.reset(new WebSocketHandler("Camera"));
  plugin_ws_.reset(new WebSocketHandler("Plugin"));
  hmi_ws_.reset(new WebSocketHandler("HMI"));
  sim_world_ws_.reset(new WebSocketHandler("SimWorld"));
  obstacle_ws_.reset(new WebSocketHandler("Obstacle"));
  channels_info_ws_.reset(new WebSocketHandler("ChannelsInfo"));

  // 5. 创建核心服务
  map_service_.reset(new MapService());  // 地图服务
  image_.reset(new ImageHandler());      // 图片HTTP接口
  proto_handler_.reset(new ProtoHandler());  // Protobuf HTTP接口

  // 6. 创建数据更新器
  perception_camera_updater_.reset(
      new PerceptionCameraUpdater(camera_ws_.get()));  // 相机更新器

  hmi_.reset(new HMI(websocket_.get(), map_service_.get(), hmi_ws_.get()));

  plugin_manager_.reset(new PluginManager(plugin_ws_.get()));

  sim_world_updater_.reset(new SimulationWorldUpdater(
      websocket_.get(), map_ws_.get(), plugin_ws_.get(), map_service_.get(),
      plugin_manager_.get(), sim_world_ws_.get(), hmi_.get(),
      FLAGS_routing_from_file));

  point_cloud_updater_.reset(new PointCloudUpdater(point_cloud_ws_.get()));
  map_updater_.reset(new MapUpdater(map_ws_.get(), map_service_.get()));
  obstacle_updater_.reset(new ObstacleUpdater(obstacle_ws_.get()));
  channels_info_updater_.reset(new ChannelsUpdater(channels_info_ws_.get()));

  updater_manager_.reset(new UpdaterManager());
  RegisterUpdaters();  // 注册所有更新器

  dv_plugin_manager_.reset(
      new DvPluginManager(server_.get(), updater_manager_.get()));

  // 7. 注册WebSocket路由
  server_->addWebSocketHandler("/websocket", *websocket_);
  server_->addWebSocketHandler("/map", *map_ws_);
  server_->addWebSocketHandler("/pointcloud", *point_cloud_ws_);
  server_->addWebSocketHandler("/camera", *camera_ws_);
  server_->addWebSocketHandler("/plugin", *plugin_ws_);
  server_->addWebSocketHandler("/simworld", *sim_world_ws_);
  server_->addWebSocketHandler("/hmi", *hmi_ws_);
  server_->addWebSocketHandler("/socketmanager", *socket_manager_ws_);
  server_->addWebSocketHandler("/obstacle", *obstacle_ws_);
  server_->addWebSocketHandler("/channelsinfo", *channels_info_ws_);

  // 8. 注册HTTP路由
  server_->addHandler("/image", *image_);
  server_->addHandler("/proto", *proto_handler_);

  // 9. 初始化插件管理器
  dv_plugin_manager_->Init();

  // 10. 创建SocketManager
  socket_manager_.reset(new SocketManager(
      websocket_.get(), updater_manager_.get(), dv_plugin_manager_.get()));

  return Status::OK();
}

初始化步骤总结:

  1. 初始化车辆配置
  2. 创建CivetWeb HTTP/WebSocket服务器
  3. 创建9个WebSocket处理器
  4. 创建核心服务(Map、HMI、Plugin等)
  5. 创建数据更新器(SimWorld、Map、Obstacle等)
  6. 注册WebSocket路由
  7. 注册HTTP路由
  8. 初始化插件系统
  9. 创建Socket管理器

3.3 CivetWeb服务器配置

cpp 复制代码
// CivetWeb服务器选项

std::vector<std::string> options = {
    // 静态文件目录 (前端HTML/JS/CSS)
    "document_root", "/apollo/modules/dreamview_plus/frontend/dist",

    // 监听端口 (默认8888)
    "listening_ports", "8888",

    // WebSocket超时 (毫秒)
    "websocket_timeout_ms", "3600000",  // 1小时

    // HTTP请求超时 (毫秒)
    "request_timeout_ms", "2000",

    // 启用HTTP Keep-Alive
    "enable_keep_alive", "yes",

    // 启用TCP_NODELAY (禁用Nagle算法)
    "tcp_nodelay", "1",

    // Keep-Alive超时
    "keep_alive_timeout_ms", "500"
};

关键配置说明:

  • document_root: 静态文件根目录,serve前端build产物
  • listening_ports : 支持多端口,格式: 8888,8889s (s表示SSL)
  • websocket_timeout_ms: WebSocket空闲超时,默认1小时
  • tcp_nodelay: 禁用Nagle算法,降低延迟
  • SSL证书: 可选HTTPS支持

4. 前端架构详解

4.1 Monorepo结构

Dreamview Plus前端采用Lerna管理的Monorepo结构:

复制代码
frontend/
├── packages/
│   ├── dreamview/                  # 主应用
│   ├── dreamview-core/             # 核心逻辑
│   ├── dreamview-ui/               # UI组件库
│   ├── dreamview-carviz/           # 3D可视化
│   ├── dreamview-theme/            # 主题配置
│   ├── dreamview-lang/             # 国际化
│   ├── dreamview-log/              # 日志系统
│   ├── dreamview-analysis/         # 数据分析
│   ├── dreamview-web/              # Web工具
│   ├── dreamview-debug-extension/  # 调试扩展
│   ├── dreamview-mock/             # Mock数据
│   ├── eslint-config-dreamview/    # ESLint配置
│   ├── tslint-config-dreamview/    # TSLint配置
│   └── platforms/                  # 平台适配
├── lerna.json                      # Lerna配置
├── package.json                    # 根package.json
└── tsconfig.json                   # TypeScript配置

Monorepo优势:

  • 代码复用: 共享组件、工具、配置
  • 统一管理: 统一版本、依赖、构建
  • 原子提交: 跨包修改一次提交
  • 类型安全: TypeScript跨包类型检查

4.2 核心包说明

包名 职责 主要内容
dreamview 主应用入口 应用启动、路由、全局状态
dreamview-core 核心业务逻辑 WebSocket管理、数据处理、状态管理
dreamview-ui UI组件库 可复用React组件
dreamview-carviz 3D可视化引擎 Three.js封装、地图渲染、车辆渲染
dreamview-theme 主题系统 颜色、字体、尺寸配置
dreamview-lang 国际化 中英文语言包
dreamview-log 日志系统 前端日志收集与上报

4.3 技术栈详细说明

核心框架:

json 复制代码
{
  "react": "^18.2.0",
  "react-dom": "^18.2.0",
  "typescript": "^5.0.0"
}

3D渲染:

json 复制代码
{
  "three": "^0.150.0",
  "@types/three": "^0.150.0"
}

状态管理:

json 复制代码
{
  "mobx": "^6.9.0",
  "mobx-react": "^7.6.0"
}

UI组件:

json 复制代码
{
  "antd": "^5.4.0",
  "@ant-design/icons": "^5.0.0"
}

通信:

json 复制代码
{
  "ws": "^8.13.0",          // WebSocket客户端
  "axios": "^1.4.0"         // HTTP客户端
}

5. WebSocket通信机制

5.1 WebSocket处理器基类

cpp 复制代码
// 文件: modules/dreamview/backend/common/handlers/websocket_handler.h

class WebSocketHandler : public CivetWebSocketHandler {
 public:
  // 连接类型定义
  struct Connection {
    std::mutex mutex;
    CivetServer* server;
    struct mg_connection* connection;
  };

  explicit WebSocketHandler(const std::string& name);

  // ========== CivetWebSocketHandler接口 ==========

  // WebSocket连接建立
  bool handleConnection(CivetServer* server,
                       const struct mg_connection* conn) override;

  // WebSocket连接就绪
  void handleReadyState(CivetServer* server,
                       struct mg_connection* conn) override;

  // 接收WebSocket数据
  bool handleData(CivetServer* server,
                 struct mg_connection* conn,
                 int bits,
                 char* data,
                 size_t data_len) override;

  // WebSocket连接关闭
  void handleClose(CivetServer* server,
                  const struct mg_connection* conn) override;

  // ========== 消息发送接口 ==========

  // 广播消息给所有连接
  void BroadcastData(const std::string& data, bool skippable = false);
  void BroadcastBinaryData(const std::string& data, bool skippable = false);

  // 发送消息给特定连接
  void SendData(Connection* conn, const std::string& data,
               bool skippable = false);
  void SendBinaryData(Connection* conn, const std::string& data,
                     bool skippable = false);

  // ========== 消息处理注册 ==========

  // 注册JSON消息处理器
  void RegisterMessageHandler(
      const std::string& message_type,
      std::function<void(const nlohmann::json&, Connection*)> handler);

  // 注册二进制消息处理器
  void RegisterBinaryMessageHandler(
      const std::string& message_type,
      std::function<void(const std::string&, Connection*)> handler);

  // ========== 连接管理 ==========

  size_t GetConnectionCount() const;
  bool HasConnection() const;

 private:
  void ProcessData(struct mg_connection* conn, const std::string& data);

  std::string name_;  // WebSocket名称

  // 连接池
  std::vector<std::unique_ptr<Connection>> connections_;
  mutable std::mutex mutex_;

  // 消息处理器映射
  std::unordered_map<std::string,
      std::function<void(const nlohmann::json&, Connection*)>>
      message_handlers_;

  std::unordered_map<std::string,
      std::function<void(const std::string&, Connection*)>>
      binary_message_handlers_;
};

5.2 WebSocket消息格式

5.2.1 JSON消息格式
json 复制代码
{
  "type": "MessageType",      // 消息类型
  "data": {                   // 消息数据
    "field1": "value1",
    "field2": 123
  },
  "timestamp": 1234567890.123 // 时间戳 (可选)
}

常见消息类型:

  • RequestSimulationWorld: 请求仿真世界数据
  • RequestRoutePath: 请求路径规划
  • SendRoutingRequest: 发送路由请求
  • SubscribeChannel: 订阅数据通道
  • UnsubscribeChannel: 取消订阅通道
  • ChangeMode: 切换驾驶模式
  • StartModule: 启动模块
  • StopModule: 停止模块
5.2.2 二进制消息格式
复制代码
┌────────────────┬─────────────────────────────┐
│  Header (4B)   │       Payload (N bytes)     │
├────────────────┼─────────────────────────────┤
│ Message Type   │   Binary Data (Protobuf)    │
│   (uint32)     │   or Raw Binary (点云/图像)  │
└────────────────┴─────────────────────────────┘

用于传输:

  • 点云数据 (PointCloud2)
  • 相机图像 (JPEG/PNG)
  • Protobuf序列化数据

5.3 消息处理流程

复制代码
┌──────────────┐
│  Frontend    │
│  发送消息     │
└──────┬───────┘
       │ WebSocket Message
       ▼
┌─────────────────────────────────────────┐
│  WebSocketHandler::handleData()         │
│  1. 接收WebSocket数据                    │
│  2. 解析消息类型                         │
└──────┬──────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────────┐
│  WebSocketHandler::ProcessData()        │
│  1. JSON解析                             │
│  2. 查找消息处理器                       │
└──────┬──────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────────┐
│  Registered Message Handler              │
│  1. 业务逻辑处理                         │
│  2. 调用CyberRT发布消息 (如需要)         │
│  3. 生成响应消息                         │
└──────┬──────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────────┐
│  WebSocketHandler::SendData() /         │
│  WebSocketHandler::BroadcastData()      │
│  1. 发送响应消息                         │
└──────┬──────────────────────────────────┘
       │ WebSocket Response
       ▼
┌──────────────┐
│  Frontend    │
│  接收响应     │
└──────────────┘

5.4 消息处理器注册示例

cpp 复制代码
// 文件: modules/dreamview_plus/backend/hmi/hmi.cc

void HMI::RegisterMessageHandlers() {
  // 注册"ChangeMode"消息处理器
  websocket_->RegisterMessageHandler(
      "ChangeMode",
      [this](const nlohmann::json& json, WebSocketHandler::Connection* conn) {
        // 解析消息
        std::string mode = json["mode"];

        // 处理业务逻辑
        if (mode == "auto") {
          hmi_worker_->ChangeToAutoDriveMode();
        } else if (mode == "manual") {
          hmi_worker_->ChangeToManualMode();
        }

        // 发送响应
        nlohmann::json response;
        response["type"] = "ChangeModeResponse";
        response["success"] = true;
        websocket_->SendData(conn, response.dump());
      });

  // 注册"StartModule"消息处理器
  websocket_->RegisterMessageHandler(
      "StartModule",
      [this](const nlohmann::json& json, WebSocketHandler::Connection* conn) {
        std::string module_name = json["module"];

        bool success = hmi_worker_->StartModule(module_name);

        nlohmann::json response;
        response["type"] = "StartModuleResponse";
        response["module"] = module_name;
        response["success"] = success;
        websocket_->SendData(conn, response.dump());
      });
}

5.5 前端WebSocket客户端

typescript 复制代码
// 前端WebSocket管理器伪代码

class WebSocketManager {
  private connections: Map<string, WebSocket> = new Map();

  // 创建WebSocket连接
  connect(url: string, name: string) {
    const ws = new WebSocket(url);

    ws.onopen = () => {
      console.log(`${name} WebSocket connected`);
      this.connections.set(name, ws);
    };

    ws.onmessage = (event) => {
      const message = JSON.parse(event.data);
      this.handleMessage(name, message);
    };

    ws.onerror = (error) => {
      console.error(`${name} WebSocket error:`, error);
    };

    ws.onclose = () => {
      console.log(`${name} WebSocket closed`);
      this.connections.delete(name);
      // 自动重连
      setTimeout(() => this.connect(url, name), 5000);
    };
  }

  // 发送消息
  send(name: string, message: any) {
    const ws = this.connections.get(name);
    if (ws && ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify(message));
    }
  }

  // 处理接收到的消息
  handleMessage(name: string, message: any) {
    // 根据消息类型分发到不同的处理器
    switch (message.type) {
      case 'SimulationWorld':
        this.handleSimulationWorld(message.data);
        break;
      case 'MapData':
        this.handleMapData(message.data);
        break;
      // ... 其他消息类型
    }
  }
}

// 初始化所有WebSocket连接
const wsManager = new WebSocketManager();
wsManager.connect('ws://localhost:8888/websocket', 'main');
wsManager.connect('ws://localhost:8888/map', 'map');
wsManager.connect('ws://localhost:8888/simworld', 'simworld');
// ... 其他连接

6. 核心功能模块

6.1 数据更新器架构

所有数据更新器继承自UpdaterBase基类:

cpp 复制代码
// 文件: modules/dreamview_plus/backend/updater/updater_base.h:38-65

class UpdaterBase {
 public:
  UpdaterBase();

  // ========== 核心接口 ==========

  // 启动数据流
  // time_interval_ms: 数据流发送频率 (0表示单次订阅)
  // channel_name: 通道名称 (可选)
  // subscribe_param: 订阅参数 (可选)
  virtual void StartStream(const double& time_interval_ms,
                           const std::string& channel_name = "",
                           nlohmann::json* subscribe_param = nullptr) = 0;

  // 停止数据流
  virtual void StopStream(const std::string& channel_name = "") = 0;

  // 发布消息到前端
  virtual void PublishMessage(const std::string& channel_name = "") = 0;

  virtual ~UpdaterBase() {}
};

更新器工作流程:

复制代码
┌─────────────────┐
│  Frontend       │
│  发送订阅请求    │
└────────┬────────┘
         │ WebSocket: {"type": "Subscribe", "channel": "SimWorld"}
         ▼
┌─────────────────────────────────────────┐
│  SocketManager                          │
│  处理订阅请求                            │
└────────┬────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────┐
│  UpdaterManager                         │
│  查找对应的Updater                       │
└────────┬────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────┐
│  SimulationWorldUpdater::StartStream()  │
│  1. 创建定时器 (10-30Hz)                 │
│  2. 订阅CyberRT话题                      │
└────────┬────────────────────────────────┘
         │
         ▼ 定时器触发
┌─────────────────────────────────────────┐
│  SimulationWorldUpdater::OnTimer()      │
│  1. 从CyberRT读取最新数据                │
│  2. 数据转换和聚合                       │
│  3. 生成JSON                            │
└────────┬────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────┐
│  SimulationWorldUpdater::PublishMessage()│
│  通过WebSocket发送给前端                 │
└────────┬────────────────────────────────┘
         │ WebSocket: SimulationWorld JSON
         ▼
┌─────────────────┐
│  Frontend       │
│  渲染可视化      │
└─────────────────┘

6.2 SimulationWorldUpdater (仿真世界更新器)

职责: 聚合并推送车辆状态、障碍物、规划轨迹等核心数据

cpp 复制代码
// 文件: modules/dreamview_plus/backend/simulation_world/simulation_world_updater.h:61-91

class SimulationWorldUpdater : public UpdaterBase {
 public:
  SimulationWorldUpdater(WebSocketHandler *websocket,
                         WebSocketHandler *map_ws,
                         WebSocketHandler *plugin_ws,
                         const MapService *map_service,
                         PluginManager *plugin_manager,
                         WebSocketHandler *sim_world_ws,
                         HMI *hmi,
                         bool routing_from_file = false);

  // 启动数据流 (默认30Hz)
  void StartStream(const double &time_interval_ms,
                   const std::string &channel_name = "",
                   nlohmann::json *subscribe_param = nullptr) override;

  void StopStream(const std::string &channel_name = "") override;
  void PublishMessage(const std::string &channel_name = "") override;

 private:
  // 定时器回调
  void OnTimer(const std::string &channel_name = "");

  // 数据流推送间隔 (毫秒)
  double time_interval_ms_;

  // 上次推送的ADC时间戳
  double last_pushed_adc_timestamp_sec_;

  // WebSocket处理器
  WebSocketHandler *websocket_;
  WebSocketHandler *sim_world_ws_;

  // 核心服务
  std::unique_ptr<SimulationWorldService> sim_world_service_;
  const MapService *map_service_;

  // 定时器
  std::unique_ptr<cyber::Timer> timer_;
};

SimulationWorld数据结构 (JSON格式):

json 复制代码
{
  "timestamp": 1234567890.123,
  "sequenceNum": 12345,

  "autoDrivingCar": {
    "positionX": 587123.45,
    "positionY": 4141234.56,
    "heading": 1.57,
    "speed": 12.5,
    "speedAcceleration": 0.5,
    "speedJerk": 0.1,
    "steeringAngle": -0.2,
    "steeringPercentage": 10.5,
    "steeringTorque": 2.3,
    "throttlePercentage": 30.0,
    "brakePercentage": 0.0,
    "gearLocation": "GEAR_DRIVE"
  },

  "object": [
    {
      "id": "obstacle_001",
      "type": "VEHICLE",
      "positionX": 587130.0,
      "positionY": 4141240.0,
      "heading": 1.6,
      "length": 4.5,
      "width": 1.8,
      "height": 1.5,
      "speed": 10.0,
      "speedHeading": 1.6,
      "confidence": 0.95,
      "trajectoryPoint": [...]
    }
  ],

  "planningTrajectory": [
    {
      "positionX": 587123.5,
      "positionY": 4141234.6,
      "heading": 1.57,
      "speed": 12.6,
      "accelerationS": 0.5,
      "relativeTime": 0.1
    }
  ],

  "routePath": [...],
  "trafficSignal": [...],
  "speedLimit": 60.0,
  "engageAdvice": "READY_TO_ENGAGE",
  "disengageType": "DISENGAGE_NONE"
}

数据聚合流程:

cpp 复制代码
// 伪代码: SimulationWorldUpdater::OnTimer()

void SimulationWorldUpdater::OnTimer() {
  nlohmann::json sim_world_json;

  // 1. 获取车辆状态 (订阅 /apollo/chassis)
  auto chassis = GetLatestChassis();
  sim_world_json["autoDrivingCar"]["speed"] = chassis.speed_mps();
  sim_world_json["autoDrivingCar"]["throttlePercentage"] =
      chassis.throttle_percentage();

  // 2. 获取定位信息 (订阅 /apollo/localization/pose)
  auto localization = GetLatestLocalization();
  sim_world_json["autoDrivingCar"]["positionX"] =
      localization.pose().position().x();
  sim_world_json["autoDrivingCar"]["positionY"] =
      localization.pose().position().y();

  // 3. 获取障碍物 (订阅 /apollo/perception/obstacles)
  auto obstacles = GetLatestObstacles();
  for (const auto& obstacle : obstacles.perception_obstacle()) {
    nlohmann::json obj;
    obj["id"] = obstacle.id();
    obj["type"] = obstacle.type();
    obj["positionX"] = obstacle.position().x();
    obj["positionY"] = obstacle.position().y();
    sim_world_json["object"].push_back(obj);
  }

  // 4. 获取规划轨迹 (订阅 /apollo/planning)
  auto planning = GetLatestPlanning();
  for (const auto& point : planning.trajectory_point()) {
    nlohmann::json tp;
    tp["positionX"] = point.path_point().x();
    tp["positionY"] = point.path_point().y();
    tp["speed"] = point.v();
    sim_world_json["planningTrajectory"].push_back(tp);
  }

  // 5. 获取路由路径 (订阅 /apollo/routing_response)
  auto routing = GetLatestRouting();
  // ... 处理路由数据

  // 6. 通过WebSocket发送
  PublishMessage();
}

订阅的CyberRT话题:

话题名称 消息类型 频率 用途
/apollo/localization/pose LocalizationEstimate 100Hz 车辆位置、姿态
/apollo/chassis Chassis 100Hz 车辆底盘状态
/apollo/perception/obstacles PerceptionObstacles 10Hz 障碍物信息
/apollo/planning ADCTrajectory 10Hz 规划轨迹
/apollo/routing_response RoutingResponse 按需 路由路径
/apollo/control ControlCommand 10Hz 控制命令
/apollo/prediction PredictionObstacles 10Hz 预测轨迹
/apollo/perception/traffic_light TrafficLightDetection 10Hz 红绿灯检测

6.3 MapUpdater (地图更新器)

职责: 加载和推送高精地图数据

cpp 复制代码
class MapUpdater : public UpdaterBase {
 public:
  MapUpdater(WebSocketHandler *map_ws, const MapService *map_service);

  void StartStream(const double &time_interval_ms,
                   const std::string &channel_name = "",
                   nlohmann::json *subscribe_param = nullptr) override;

  void StopStream(const std::string &channel_name = "") override;
  void PublishMessage(const std::string &channel_name = "") override;

 private:
  // 地图元素提取
  void ExtractLanes(nlohmann::json &map_json);
  void ExtractCrosswalks(nlohmann::json &map_json);
  void ExtractJunctions(nlohmann::json &map_json);
  void ExtractStopSigns(nlohmann::json &map_json);
  void ExtractYieldSigns(nlohmann::json &map_json);
  void ExtractSpeedBumps(nlohmann::json &map_json);

  WebSocketHandler *map_ws_;
  const MapService *map_service_;
};

地图数据格式:

json 复制代码
{
  "type": "MapData",
  "lane": [
    {
      "id": "lane_001",
      "centralCurve": [
        {"x": 587123.0, "y": 4141234.0, "z": 10.5},
        {"x": 587124.0, "y": 4141235.0, "z": 10.5}
      ],
      "leftBoundary": [...],
      "rightBoundary": [...],
      "speedLimit": 60.0,
      "type": "CITY_DRIVING",
      "turn": "NO_TURN",
      "predecessorId": ["lane_000"],
      "successorId": ["lane_002"]
    }
  ],
  "crosswalk": [
    {
      "id": "crosswalk_001",
      "polygon": [
        {"x": 587120.0, "y": 4141230.0},
        {"x": 587125.0, "y": 4141230.0},
        {"x": 587125.0, "y": 4141235.0},
        {"x": 587120.0, "y": 4141235.0}
      ]
    }
  ],
  "junction": [...],
  "stopSign": [...],
  "speedBump": [...]
}

6.4 PointCloudUpdater (点云更新器)

职责: 推送激光雷达点云数据

cpp 复制代码
class PointCloudUpdater : public UpdaterBase {
 public:
  explicit PointCloudUpdater(WebSocketHandler *point_cloud_ws);

  void StartStream(const double &time_interval_ms,
                   const std::string &channel_name = "",
                   nlohmann::json *subscribe_param = nullptr) override;

  void StopStream(const std::string &channel_name = "") override;
  void PublishMessage(const std::string &channel_name = "") override;

 private:
  // 点云消息回调
  void OnPointCloud(const std::shared_ptr<PointCloud>& point_cloud);

  // 点云数据压缩
  std::string CompressPointCloud(const PointCloud& point_cloud);

  WebSocketHandler *point_cloud_ws_;
  std::shared_ptr<cyber::Reader<PointCloud>> point_cloud_reader_;
};

点云数据传输:

复制代码
┌────────────────┐
│  LiDAR Driver  │
│  发布点云数据   │
└────────┬───────┘
         │ /apollo/sensor/lidar/compensator/PointCloud2
         ▼
┌─────────────────────────────────────────┐
│  PointCloudUpdater                      │
│  1. 订阅点云话题                         │
│  2. 点云下采样 (减少数据量)              │
│  3. 二进制编码                          │
│  4. 可选压缩 (zlib)                     │
└────────┬────────────────────────────────┘
         │ Binary WebSocket Message
         ▼
┌─────────────────┐
│  Frontend       │
│  Three.js渲染   │
└─────────────────┘

点云二进制格式:

复制代码
┌───────────────┬──────────────┬────────────────────────────┐
│ Header (12B)  │ Points Count │    Point Data (N * 16B)    │
├───────────────┼──────────────┼────────────────────────────┤
│ Magic (4B)    │  uint32_t    │  x (float) + y (float) +   │
│ Version (4B)  │              │  z (float) + intensity(f)  │
│ Flags (4B)    │              │    (重复N次)                │
└───────────────┴──────────────┴────────────────────────────┘

6.5 CameraUpdater (相机更新器)

职责: 推送相机图像数据

cpp 复制代码
class PerceptionCameraUpdater : public UpdaterBase {
 public:
  explicit PerceptionCameraUpdater(WebSocketHandler *camera_ws);

  void StartStream(const double &time_interval_ms,
                   const std::string &channel_name = "",
                   nlohmann::json *subscribe_param = nullptr) override;

  void StopStream(const std::string &channel_name = "") override;
  void PublishMessage(const std::string &channel_name = "") override;

 private:
  // 相机图像回调
  void OnCameraImage(const std::shared_ptr<Image>& image);

  // JPEG编码
  std::string EncodeToJPEG(const Image& image, int quality = 80);

  WebSocketHandler *camera_ws_;

  // 支持多个相机
  std::map<std::string, std::shared_ptr<cyber::Reader<Image>>> camera_readers_;
};

相机图像传输:

复制代码
┌────────────────┐
│ Camera Driver  │
│  发布图像数据   │
└────────┬───────┘
         │ /apollo/sensor/camera/front_6mm/image
         ▼
┌─────────────────────────────────────────┐
│  PerceptionCameraUpdater                │
│  1. 订阅相机话题                         │
│  2. 图像解码 (如果是压缩格式)            │
│  3. 缩放 (可选, 减少带宽)                │
│  4. JPEG编码 (质量80)                   │
└────────┬────────────────────────────────┘
         │ Binary WebSocket Message
         ▼
┌─────────────────┐
│  Frontend       │
│  Canvas渲染     │
└─────────────────┘

图像数据格式:

复制代码
┌───────────────┬────────────────────────────┐
│ Header (JSON) │    JPEG Data (Binary)      │
├───────────────┼────────────────────────────┤
│ {             │                            │
│  "channel":   │    JPEG Encoded Image      │
│  "timestamp": │                            │
│  "width":     │                            │
│  "height":    │                            │
│ }             │                            │
└───────────────┴────────────────────────────┘

6.6 ObstacleUpdater (障碍物更新器)

职责: 推送感知障碍物详细信息

cpp 复制代码
class ObstacleUpdater : public UpdaterBase {
 public:
  explicit ObstacleUpdater(WebSocketHandler *obstacle_ws);

  void StartStream(const double &time_interval_ms,
                   const std::string &channel_name = "",
                   nlohmann::json *subscribe_param = nullptr) override;

  void StopStream(const std::string &channel_name = "") override;
  void PublishMessage(const std::string &channel_name = "") override;

 private:
  void OnTimer();

  WebSocketHandler *obstacle_ws_;
  std::unique_ptr<cyber::Timer> timer_;

  // 订阅感知障碍物
  std::shared_ptr<cyber::Reader<PerceptionObstacles>> perception_obstacles_reader_;
};

障碍物数据格式:

json 复制代码
{
  "type": "ObstacleData",
  "timestamp": 1234567890.123,
  "obstacles": [
    {
      "id": 1001,
      "type": "VEHICLE",
      "position": {"x": 587130.0, "y": 4141240.0, "z": 10.5},
      "velocity": {"x": 10.0, "y": 0.5, "z": 0.0},
      "acceleration": {"x": 0.5, "y": 0.0, "z": 0.0},
      "theta": 1.57,
      "length": 4.5,
      "width": 1.8,
      "height": 1.5,
      "confidence": 0.95,
      "trackingTime": 2.5,
      "polygon": [
        {"x": 587128.0, "y": 4141238.5},
        {"x": 587132.0, "y": 4141238.5},
        {"x": 587132.0, "y": 4141241.5},
        {"x": 587128.0, "y": 4141241.5}
      ],
      "predictedTrajectory": [
        {
          "time": 0.5,
          "position": {"x": 587135.0, "y": 4141240.5}
        },
        {
          "time": 1.0,
          "position": {"x": 587140.0, "y": 4141241.0}
        }
      ]
    }
  ]
}

6.7 ChannelsUpdater (通道信息更新器)

职责: 推送CyberRT所有通道信息

cpp 复制代码
class ChannelsUpdater : public UpdaterBase {
 public:
  explicit ChannelsUpdater(WebSocketHandler *channels_info_ws);

  void StartStream(const double &time_interval_ms,
                   const std::string &channel_name = "",
                   nlohmann::json *subscribe_param = nullptr) override;

  void StopStream(const std::string &channel_name = "") override;
  void PublishMessage(const std::string &channel_name = "") override;

 private:
  void OnTimer();

  // 获取所有通道信息
  void GetAllChannels(nlohmann::json &channels_json);

  WebSocketHandler *channels_info_ws_;
  std::unique_ptr<cyber::Timer> timer_;
};

通道信息格式:

json 复制代码
{
  "type": "ChannelsInfo",
  "timestamp": 1234567890.123,
  "channels": [
    {
      "name": "/apollo/planning",
      "messageType": "apollo.planning.ADCTrajectory",
      "readerNum": 3,
      "writerNum": 1,
      "messageRate": 10.5
    },
    {
      "name": "/apollo/perception/obstacles",
      "messageType": "apollo.perception.PerceptionObstacles",
      "readerNum": 5,
      "writerNum": 1,
      "messageRate": 10.2
    }
  ]
}

7. HMI人机交互

7.1 HMI架构

HMI (Human Machine Interface) 模块负责处理所有用户交互操作。

cpp 复制代码
// 文件: modules/dreamview_plus/backend/hmi/hmi.h:35-75

class HMI : public UpdaterBase {
 public:
  using DvCallback = std::function<nlohmann::json(
      const std::string &function_name, const nlohmann::json &param_json)>;

  HMI(WebSocketHandler *websocket, MapService *map_service,
      WebSocketHandler *hmi_websocket);

  void Start(DvCallback callback_api);
  void Stop();

  void StartStream(const double &time_interval_ms,
                   const std::string &channel_name = "",
                   nlohmann::json *subscribe_param = nullptr) override;

  void StopStream(const std::string &channel_name = "") override;
  void PublishMessage(const std::string &channel_name = "") override;

  void OnTimer(const std::string &channel_name = "");

  // ========== 状态更新 ==========

  bool UpdateDynamicModelToStatus(const std::string &dynamic_model_name);
  bool UpdateMapToStatus(const std::string &map_name = "");
  bool UpdateRecordToStatus();
  bool UpdateVehicleToStatus();
  bool UpdateCameraChannelToStatus(const std::string &channel_name);
  bool UpdatePointChannelToStatus(const std::string &channel_name);
  bool isProcessRunning(const std::string &process_name);

 private:
  // 发送车辆参数
  void SendVehicleParam(WebSocketHandler::Connection *conn = nullptr);

  // 注册消息处理器
  void RegisterMessageHandlers();
  void RegisterDBMessageHandlers();
  void RegisterFrontendConfMessageHandlers();

  std::unique_ptr<HMIWorker> hmi_worker_;

  WebSocketHandler *websocket_;
  MapService *map_service_;
  WebSocketHandler *hmi_ws_;

  double time_interval_ms_;
  std::unique_ptr<cyber::Timer> timer_;
};

7.2 HMI消息类型

消息类型 方向 功能 示例
StartModule 前端→后端 启动模块 {"type":"StartModule","module":"planning"}
StopModule 前端→后端 停止模块 {"type":"StopModule","module":"planning"}
ChangeMode 前端→后端 切换驾驶模式 {"type":"ChangeMode","mode":"auto"}
SendRoutingRequest 前端→后端 发送路由请求 {"type":"SendRoutingRequest","start":{...},"end":{...}}
ResetAllMode 前端→后端 重置所有模块 {"type":"ResetAllMode"}
ChangeMap 前端→后端 切换地图 {"type":"ChangeMap","map":"sunnyvale"}
ChangeVehicle 前端→后端 切换车辆 {"type":"ChangeVehicle","vehicle":"lincoln"}
HMIStatus 后端→前端 HMI状态推送 {"type":"HMIStatus","modules":{...},"hardware":{...}}
VehicleParam 后端→前端 车辆参数 {"type":"VehicleParam","brand":"lincoln",...}

7.3 HMI状态数据结构

json 复制代码
{
  "type": "HMIStatus",
  "timestamp": 1234567890.123,

  "currentMode": "NAVIGATION",
  "currentMap": "sunnyvale",
  "currentVehicle": "lincoln_mkz",
  "currentRecordFile": "",

  "modules": {
    "Canbus": "STARTED",
    "GPS": "STARTED",
    "Localization": "STARTED",
    "Perception": "STARTED",
    "Prediction": "STARTED",
    "Planning": "STARTED",
    "Routing": "STARTED",
    "Control": "STARTED",
    "Transform": "STARTED",
    "Guardian": "STARTED"
  },

  "hardware": {
    "GPS": {
      "status": "OK",
      "message": "GPS signal good"
    },
    "CAN": {
      "status": "OK",
      "message": "CAN bus connected"
    },
    "Camera": {
      "status": "OK",
      "message": "6 cameras online"
    },
    "Lidar": {
      "status": "WARNING",
      "message": "Lidar frequency low"
    }
  },

  "systemStatus": "OK",
  "errorMessage": ""
}

7.4 模块启停控制

cpp 复制代码
// 伪代码: HMI模块启停

void HMI::RegisterMessageHandlers() {
  // 注册"StartModule"消息处理器
  websocket_->RegisterMessageHandler(
      "StartModule",
      [this](const nlohmann::json& json, WebSocketHandler::Connection* conn) {
        std::string module_name = json["module"];

        // 1. 构造启动命令
        std::string start_cmd = absl::StrCat(
            "cyber_launch start ",
            "/apollo/modules/", module_name, "/launch/", module_name, ".launch");

        // 2. 执行启动命令
        int ret = system(start_cmd.c_str());

        // 3. 等待模块启动
        std::this_thread::sleep_for(std::chrono::seconds(2));

        // 4. 检查模块状态
        bool is_running = hmi_worker_->IsModuleRunning(module_name);

        // 5. 发送响应
        nlohmann::json response;
        response["type"] = "StartModuleResponse";
        response["module"] = module_name;
        response["success"] = is_running;
        response["message"] = is_running ? "Module started" : "Failed to start";

        websocket_->SendData(conn, response.dump());

        // 6. 广播HMI状态更新
        BroadcastHMIStatus();
      });

  // 注册"StopModule"消息处理器
  websocket_->RegisterMessageHandler(
      "StopModule",
      [this](const nlohmann::json& json, WebSocketHandler::Connection* conn) {
        std::string module_name = json["module"];

        // 1. 构造停止命令
        std::string stop_cmd = absl::StrCat(
            "cyber_launch stop ",
            "/apollo/modules/", module_name, "/launch/", module_name, ".launch");

        // 2. 执行停止命令
        int ret = system(stop_cmd.c_str());

        // 3. 等待模块停止
        std::this_thread::sleep_for(std::chrono::milliseconds(500));

        // 4. 检查模块状态
        bool is_stopped = !hmi_worker_->IsModuleRunning(module_name);

        // 5. 发送响应
        nlohmann::json response;
        response["type"] = "StopModuleResponse";
        response["module"] = module_name;
        response["success"] = is_stopped;

        websocket_->SendData(conn, response.dump());

        // 6. 广播HMI状态更新
        BroadcastHMIStatus();
      });
}

7.5 路由请求处理

cpp 复制代码
// 伪代码: 路由请求处理

void HMI::RegisterMessageHandlers() {
  websocket_->RegisterMessageHandler(
      "SendRoutingRequest",
      [this](const nlohmann::json& json, WebSocketHandler::Connection* conn) {
        // 1. 解析起点和终点
        double start_x = json["start"]["x"];
        double start_y = json["start"]["y"];
        double end_x = json["end"]["x"];
        double end_y = json["end"]["y"];

        // 2. 构造RoutingRequest消息
        apollo::routing::RoutingRequest routing_request;

        auto* start_point = routing_request.add_waypoint();
        start_point->mutable_pose()->set_x(start_x);
        start_point->mutable_pose()->set_y(start_y);

        auto* end_point = routing_request.add_waypoint();
        end_point->mutable_pose()->set_x(end_x);
        end_point->mutable_pose()->set_y(end_y);

        // 3. 通过CyberRT发布路由请求
        auto routing_request_writer =
            node_->CreateWriter<apollo::routing::RoutingRequest>(
                "/apollo/routing_request");

        routing_request_writer->Write(routing_request);

        // 4. 发送响应
        nlohmann::json response;
        response["type"] = "SendRoutingRequestResponse";
        response["success"] = true;
        response["message"] = "Routing request sent";

        websocket_->SendData(conn, response.dump());

        AINFO << "Routing request sent: (" << start_x << "," << start_y
              << ") -> (" << end_x << "," << end_y << ")";
      });
}

8. 插件系统

8.1 插件架构

Dreamview Plus支持动态插件系统,允许扩展功能而无需修改核心代码。

cpp 复制代码
// 文件: modules/dreamview_plus/backend/dv_plugin/dv_plugin_manager.h

class DvPluginManager {
 public:
  DvPluginManager(CivetServer* server, UpdaterManager* updater_manager);

  // 初始化插件管理器
  void Init();

  // 加载插件
  bool LoadPlugin(const std::string& plugin_path);

  // 卸载插件
  bool UnloadPlugin(const std::string& plugin_name);

  // 获取插件列表
  std::vector<std::string> GetPluginList() const;

 private:
  // 扫描插件目录
  void ScanPluginDirectory();

  // 插件配置
  std::map<std::string, PluginConfig> plugin_configs_;

  // 已加载的插件
  std::map<std::string, std::unique_ptr<DvPluginBase>> loaded_plugins_;

  CivetServer* server_;
  UpdaterManager* updater_manager_;
};

8.2 插件基类

cpp 复制代码
// 文件: modules/dreamview_plus/backend/dv_plugin/dv_plugin_base.h

class DvPluginBase {
 public:
  DvPluginBase() = default;
  virtual ~DvPluginBase() = default;

  // ========== 生命周期 ==========

  // 初始化插件
  virtual bool Init(CivetServer* server,
                   UpdaterManager* updater_manager) = 0;

  // 启动插件
  virtual bool Start() = 0;

  // 停止插件
  virtual void Stop() = 0;

  // ========== 插件信息 ==========

  // 获取插件名称
  virtual std::string GetName() const = 0;

  // 获取插件版本
  virtual std::string GetVersion() const = 0;

  // 获取插件描述
  virtual std::string GetDescription() const = 0;

  // ========== 消息处理 ==========

  // 处理WebSocket消息
  virtual bool HandleMessage(const std::string& message_type,
                            const nlohmann::json& message_data) = 0;

  // 处理HTTP请求
  virtual bool HandleHttpRequest(const std::string& uri,
                                CivetServer* server,
                                struct mg_connection* conn) = 0;
};

8.3 插件示例: 数据录制插件

cpp 复制代码
// 示例插件: 数据录制插件

class RecordPlugin : public DvPluginBase {
 public:
  RecordPlugin() = default;
  ~RecordPlugin() override = default;

  bool Init(CivetServer* server, UpdaterManager* updater_manager) override {
    server_ = server;
    updater_manager_ = updater_manager;

    // 创建CyberRT节点
    node_ = cyber::CreateNode("record_plugin");

    // 注册HTTP路由
    server_->addHandler("/api/record/start", *this);
    server_->addHandler("/api/record/stop", *this);
    server_->addHandler("/api/record/list", *this);

    return true;
  }

  bool Start() override {
    AINFO << "RecordPlugin started";
    return true;
  }

  void Stop() override {
    if (is_recording_) {
      StopRecording();
    }
    AINFO << "RecordPlugin stopped";
  }

  std::string GetName() const override {
    return "RecordPlugin";
  }

  std::string GetVersion() const override {
    return "1.0.0";
  }

  std::string GetDescription() const override {
    return "Data recording plugin for Dreamview";
  }

  bool HandleMessage(const std::string& message_type,
                    const nlohmann::json& message_data) override {
    if (message_type == "StartRecord") {
      return StartRecording(message_data["channels"]);
    } else if (message_type == "StopRecord") {
      return StopRecording();
    }
    return false;
  }

  bool HandleHttpRequest(const std::string& uri,
                        CivetServer* server,
                        struct mg_connection* conn) override {
    if (uri == "/api/record/start") {
      // 处理录制启动请求
      nlohmann::json response;
      response["success"] = StartRecording({"/apollo/planning", "/apollo/perception/obstacles"});
      mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n");
      mg_printf(conn, "%s", response.dump().c_str());
      return true;
    } else if (uri == "/api/record/stop") {
      // 处理录制停止请求
      nlohmann::json response;
      response["success"] = StopRecording();
      mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n");
      mg_printf(conn, "%s", response.dump().c_str());
      return true;
    }
    return false;
  }

 private:
  bool StartRecording(const std::vector<std::string>& channels) {
    if (is_recording_) {
      AWARN << "Already recording";
      return false;
    }

    // 创建录制文件名
    auto now = std::time(nullptr);
    std::string filename = absl::StrCat(
        "/apollo/data/bag/",
        std::put_time(std::localtime(&now), "%Y%m%d_%H%M%S"),
        ".record");

    // 启动cyber_recorder
    std::string cmd = "cyber_recorder record";
    for (const auto& channel : channels) {
      cmd += " -c " + channel;
    }
    cmd += " -o " + filename + " &";

    int ret = system(cmd.c_str());
    if (ret == 0) {
      is_recording_ = true;
      current_record_file_ = filename;
      AINFO << "Recording started: " << filename;
      return true;
    }

    return false;
  }

  bool StopRecording() {
    if (!is_recording_) {
      AWARN << "Not recording";
      return false;
    }

    // 停止cyber_recorder
    system("pkill -INT cyber_recorder");

    is_recording_ = false;
    AINFO << "Recording stopped: " << current_record_file_;
    current_record_file_.clear();

    return true;
  }

  CivetServer* server_ = nullptr;
  UpdaterManager* updater_manager_ = nullptr;
  std::shared_ptr<cyber::Node> node_;

  bool is_recording_ = false;
  std::string current_record_file_;
};

// 插件导出宏
CYBER_PLUGIN_EXPORT(RecordPlugin)

8.4 插件配置

json 复制代码
// 文件: modules/dreamview_plus/conf/plugin_config.json

{
  "plugins": [
    {
      "name": "RecordPlugin",
      "path": "/apollo/bazel-bin/modules/dreamview_plus/plugins/librecord_plugin.so",
      "enabled": true,
      "config": {
        "default_channels": [
          "/apollo/planning",
          "/apollo/perception/obstacles",
          "/apollo/localization/pose"
        ],
        "max_recording_duration": 3600,
        "auto_split_size_mb": 1024
      }
    },
    {
      "name": "PerformanceMonitorPlugin",
      "path": "/apollo/bazel-bin/modules/dreamview_plus/plugins/libperf_monitor_plugin.so",
      "enabled": true,
      "config": {
        "sample_interval_ms": 1000,
        "metrics": ["cpu", "memory", "network"]
      }
    }
  ]
}

9. 配置与部署

9.1 Dreamview Plus配置文件

9.1.1 主配置文件
bash 复制代码
# 文件: modules/dreamview_plus/conf/dreamview.conf

# ========== Web服务器配置 ==========

# 静态文件目录
--static_file_dir=/apollo/modules/dreamview_plus/frontend/dist

# 监听端口
--server_ports=8888

# WebSocket超时 (毫秒)
--websocket_timeout_ms=3600000

# HTTP请求超时 (毫秒)
--request_timeout_ms=2000

# SSL证书 (可选)
--ssl_certificate=

# ========== 数据更新频率 ==========

# SimulationWorld更新频率 (Hz)
--sim_world_update_rate=30

# 地图更新频率 (Hz)
--map_update_rate=1

# 点云更新频率 (Hz)
--pointcloud_update_rate=10

# 相机更新频率 (Hz)
--camera_update_rate=10

# ========== 功能开关 ==========

# 启用点云可视化
--enable_pointcloud=true

# 启用相机可视化
--enable_camera=true

# 启用性能分析
--dv_cpu_profile=false
--dv_heap_profile=false

# Profiling模式 (自动退出)
--dreamview_profiling_mode=false
--dreamview_profiling_duration=60.0

# ========== 路由配置 ==========

# 从文件读取初始路由
--routing_from_file=false

# ========== 地图配置 ==========

# 默认地图
--default_map=sunnyvale

# ========== 车辆配置 ==========

# 默认车辆
--default_vehicle=lincoln_mkz
9.1.2 前端配置
javascript 复制代码
// 文件: modules/dreamview_plus/frontend/packages/dreamview/src/config.ts

export const DreamviewConfig = {
  // WebSocket服务器地址
  websocket: {
    host: window.location.hostname,
    port: 8888,
    secure: window.location.protocol === 'https:',
  },

  // 更新频率
  updateInterval: {
    simWorld: 33,        // 30Hz
    map: 1000,           // 1Hz
    pointcloud: 100,     // 10Hz
    camera: 100,         // 10Hz
    obstacle: 100,       // 10Hz
    hmiStatus: 200,      // 5Hz
  },

  // 3D渲染配置
  rendering: {
    camera: {
      fov: 60,
      near: 1,
      far: 10000,
      height: 3,
    },
    pointcloud: {
      size: 0.05,
      colorMode: 'intensity',
    },
    obstacle: {
      showId: true,
      showVelocity: true,
      showPrediction: true,
    },
  },

  // 地图配置
  map: {
    center: [0, 0],
    zoom: 18,
    tileSize: 512,
  },
};

9.2 部署流程

9.2.1 Docker部署
bash 复制代码
# 1. 构建Docker镜像
cd /apollo
bash docker/scripts/dev_start.sh

# 2. 进入Docker容器
bash docker/scripts/dev_into.sh

# 3. 编译Dreamview Plus
bash apollo.sh build_opt dreamview_plus

# 4. 启动Dreamview Plus
cyber_launch start modules/dreamview_plus/launch/dreamview_plus.launch

# 5. 访问Web界面
# 浏览器打开: http://localhost:8888
9.2.2 编译配置
python 复制代码
# 文件: modules/dreamview_plus/BUILD

load("//tools:apollo_package.bzl", "apollo_package")
load("//tools:cpplint.bzl", "cpplint")

apollo_cc_binary(
    name = "dreamview_plus",
    srcs = ["main.cc"],
    linkopts = [
        "-lpthread",
        "-lboost_system",
        "-lboost_thread",
    ],
    deps = [
        "//cyber",
        "//modules/common/configs:vehicle_config_helper",
        "//modules/dreamview_plus/backend:dreamview_lib",
        "@com_github_gflags_gflags//:gflags",
        "@com_github_google_glog//:glog",
        "@com_google_googletest//:gtest_main",
    ],
)

# 前端构建
genrule(
    name = "frontend",
    srcs = glob([
        "frontend/**/*",
    ]),
    outs = ["frontend_dist"],
    cmd = """
        cd modules/dreamview_plus/frontend && \
        npm install && \
        npm run build && \
        cp -r dist $(location frontend_dist)
    """,
)
9.2.3 Launch文件
xml 复制代码
<!-- 文件: modules/dreamview_plus/launch/dreamview_plus.launch -->

<cyber>
  <module>
    <name>dreamview_plus</name>
    <dag_conf>modules/dreamview_plus/dag/dreamview_plus.dag</dag_conf>
    <process_name>dreamview_plus</process_name>
  </module>
</cyber>
xml 复制代码
<!-- 文件: modules/dreamview_plus/dag/dreamview_plus.dag -->

<dag>
  <module_config module_library="bazel-bin/modules/dreamview_plus/libdreamview_plus_lib.so">
    <components>
      <component class_name="DreamviewPlus" config="">
        <flag_file>modules/dreamview_plus/conf/dreamview.conf</flag_file>
      </component>
    </components>
  </module_config>
</dag>

9.3 性能优化

9.3.1 WebSocket性能优化
cpp 复制代码
// 1. 消息批处理
class WebSocketBatcher {
 public:
  void AddMessage(const std::string& message) {
    std::lock_guard<std::mutex> lock(mutex_);
    batch_.push_back(message);

    if (batch_.size() >= batch_size_ || ShouldFlush()) {
      Flush();
    }
  }

 private:
  void Flush() {
    if (batch_.empty()) return;

    // 合并多个消息
    nlohmann::json batch_json;
    batch_json["type"] = "Batch";
    batch_json["messages"] = batch_;

    // 发送批量消息
    websocket_->BroadcastData(batch_json.dump());

    batch_.clear();
    last_flush_time_ = std::chrono::steady_clock::now();
  }

  bool ShouldFlush() {
    auto now = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
        now - last_flush_time_).count();
    return elapsed >= flush_interval_ms_;
  }

  std::vector<std::string> batch_;
  size_t batch_size_ = 10;
  int flush_interval_ms_ = 50;
  std::chrono::steady_clock::time_point last_flush_time_;
  std::mutex mutex_;
  WebSocketHandler* websocket_;
};
9.3.2 数据压缩
cpp 复制代码
// 2. 点云数据压缩
#include <zlib.h>

std::string CompressPointCloud(const PointCloud& point_cloud) {
  // 1. 序列化点云数据
  std::string raw_data;
  point_cloud.SerializeToString(&raw_data);

  // 2. 计算压缩后大小 (保守估计)
  uLongf compressed_size = compressBound(raw_data.size());
  std::vector<Bytef> compressed_data(compressed_size);

  // 3. zlib压缩
  int result = compress2(
      compressed_data.data(),
      &compressed_size,
      reinterpret_cast<const Bytef*>(raw_data.data()),
      raw_data.size(),
      Z_BEST_SPEED);  // 快速压缩

  if (result != Z_OK) {
    AERROR << "Compression failed";
    return raw_data;
  }

  // 4. 返回压缩后的数据
  compressed_data.resize(compressed_size);
  return std::string(compressed_data.begin(), compressed_data.end());
}
9.3.3 前端性能优化
typescript 复制代码
// 3. Three.js渲染优化

class PointCloudRenderer {
  private geometry: THREE.BufferGeometry;
  private material: THREE.PointsMaterial;
  private points: THREE.Points;

  updatePointCloud(data: PointCloudData) {
    // 使用BufferGeometry避免重新分配内存
    const positions = this.geometry.attributes.position.array;
    const colors = this.geometry.attributes.color.array;

    // 直接更新顶点数据
    for (let i = 0; i < data.points.length; i++) {
      const point = data.points[i];
      positions[i * 3] = point.x;
      positions[i * 3 + 1] = point.y;
      positions[i * 3 + 2] = point.z;

      // 根据强度设置颜色
      const intensity = point.intensity / 255.0;
      colors[i * 3] = intensity;
      colors[i * 3 + 1] = intensity;
      colors[i * 3 + 2] = intensity;
    }

    // 标记需要更新
    this.geometry.attributes.position.needsUpdate = true;
    this.geometry.attributes.color.needsUpdate = true;

    // 更新包围盒
    this.geometry.computeBoundingSphere();
  }

  // 使用LOD (Level of Detail)
  setupLOD() {
    const lod = new THREE.LOD();

    // 高详细度 (< 100m)
    const highDetail = this.createPointCloud(this.fullData);
    lod.addLevel(highDetail, 0);

    // 中详细度 (100m - 500m)
    const mediumDetail = this.createPointCloud(this.downsample(this.fullData, 0.5));
    lod.addLevel(mediumDetail, 100);

    // 低详细度 (> 500m)
    const lowDetail = this.createPointCloud(this.downsample(this.fullData, 0.25));
    lod.addLevel(lowDetail, 500);

    return lod;
  }

  downsample(data: Point[], ratio: number): Point[] {
    const step = Math.floor(1 / ratio);
    return data.filter((_, index) => index % step === 0);
  }
}

10. 开发与扩展

10.1 添加自定义Updater

cpp 复制代码
// 1. 创建自定义Updater类

// 文件: modules/dreamview_plus/backend/my_updater/my_updater.h

#pragma once

#include "modules/dreamview_plus/backend/updater/updater_base.h"
#include "modules/dreamview/backend/common/handlers/websocket_handler.h"

namespace apollo {
namespace dreamview {

class MyUpdater : public UpdaterBase {
 public:
  explicit MyUpdater(WebSocketHandler* websocket);

  void StartStream(const double& time_interval_ms,
                   const std::string& channel_name = "",
                   nlohmann::json* subscribe_param = nullptr) override;

  void StopStream(const std::string& channel_name = "") override;
  void PublishMessage(const std::string& channel_name = "") override;

 private:
  void OnTimer();

  WebSocketHandler* websocket_;
  std::unique_ptr<cyber::Timer> timer_;

  // 订阅的CyberRT话题
  std::shared_ptr<cyber::Reader<MyMessage>> my_message_reader_;
};

}  // namespace dreamview
}  // namespace apollo
cpp 复制代码
// 文件: modules/dreamview_plus/backend/my_updater/my_updater.cc

#include "modules/dreamview_plus/backend/my_updater/my_updater.h"

namespace apollo {
namespace dreamview {

MyUpdater::MyUpdater(WebSocketHandler* websocket)
    : websocket_(websocket) {
  // 创建CyberRT Reader
  auto node = cyber::CreateNode("my_updater");
  my_message_reader_ = node->CreateReader<MyMessage>(
      "/apollo/my_channel",
      [this](const std::shared_ptr<MyMessage>& message) {
        // 处理接收到的消息
        this->OnMyMessage(message);
      });
}

void MyUpdater::StartStream(const double& time_interval_ms,
                            const std::string& channel_name,
                            nlohmann::json* subscribe_param) {
  if (timer_) {
    AWARN << "MyUpdater already started";
    return;
  }

  // 创建定时器
  auto period = static_cast<uint64_t>(time_interval_ms * 1000);  // 转换为微秒
  timer_.reset(new cyber::Timer(
      period,
      [this]() { this->OnTimer(); },
      false));

  timer_->Start();
  AINFO << "MyUpdater started with interval: " << time_interval_ms << " ms";
}

void MyUpdater::StopStream(const std::string& channel_name) {
  if (timer_) {
    timer_->Stop();
    timer_.reset();
    AINFO << "MyUpdater stopped";
  }
}

void MyUpdater::PublishMessage(const std::string& channel_name) {
  // 构造JSON数据
  nlohmann::json json_data;
  json_data["type"] = "MyData";
  json_data["timestamp"] = cyber::Time::Now().ToSecond();

  // 添加自定义数据
  json_data["customField1"] = custom_value1_;
  json_data["customField2"] = custom_value2_;

  // 通过WebSocket发送
  websocket_->BroadcastData(json_data.dump());
}

void MyUpdater::OnTimer() {
  // 定时器回调,发布消息
  PublishMessage();
}

}  // namespace dreamview
}  // namespace apollo
cpp 复制代码
// 2. 在Dreamview中注册Updater

// 文件: modules/dreamview_plus/backend/dreamview.cc

Status Dreamview::Init() {
  // ... 其他初始化代码 ...

  // 创建自定义Updater
  my_updater_.reset(new MyUpdater(websocket_.get()));

  // 注册到UpdaterManager
  updater_manager_->RegisterUpdater("MyUpdater", my_updater_.get());

  return Status::OK();
}

10.2 添加前端组件

typescript 复制代码
// 1. 创建自定义React组件

// 文件: packages/dreamview/src/components/MyComponent/index.tsx

import React, { useEffect, useState } from 'react';
import { useWebSocket } from '@dreamview/dreamview-core';

interface MyData {
  timestamp: number;
  customField1: string;
  customField2: number;
}

export const MyComponent: React.FC = () => {
  const [data, setData] = useState<MyData | null>(null);
  const { subscribe, unsubscribe, send } = useWebSocket();

  useEffect(() => {
    // 订阅自定义数据
    const handler = (message: any) => {
      if (message.type === 'MyData') {
        setData(message as MyData);
      }
    };

    subscribe('MyUpdater', handler);

    // 发送订阅请求
    send({
      type: 'Subscribe',
      channel: 'MyUpdater',
      interval: 100, // 100ms更新间隔
    });

    return () => {
      // 取消订阅
      send({
        type: 'Unsubscribe',
        channel: 'MyUpdater',
      });
      unsubscribe('MyUpdater', handler);
    };
  }, []);

  return (
    <div className="my-component">
      <h2>My Custom Component</h2>
      {data ? (
        <div>
          <p>Timestamp: {data.timestamp}</p>
          <p>Field 1: {data.customField1}</p>
          <p>Field 2: {data.customField2}</p>
        </div>
      ) : (
        <p>Loading...</p>
      )}
    </div>
  );
};
typescript 复制代码
// 2. 注册到主应用

// 文件: packages/dreamview/src/App.tsx

import { MyComponent } from './components/MyComponent';

function App() {
  return (
    <DreamviewLayout>
      <DreamviewHeader />
      <DreamviewContent>
        {/* 其他组件 */}
        <SimulationWorldPanel />
        <MapPanel />

        {/* 添加自定义组件 */}
        <MyComponent />
      </DreamviewContent>
    </DreamviewLayout>
  );
}

10.3 调试技巧

10.3.1 后端调试
bash 复制代码
# 1. 启用详细日志
export GLOG_v=4
export GLOG_logtostderr=1

# 2. 使用GDB调试
gdb --args /apollo/bazel-bin/modules/dreamview_plus/dreamview_plus

# 3. 查看WebSocket连接
netstat -an | grep 8888

# 4. 查看CyberRT话题
cyber_channel list

# 5. 监控话题消息
cyber_monitor

# 6. 性能分析
# 启用CPU profiling
./dreamview_plus --dv_cpu_profile=true

# 查看性能报告
pprof --text dreamview_plus_cpu.prof
10.3.2 前端调试
typescript 复制代码
// 1. 启用调试日志
localStorage.setItem('dreamview_debug', 'true');

// 2. 监控WebSocket消息
const originalSend = WebSocket.prototype.send;
WebSocket.prototype.send = function(data) {
  console.log('[WS Send]', data);
  return originalSend.call(this, data);
};

// 3. React DevTools
// 安装Chrome扩展: React Developer Tools

// 4. Redux DevTools (如果使用Redux)
// 安装Chrome扩展: Redux DevTools

// 5. 性能分析
// Chrome DevTools -> Performance tab
// 录制渲染性能

// 6. 内存分析
// Chrome DevTools -> Memory tab
// 查找内存泄漏
10.3.3 WebSocket调试工具
javascript 复制代码
// WebSocket调试脚本

class WebSocketDebugger {
  constructor(url) {
    this.ws = new WebSocket(url);
    this.setupListeners();
  }

  setupListeners() {
    this.ws.onopen = () => {
      console.log('[WS] Connected');
    };

    this.ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      console.log('[WS] Received:', data.type, data);
    };

    this.ws.onerror = (error) => {
      console.error('[WS] Error:', error);
    };

    this.ws.onclose = () => {
      console.log('[WS] Disconnected');
    };
  }

  send(type, data) {
    const message = { type, ...data };
    console.log('[WS] Sending:', message);
    this.ws.send(JSON.stringify(message));
  }

  // 快捷测试方法
  requestSimWorld() {
    this.send('RequestSimulationWorld', {});
  }

  sendRoutingRequest(start, end) {
    this.send('SendRoutingRequest', {
      start: { x: start[0], y: start[1] },
      end: { x: end[0], y: end[1] },
    });
  }

  startModule(module) {
    this.send('StartModule', { module });
  }

  stopModule(module) {
    this.send('StopModule', { module });
  }
}

// 使用示例
const debugger = new WebSocketDebugger('ws://localhost:8888/websocket');
debugger.requestSimWorld();
debugger.startModule('planning');

参考资料与引用

官方资源

  1. Apollo 官方 GitHub 仓库

    https://github.com/ApolloAuto/apollo

    • Apollo 开源项目主仓库,包含完整源代码
  2. Apollo 官方文档

    https://apollo.baidu.com/docs

    • 官方技术文档和开发指南
  3. Apollo 开发者社区

    https://apollo.baidu.com/community

    • 官方开发者论坛和技术交流平台

技术规范与标准

  1. ISO 26262 - 道路车辆功能安全标准

    https://www.iso.org/standard/68383.html

  2. ISO 21448 (SOTIF) - 预期功能安全标准

    https://www.iso.org/standard/77490.html

学术论文与技术资源

  1. CenterPoint: Center-based 3D Object Detection and Tracking

    Yin, T., Zhou, X., & Krähenbühl, P. (2021)

    https://arxiv.org/abs/2006.11275

  2. BEVFormer: Learning Bird's-Eye-View Representation from Multi-Camera Images

    Li, Z., et al. (2022)

    https://arxiv.org/abs/2203.17270

  3. OpenDRIVE 地图标准

    https://www.asam.net/standards/detail/opendrive/

开源工具与库

  1. Bazel 构建系统

    https://bazel.build/

  2. Fast-DDS (eProsima)

    https://www.eprosima.com/index.php/products-all/eprosima-fast-dds

  3. PROJ 坐标转换库

    https://proj.org/

  4. TensorRT 开发指南

    https://docs.nvidia.com/deeplearning/tensorrt/

  5. PCL 点云库文档

    https://pointclouds.org/

  6. IPOPT 优化求解器

    https://coin-or.github.io/Ipopt/

说明

本文档内容整理自上述官方资料、开源代码以及相关技术文档。所有代码示例和技术细节均基于 Apollo10.0 版本。如需获取最新信息,请访问 Apollo 官方网站和 GitHub 仓库。

版权说明

Apollo® 是百度公司的注册商标。本文档为基于开源项目的非官方技术研究文档,仅供学习参考使用。

相关推荐
qq_317620315 小时前
14.Calibration模块详解
apollo·calibration
qq_317620316 小时前
05.Transform模块详解
apollo·transform
Coder个人博客4 天前
Apollo VehicleState 车辆状态模块接口调用流程图与源码分析
人工智能·自动驾驶·apollo
程序员龙一5 天前
百度Apollo Cyber RT底层原理解析
自动驾驶·ros·apollo·cyber rt
Coder个人博客8 天前
Apollo Canbus 底盘通信模块接口调用流程图与源码分析
人工智能·自动驾驶·apollo
Coder个人博客8 天前
Apollo Prediction 预测模块接口调用流程图与源码分析
人工智能·自动驾驶·apollo
johnny_hhh14 天前
apollo配置环境
apollo
Hi202402174 个月前
使用 Apollo TransformWrapper 生成相机到各坐标系的变换矩阵
数码相机·线性代数·矩阵·自动驾驶·apollo
Hi202402174 个月前
Orin-Apollo园区版本:订阅多个摄像头画面拼接与硬编码RTMP推流
ffmpeg·apollo·orin·图像拼接·图传