将 note 笔记库同步到 note_sync,AI_compiler 作为 submodule
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "AI_compiler"]
|
||||||
|
path = AI_compiler
|
||||||
|
url = https://git.hyonglin.top/ylhan/note_AI_compiler.git
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"pdfExportSettings": {
|
||||||
|
"includeName": true,
|
||||||
|
"pageSize": "Letter",
|
||||||
|
"landscape": false,
|
||||||
|
"margin": "0",
|
||||||
|
"downscalePercent": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
Vendored
+33
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"file-explorer": true,
|
||||||
|
"global-search": true,
|
||||||
|
"switcher": true,
|
||||||
|
"graph": true,
|
||||||
|
"backlink": true,
|
||||||
|
"canvas": true,
|
||||||
|
"outgoing-link": true,
|
||||||
|
"tag-pane": true,
|
||||||
|
"footnotes": false,
|
||||||
|
"properties": true,
|
||||||
|
"page-preview": true,
|
||||||
|
"daily-notes": true,
|
||||||
|
"templates": true,
|
||||||
|
"note-composer": true,
|
||||||
|
"command-palette": true,
|
||||||
|
"slash-command": false,
|
||||||
|
"editor-status": true,
|
||||||
|
"bookmarks": true,
|
||||||
|
"markdown-importer": false,
|
||||||
|
"zk-prefixer": false,
|
||||||
|
"random-note": false,
|
||||||
|
"outline": true,
|
||||||
|
"word-count": true,
|
||||||
|
"slides": false,
|
||||||
|
"audio-recorder": false,
|
||||||
|
"workspaces": false,
|
||||||
|
"file-recovery": true,
|
||||||
|
"publish": false,
|
||||||
|
"sync": true,
|
||||||
|
"bases": true,
|
||||||
|
"webviewer": false
|
||||||
|
}
|
||||||
Vendored
+22
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"collapse-filter": false,
|
||||||
|
"search": "",
|
||||||
|
"showTags": false,
|
||||||
|
"showAttachments": false,
|
||||||
|
"hideUnresolved": false,
|
||||||
|
"showOrphans": false,
|
||||||
|
"collapse-color-groups": false,
|
||||||
|
"colorGroups": [],
|
||||||
|
"collapse-display": true,
|
||||||
|
"showArrow": false,
|
||||||
|
"textFadeMultiplier": 0,
|
||||||
|
"nodeSizeMultiplier": 1,
|
||||||
|
"lineSizeMultiplier": 1,
|
||||||
|
"collapse-forces": true,
|
||||||
|
"centerStrength": 0.518713248970312,
|
||||||
|
"repelStrength": 10,
|
||||||
|
"linkStrength": 1,
|
||||||
|
"linkDistance": 250,
|
||||||
|
"scale": 1,
|
||||||
|
"close": false
|
||||||
|
}
|
||||||
Vendored
+254
@@ -0,0 +1,254 @@
|
|||||||
|
{
|
||||||
|
"main": {
|
||||||
|
"id": "baaef7f0d0c37abd",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "eaf4cbbe01345c1b",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "a64a4cd245fb22ec",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "markdown",
|
||||||
|
"state": {
|
||||||
|
"file": "履带车T10遥控器协议与操作说明.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-file",
|
||||||
|
"title": "履带车T10遥控器协议与操作说明"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ead3240747740b7d",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "markdown",
|
||||||
|
"state": {
|
||||||
|
"file": "ros/ros2/ros2_control/环境.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-file",
|
||||||
|
"title": "环境"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "115caef4c284a702",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "markdown",
|
||||||
|
"state": {
|
||||||
|
"file": "自建服务/Silverbullet部署指南.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-file",
|
||||||
|
"title": "Silverbullet部署指南"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"currentTab": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "vertical"
|
||||||
|
},
|
||||||
|
"left": {
|
||||||
|
"id": "b2e8a489e5c74a84",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "20cece044921a370",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "0a844a1838a0afc7",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "file-explorer",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"autoReveal": false,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-folder-closed",
|
||||||
|
"title": "文件列表"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7d36ad1a0e870585",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "search",
|
||||||
|
"state": {
|
||||||
|
"query": "",
|
||||||
|
"matchingCase": false,
|
||||||
|
"explainSearch": false,
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical"
|
||||||
|
},
|
||||||
|
"icon": "lucide-search",
|
||||||
|
"title": "搜索"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bda7c9d5257639de",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "bookmarks",
|
||||||
|
"state": {},
|
||||||
|
"icon": "lucide-bookmark",
|
||||||
|
"title": "书签"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"id": "151f2874cea23ad8",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "7c0d580356baa113",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "7cc083e6d69c3d69",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "backlink",
|
||||||
|
"state": {
|
||||||
|
"file": "大模型/DeepSeek V4 系列.md",
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": "",
|
||||||
|
"backlinkCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
},
|
||||||
|
"icon": "links-coming-in",
|
||||||
|
"title": "DeepSeek V4 系列 的反向链接列表"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "adaff8d134c6c028",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outgoing-link",
|
||||||
|
"state": {
|
||||||
|
"file": "履带车T10遥控器协议与操作说明.md",
|
||||||
|
"linksCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
},
|
||||||
|
"icon": "links-going-out",
|
||||||
|
"title": "履带车T10遥控器协议与操作说明 的出链列表"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2d6594801d830dfe",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "tag",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"useHierarchy": true,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-tags",
|
||||||
|
"title": "标签"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bb36402a7e978df7",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "all-properties",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-archive",
|
||||||
|
"title": "添加笔记属性"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d3338eaffa18cf65",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outline",
|
||||||
|
"state": {
|
||||||
|
"file": "履带车T10遥控器协议与操作说明.md",
|
||||||
|
"followCursor": false,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-list",
|
||||||
|
"title": "履带车T10遥控器协议与操作说明 的大纲"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300,
|
||||||
|
"collapsed": true
|
||||||
|
},
|
||||||
|
"left-ribbon": {
|
||||||
|
"hiddenItems": {
|
||||||
|
"switcher:打开快速切换": false,
|
||||||
|
"graph:查看关系图谱": false,
|
||||||
|
"canvas:新建白板": false,
|
||||||
|
"daily-notes:打开/创建今天的日记": false,
|
||||||
|
"templates:插入模板": false,
|
||||||
|
"command-palette:打开命令面板": false,
|
||||||
|
"bases:新建数据库": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": "115caef4c284a702",
|
||||||
|
"lastOpenFiles": [
|
||||||
|
"大模型/FFN 前馈网络详解.md",
|
||||||
|
"自建服务/Silverbullet部署指南.md",
|
||||||
|
"自建服务",
|
||||||
|
"技术趋势/AI编译器现状与前景.md",
|
||||||
|
"大模型/DeepSeek V4 系列.md",
|
||||||
|
"技术趋势",
|
||||||
|
"ros/ros2/ros2_control/环境.md",
|
||||||
|
"未命名 1.base",
|
||||||
|
"未命名.base",
|
||||||
|
"大模型/MoE 混合专家架构.md",
|
||||||
|
"大模型/Transformer 架构详解.md",
|
||||||
|
"大模型/MoE 混合专家架构.md.tmp.33168.91e110d04189",
|
||||||
|
"大模型/MoE 混合专家架构.md.tmp.33168.aec6279f2917",
|
||||||
|
"大模型/大模型架构基础.md",
|
||||||
|
"工作/机械臂分析.md",
|
||||||
|
"工作/履带车T10遥控器协议与操作说明.md",
|
||||||
|
"工作",
|
||||||
|
"大模型/多模态大模型.md",
|
||||||
|
"大模型架构基础.md",
|
||||||
|
"autoware_w7/w7.md",
|
||||||
|
"大模型",
|
||||||
|
"工作/nav2 优缺点.md",
|
||||||
|
"工作/VCU控制逻辑(v0.2).md",
|
||||||
|
"工作/VCU控制逻辑_精简版.md",
|
||||||
|
"ros/ros2/nav2/debug.md",
|
||||||
|
"VCU控制逻辑(v0.2).md.tmp.17548.1776933572846",
|
||||||
|
"ros/ros2/nav2/debug",
|
||||||
|
"工作/Pasted image 20260402112951.png",
|
||||||
|
"ros/ros2/nav2/nav2_bringup_gps_demo.md",
|
||||||
|
"工作/Pasted image 20260402112914.png",
|
||||||
|
"ros/ros2/nav2/nav2.md",
|
||||||
|
"ros/履带底盘机械臂.md",
|
||||||
|
"ros/ros2/安装配置/ros2_structure.md",
|
||||||
|
"ros/ros2/概念/基础概念.md"
|
||||||
|
]
|
||||||
|
}
|
||||||
Submodule
+1
Submodule AI_compiler added at 86ed9b3b1a
@@ -0,0 +1,233 @@
|
|||||||
|
# Autoware W7 启动概览
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
以下内容基于命令:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ros2 launch autoware_launch autoware.launch.xml \
|
||||||
|
|
||||||
|
sensor_model:=sample_sensor_kit \
|
||||||
|
|
||||||
|
vehicle_model:=sample_vehicle \
|
||||||
|
|
||||||
|
vehicle_id:=W7 \
|
||||||
|
|
||||||
|
map_path:=/media/nvidia/nvme0n1pnvme0n1p1/autoware_map/test_map_A4_and_PARK/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 模块关系(Mermaid)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
|
||||||
|
graph LR
|
||||||
|
|
||||||
|
subgraph SENSING["感知层 Sensing"]
|
||||||
|
|
||||||
|
SENSINGN(Pointcloud / Camera / Radar)
|
||||||
|
|
||||||
|
PCCTR[pointcloud_container]
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
subgraph MAPGRP["地图 Map"]
|
||||||
|
|
||||||
|
PC_MAP(Pointcloud Map)
|
||||||
|
|
||||||
|
LL_MAP(Lanelet2 Map)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
subgraph LOCAL["定位 Localization"]
|
||||||
|
|
||||||
|
LOCN(Localization)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
subgraph PER["感知 Perception"]
|
||||||
|
|
||||||
|
PERN(Detection / Tracking / TLR)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
subgraph PLAN["规划 Planning"]
|
||||||
|
|
||||||
|
PLANN(Mission / Behavior / Motion)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
subgraph CTRL["控制 Control"]
|
||||||
|
|
||||||
|
CTRLN(Trajectory Follower)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
subgraph VEH["车辆 Vehicle"]
|
||||||
|
|
||||||
|
VIF(Vehicle Interface)
|
||||||
|
|
||||||
|
RSP(robot_state_publisher)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RVIZ[RViz2]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SENSINGN -->|点云/图像| PERN
|
||||||
|
|
||||||
|
SENSINGN -->|点云| LOCN
|
||||||
|
|
||||||
|
PCCTR -->|聚合点云| PERN
|
||||||
|
|
||||||
|
PCCTR -->|聚合点云| LOCN
|
||||||
|
|
||||||
|
PC_MAP -->|点云地图| LOCN
|
||||||
|
|
||||||
|
LL_MAP -->|lanelet2| PLANN
|
||||||
|
|
||||||
|
LOCN -->|pose/tf| PLANN
|
||||||
|
|
||||||
|
PERN -->|detected_objects| PLANN
|
||||||
|
|
||||||
|
PLANN -->|trajectory| CTRLN
|
||||||
|
|
||||||
|
CTRLN -->|vehicle_cmd| VIF
|
||||||
|
|
||||||
|
VIF -->|状态| PLANN
|
||||||
|
|
||||||
|
RSP -->|tf| RVIZ
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 主要模块与说明
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Vehicle:车辆描述与接口(`robot_state_publisher`、`vehicle_interface`、`raw_vehicle_cmd_converter`)
|
||||||
|
|
||||||
|
- System:系统监控、诊断(health、diagnostics)
|
||||||
|
|
||||||
|
- Map:点云地图 (`pointcloud_map.pcd`) 与 Lanelet2 (`lanelet2_map.osm`) 加载
|
||||||
|
|
||||||
|
- Sensing:传感器驱动、预处理、`pointcloud_container`
|
||||||
|
|
||||||
|
- Localization:ND T / yabloc / eagleye / EKF 等定位组件,依赖点云与地图
|
||||||
|
|
||||||
|
- Perception:地面分割、检测、跟踪、交通灯识别、融合
|
||||||
|
|
||||||
|
- Planning:mission、behavior、motion(包含 diffusion_planner 可选)
|
||||||
|
|
||||||
|
- Control:轨迹跟踪(MPC/PID 等)并输出 `vehicle_cmd`
|
||||||
|
|
||||||
|
- API/Tools:Autoware API、RViz2 等
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 收集到的关键节点(从相关 launch 文件)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- `robot_state_publisher` (Vehicle)
|
||||||
|
|
||||||
|
- `raw_vehicle_cmd_converter` (Vehicle Interface)
|
||||||
|
|
||||||
|
- `map_hash_generator` (Map)
|
||||||
|
|
||||||
|
- `trajectory_relay`(topic_tools relay,将 `/planning/trajectory` 转发到 `/planning/scenario_planning/trajectory`)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Sensing / Sensor kit 示例节点:
|
||||||
|
|
||||||
|
- `tl_camera_info_relay`(topic_tools relay for camera)
|
||||||
|
|
||||||
|
- `tl_compressed_image_relay`(topic_tools relay)
|
||||||
|
|
||||||
|
- `imu_to_autoware_orientation`(GNSS/IMU 预处理)
|
||||||
|
|
||||||
|
- `imu_data_compat_relay`(topic_tools relay)
|
||||||
|
|
||||||
|
- `tag_serial_driver`(IMU 驱动)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Localization / eagleye 相关节点(部分):
|
||||||
|
|
||||||
|
- `gnss_converter_node`(eagleye_gnss_converter)
|
||||||
|
|
||||||
|
- `eagleye_output_twist_relay`(topic_tools relay)
|
||||||
|
|
||||||
|
- `twist_relay`, `tf_converted_imu`, `velocity_scale_factor_node`, `yaw_rate_offset_*`, `heading_*`, `position`, `smoothing`, `height`, `monitor`(eagleye_rt 包内多个辅助节点)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Perception 相关节点(示例):
|
||||||
|
|
||||||
|
- `simple_object_merger`(autoware_simple_object_merger)
|
||||||
|
|
||||||
|
- `empty_objects_publisher`(autoware_dummy_perception_publisher,用于仿真/占位)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Planning / Diffusion 示例节点:
|
||||||
|
|
||||||
|
- `velocity_smoother`(demo_nodes_cpp parameter_blackboard 用作示例)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Control 相关节点:
|
||||||
|
|
||||||
|
- `controller_node_exe`(autoware_smart_mpc_trajectory_follower 的 Python 接口)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Simulator / 工具节点(示例):
|
||||||
|
|
||||||
|
- `elevation_map_loader`, `autoware_vehicle_velocity_converter`, `autoware_scenario_simulator_v2_adapter_node`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
> 注:上面列举的是主要/代表性节点,Autoware 启动会包含大量子包内的节点(许多由组件的 `launch.xml` 或 `launch.py` 再次 include)。如需我逐个组件展开完整节点列表,我可以继续递归读取每个组件的 launch 目录并生成更详尽的清单。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
文件已保存到:
|
||||||
|
|
||||||
|
- 工作区(副本,可点击查看): `docs/autoware_w7/Autoware_W7_overview.md`
|
||||||
|
|
||||||
|
- 你的指定路径副本: `/media/nvidia/nvme0n1pnvme0n1p1/ylhan/autoware_w7/Autoware_W7_overview.md`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
如果需要,我可以:
|
||||||
|
|
||||||
|
- 生成更详细的每个子包启动节点清单并保存为文本或 CSV;
|
||||||
|
|
||||||
|
- 将 Mermaid 图另存为 SVG;
|
||||||
|
|
||||||
|
- 针对 `vehicle_interface.launch.xml`、`sensing.launch.xml` 等列出完整的 node 列表。
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"promptDelete": false
|
||||||
|
}
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
Vendored
+33
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"file-explorer": true,
|
||||||
|
"global-search": true,
|
||||||
|
"switcher": true,
|
||||||
|
"graph": true,
|
||||||
|
"backlink": true,
|
||||||
|
"canvas": true,
|
||||||
|
"outgoing-link": true,
|
||||||
|
"tag-pane": true,
|
||||||
|
"footnotes": false,
|
||||||
|
"properties": true,
|
||||||
|
"page-preview": true,
|
||||||
|
"daily-notes": true,
|
||||||
|
"templates": true,
|
||||||
|
"note-composer": true,
|
||||||
|
"command-palette": true,
|
||||||
|
"slash-command": false,
|
||||||
|
"editor-status": true,
|
||||||
|
"bookmarks": true,
|
||||||
|
"markdown-importer": false,
|
||||||
|
"zk-prefixer": false,
|
||||||
|
"random-note": false,
|
||||||
|
"outline": true,
|
||||||
|
"word-count": true,
|
||||||
|
"slides": false,
|
||||||
|
"audio-recorder": false,
|
||||||
|
"workspaces": false,
|
||||||
|
"file-recovery": true,
|
||||||
|
"publish": false,
|
||||||
|
"sync": true,
|
||||||
|
"bases": true,
|
||||||
|
"webviewer": false
|
||||||
|
}
|
||||||
Vendored
+30
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"collapse-filter": false,
|
||||||
|
"search": "",
|
||||||
|
"showTags": false,
|
||||||
|
"showAttachments": false,
|
||||||
|
"hideUnresolved": false,
|
||||||
|
"showOrphans": true,
|
||||||
|
"collapse-color-groups": false,
|
||||||
|
"colorGroups": [
|
||||||
|
{
|
||||||
|
"query": "tag:",
|
||||||
|
"color": {
|
||||||
|
"a": 1,
|
||||||
|
"rgb": 14048348
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"collapse-display": true,
|
||||||
|
"showArrow": false,
|
||||||
|
"textFadeMultiplier": 0,
|
||||||
|
"nodeSizeMultiplier": 1,
|
||||||
|
"lineSizeMultiplier": 1,
|
||||||
|
"collapse-forces": true,
|
||||||
|
"centerStrength": 0.518713248970312,
|
||||||
|
"repelStrength": 10,
|
||||||
|
"linkStrength": 1,
|
||||||
|
"linkDistance": 250,
|
||||||
|
"scale": 1,
|
||||||
|
"close": true
|
||||||
|
}
|
||||||
Vendored
+201
@@ -0,0 +1,201 @@
|
|||||||
|
{
|
||||||
|
"main": {
|
||||||
|
"id": "914c9e8d9774b62f",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "22be749e4ad854f0",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "0f14a7f3e342ee77",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "markdown",
|
||||||
|
"state": {
|
||||||
|
"file": "ros2/概念/基础概念.md",
|
||||||
|
"mode": "preview",
|
||||||
|
"source": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-file",
|
||||||
|
"title": "基础概念"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "vertical"
|
||||||
|
},
|
||||||
|
"left": {
|
||||||
|
"id": "3d550c51e4dc52dd",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "64ee6b66868da0e5",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "4a3332297ce1ac65",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "file-explorer",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"autoReveal": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-folder-closed",
|
||||||
|
"title": "文件列表"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "94dc470ccbf6e453",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "search",
|
||||||
|
"state": {
|
||||||
|
"query": "",
|
||||||
|
"matchingCase": false,
|
||||||
|
"explainSearch": false,
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical"
|
||||||
|
},
|
||||||
|
"icon": "lucide-search",
|
||||||
|
"title": "搜索"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a49ddb63b7b71d3d",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "bookmarks",
|
||||||
|
"state": {},
|
||||||
|
"icon": "lucide-bookmark",
|
||||||
|
"title": "书签"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"id": "94ee3ffae97277f1",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "30c22dd0ea555284",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "e08ac0b7a754e82a",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "backlink",
|
||||||
|
"state": {
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": "",
|
||||||
|
"backlinkCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
},
|
||||||
|
"icon": "links-coming-in",
|
||||||
|
"title": "反向链接"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c28b4721bbc7549d",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outgoing-link",
|
||||||
|
"state": {
|
||||||
|
"linksCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
},
|
||||||
|
"icon": "links-going-out",
|
||||||
|
"title": "出链"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "951c9abc2fe22169",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "tag",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"useHierarchy": true,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-tags",
|
||||||
|
"title": "标签"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ced613ec67772cc8",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "all-properties",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-archive",
|
||||||
|
"title": "添加笔记属性"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "31cad42ee1968b90",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outline",
|
||||||
|
"state": {
|
||||||
|
"followCursor": false,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-list",
|
||||||
|
"title": "大纲"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300,
|
||||||
|
"collapsed": true
|
||||||
|
},
|
||||||
|
"left-ribbon": {
|
||||||
|
"hiddenItems": {
|
||||||
|
"switcher:打开快速切换": false,
|
||||||
|
"graph:查看关系图谱": false,
|
||||||
|
"canvas:新建白板": false,
|
||||||
|
"daily-notes:打开/创建今天的日记": false,
|
||||||
|
"templates:插入模板": false,
|
||||||
|
"command-palette:打开命令面板": false,
|
||||||
|
"bases:新建数据库": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": "0f14a7f3e342ee77",
|
||||||
|
"lastOpenFiles": [
|
||||||
|
"ros2/概念/基础概念.md",
|
||||||
|
"ros2/安装配置/环境配置.md",
|
||||||
|
"ros2/概念",
|
||||||
|
"ros2/新建文件夹",
|
||||||
|
"未命名",
|
||||||
|
"ros2/安装配置",
|
||||||
|
"ros2/安装配置/代码更新_zh.md",
|
||||||
|
"未命名.md",
|
||||||
|
"ros2/安装配置/ros2_structure.md",
|
||||||
|
"ros2/安装配置/安装_zh.md",
|
||||||
|
"ros2/安装配置/安装.md",
|
||||||
|
"欢迎.md",
|
||||||
|
"创建链接.md",
|
||||||
|
"ros2",
|
||||||
|
"desktop.ini"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
``` bash
|
||||||
|
root@nvidia:~/ros2_ws# ros2 topic echo /goal_pose
|
||||||
|
header:
|
||||||
|
stamp:
|
||||||
|
sec: 1776912839
|
||||||
|
nanosec: 772353086
|
||||||
|
frame_id: map
|
||||||
|
pose:
|
||||||
|
position:
|
||||||
|
x: -0.2929971516132355
|
||||||
|
y: -28.93631362915039
|
||||||
|
z: 0.0
|
||||||
|
orientation:
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: -0.7140266359687852
|
||||||
|
w: 0.7001185350546718
|
||||||
|
---
|
||||||
|
header:
|
||||||
|
stamp:
|
||||||
|
sec: 1776912894
|
||||||
|
nanosec: 349057427
|
||||||
|
frame_id: map
|
||||||
|
pose:
|
||||||
|
position:
|
||||||
|
x: 1.0191293954849243
|
||||||
|
y: -23.940237045288086
|
||||||
|
z: 0.0
|
||||||
|
orientation:
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: -0.758253550259611
|
||||||
|
w: 0.6519597790651626
|
||||||
|
---
|
||||||
|
header:
|
||||||
|
stamp:
|
||||||
|
sec: 1776912930
|
||||||
|
nanosec: 59193832
|
||||||
|
frame_id: map
|
||||||
|
pose:
|
||||||
|
position:
|
||||||
|
x: -0.25821736454963684
|
||||||
|
y: -26.604511260986328
|
||||||
|
z: 0.0
|
||||||
|
orientation:
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: -0.7286561115363753
|
||||||
|
w: 0.6848797493872113
|
||||||
|
---
|
||||||
|
header:
|
||||||
|
stamp:
|
||||||
|
sec: 1776913007
|
||||||
|
nanosec: 811936088
|
||||||
|
frame_id: map
|
||||||
|
pose:
|
||||||
|
position:
|
||||||
|
x: -0.5403046607971191
|
||||||
|
y: -23.95861053466797
|
||||||
|
z: 0.0
|
||||||
|
orientation:
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: -0.7323575592769619
|
||||||
|
w: 0.6809202635917743
|
||||||
|
---
|
||||||
|
header:
|
||||||
|
stamp:
|
||||||
|
sec: 1776913105
|
||||||
|
nanosec: 601216801
|
||||||
|
frame_id: map
|
||||||
|
pose:
|
||||||
|
position:
|
||||||
|
x: -0.13717754185199738
|
||||||
|
y: -31.840221405029297
|
||||||
|
z: 0.0
|
||||||
|
orientation:
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: -0.6531641242066932
|
||||||
|
w: 0.7572163672618966
|
||||||
|
---
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
雷达同步问题
|
||||||
|
```
|
||||||
|
ros2_ws\src\rslidar_sdk\config\config.yaml
|
||||||
|
use_lidar_clock: false
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
⚠️ 警告1:No goal checker was specified in parameter 'current_goal_checker'. Server will use only plugin loaded
|
||||||
|
general_goal_checker
|
||||||
|
|
||||||
|
含义
|
||||||
|
|
||||||
|
这是配置缺失类警告,不影响功能,只是提示你没有显式指定当前使用的目标检查器,系统自动用了第一个加载的general_goal_check
|
||||||
|
er。
|
||||||
|
根因
|
||||||
|
|
||||||
|
ROS2 Humble及以上版本的Nav2新增了current_goal_checker强制配置项,你的配置里只定义了goal_checker插件,但没有指定当前使
|
||||||
|
用哪一个。
|
||||||
|
✅ 解决方案
|
||||||
|
|
||||||
|
在controller_server的ros__parameters下添加一行即可:
|
||||||
|
controller_server:
|
||||||
|
ros__parameters:
|
||||||
|
current_goal_checker: "general_goal_checker" # 新增这行
|
||||||
|
controller_frequency: 20.0
|
||||||
|
# ... 其他原有配置
|
||||||
|
|
||||||
|
---
|
||||||
|
⚠️ 警告2:Behavior Tree tick rate 100.00 was exceeded!
|
||||||
|
|
||||||
|
含义
|
||||||
|
|
||||||
|
这是性能类警告,行为树默认tick频率是100Hz(每10ms执行一次),现在单次tick执行时间超过了10ms,导致频率不达标。
|
||||||
|
根因
|
||||||
|
|
||||||
|
行为树中的计算密集型节点执行太慢,90%的情况是MPPI控制器计算耗时过长,小概率是系统CPU负载过高、规划器卡顿等。
|
||||||
|
✅ 排查&解决方案
|
||||||
|
|
||||||
|
1. 先看CPU占用:top 看controller_server进程的CPU占比,如果超过100%就是计算量太大
|
||||||
|
2. 优先优化MPPI参数(你的当前配置计算量过高),后面警告3会详细说
|
||||||
|
3. 实在优化不了可以调大BT的tick间隔,在bt_navigator下加:
|
||||||
|
bt_navigator:
|
||||||
|
ros__parameters:
|
||||||
|
bt_loop_duration: 20 # 从10ms改成20ms,频率降到50Hz,不推荐,优先优化控制器
|
||||||
|
|
||||||
|
---
|
||||||
|
⚠️ 警告3:Control loop missed its desired rate of 20.0000Hz
|
||||||
|
|
||||||
|
含义
|
||||||
|
|
||||||
|
这是核心性能警告,控制器要求20Hz的控制频率(每50ms输出一次速度指令),现在单次循环执行超过了50ms,频率不达标。
|
||||||
|
⚠️ 这个问题必须优先解决:控制频率低于15Hz会导致MPPI控制不稳定,甚至出现急刹、撞障碍物的情况。
|
||||||
|
根因
|
||||||
|
|
||||||
|
你的MPPI配置计算量过大,两个核心参数超标:
|
||||||
|
FollowPath:
|
||||||
|
batch_size: 2000 # 单次迭代采样2000条轨迹,计算量极大
|
||||||
|
time_steps: 56 # 每条轨迹预测56步(0.05*56=2.8秒预测时长)
|
||||||
|
- 2000的batch_size在Jetson NX级别的嵌入式平台单次计算就要60-80ms,肯定达不到50ms的要求
|
||||||
|
- 额外加重负载的配置:local costmap的obstacle_max_range: 20.0,local
|
||||||
|
costmap本身只有6m×6m,处理20米内的点云完全是浪费CPU
|
||||||
|
✅ 解决方案(按优先级)
|
||||||
|
|
||||||
|
1. 调小MPPI计算量(优先保证控制频率达标):
|
||||||
|
FollowPath:
|
||||||
|
batch_size: 1000 # 降到800-1200,轨迹采样数减半,性能提升一倍,效果下降不明显
|
||||||
|
time_steps: 40 # 降到32-40,预测时长2秒足够,履带车速度慢不需要太长预测
|
||||||
|
2. 缩小local costmap障碍物检测范围:
|
||||||
|
# local_costmap的voxel_layer下的scan配置
|
||||||
|
obstacle_max_range: 10.0 # 从20米改成10米,足够覆盖6m的local costmap范围
|
||||||
|
3. 验证效果:改完后用ros2 topic hz /cmd_vel_nav看频率,稳定在18Hz以上就算合格
|
||||||
|
|
||||||
|
---
|
||||||
|
❌ 错误1:Failed to create a plan from potential when a legal potential was found. This shouldn't happen.
|
||||||
|
|
||||||
|
含义
|
||||||
|
|
||||||
|
这是Navfn规划器内部错误:规划器已经算出了从起点到终点的势场(理论上存在可行路径),但实际提取路径的时候失败了。
|
||||||
|
根因
|
||||||
|
|
||||||
|
结合你的配置,最可能的几个原因:
|
||||||
|
4. 可行通道太窄:你的膨胀半径是1.8m,车身本身宽1.8m,通道宽度必须大于3.6m才能通过,如果路径上有窄于这个宽度的通道,膨
|
||||||
|
胀后就没有可行空间了
|
||||||
|
5. 起点/终点落在膨胀区内:虽然势场是通的,但膨胀后的代价太高,路径提取的时候找不到合法的起点/终点
|
||||||
|
6. 膨胀半径过大:1.8m的膨胀半径刚好是车身宽度,没有冗余,稍微有点障碍物就会把通道堵死
|
||||||
|
7. 全局costmap噪点过多:点云误检的障碍物挡住了路径
|
||||||
|
✅ 排查&解决方案
|
||||||
|
|
||||||
|
8. 排查路径情况:规划失败时,在rviz上看起点到终点的通道宽度,是不是小于3.6m
|
||||||
|
9. 优化膨胀半径(如果通道普遍较窄):
|
||||||
|
# 全局和局部costmap的inflation_radius都可以降到1.5m(只要大于车身最大半长1.2m就满足SMAC优化要求)
|
||||||
|
inflation_radius: 1.5
|
||||||
|
10. 优化Navfn参数:
|
||||||
|
GridBased:
|
||||||
|
tolerance: 1.0 # 从0.5米改成1.0米,允许终点有更大的容忍范围
|
||||||
|
11. 终极方案:换规划器:如果经常走窄通道,把Navfn换成nav2_smac_planner/SmacPlanner,对窄通道的支持好很多
|
||||||
|
12. 检查全局costmap噪点:如果有很多误检的小障碍物,调大mark_threshold过滤噪点
|
||||||
|
|
||||||
|
---
|
||||||
|
❌ 错误2:Failed to get result for follow_path in node halt!
|
||||||
|
|
||||||
|
含义
|
||||||
|
|
||||||
|
这是次生错误,不影响功能,只是日志提示:行为树在终止(halt)的时候,尝试获取follow_path节点的执行结果,但结果不存在。
|
||||||
|
根因
|
||||||
|
|
||||||
|
完全是前面的规划失败导致的连锁反应:规划失败后整个导航任务提前终止,follow_path节点还没来得及产生结果就被强制停止了。
|
||||||
|
✅ 解决方案
|
||||||
|
|
||||||
|
解决前面的规划失败问题后,这个错误会自动消失,不需要单独处理。
|
||||||
|
|
||||||
|
---
|
||||||
|
🎯 解决优先级建议
|
||||||
|
|
||||||
|
13. 【最高优先级】先解决控制循环频率不够的问题,直接影响导航安全性
|
||||||
|
14. 【次高优先级】解决规划失败的问题,影响导航可用性
|
||||||
|
15. 【低优先级】解决剩下的配置类警告,不影响功能只是优化日志
|
||||||
|
|
||||||
|
额外优化建议
|
||||||
|
|
||||||
|
你现在的voxel层mark_threshold: 10有点太高了,需要10个点才能标记障碍物,容易漏检小障碍物,建议调到3-5更合适:
|
||||||
|
voxel_layer:
|
||||||
|
mark_threshold: 3 # 从10改成3,平衡噪点过滤和小障碍物检测
|
||||||
|
```
|
||||||
@@ -0,0 +1,356 @@
|
|||||||
|
# Navigation2 详解:nav2_bringup 与 nav2_gps_waypoint_follower_demo
|
||||||
|
|
||||||
|
## 1. Navigation2 整体介绍
|
||||||
|
Navigation2(简称Nav2)是ROS2生态中最成熟的开源导航框架,是ROS1 Navigation Stack的官方继任者,专为移动机器人自主导航设计。
|
||||||
|
|
||||||
|
### 1.1 核心功能
|
||||||
|
- **定位**:支持AMCL、SLAM(Cartographer、SLAM Toolbox等)、GPS/RTK等多源定位
|
||||||
|
- **全局路径规划**:支持A*、Dijkstra、NavFn等多种规划算法
|
||||||
|
- **局部路径跟踪**:支持DWA、TEB、MPPI、Pure Pursuit等跟踪算法
|
||||||
|
- **避障与行为树**:通过行为树实现复杂导航逻辑,支持动态障碍物规避
|
||||||
|
- **重规划与恢复行为**:导航失败时自动执行恢复策略(旋转、回退、清图等)
|
||||||
|
- **多机器人支持**:支持命名空间隔离的多机器人导航
|
||||||
|
|
||||||
|
### 1.2 整体架构
|
||||||
|
Nav2采用模块化插件式设计,核心模块包括:
|
||||||
|
```
|
||||||
|
├── 感知层
|
||||||
|
│ ├── 传感器数据处理(LiDAR、Camera、IMU、GPS等)
|
||||||
|
│ └── 障碍物检测/语义分割
|
||||||
|
├── 定位层
|
||||||
|
│ ├── AMCL(蒙特卡洛定位)
|
||||||
|
│ ├── SLAM 建图
|
||||||
|
│ └── 多传感器融合定位
|
||||||
|
├── 地图层
|
||||||
|
│ ├── 代价地图(全局/局部)
|
||||||
|
│ ├── 图层插件(静态层、障碍层、膨胀层、社会层等)
|
||||||
|
├── 规划层
|
||||||
|
│ ├── 全局路径规划器
|
||||||
|
│ └── 平滑器
|
||||||
|
├── 控制层
|
||||||
|
│ ├── 局部路径规划器
|
||||||
|
│ └── 轨迹跟踪控制器
|
||||||
|
├── 行为决策层
|
||||||
|
│ ├── 行为树执行器
|
||||||
|
│ └── 恢复行为管理器
|
||||||
|
└── 接口层
|
||||||
|
├── RViz 可视化
|
||||||
|
├── Action/Topic API
|
||||||
|
└── 配置参数系统
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. nav2_bringup 包详解
|
||||||
|
nav2_bringup是Nav2的官方启动集成包,提供了开箱即用的启动文件、配置模板和参数集合,是快速部署Nav2系统的入口。
|
||||||
|
|
||||||
|
### 2.1 代码结构
|
||||||
|
```
|
||||||
|
nav2_bringup/
|
||||||
|
├── bringup/ # 启动相关核心目录
|
||||||
|
│ ├── launch/ # 启动文件集合
|
||||||
|
│ │ ├── bringup_launch.py # 主启动文件,集成所有导航模块
|
||||||
|
│ │ ├── localization_launch.py # 单独启动定位模块(AMCL/SLAM)
|
||||||
|
│ │ ├── navigation_launch.py # 单独启动导航模块(规划/控制/行为树)
|
||||||
|
│ │ ├── rviz_launch.py # 启动RViz可视化
|
||||||
|
│ │ ├── slam_launch.py # 启动SLAM建图
|
||||||
|
│ │ └── urdf_launch.py # 加载机器人URDF模型
|
||||||
|
│ ├── params/ # 参数配置文件目录
|
||||||
|
│ │ ├── nav2_params.yaml # 导航全模块默认参数
|
||||||
|
│ │ ├── nav2_params_no_odom.yaml # 无里程计场景参数
|
||||||
|
│ │ ├── nav2_slam_params.yaml # SLAM模式参数
|
||||||
|
│ │ └── robot_localization/ # 传感器融合参数模板
|
||||||
|
│ └── rviz/ # RViz配置文件
|
||||||
|
│ └── nav2_default_view.rviz # Nav2默认RViz配置
|
||||||
|
├── docker/ # Docker部署相关文件
|
||||||
|
├── scripts/ # 辅助脚本
|
||||||
|
├── CMakeLists.txt
|
||||||
|
├── package.xml
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 核心启动文件说明
|
||||||
|
|
||||||
|
#### 2.2.1 bringup_launch.py
|
||||||
|
这是最常用的一站式启动文件,集成了完整的导航流程,支持参数配置:
|
||||||
|
```python
|
||||||
|
# 关键参数
|
||||||
|
'namespace': '', # 多机器人命名空间
|
||||||
|
'use_sim_time': False, # 是否使用仿真时间
|
||||||
|
'rviz_config_file': '', # RViz配置文件路径
|
||||||
|
'params_file': '', # 导航参数文件路径
|
||||||
|
'autostart': True, # 启动后自动激活导航栈
|
||||||
|
'use_composition': True, # 使用组件化节点(减少进程数,提高性能)
|
||||||
|
'use_respawn': False, # 节点崩溃时自动重启
|
||||||
|
'map': '', # 静态地图文件路径(.yaml/.pgm)
|
||||||
|
'slam': False, # 是否启用SLAM模式
|
||||||
|
'localization_type': 'amcl' # 定位方式:amcl/slam_toolbox等
|
||||||
|
```
|
||||||
|
启动示例:
|
||||||
|
```bash
|
||||||
|
# 仿真环境启动导航
|
||||||
|
ros2 launch nav2_bringup bringup_launch.py use_sim_time:=True map:=/path/to/map.yaml
|
||||||
|
|
||||||
|
# 真机环境启用SLAM建图
|
||||||
|
ros2 launch nav2_bringup bringup_launch.py slam:=True params_file:=/path/to/my_params.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2.2 localization_launch.py
|
||||||
|
单独启动定位模块,适合只需要定位不需要完整导航的场景:
|
||||||
|
```bash
|
||||||
|
# 仅启动AMCL定位
|
||||||
|
ros2 launch nav2_bringup localization_launch.py map:=/path/to/map.yaml use_sim_time:=True
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2.3 navigation_launch.py
|
||||||
|
单独启动导航模块(规划/控制/行为树),适合定位已由其他系统提供的场景:
|
||||||
|
```bash
|
||||||
|
# 仅启动导航模块,使用已有的定位信息
|
||||||
|
ros2 launch nav2_bringup navigation_launch.py params_file:=/path/to/my_params.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 配置文件详解
|
||||||
|
nav2_params.yaml是核心参数配置文件,采用分层结构,每个模块单独配置:
|
||||||
|
```yaml
|
||||||
|
amcl:
|
||||||
|
ros__parameters:
|
||||||
|
base_frame_id: "base_footprint" # 机器人基坐标系
|
||||||
|
global_frame_id: "map" # 全局坐标系
|
||||||
|
odom_frame_id: "odom" # 里程计坐标系
|
||||||
|
max_particles: 2000 # 最大粒子数
|
||||||
|
min_particles: 500 # 最小粒子数
|
||||||
|
update_min_a: 0.2 # 角度变化超过0.2rad时更新
|
||||||
|
update_min_d: 0.25 # 位移超过0.25m时更新
|
||||||
|
|
||||||
|
bt_navigator:
|
||||||
|
ros__parameters:
|
||||||
|
use_sim_time: False
|
||||||
|
bt_xml_filename: "navigate_w_replanning_and_recovery.xml" # 行为树文件
|
||||||
|
|
||||||
|
global_costmap:
|
||||||
|
global_costmap:
|
||||||
|
ros__parameters:
|
||||||
|
update_frequency: 1.0
|
||||||
|
publish_frequency: 1.0
|
||||||
|
global_frame: map
|
||||||
|
robot_base_frame: base_footprint
|
||||||
|
resolution: 0.05
|
||||||
|
plugins:
|
||||||
|
- {name: static_layer, type: "costmap_2d::StaticLayer"}
|
||||||
|
- {name: obstacle_layer, type: "costmap_2d::ObstacleLayer"}
|
||||||
|
- {name: inflation_layer, type: "costmap_2d::InflationLayer"}
|
||||||
|
|
||||||
|
local_costmap:
|
||||||
|
local_costmap:
|
||||||
|
ros__parameters:
|
||||||
|
update_frequency: 5.0
|
||||||
|
publish_frequency: 2.0
|
||||||
|
global_frame: odom
|
||||||
|
robot_base_frame: base_footprint
|
||||||
|
width: 3
|
||||||
|
height: 3
|
||||||
|
resolution: 0.05
|
||||||
|
rolling_window: true # 局部代价地图随机器人移动
|
||||||
|
|
||||||
|
planner_server:
|
||||||
|
ros__parameters:
|
||||||
|
expected_planner_frequency: 1.0
|
||||||
|
planner_plugins: ["GridBased"]
|
||||||
|
GridBased:
|
||||||
|
plugin: "nav2_navfn_planner/NavfnPlanner" # 默认使用NavFn规划器
|
||||||
|
use_astar: true # 启用A*算法
|
||||||
|
|
||||||
|
controller_server:
|
||||||
|
ros__parameters:
|
||||||
|
controller_frequency: 20.0
|
||||||
|
min_x_velocity_threshold: 0.001
|
||||||
|
min_y_velocity_threshold: 0.5
|
||||||
|
controller_plugins: ["FollowPath"]
|
||||||
|
FollowPath:
|
||||||
|
plugin: "nav2_regulated_pure_pursuit_controller/RegulatedPurePursuitController" # 默认使用Pure Pursuit控制器
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4 最佳实践
|
||||||
|
1. **不要直接修改默认参数文件**:将nav2_params.yaml复制到自己的工作空间进行修改,通过`params_file`参数传入
|
||||||
|
2. **组件化启动**:默认启用`use_composition:=True`可以显著减少内存占用和通信开销
|
||||||
|
3. **分层配置**:将通用参数和机器人特定参数分开存放,便于维护
|
||||||
|
4. **仿真与真机分离**:使用`use_sim_time`参数区分仿真和真机环境,分别配置不同的参数值
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. nav2_gps_waypoint_follower_demo 详解
|
||||||
|
这是Nav2官方提供的室外导航示例,演示了如何结合GPS/RTK定位实现全局航点跟随功能,适用于无人车、巡检机器人等室外场景。
|
||||||
|
|
||||||
|
### 3.1 代码结构
|
||||||
|
该包位于navigation2_tutorials仓库中,结构如下:
|
||||||
|
```
|
||||||
|
nav2_gps_waypoint_follower_demo/
|
||||||
|
├── bringup/
|
||||||
|
│ ├── launch/
|
||||||
|
│ │ ├── gps_waypoint_follower_launch.py # Demo主启动文件
|
||||||
|
│ │ ├── rviz.launch.py # RViz启动
|
||||||
|
│ │ └── dual_ekf.launch.py # 双EKF传感器融合启动
|
||||||
|
│ ├── params/
|
||||||
|
│ │ ├── dual_ekf.yaml # 传感器融合参数
|
||||||
|
│ │ ├── nav2_params.yaml # 导航参数(适配GPS场景)
|
||||||
|
│ │ └── waypoint_follower_params.yaml # 航点跟随器参数
|
||||||
|
│ ├── rviz/
|
||||||
|
│ │ └── gps_waypoint.rviz # GPS导航专用RViz配置
|
||||||
|
│ └── worlds/
|
||||||
|
│ └── gps_world.world # 仿真世界文件(含GPS插件)
|
||||||
|
├── config/
|
||||||
|
│ └── sample_waypoints.yaml # 示例航点配置文件
|
||||||
|
├── src/
|
||||||
|
│ └── gps_waypoint_logger.cpp # 航点到达日志节点(可选)
|
||||||
|
├── CMakeLists.txt
|
||||||
|
├── package.xml
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 核心组件说明
|
||||||
|
GPS航点跟随系统主要由三个核心部分组成:
|
||||||
|
1. **传感器融合模块**(robot_localization):融合GPS、IMU、轮式里程计数据,输出全局定位
|
||||||
|
2. **导航栈模块**:基于全局定位进行路径规划和跟踪
|
||||||
|
3. **航点跟随器**:按照预设的GPS航点序列依次导航
|
||||||
|
|
||||||
|
#### 3.2.1 双EKF传感器融合
|
||||||
|
demo使用两个扩展卡尔曼滤波器(EKF)实现多传感器融合:
|
||||||
|
```yaml
|
||||||
|
# dual_ekf.yaml 核心配置
|
||||||
|
ekf_filter_node_odom:
|
||||||
|
ros__parameters:
|
||||||
|
frequency: 30.0
|
||||||
|
sensor_timeout: 0.1
|
||||||
|
two_d_mode: true
|
||||||
|
publish_tf: true
|
||||||
|
odom_frame: odom
|
||||||
|
base_link_frame: base_link
|
||||||
|
world_frame: odom
|
||||||
|
# 融合IMU和轮式里程计,输出odom->base_link变换
|
||||||
|
imu0: /imu/data
|
||||||
|
odom0: /wheel/odometry
|
||||||
|
|
||||||
|
ekf_filter_node_map:
|
||||||
|
ros__parameters:
|
||||||
|
frequency: 30.0
|
||||||
|
sensor_timeout: 0.1
|
||||||
|
two_d_mode: true
|
||||||
|
publish_tf: true
|
||||||
|
odom_frame: odom
|
||||||
|
base_link_frame: base_link
|
||||||
|
world_frame: map
|
||||||
|
# 融合GPS数据,输出map->odom变换
|
||||||
|
odom1: /gps/fix
|
||||||
|
odom1_differential: false
|
||||||
|
odom1_relative: false
|
||||||
|
```
|
||||||
|
- 第一个EKF(odom系):融合IMU和轮式里程计,提供短时间内高精度的局部定位,无漂移
|
||||||
|
- 第二个EKF(map系):融合GPS数据,提供全局绝对定位,修正长期漂移
|
||||||
|
|
||||||
|
#### 3.2.2 导航参数适配(nav2_params.yaml)
|
||||||
|
GPS导航场景需要对默认导航参数进行调整:
|
||||||
|
```yaml
|
||||||
|
amcl:
|
||||||
|
ros__parameters:
|
||||||
|
# GPS导航场景下禁用AMCL,使用EKF融合提供定位
|
||||||
|
use_sim_time: False
|
||||||
|
# AMCL相关参数全部注释或删除
|
||||||
|
|
||||||
|
global_costmap:
|
||||||
|
global_costmap:
|
||||||
|
ros__parameters:
|
||||||
|
# GPS模式下不使用静态地图,使用动态生成的代价地图
|
||||||
|
plugins:
|
||||||
|
- {name: obstacle_layer, type: "costmap_2d::ObstacleLayer"}
|
||||||
|
- {name: inflation_layer, type: "costmap_2d::InflationLayer"}
|
||||||
|
# 代价地图大小足够覆盖所有航点范围
|
||||||
|
width: 1000
|
||||||
|
height: 1000
|
||||||
|
resolution: 0.1
|
||||||
|
rolling_window: false # 全局代价地图固定,不随机器人移动
|
||||||
|
origin_x: -500
|
||||||
|
origin_y: -500
|
||||||
|
|
||||||
|
planner_server:
|
||||||
|
ros__parameters:
|
||||||
|
# 使用适合长距离规划的算法
|
||||||
|
GridBased:
|
||||||
|
plugin: "nav2_navfn_planner/NavfnPlanner"
|
||||||
|
use_astar: true
|
||||||
|
allow_unknown: true # 允许在未知区域规划路径
|
||||||
|
|
||||||
|
controller_server:
|
||||||
|
ros__parameters:
|
||||||
|
# 使用适合高速行驶的控制器
|
||||||
|
FollowPath:
|
||||||
|
plugin: "nav2_mppi_controller/MPPIController" # 或者TEB控制器
|
||||||
|
max_vel_x: 5.0 # 室外场景允许更高速度
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2.3 航点跟随器配置
|
||||||
|
```yaml
|
||||||
|
# waypoint_follower_params.yaml
|
||||||
|
waypoint_follower:
|
||||||
|
ros__parameters:
|
||||||
|
loop: False # 航点是否循环执行
|
||||||
|
waypoint_timeout: 300.0 # 单个航点导航超时时间(秒)
|
||||||
|
stop_on_failure: True # 某个航点导航失败时停止
|
||||||
|
action_server_name: "follow_waypoints"
|
||||||
|
# 航点到达阈值
|
||||||
|
goal_tolerance_x: 0.5
|
||||||
|
goal_tolerance_y: 0.5
|
||||||
|
goal_tolerance_yaw: 0.25
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 航点配置
|
||||||
|
sample_waypoints.yaml是预设的GPS航点文件,格式如下:
|
||||||
|
```yaml
|
||||||
|
waypoints:
|
||||||
|
- latitude: 37.7749
|
||||||
|
longitude: -122.4194
|
||||||
|
yaw: 0.0 # 到达后的朝向(弧度)
|
||||||
|
frame_id: "wgs84" # GPS坐标系
|
||||||
|
- latitude: 37.7750
|
||||||
|
longitude: -122.4195
|
||||||
|
yaw: 1.57
|
||||||
|
frame_id: "wgs84"
|
||||||
|
- latitude: 37.7751
|
||||||
|
longitude: -122.4196
|
||||||
|
yaw: 3.14
|
||||||
|
frame_id: "wgs84"
|
||||||
|
```
|
||||||
|
航点使用WGS84坐标系(标准GPS坐标),也可以配置为UTM坐标系。
|
||||||
|
|
||||||
|
### 3.4 运行流程
|
||||||
|
1. **启动仿真/真机驱动**:加载机器人模型、传感器驱动、GPS插件
|
||||||
|
2. **启动传感器融合**:`ros2 launch nav2_gps_waypoint_follower_demo dual_ekf.launch.py`
|
||||||
|
3. **启动导航栈**:`ros2 launch nav2_gps_waypoint_follower_demo gps_waypoint_follower_launch.py`
|
||||||
|
4. **加载航点**:`ros2 run nav2_waypoint_follower waypoint_follower --ros-args -p waypoint_file:=/path/to/sample_waypoints.yaml`
|
||||||
|
5. **启动航点跟随**:通过RViz发送FollowWaypoints action请求,或者用命令行启动:
|
||||||
|
```bash
|
||||||
|
ros2 action send_goal /follow_waypoints nav2_msgs/action/FollowWaypoints "{waypoints: []}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.5 关键注意事项
|
||||||
|
1. **GPS信号质量**:室外场景下需要确保GPS信号良好,RTK定位能达到厘米级精度,普通GPS只有米级精度,可能影响导航效果
|
||||||
|
2. **坐标系转换**:需要正确配置WGS84到UTM再到机器人本地坐标系的转换参数
|
||||||
|
3. **航点规划**:航点之间需要有可行路径,避免有障碍物阻挡
|
||||||
|
4. **动态障碍物**:室外场景需要配置合适的障碍物检测和避障参数
|
||||||
|
5. **TF树检查**:确保`map->odom->base_link`的TF变换正确发布,这是GPS导航的基础
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 常用调试技巧
|
||||||
|
1. **查看TF树**:`ros2 run tf2_tools view_frames`,检查坐标系变换是否正确
|
||||||
|
2. **检查定位质量**:`ros2 topic echo /gps/fix` 查看GPS信号质量,`ros2 topic echo /odometry/filtered` 查看融合后的定位输出
|
||||||
|
3. **可视化调试**:在RViz中显示全局/局部代价地图、规划路径、当前目标点等信息
|
||||||
|
4. **参数动态调整**:使用`ros2 param`命令动态修改参数,无需重启导航栈
|
||||||
|
5. **日志分析**:查看`/tf`, `/cmd_vel`, `/plan`等话题的输出,排查导航失败原因
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参考资料
|
||||||
|
- [Navigation2 官方文档](https://navigation.ros.org/)
|
||||||
|
- [nav2_bringup 源码](https://github.com/ros-navigation/navigation2/tree/main/nav2_bringup)
|
||||||
|
- [GPS Waypoint Follower 教程](https://navigation.ros.org/tutorials/docs/gps_waypoint_follower.html)
|
||||||
|
- [navigation2_tutorials 仓库](https://github.com/ros-navigation/navigation2_tutorials)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#### 拉取镜像
|
||||||
|
```bash
|
||||||
|
docker pull arm64v8/ros:humble
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 启动脚本
|
||||||
|
```code
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 允许 Docker 访问 X 服务器(用于 GUI)
|
||||||
|
xhost +local:docker
|
||||||
|
|
||||||
|
# 容器名称
|
||||||
|
CONTAINER_NAME="ylhan_ros2_humble"
|
||||||
|
|
||||||
|
# 检查容器是否存在
|
||||||
|
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||||
|
# 容器存在
|
||||||
|
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||||
|
# 容器正在运行,直接进入
|
||||||
|
echo "容器 ${CONTAINER_NAME} 正在运行,进入容器..."
|
||||||
|
docker exec -it ${CONTAINER_NAME} bash
|
||||||
|
else
|
||||||
|
# 容器已存在但未运行,启动并进入
|
||||||
|
echo "容器 ${CONTAINER_NAME} 已存在但未运行,启动容器..."
|
||||||
|
docker start -i ${CONTAINER_NAME}
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# 容器不存在,创建并运行新容器
|
||||||
|
echo "容器 ${CONTAINER_NAME} 不存在,创建新容器..."
|
||||||
|
docker run -it --rm \
|
||||||
|
--name ${CONTAINER_NAME} \
|
||||||
|
--network host \
|
||||||
|
--privileged \
|
||||||
|
-e DISPLAY=$DISPLAY \
|
||||||
|
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
|
||||||
|
-v /home/ylhan/ros2_ws:/root/ros2_ws \
|
||||||
|
-v /dev:/dev \
|
||||||
|
arm64v8/ros:humble \
|
||||||
|
bash
|
||||||
|
fi
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 环境设置
|
||||||
|
宿主机
|
||||||
|
```bash
|
||||||
|
echo $DISPLAY
|
||||||
|
```
|
||||||
|
假设输出为nvidia:13.0,在docker内:
|
||||||
|
```bash
|
||||||
|
export DISPLAY=nvidia:13.0
|
||||||
|
```
|
||||||
|
复制宿主机home目录下.Xauthority文件到docker中home目录下,使用xeyes测试
|
||||||
|
|
||||||
|
ros2 docker隔离
|
||||||
|
```bash
|
||||||
|
export ROS_DOMAIN_ID=79 #设置独立的DOMAIN_ID
|
||||||
|
```
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
# ROS2 代码结构图
|
||||||
|
|
||||||
|
## ROS2 工作区目录结构
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
Workspace[ROS2 工作区] --> src[src/ 源代码目录]
|
||||||
|
Workspace --> build[build/ 构建目录]
|
||||||
|
Workspace --> install[install/ 安装目录]
|
||||||
|
Workspace --> log[log/ 日志目录]
|
||||||
|
|
||||||
|
src --> Package1[包1]
|
||||||
|
src --> Package2[包2]
|
||||||
|
src --> PackageN[...]
|
||||||
|
|
||||||
|
Package1 --> P1_CMake[CMakeLists.txt]
|
||||||
|
Package1 --> P1_PackageXML[package.xml]
|
||||||
|
Package1 --> P1_src[src/ 源代码]
|
||||||
|
Package1 --> P1_include[include/ 头文件]
|
||||||
|
Package1 --> P1_msgs[msg/ 消息定义]
|
||||||
|
Package1 --> P1_srvs[srv/ 服务定义]
|
||||||
|
Package1 --> P1_actions[action/ 动作定义]
|
||||||
|
```
|
||||||
|
|
||||||
|
## ROS2 软件架构
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
App[应用程序] --> ClientLibs[客户端库]
|
||||||
|
|
||||||
|
subgraph ClientLibs [客户端库]
|
||||||
|
direction LR
|
||||||
|
RCLcpp[C++ 客户端库 rclcpp]
|
||||||
|
RCLpy[Python 客户端库 rclpy]
|
||||||
|
RCL[C 客户端库 rcl]
|
||||||
|
end
|
||||||
|
|
||||||
|
ClientLibs --> RCL_Interface[RCL 接口]
|
||||||
|
RCL_Interface --> RMW[ROS 中间件接口 RMW]
|
||||||
|
|
||||||
|
subgraph DDS_Implementations [DDS 实现]
|
||||||
|
direction LR
|
||||||
|
FastDDS[Fast DDS]
|
||||||
|
CycloneDDS[Cyclone DDS]
|
||||||
|
RTI_Connext[RTI Connext]
|
||||||
|
OpenSplice[OpenSplice]
|
||||||
|
end
|
||||||
|
|
||||||
|
RMW --> DDS_Implementations
|
||||||
|
DDS_Implementations --> Network[网络通信]
|
||||||
|
```
|
||||||
|
|
||||||
|
## ROS2 核心包依赖关系
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
ROS2_Core[ROS2 核心] --> ament_core[ament_core<br/>构建系统]
|
||||||
|
ROS2_Core --> rcl[rcl<br/>C语言客户端库]
|
||||||
|
ROS2_Core --> rclcpp[rclcpp<br/>C++客户端库]
|
||||||
|
ROS2_Core --> rclpy[rclpy<br/>Python客户端库]
|
||||||
|
|
||||||
|
rcl --> rmw[rmw<br/>中间件接口]
|
||||||
|
rclcpp --> rcl
|
||||||
|
rclpy --> rcl
|
||||||
|
|
||||||
|
rmw --> rmw_implementation[rmw_implementation<br/>中间件实现]
|
||||||
|
rmw_implementation --> DDS[DDS 实现]
|
||||||
|
|
||||||
|
ROS2_Tools[ROS2 工具] --> ros2cli[ros2cli<br/>命令行工具]
|
||||||
|
ROS2_Tools --> colcon[colcon<br/>构建工具]
|
||||||
|
ROS2_Tools --> launch_ros[launch_ros<br/>启动系统]
|
||||||
|
```
|
||||||
|
|
||||||
|
## ROS2 节点通信模型
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
NodeA[ROS2 节点 A] -->|发布话题| Topic1[话题 /topic1]
|
||||||
|
NodeB[ROS2 节点 B] -->|订阅话题| Topic1
|
||||||
|
|
||||||
|
NodeC[ROS2 节点 C] -->|请求服务| Service1[服务 /service1]
|
||||||
|
NodeD[ROS2 节点 D] -->|提供服务| Service1
|
||||||
|
|
||||||
|
NodeE[ROS2 节点 E] -->|发送目标| Action1[动作 /action1]
|
||||||
|
NodeF[ROS2 节点 F] -->|执行动作| Action1
|
||||||
|
NodeF -->|反馈| NodeE
|
||||||
|
NodeF -->|结果| NodeE
|
||||||
|
```
|
||||||
|
|
||||||
|
## 说明
|
||||||
|
|
||||||
|
### 1. 工作区目录结构
|
||||||
|
- **src/**: 包含所有ROS2包的源代码
|
||||||
|
- **build/**: 构建过程中生成的中间文件
|
||||||
|
- **install/**: 安装目录,包含可执行文件、库和资源
|
||||||
|
- **log/**: 构建和运行时的日志文件
|
||||||
|
|
||||||
|
### 2. ROS2包的基本结构
|
||||||
|
每个ROS2包通常包含:
|
||||||
|
- `CMakeLists.txt`: CMake构建配置文件
|
||||||
|
- `package.xml`: 包元数据文件
|
||||||
|
- `src/`: C++或Python源代码
|
||||||
|
- `include/`: C++头文件
|
||||||
|
- `msg/`, `srv/`, `action/`: 消息、服务、动作定义文件
|
||||||
|
|
||||||
|
### 3. 软件架构层次
|
||||||
|
1. **应用程序层**: 用户编写的ROS2节点
|
||||||
|
2. **客户端库层**: 语言特定的API(C++、Python、C)
|
||||||
|
3. **RCL层**: 通用的ROS客户端库
|
||||||
|
4. **RMW层**: ROS中间件抽象接口
|
||||||
|
5. **DDS层**: 具体的DDS实现
|
||||||
|
|
||||||
|
### 4. 通信模式
|
||||||
|
- **话题(Topics)**: 发布/订阅模式,单向异步通信
|
||||||
|
- **服务(Services)**: 请求/响应模式,同步通信
|
||||||
|
- **动作(Actions)**: 目标/反馈/结果模式,长时间运行的任务
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
1. 将本文件在支持 Mermaid 图的 Markdown 查看器中打开(如 VS Code with Mermaid 插件、GitHub、GitLab 等)
|
||||||
|
2. 图表将自动渲染为可视化图形
|
||||||
|
3. 如需修改图表,编辑对应的 Mermaid 代码块
|
||||||
|
|
||||||
|
## 相关资源
|
||||||
|
|
||||||
|
- [ROS2 官方文档](https://docs.ros.org/)
|
||||||
|
- [ROS2 架构设计](https://design.ros2.org/)
|
||||||
|
- [Mermaid 语法指南](https://mermaid.js.org/syntax/flowchart.html)
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# 维护 ROS 2 源代码检出
|
||||||
|
|
||||||
|
## [概述](https://docs.ros.org/en/humble/Installation/Maintaining-a-Source-Checkout.html)
|
||||||
|
|
||||||
|
本文档介绍如何维护从源代码构建的 ROS 2 安装。如果您已经从源代码安装了 ROS 2,并且想要更新到最新的错误修复和功能,请遵循本指南。
|
||||||
|
|
||||||
|
## [更新 ROS 2 源代码](https://docs.ros.org/en/humble/Installation/Maintaining-a-Source-Checkout.html#updating-ros-2-source-code)
|
||||||
|
|
||||||
|
### 1. 更新仓库列表文件
|
||||||
|
|
||||||
|
首先,您需要获取最新的 `ros2.repos` 文件,该文件定义了构建 ROS 2 所需的所有仓库及其分支。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 对于 Humble Hawksbill 版本
|
||||||
|
cd ~/ros2_humble
|
||||||
|
wget https://raw.githubusercontent.com/ros2/ros2/humble/ros2.repos -O ros2.repos
|
||||||
|
```
|
||||||
|
|
||||||
|
或者,如果您想使用特定分支(例如主分支)而不是发布分支:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 使用主分支(开发版本)
|
||||||
|
wget https://raw.githubusercontent.com/ros2/ros2/master/ros2.repos -O ros2.repos
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 更新本地仓库
|
||||||
|
|
||||||
|
使用 `vcs` 工具更新您的本地仓库:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 更新所有仓库的远程引用
|
||||||
|
vcs custom --args remote update
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 下载新的源代码
|
||||||
|
|
||||||
|
现在,使用新的 `ros2.repos` 文件导入并拉取最新的代码:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 导入新仓库定义
|
||||||
|
vcs import src < ros2.repos
|
||||||
|
|
||||||
|
# 拉取所有仓库的最新代码
|
||||||
|
vcs pull src
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:`vcs import` 命令将覆盖 `src` 目录中现有的仓库定义。如果您有本地修改或添加了额外的仓库,请确保在运行此命令之前备份您的更改。
|
||||||
|
|
||||||
|
### 4. 重新构建工作空间
|
||||||
|
|
||||||
|
更新源代码后,需要重新构建工作空间:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 返回到工作空间根目录
|
||||||
|
cd ~/ros2_humble
|
||||||
|
|
||||||
|
# 使用 colcon 重新构建
|
||||||
|
colcon build --symlink-install
|
||||||
|
```
|
||||||
|
|
||||||
|
构建选项说明:
|
||||||
|
- `--symlink-install`:使用符号链接而不是复制文件,这可以加快构建速度并减少磁盘空间使用
|
||||||
|
|
||||||
|
### 5. 检查源代码状态
|
||||||
|
|
||||||
|
要查看当前工作空间中所有仓库的状态,可以导出当前的仓库配置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 导出当前仓库状态
|
||||||
|
vcs export src > my_ros2.repos
|
||||||
|
```
|
||||||
|
|
||||||
|
这将在当前目录下创建一个 `my_ros2.repos` 文件,其中包含所有仓库的当前提交哈希值。您可以将此文件用于:
|
||||||
|
- 备份当前的源代码状态
|
||||||
|
- 在其他机器上复制相同的配置
|
||||||
|
- 调试构建问题
|
||||||
|
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
## [System requirements](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id1)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#system-requirements "Link to this heading")
|
||||||
|
|
||||||
|
The current Debian-based target platforms for Humble Hawksbill are:
|
||||||
|
|
||||||
|
- Tier 1: Ubuntu Linux - Jammy (22.04) 64-bit
|
||||||
|
|
||||||
|
- Tier 3: Ubuntu Linux - Focal (20.04) 64-bit
|
||||||
|
|
||||||
|
- Tier 3: Debian Linux - Bullseye (11) 64-bit
|
||||||
|
|
||||||
|
|
||||||
|
Other Linux platforms with varying support levels include:
|
||||||
|
|
||||||
|
- Arch Linux, see [alternate instructions](https://wiki.archlinux.org/index.php/ROS#ROS_2)
|
||||||
|
|
||||||
|
- Fedora Linux, see [alternate instructions](https://ros2docs.robook.org/humble/Installation/Alternatives/Fedora-Development-Setup.html)
|
||||||
|
|
||||||
|
- OpenEmbedded / webOS OSE, see [alternate instructions](https://github.com/ros/meta-ros/wiki/OpenEmbedded-Build-Instructions)
|
||||||
|
|
||||||
|
|
||||||
|
As defined in [REP 2000](https://www.ros.org/reps/rep-2000.html).
|
||||||
|
|
||||||
|
## [System setup](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id2)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#system-setup "Link to this heading")
|
||||||
|
|
||||||
|
### [Set locale](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id3)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#set-locale "Link to this heading")
|
||||||
|
|
||||||
|
请确保您有一个支持 `UTF-8` 的区域设置。 如果您处于最简环境中(例如 docker 容器),区域设置可能是一些类似 `POSIX` 的选项。 我们使用以下设置通过了测试。但是,如果您使用不同的支持 `UTF-8` 的区域设置,也应该没问题。
|
||||||
|
|
||||||
|
`locale # check for UTF-8`
|
||||||
|
`sudo apt update && sudo apt install locales`
|
||||||
|
`sudo locale-gen en_US en_US.UTF-8`
|
||||||
|
`sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8`
|
||||||
|
`export LANG=en_US.UTF-8`
|
||||||
|
`locale # verify settings`
|
||||||
|
|
||||||
|
### [Add the ROS 2 apt repository](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id4)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#add-the-ros-2-apt-repository "Link to this heading")
|
||||||
|
|
||||||
|
你需要将 ROS 2 apt 仓库添加到你的系统中。
|
||||||
|
|
||||||
|
首先确保 [Ubuntu Universe 仓库](https://help.ubuntu.com/community/Repositories/Ubuntu) 已启用。
|
||||||
|
|
||||||
|
`sudo apt install software-properties-common`
|
||||||
|
`sudo add-apt-repository universe`
|
||||||
|
|
||||||
|
然后使用 apt 添加 ROS 2 GPG 密钥。
|
||||||
|
|
||||||
|
`sudo apt update && sudo apt install curl -y`
|
||||||
|
`sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg`
|
||||||
|
|
||||||
|
然后将仓库添加到你的源列表中。
|
||||||
|
|
||||||
|
`echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null`
|
||||||
|
|
||||||
|
### [Install development tools and ROS tools](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id5)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#install-development-tools-and-ros-tools "Link to this heading")
|
||||||
|
|
||||||
|
Install common packages.
|
||||||
|
|
||||||
|
`sudo apt update && sudo apt install -y \`
|
||||||
|
`python3-flake8-docstrings \`
|
||||||
|
`python3-pip \`
|
||||||
|
`python3-pytest-cov \`
|
||||||
|
`ros-dev-tools`
|
||||||
|
|
||||||
|
Install packages according to your Ubuntu version.
|
||||||
|
|
||||||
|
Ubuntu 22.04 LTS and laterUbuntu 20.04 LTS
|
||||||
|
|
||||||
|
`sudo apt install -y \`
|
||||||
|
`python3-flake8-blind-except \`
|
||||||
|
`python3-flake8-builtins \`
|
||||||
|
`python3-flake8-class-newline \`
|
||||||
|
`python3-flake8-comprehensions \`
|
||||||
|
`python3-flake8-deprecated \`
|
||||||
|
`python3-flake8-import-order \`
|
||||||
|
`python3-flake8-quotes \`
|
||||||
|
`python3-pytest-repeat \`
|
||||||
|
`python3-pytest-rerunfailures`
|
||||||
|
|
||||||
|
## [Get ROS 2 code](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id6)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#get-ros-2-code "Link to this heading")
|
||||||
|
|
||||||
|
Create a workspace and clone all repos:
|
||||||
|
|
||||||
|
`mkdir -p ~/ros2_humble/src`
|
||||||
|
`cd ~/ros2_humble`
|
||||||
|
`vcs import --input https://raw.githubusercontent.com/ros2/ros2/humble/ros2.repos src`
|
||||||
|
|
||||||
|
## [Install dependencies using rosdep](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id7)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#install-dependencies-using-rosdep "Link to this heading")
|
||||||
|
|
||||||
|
ROS 2 包是在经常更新的 Ubuntu 系统上构建的。 在安装新包之前,建议您确保系统是最新的。
|
||||||
|
|
||||||
|
%% `sudo apt upgrade` %%
|
||||||
|
|
||||||
|
`sudo rosdep init`
|
||||||
|
`rosdep update`
|
||||||
|
`rosdep install --from-paths src --ignore-src -y --skip-keys "fastcdr rti-connext-dds-6.0.1 urdfdom_headers"`
|
||||||
|
|
||||||
|
**Note**: If you’re using a distribution that is based on Ubuntu (like Linux Mint) but does not identify itself as such, you’ll get an error message like `Unsupported OS [mint]`. In this case append `--os=ubuntu:jammy` to the above command.
|
||||||
|
|
||||||
|
## [Install additional DDS implementations (optional)](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id8)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#install-additional-dds-implementations-optional "Link to this heading")
|
||||||
|
|
||||||
|
If you would like to use another DDS or RTPS vendor besides the default, you can find instructions [here](https://ros2docs.robook.org/humble/Installation/DDS-Implementations.html).
|
||||||
|
|
||||||
|
## [Build the code in the workspace](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id9)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#build-the-code-in-the-workspace "Link to this heading")
|
||||||
|
|
||||||
|
If you have already installed ROS 2 another way (either via debs or the binary distribution), make sure that you run the below commands in a fresh environment that does not have those other installations sourced. Also ensure that you do not have `source /opt/ros/${ROS_DISTRO}/setup.bash` in your `.bashrc`. You can make sure that ROS 2 is not sourced with the command `printenv | grep -i ROS`. The output should be empty.
|
||||||
|
|
||||||
|
More info on working with a ROS workspace can be found in [this tutorial](https://ros2docs.robook.org/humble/Tutorials/Beginner-Client-Libraries/Colcon-Tutorial.html).
|
||||||
|
|
||||||
|
`cd ~/ros2_humble/`
|
||||||
|
`colcon build --symlink-install`
|
||||||
|
|
||||||
|
Note: if you are having trouble compiling all examples and this is preventing you from completing a successful build, you can use `COLCON_IGNORE` in the same manner as [CATKIN_IGNORE](https://github.com/ros-infrastructure/rep/blob/master/rep-0128.rst) to ignore the subtree or remove the folder from the workspace. Take for instance: you would like to avoid installing the large OpenCV library. Well then simply run `touch COLCON_IGNORE` in the `cam2image` demo directory to leave it out of the build process.
|
||||||
|
|
||||||
|
## [Environment setup](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id10)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#environment-setup "Link to this heading")
|
||||||
|
|
||||||
|
### [Source the setup script](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id11)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#source-the-setup-script "Link to this heading")
|
||||||
|
|
||||||
|
Set up your environment by sourcing the following file.
|
||||||
|
|
||||||
|
# Replace ".bash" with your shell if you're not using bash
|
||||||
|
# Possible values are: setup.bash, setup.sh, setup.zsh
|
||||||
|
|
||||||
|
`. ~/ros2_humble/install/local_setup.bash`
|
||||||
|
|
||||||
|
## [Try some examples](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id12)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#try-some-examples "Link to this heading")
|
||||||
|
|
||||||
|
In one terminal, source the setup file and then run a C++ `talker`:
|
||||||
|
|
||||||
|
`. ~/ros2_humble/install/local_setup.bash`
|
||||||
|
`ros2 run demo_nodes_cpp talker`
|
||||||
|
|
||||||
|
In another terminal source the setup file and then run a Python `listener`:
|
||||||
|
|
||||||
|
`. ~/ros2_humble/install/local_setup.bash`
|
||||||
|
`ros2 run demo_nodes_py listener`
|
||||||
|
|
||||||
|
You should see the `talker` saying that it’s `Publishing` messages and the `listener` saying `I heard` those messages. This verifies both the C++ and Python APIs are working properly. Hooray!
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
## [系统要求](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id1)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#system-requirements "Link to this heading")
|
||||||
|
|
||||||
|
当前 Humble Hawksbill 基于 Debian 的目标平台包括:
|
||||||
|
|
||||||
|
- 第一级:Ubuntu Linux - Jammy (22.04) 64位
|
||||||
|
|
||||||
|
- 第三级:Ubuntu Linux - Focal (20.04) 64位
|
||||||
|
|
||||||
|
- 第三级:Debian Linux - Bullseye (11) 64位
|
||||||
|
|
||||||
|
|
||||||
|
其他支持程度不同的 Linux 平台包括:
|
||||||
|
|
||||||
|
- Arch Linux,请参阅[替代安装说明](https://wiki.archlinux.org/index.php/ROS#ROS_2)
|
||||||
|
|
||||||
|
- Fedora Linux,请参阅[替代安装说明](https://ros2docs.robook.org/humble/Installation/Alternatives/Fedora-Development-Setup.html)
|
||||||
|
|
||||||
|
- OpenEmbedded / webOS OSE,请参阅[替代安装说明](https://github.com/ros/meta-ros/wiki/OpenEmbedded-Build-Instructions)
|
||||||
|
|
||||||
|
|
||||||
|
如 [REP 2000](https://www.ros.org/reps/rep-2000.html) 中所定义。
|
||||||
|
|
||||||
|
## [系统设置](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id2)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#system-setup "Link to this heading")
|
||||||
|
|
||||||
|
### [设置区域](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id3)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#set-locale "Link to this heading")
|
||||||
|
|
||||||
|
请确保您有一个支持 `UTF-8` 的区域设置。如果您处于最简环境中(例如 docker 容器),区域设置可能是一些类似 `POSIX` 的选项。我们使用以下设置通过了测试。但是,如果您使用不同的支持 `UTF-8` 的区域设置,也应该没问题。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
locale # 检查 UTF-8 支持
|
||||||
|
sudo apt update && sudo apt install locales
|
||||||
|
sudo locale-gen en_US en_US.UTF-8
|
||||||
|
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
|
||||||
|
export LANG=en_US.UTF-8
|
||||||
|
locale # 验证设置
|
||||||
|
```
|
||||||
|
|
||||||
|
### [添加 ROS 2 apt 仓库](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id4)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#add-the-ros-2-apt-repository "Link to this heading")
|
||||||
|
|
||||||
|
你需要将 ROS 2 apt 仓库添加到你的系统中。
|
||||||
|
|
||||||
|
首先确保 [Ubuntu Universe 仓库](https://help.ubuntu.com/community/Repositories/Ubuntu) 已启用。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install software-properties-common
|
||||||
|
sudo add-apt-repository universe
|
||||||
|
```
|
||||||
|
|
||||||
|
然后使用 apt 添加 ROS 2 GPG 密钥。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt install curl -y
|
||||||
|
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
|
||||||
|
```
|
||||||
|
|
||||||
|
然后将仓库添加到你的源列表中。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
### [安装开发工具和 ROS 工具](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id5)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#install-development-tools-and-ros-tools "Link to this heading")
|
||||||
|
|
||||||
|
安装常用软件包。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt install -y \
|
||||||
|
python3-flake8-docstrings \
|
||||||
|
python3-pip \
|
||||||
|
python3-pytest-cov \
|
||||||
|
ros-dev-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
根据您的 Ubuntu 版本安装软件包。
|
||||||
|
|
||||||
|
Ubuntu 22.04 LTS 及更高版本 Ubuntu 20.04 LTS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install -y \
|
||||||
|
python3-flake8-blind-except \
|
||||||
|
python3-flake8-builtins \
|
||||||
|
python3-flake8-class-newline \
|
||||||
|
python3-flake8-comprehensions \
|
||||||
|
python3-flake8-deprecated \
|
||||||
|
python3-flake8-import-order \
|
||||||
|
python3-flake8-quotes \
|
||||||
|
python3-pytest-repeat \
|
||||||
|
python3-pytest-rerunfailures
|
||||||
|
```
|
||||||
|
|
||||||
|
## [获取 ROS 2 代码](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id6)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#get-ros-2-code "Link to this heading")
|
||||||
|
|
||||||
|
创建工作区并克隆所有仓库:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/ros2_humble/src
|
||||||
|
cd ~/ros2_humble
|
||||||
|
vcs import --input https://raw.githubusercontent.com/ros2/ros2/humble/ros2.repos src
|
||||||
|
```
|
||||||
|
|
||||||
|
## [使用 rosdep 安装依赖](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id7)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#install-dependencies-using-rosdep "Link to this heading")
|
||||||
|
|
||||||
|
ROS 2 包是在经常更新的 Ubuntu 系统上构建的。在安装新包之前,建议您确保系统是最新的。
|
||||||
|
|
||||||
|
%% `sudo apt upgrade` %%
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo rosdep init
|
||||||
|
rosdep update
|
||||||
|
rosdep install --from-paths src --ignore-src -y --skip-keys "fastcdr rti-connext-dds-6.0.1 urdfdom_headers"
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:如果您使用的是基于 Ubuntu 的发行版(如 Linux Mint)但系统未标识为 Ubuntu,您可能会收到类似 `Unsupported OS [mint]` 的错误消息。在这种情况下,请在上述命令后追加 `--os=ubuntu:jammy`。
|
||||||
|
|
||||||
|
## [安装额外的 DDS 实现(可选)](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id8)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#install-additional-dds-implementations-optional "Link to this heading")
|
||||||
|
|
||||||
|
如果您想使用默认之外的 DDS 或 RTPS 供应商,可以在此处找到说明[这里](https://ros2docs.robook.org/humble/Installation/DDS-Implementations.html)。
|
||||||
|
|
||||||
|
## [在工作区中构建代码](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id9)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#build-the-code-in-the-workspace "Link to this heading")
|
||||||
|
|
||||||
|
如果您已经通过其他方式(deb 包或二进制发行版)安装了 ROS 2,请确保在未激活其他安装的新环境中运行以下命令。同时确保您的 `.bashrc` 中没有 `source /opt/ros/${ROS_DISTRO}/setup.bash`。您可以使用命令 `printenv | grep -i ROS` 来确保 ROS 2 未被激活。输出应为空。
|
||||||
|
|
||||||
|
有关使用 ROS 工作区的更多信息,请参阅[本教程](https://ros2docs.robook.org/humble/Tutorials/Beginner-Client-Libraries/Colcon-Tutorial.html)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ros2_humble/
|
||||||
|
colcon build --symlink-install
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:如果编译所有示例时遇到问题,导致无法成功构建,您可以像使用 [CATKIN_IGNORE](https://github.com/ros-infrastructure/rep/blob/master/rep-0128.rst) 一样使用 `COLCON_IGNORE` 来忽略子树或从工作区中移除文件夹。例如:如果您想避免安装庞大的 OpenCV 库,只需在 `cam2image` 演示目录中运行 `touch COLCON_IGNORE` 即可将其排除在构建过程之外。
|
||||||
|
|
||||||
|
## [环境设置](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id10)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#environment-setup "Link to this heading")
|
||||||
|
|
||||||
|
### [源化安装脚本](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id11)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#source-the-setup-script "Link to this heading")
|
||||||
|
|
||||||
|
通过源化以下文件来设置您的环境。
|
||||||
|
|
||||||
|
# 如果不使用 bash,请将 ".bash" 替换为您的 shell
|
||||||
|
# 可能的取值为:setup.bash, setup.sh, setup.zsh
|
||||||
|
|
||||||
|
```bash
|
||||||
|
. ~/ros2_humble/install/local_setup.bash
|
||||||
|
```
|
||||||
|
|
||||||
|
## [尝试一些示例](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#id12)[](https://ros2docs.robook.org/humble/Installation/Alternatives/Ubuntu-Development-Setup.html#try-some-examples "Link to this heading")
|
||||||
|
|
||||||
|
在一个终端中,源化安装脚本然后运行 C++ `talker`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
. ~/ros2_humble/install/local_setup.bash
|
||||||
|
ros2 run demo_nodes_cpp talker
|
||||||
|
```
|
||||||
|
|
||||||
|
在另一个终端中源化安装脚本然后运行 Python `listener`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
. ~/ros2_humble/install/local_setup.bash
|
||||||
|
ros2 run demo_nodes_py listener
|
||||||
|
```
|
||||||
|
|
||||||
|
您应该能看到 `talker` 显示它正在 `Publishing` 消息,而 `listener` 显示 `I heard` 这些消息。这表明 C++ 和 Python API 都能正常工作。太好了!
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
``` bash
|
||||||
|
source install/local_setup.bash
|
||||||
|
# export ROS_DOMAIN_ID=<your_domain_id>
|
||||||
|
# echo "export ROS_DOMAIN_ID=<your_domain_id>" >> ~/.bashrc
|
||||||
|
# export ROS_LOCALHOST_ONLY=1
|
||||||
|
# echo "export ROS_LOCALHOST_ONLY=1" >> ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
# ROS 2 基础概念
|
||||||
|
|
||||||
|
ROS 2 (Robot Operating System 2) 是一个用于构建机器人应用程序的开源框架。它提供了一套工具、库和约定,帮助开发者创建可维护、可扩展且可重用的机器人软件。
|
||||||
|
|
||||||
|
## 1. Node (节点)
|
||||||
|
|
||||||
|
**节点** 是 ROS 2 中最小的可执行单元,代表一个单一功能模块。每个节点执行特定任务(如控制传感器、处理图像、规划路径等),并通过标准接口与其他节点通信。
|
||||||
|
|
||||||
|
- **特点**:
|
||||||
|
- 轻量级,单一职责
|
||||||
|
- 使用命名空间避免命名冲突
|
||||||
|
- 支持多种客户端库(C++、Python、Java等)
|
||||||
|
|
||||||
|
- **核心概念**:
|
||||||
|
- 节点名称:唯一标识符,如 `/camera_driver`
|
||||||
|
- 命名空间:用于组织节点,如 `/robot1/camera_driver`
|
||||||
|
|
||||||
|
## 2. Discovery (发现机制)
|
||||||
|
|
||||||
|
**发现机制** 是 ROS 2 中节点自动发现其他节点和服务的过程。它允许节点在网络中找到彼此并建立通信,无需硬编码地址。
|
||||||
|
|
||||||
|
- **工作原理**:
|
||||||
|
- 使用 DDS (Data Distribution Service) 作为底层通信中间件
|
||||||
|
- 通过参与者(Participant)、主题(Topic)和服务(Service)的发现实现
|
||||||
|
- 自动管理连接的建立和断开
|
||||||
|
|
||||||
|
- **关键组件**:
|
||||||
|
- ROS 2 守护进程 `ros2 daemon`(后台运行,管理发现)
|
||||||
|
- DDS 域(Domain ID):控制节点可见性(同一域的节点才能通信)
|
||||||
|
|
||||||
|
## 3. Interfaces (接口)
|
||||||
|
|
||||||
|
**接口** 定义了节点之间通信的消息格式。ROS 2 提供了三种主要通信接口类型:
|
||||||
|
|
||||||
|
### 3.1 Topics (话题) - 发布/订阅通信
|
||||||
|
|
||||||
|
**话题** 是节点之间传递数据的命名通道。一个节点可以**发布**(发送)数据到某个话题,其他节点可以**订阅**(接收)该话题的数据。
|
||||||
|
|
||||||
|
- **特点**:
|
||||||
|
- 单向、异步通信
|
||||||
|
- 一对多或多对多通信模式
|
||||||
|
- 消息类型严格定义(如 `std_msgs/String`、`sensor_msgs/Image`)
|
||||||
|
|
||||||
|
- **使用场景**:
|
||||||
|
- 持续数据流(如传感器数据、状态信息)
|
||||||
|
|
||||||
|
### 3.2 Services (服务) - 请求/响应通信
|
||||||
|
|
||||||
|
**服务** 实现节点之间的双向同步通信。一个节点提供**服务**,其他节点发送**请求**并等待**响应**。
|
||||||
|
|
||||||
|
- **特点**:
|
||||||
|
- 请求/响应模式
|
||||||
|
- 同步通信(客户端等待服务端处理)
|
||||||
|
- 需要定义请求和响应的消息类型(.srv 文件)
|
||||||
|
|
||||||
|
- **使用场景**:
|
||||||
|
- 一次性任务(如获取配置、执行动作)
|
||||||
|
|
||||||
|
### 3.3 Actions (动作) - 目标导向通信
|
||||||
|
|
||||||
|
**动作** 是服务的扩展,支持长时间运行的任务,并提供反馈和取消功能。
|
||||||
|
|
||||||
|
- **特点**:
|
||||||
|
- 目标-反馈-结果模式
|
||||||
|
- 可取消、可获取进度反馈
|
||||||
|
- 异步执行
|
||||||
|
- 消息类型定义在 .action 文件中
|
||||||
|
|
||||||
|
- **使用场景**:
|
||||||
|
- 长时间运行的任务(如导航、抓取物体)
|
||||||
|
|
||||||
|
## 4. Parameters (参数)
|
||||||
|
|
||||||
|
**参数** 是节点的配置值,可以在运行时动态修改。参数支持多种数据类型(整数、浮点数、字符串、布尔值等)。
|
||||||
|
|
||||||
|
- **管理方式**:
|
||||||
|
- 命令行设置
|
||||||
|
- 配置文件(YAML)
|
||||||
|
- 运行时动态修改(通过 `ros2 param` 命令或 API)
|
||||||
|
|
||||||
|
- **常用操作**:
|
||||||
|
- `ros2 param list`:列出节点参数
|
||||||
|
- `ros2 param set`:设置参数值
|
||||||
|
- `ros2 param get`:获取参数值
|
||||||
|
|
||||||
|
## 5. Introspection (内省)
|
||||||
|
|
||||||
|
**内省** 允许开发者在运行时检查和监控 ROS 2 系统的状态。通过内省工具,您可以查看节点、话题、服务和参数的信息。
|
||||||
|
|
||||||
|
- **常用工具**:
|
||||||
|
- `ros2 node list`:列出所有节点
|
||||||
|
- `ros2 topic list`:列出所有话题
|
||||||
|
- `ros2 service list`:列出所有服务
|
||||||
|
- `ros2 topic echo`:查看话题消息内容
|
||||||
|
- `ros2 node info`:查看节点详细信息
|
||||||
|
|
||||||
|
## 6. Launch (启动系统)
|
||||||
|
|
||||||
|
**Launch** 允许您同时启动多个节点和配置它们的参数。使用 Python 或 XML 编写的启动文件可以简化系统启动过程。
|
||||||
|
|
||||||
|
- **特点**:
|
||||||
|
- 同时启动多个节点
|
||||||
|
- 配置节点参数
|
||||||
|
- 设置命名空间和重映射
|
||||||
|
- 支持条件启动和依赖关系
|
||||||
|
|
||||||
|
- **常用工具**:
|
||||||
|
- `ros2 launch`:执行启动文件
|
||||||
|
- 启动文件格式:Python(推荐)、XML、YAML
|
||||||
|
|
||||||
|
## 7. Client Libraries (客户端库)
|
||||||
|
|
||||||
|
**客户端库** 是 ROS 2 提供的编程接口,允许开发者使用不同语言编写节点。
|
||||||
|
|
||||||
|
- **主要客户端库**:
|
||||||
|
- **rclcpp**:C++ 客户端库(推荐用于高性能应用)
|
||||||
|
- **rclpy**:Python 客户端库(推荐用于快速原型开发)
|
||||||
|
- **rcljava**:Java 客户端库
|
||||||
|
- **其他**:Swift、Go 等语言的社区支持
|
||||||
|
|
||||||
|
- **核心特性**:
|
||||||
|
- 统一的 API 接口
|
||||||
|
- 自动内存管理
|
||||||
|
- 支持所有 ROS 2 通信模式
|
||||||
|
|
||||||
|
## 8. 通信中间件
|
||||||
|
|
||||||
|
ROS 2 使用 **DDS (Data Distribution Service)** 作为默认通信中间件,提供可靠的实时数据交换。DDS 是工业标准的中间件,适用于嵌入式系统和高性能计算。
|
||||||
|
|
||||||
|
- **DDS 特性**:
|
||||||
|
- 高可靠性
|
||||||
|
- 低延迟
|
||||||
|
- 实时支持
|
||||||
|
- 可扩展性
|
||||||
|
- 服务质量(QoS)配置
|
||||||
|
|
||||||
|
## 9. 服务质量(QoS)
|
||||||
|
|
||||||
|
**QoS (Quality of Service)** 配置允许您控制通信的可靠性、持久性和其他特性。QoS 设置对于确保系统在不同环境下的性能至关重要。
|
||||||
|
|
||||||
|
- **主要 QoS 策略**:
|
||||||
|
- Reliability:可靠传输(保证交付)或最佳 effort(不保证交付)
|
||||||
|
- Durability:数据是否持久化(对晚加入的节点可见)
|
||||||
|
- History:保留消息历史的深度
|
||||||
|
- Deadline/Lifespan:消息的截止时间和寿命
|
||||||
|
|
||||||
|
## 10. 系统架构概览
|
||||||
|
|
||||||
|
ROS 2 系统由以下层次组成:
|
||||||
|
|
||||||
|
1. **应用层**:节点、话题、服务、动作
|
||||||
|
2. **中间件层**:DDS 通信系统
|
||||||
|
3. **工具层**:命令行工具、可视化工具、调试工具
|
||||||
|
4. **硬件抽象层**:传感器、执行器、硬件接口
|
||||||
|
|
||||||
|
## 11. 与 ROS 1 的主要区别
|
||||||
|
|
||||||
|
- **通信中间件**:ROS 1 使用 TCPROS/UDPROS,ROS 2 使用 DDS
|
||||||
|
- **节点发现**:ROS 1 依赖 roscore,ROS 2 去中心化
|
||||||
|
- **接口类型**:ROS 2 添加了 Actions
|
||||||
|
- **参数系统**:ROS 2 支持动态参数配置
|
||||||
|
- **编译系统**:ROS 1 使用 catkin,ROS 2 使用 colcon
|
||||||
|
- **支持的语言**:ROS 2 对 Python 3 的支持更好,添加了更多语言选项
|
||||||
|
|
||||||
|
这些基础概念是理解和使用 ROS 2 的核心。通过掌握这些概念,您可以开始构建复杂的机器人系统,并利用 ROS 2 的强大功能。
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[差速驱动移动基座和机械臂的规划 — MoveIt documentation documentation](https://www.ncnynl.com/ros2docs/cn/moveit2/doc/examples/mobile_base_arm/mobile_base_arm_tutorial.html)
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# DeepSeek V4 系列
|
||||||
|
|
||||||
|
> 发布日期:2026年4月24日 | 开源协议:MIT
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
DeepSeek V4 是深度求索(DeepSeek)在 2026 年 4 月发布的新一代大语言模型系列,包含两个版本:
|
||||||
|
|
||||||
|
| | V4 Pro(旗舰版) | V4 Flash(轻量版) |
|
||||||
|
|---|---|---|
|
||||||
|
| **总参数量** | 1.6T(1.6万亿) | 284B(2840亿) |
|
||||||
|
| **激活参数** | ~36B/token | 13B/token |
|
||||||
|
| **上下文窗口** | 1M tokens | 1M tokens |
|
||||||
|
| **架构** | MoE(混合专家) | MoE(混合专家) |
|
||||||
|
| **定位** | 旗舰性能,对标 GPT-5 | 低成本、低延迟,接近 Pro 推理能力 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心技术架构
|
||||||
|
|
||||||
|
### 1. 混合专家架构(Mixture-of-Experts, MoE)
|
||||||
|
|
||||||
|
- V4 Pro:384 个专家/层,每次推理激活 6 个
|
||||||
|
- V4 Flash:精简专家数量,每次推理激活 13B 参数
|
||||||
|
- 优势:总参数大但计算量可控,推理效率高
|
||||||
|
|
||||||
|
### 2. 混合注意力机制(Hybrid Attention)
|
||||||
|
|
||||||
|
- **DSA2 稀疏注意力**:降低长上下文的计算开销
|
||||||
|
- **CSA(压缩稀疏注意力)+ HCA(重度压缩注意力)**(Flash):
|
||||||
|
- KV 缓存内存开销降低高达 90%
|
||||||
|
- 在 1M 上下文下,单 token 推理 FLOPs 仅为 V3.2 的 27%
|
||||||
|
- KV 缓存仅为 V3.2 的 10%
|
||||||
|
|
||||||
|
### 3. 其他关键技术
|
||||||
|
|
||||||
|
- **流形约束超连接(mHC)**:增强残差连接,改善跨层信号传播
|
||||||
|
- **Muon 优化器**:加速收敛,提升训练稳定性
|
||||||
|
- **多 Token 预测(MTP)**:一次预测多个 token,加速生成
|
||||||
|
- **DSpark 推测解码**(Flash):集成草稿模块加速推理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三种推理模式
|
||||||
|
|
||||||
|
| 模式 | 说明 | 适用场景 |
|
||||||
|
|---|---|---|
|
||||||
|
| **Non-think(低)** | 快速、直观的响应 | 简单对话、翻译、摘要 |
|
||||||
|
| **Think High(高)** | 显式思维链推理 | 逻辑推理、规划任务 |
|
||||||
|
| **Think Max(最大)** | 最大推理深度 | 复杂数学、竞赛编程 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 关键基准测试
|
||||||
|
|
||||||
|
### V4 Pro 亮点
|
||||||
|
|
||||||
|
| 基准测试 | 得分 | 对比 |
|
||||||
|
|---|---|---|
|
||||||
|
| Codeforces Rating | 3206 | 超越 Gemini 3.1-Pro |
|
||||||
|
| LiveCodeBench | 93.5 | 与 GPT-5.4 竞争 |
|
||||||
|
| MMLU-Pro | — | 接近 GPT-5 水平 |
|
||||||
|
|
||||||
|
### V4 Flash 亮点
|
||||||
|
|
||||||
|
| 基准测试 | 得分 |
|
||||||
|
|---|---|
|
||||||
|
| MMLU-Pro (EM) | 87.5 |
|
||||||
|
| GPQA Diamond | 90.1 |
|
||||||
|
| LiveCodeBench | 93.5 |
|
||||||
|
| SWE Verified (Resolved) | 80.6 |
|
||||||
|
| Terminal Bench 2.1 | 82.7 |
|
||||||
|
| BrowseComp | 83.4 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 定价对比
|
||||||
|
|
||||||
|
### V4 Pro(通过 DeepInfra)
|
||||||
|
|
||||||
|
| Token 类型 | 每百万 Token 价格 |
|
||||||
|
|---|---|
|
||||||
|
| 输入 | $1.74 |
|
||||||
|
| 输出 | $3.48 |
|
||||||
|
| 缓存输入 | $0.145 |
|
||||||
|
|
||||||
|
### V4 Flash
|
||||||
|
|
||||||
|
| Token 类型 | 每百万 Token 价格 |
|
||||||
|
|---|---|
|
||||||
|
| 输入 | ~$0.14 |
|
||||||
|
| 输出 | ~$0.28 |
|
||||||
|
|
||||||
|
> V4 Pro 输出成本比 Claude Opus 4.7($25/1M)便宜约 7 倍
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 独立评测(NIST/CAISI,2026年5月)
|
||||||
|
|
||||||
|
- V4 Pro 性能约为 **GPT-5 水平**(2025年8月发布)
|
||||||
|
- 距美国最前沿模型约 **8 个月**差距
|
||||||
|
- CAISI 测试过的**最强中国 AI 模型**
|
||||||
|
- 在某些非公开基准(ARC-AGI-2、CTF-Archive-Diamond)上明显落后于 GPT-5.5 和 Opus 4.6
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 战略意义
|
||||||
|
|
||||||
|
1. **芯片自主**:与华为昇腾(Ascend)、寒武纪合作优化,不依赖 NVIDIA/AMD
|
||||||
|
2. **开源生态**:MIT 协议开源,模型权重在 Hugging Face 上公开
|
||||||
|
3. **与 GPT-5.5 同日发布**:中美 AI 竞争白热化的标志性事件
|
||||||
|
4. **自我定位坦诚**:官方公开承认距前沿 3-6 个月差距
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[Transformer 架构详解]]
|
||||||
|
- [[MoE 混合专家架构]]
|
||||||
|
- [[多模态大模型]]
|
||||||
|
- [[大模型架构基础]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新:2026-08-05*
|
||||||
@@ -0,0 +1,410 @@
|
|||||||
|
# FFN 前馈网络详解
|
||||||
|
|
||||||
|
> Feed-Forward Network — Transformer 中参数量最大(~2/3)、负责知识存储和特征变换的核心组件
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、FFN 在 Transformer 中的角色
|
||||||
|
|
||||||
|
```
|
||||||
|
Transformer Block:
|
||||||
|
|
||||||
|
注意力层(信息混合) FFN 层(特征变换)
|
||||||
|
┌─────────────────┐ ┌─────────────────────┐
|
||||||
|
│ Token 之间交互 │ │ 每个 Token 独立处理 │
|
||||||
|
│ "谁跟谁有关?" │ → │ "这个 Token 是什么意思?"│
|
||||||
|
│ 参数量 ~1/3 │ │ 参数量 ~2/3 │
|
||||||
|
└─────────────────┘ └─────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
| 组件 | 参数量占比 | 功能 |
|
||||||
|
|---|---|---|
|
||||||
|
| **注意力层** | ~1/3 | Token 间的信息路由与混合("连接信息") |
|
||||||
|
| **FFN 层** | ~2/3 | Token 内部的特征变换与知识存储("存储知识") |
|
||||||
|
|
||||||
|
> **直觉**:注意力层决定"从哪读信息",FFN 层存储"读到的信息怎么理解"。研究表明 FFN 的权重矩阵充当了**联想记忆(Associative Memory)**——W₁ 的每一行是一个"模式检测器",W₂ 的对应列是"该模式的输出"。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、基础公式
|
||||||
|
|
||||||
|
### 标准 FFN(原始 Transformer)
|
||||||
|
|
||||||
|
```
|
||||||
|
FFN(x) = W₂ · ReLU(W₁ · x + b₁) + b₂
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
输入 x(d_model 维度)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
W₁: d_model → d_ff ← 升维(通常 d_ff = 4 × d_model)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
激活函数(ReLU/GELU/...) ← 引入非线性
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
W₂: d_ff → d_model ← 降维回原维度
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
输出(d_model 维度)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 参数量计算
|
||||||
|
|
||||||
|
```
|
||||||
|
标准 FFN(无偏置):
|
||||||
|
params = d_model × d_ff + d_ff × d_model
|
||||||
|
= 2 × d_model × d_ff
|
||||||
|
= 2 × d_model × 4d_model (通常 d_ff = 4d)
|
||||||
|
= 8 × d_model²
|
||||||
|
```
|
||||||
|
|
||||||
|
| d_model | d_ff (4×) | FFN 参数量 | 一层总参数(含注意力) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 512 | 2048 | 2.1M | ~3M |
|
||||||
|
| 4096 (LLaMA 7B) | 11008 (约2.7×) | ~90M | ~135M |
|
||||||
|
| 8192 (LLaMA 70B) | 22016 | ~360M | ~540M |
|
||||||
|
|
||||||
|
> 在 LLaMA 等 SwiGLU 模型中,`d_ff` 通常设为约 `8/3 × d_model`(而非 4×),以补偿 GLU 变体引入的额外参数。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、激活函数演进路线
|
||||||
|
|
||||||
|
```
|
||||||
|
2017 ─→ 2019 ────→ 2020 ──────→ 2025
|
||||||
|
ReLU GELU SwiGLU PolyGLU / 动态路由
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ └─ 每个神经元学自己的激活函数
|
||||||
|
│ │ └─ 门控线性单元,当前生产标准
|
||||||
|
│ └─ 平滑版 ReLU,不再死神经元
|
||||||
|
└─ 简单粗暴,负值直接清零
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.1 ReLU(原始 Transformer)
|
||||||
|
|
||||||
|
$$\text{ReLU}(x) = \max(0, x)$$
|
||||||
|
|
||||||
|
```
|
||||||
|
│
|
||||||
|
2 ┤ ╱
|
||||||
|
1 ┤ ╱
|
||||||
|
0 ┼════●──────── ← 负半轴完全为零
|
||||||
|
│ ╱
|
||||||
|
-1 ┤ ╱
|
||||||
|
└────────────
|
||||||
|
```
|
||||||
|
|
||||||
|
| 优点 | 缺点 |
|
||||||
|
|---|---|
|
||||||
|
| 计算极快,硬件原生支持 | **死神经元**:一旦输出为零,梯度为零,永不恢复 |
|
||||||
|
| 稀疏激活(约 50%) | 负值信息完全丢失 |
|
||||||
|
|
||||||
|
> **死神经元问题**:如果某个神经元的输出始终 ≤ 0(因为权重初始化或学习偏差),ReLU 的梯度永远为 0,这个神经元就"死了"——再也不会更新。
|
||||||
|
|
||||||
|
### 3.2 GELU(GPT-2 / BERT 时代)
|
||||||
|
|
||||||
|
$$\text{GELU}(x) = x \cdot \Phi(x) = x \cdot \frac{1}{2}\left[1 + \text{erf}\left(\frac{x}{\sqrt{2}}\right)\right]$$
|
||||||
|
|
||||||
|
```
|
||||||
|
│
|
||||||
|
2 ┤ ╱
|
||||||
|
1 ┤ ╱╱
|
||||||
|
0 ┼────●───────── ← 负半轴有小的非零输出
|
||||||
|
-1 ┤╱╱
|
||||||
|
└────────────
|
||||||
|
```
|
||||||
|
|
||||||
|
| 优点 | 缺点 |
|
||||||
|
|---|---|
|
||||||
|
| 平滑可微,梯度流更好 | 计算比 ReLU 慢(erf 函数) |
|
||||||
|
| 负值有概率性"门控"而非直接清零 | 所有输入用同一个函数处理 |
|
||||||
|
| 缓解死神经元问题 | |
|
||||||
|
|
||||||
|
> **GELU 的直觉**:把输入值 `x` 乘以它"来自正半轴的概率"——如果 x 很可能是负的,输出很小但不为零。
|
||||||
|
|
||||||
|
### 3.3 SiLU / Swish
|
||||||
|
|
||||||
|
$$\text{SiLU}(x) = x \cdot \sigma(x) = \frac{x}{1 + e^{-x}}$$
|
||||||
|
|
||||||
|
```
|
||||||
|
│
|
||||||
|
2 ┤ ╱
|
||||||
|
1 ┤ ╱╱
|
||||||
|
0 ┼─────●───────── ← 负半轴有"负沟"(non-monotonic)
|
||||||
|
-0.3┤ ╱ ╲ ← 这个沟是 SiLU 的独特特征
|
||||||
|
└────────────
|
||||||
|
```
|
||||||
|
|
||||||
|
| 关键特性 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **自门控** | 每个值决定自己通过多少:`x · σ(x)` |
|
||||||
|
| **非单调** | 负半轴先下降再回升,能捕获复杂模式 |
|
||||||
|
| **无界正值** | 正半轴可以无限大(不像 sigmoid 有上限) |
|
||||||
|
| **平滑** | 处处可微,梯度流极好 |
|
||||||
|
|
||||||
|
> SiLU 和 Swish 是**同一个函数**的两个名字。Google 叫它 Swish,PyTorch 叫它 SiLU。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、GLU 门控线性单元:范式转变
|
||||||
|
|
||||||
|
### 4.1 从"单路激活"到"双路门控"
|
||||||
|
|
||||||
|
```
|
||||||
|
标准 FFN: GLU FFN:
|
||||||
|
|
||||||
|
x x
|
||||||
|
│ ┌────┴────┐
|
||||||
|
W₁ W_gate W_up
|
||||||
|
│ │ │
|
||||||
|
Act σ │
|
||||||
|
│ │ │
|
||||||
|
W₂ └────┬────┘
|
||||||
|
│ ⊗ (逐元素相乘)
|
||||||
|
输出 │
|
||||||
|
W_down
|
||||||
|
│
|
||||||
|
输出
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 为什么乘法比加法强?
|
||||||
|
|
||||||
|
> 门控 = 逐元素乘法 = 引入**二阶交互项**
|
||||||
|
|
||||||
|
```
|
||||||
|
GLU(x) 包含 xᵢ · xⱼ 项(不同维度之间产生交互)
|
||||||
|
FFN(x) 只有 σ(Wx) 项(每个维度独立处理)
|
||||||
|
|
||||||
|
类比:
|
||||||
|
FFN = 每个特征独立打分
|
||||||
|
GLU = 特征之间可以"对话"——"我是形容词,如果前面是名词就激活我"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 SwiGLU(2020→至今的生产标准)
|
||||||
|
|
||||||
|
$$\text{SwiGLU}(x) = \text{SiLU}(x W_{\text{gate}}) \otimes (x W_{\text{up}}) \cdot W_{\text{down}}$$
|
||||||
|
|
||||||
|
```python
|
||||||
|
# SwiGLU 的实际代码(也是 LLaMA、DeepSeek、Mistral 等主流模型的实现)
|
||||||
|
|
||||||
|
class SwiGLU(nn.Module):
|
||||||
|
def __init__(self, dim, hidden_dim):
|
||||||
|
super().__init__()
|
||||||
|
# 三个权重矩阵(不是标准的两个)
|
||||||
|
self.gate_proj = nn.Linear(dim, hidden_dim, bias=False) # 门控通路
|
||||||
|
self.up_proj = nn.Linear(dim, hidden_dim, bias=False) # 值通路
|
||||||
|
self.down_proj = nn.Linear(hidden_dim, dim, bias=False) # 降维
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
# gate: 门控信号(SiLU 激活)
|
||||||
|
# up: 值信号(无激活,直接通过)
|
||||||
|
return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 参数量补偿:为什么 d_ff 变小了
|
||||||
|
|
||||||
|
| 方案 | 矩阵数 | 参数量 | d_ff(等参) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 标准 FFN | W₁, W₂ (2个) | 2 × d × d_ff | 4d |
|
||||||
|
| SwiGLU | W_gate, W_up, W_down (3个) | 3 × d × d_ff | **8d/3 ≈ 2.67d** |
|
||||||
|
|
||||||
|
```
|
||||||
|
等参数量下:
|
||||||
|
标准 FFN:d_ff = 4d → 2 × d × 4d = 8d²
|
||||||
|
SwiGLU:d_ff = 8d/3 → 3 × d × 8d/3 = 8d²
|
||||||
|
↑
|
||||||
|
参数总量相同,但 SwiGLU 表达能力更强
|
||||||
|
```
|
||||||
|
|
||||||
|
> 实际中,即使参数相当,SwiGLU 的困惑度(Perplexity)也比 GELU 低约 **8.3%**(文本任务)——这是"免费的性能提升"。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、GLU 变体对比
|
||||||
|
|
||||||
|
| 变体 | 门控激活函数 | 公式 | 特点 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **GLU(原始)** | Sigmoid | `σ(xW_g) ⊗ (xW_u)` | 门控有上限(0,1),表达受限 |
|
||||||
|
| **ReGLU** | ReLU | `ReLU(xW_g) ⊗ (xW_u)` | 最快,但仍可能死神经元 |
|
||||||
|
| **GeGLU** | GELU | `GELU(xW_g) ⊗ (xW_u)` | 视觉/多模态任务稍好 |
|
||||||
|
| **SwiGLU** | SiLU/Swish | `SiLU(xW_g) ⊗ (xW_u)` | **文本生成 SOTA,生产标准** |
|
||||||
|
|
||||||
|
### 选择指南
|
||||||
|
|
||||||
|
| 场景 | 推荐 | 原因 |
|
||||||
|
|---|---|---|
|
||||||
|
| LLM 文本生成 | **SwiGLU** | 困惑度最低,LLaMA/DeepSeek/Mistral 全部使用 |
|
||||||
|
| 视觉编码器 | GeGLU 或 GELU | 分类任务上略优(~2% Top-1 提升) |
|
||||||
|
| 延迟敏感 | ReGLU | Relu 计算成本最低,硬件原生支持 |
|
||||||
|
| 混合模态 | 编码器 GELU + 解码器 SwiGLU | 各取所长,推理可提速 ~15% |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、FFN = 知识的"键值记忆"
|
||||||
|
|
||||||
|
> 这个视角将 FFN 从"无聊的全连接层"升级为"模型的知识存储系统"
|
||||||
|
|
||||||
|
### 联想记忆假说
|
||||||
|
|
||||||
|
```
|
||||||
|
FFN(x) = W₂ · Act(W₁ · x)
|
||||||
|
|
||||||
|
W₁ 的每一行 = 一个"键"(Key),检测特定模式
|
||||||
|
W₂ 的对应列 = 一个"值"(Value),存储该模式对应的输出
|
||||||
|
|
||||||
|
过程:
|
||||||
|
1. W₁·x → 将输入与所有"键"匹配(内积 = 相似度)
|
||||||
|
2. Act → 过滤:只保留匹配度高的模式
|
||||||
|
3. W₂· ... → 激活的模式"写出"对应的值
|
||||||
|
```
|
||||||
|
|
||||||
|
### 实验证据
|
||||||
|
|
||||||
|
| 发现 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **知识定位** | FFN 的特定神经元可以对应具体的事实(如"埃菲尔铁塔在巴黎") |
|
||||||
|
| **可编辑性** | 修改 FFN 权重可以精确修改模型存储的事实(模型编辑) |
|
||||||
|
| **稀疏激活** | 对每个 Token,FFN 中只有少数神经元真正激活(和 MoE 思路一致) |
|
||||||
|
| **层间分工** | 浅层 FFN → 语法/局部模式、深层 FFN → 语义/全局知识 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、2025 前沿:激活函数本身也"可学习"
|
||||||
|
|
||||||
|
### 7.1 PolyGLU(2025年3月)
|
||||||
|
|
||||||
|
> **不再固定用一种激活函数,而是让每个神经元学习自己最适合的激活函数**
|
||||||
|
|
||||||
|
```
|
||||||
|
PolyGLU(x) = [ Σ g_k · σ_k(x·W_gate) ] ⊗ (x·W_up)
|
||||||
|
|
||||||
|
其中 σ_k 从候选池中选择:
|
||||||
|
{ ReLU, Tanh, SiLU, GELU }
|
||||||
|
|
||||||
|
g_k = 路由权重(每个神经元不同),训练中自动收敛
|
||||||
|
```
|
||||||
|
|
||||||
|
**训练后的层间分布(19K步训练)**:
|
||||||
|
|
||||||
|
```
|
||||||
|
层 0-2(浅层): GELU 35-40% | Tanh 15-25% | SiLU 15-20% | ReLU ~5%
|
||||||
|
层 3-14(中层): GELU 为主,逐步过渡
|
||||||
|
层 15-27(深层): Tanh 50-65% ← 深层网络偏好对称有界激活!
|
||||||
|
```
|
||||||
|
|
||||||
|
> 关键发现:深层网络的神经元**自发偏好 Tanh**(对称、有界),浅层偏好 GELU(概率性门控)。这暗示不同深度的层确实需要不同"类型"的非线性变换。
|
||||||
|
|
||||||
|
### 7.2 动态激活选择(LLaMA 4)
|
||||||
|
|
||||||
|
LLaMA 4 实验在 SwiGLU 和 GELU 之间做**输入级动态切换**:
|
||||||
|
- 用轻量门控网络根据输入内容选择激活函数
|
||||||
|
- 复杂推理任务 → 倾向于 SwiGLU(更强的特征交互)
|
||||||
|
- 简单模式匹配 → 倾向于 GELU(更快的计算)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、DeepSeek 风格的实际实现
|
||||||
|
|
||||||
|
### 标准 SwiGLU(如 LLaMA)
|
||||||
|
|
||||||
|
```python
|
||||||
|
class LlamaMLP(nn.Module):
|
||||||
|
def __init__(self, config):
|
||||||
|
super().__init__()
|
||||||
|
self.gate_proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
|
||||||
|
self.up_proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
|
||||||
|
self.down_proj = nn.Linear(config.intermediate_size, config.hidden_size, bias=False)
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
|
||||||
|
```
|
||||||
|
|
||||||
|
### DeepSeek-V3 的 MoE + SwiGLU
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 每个专家就是一个 SwiGLU FFN
|
||||||
|
class DeepSeekExpert(nn.Module):
|
||||||
|
def __init__(self, dim, moe_intermediate_size):
|
||||||
|
super().__init__()
|
||||||
|
self.gate_proj = nn.Linear(dim, moe_intermediate_size, bias=False)
|
||||||
|
self.up_proj = nn.Linear(dim, moe_intermediate_size, bias=False)
|
||||||
|
self.down_proj = nn.Linear(moe_intermediate_size, dim, bias=False)
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
|
||||||
|
|
||||||
|
# MoE 层:N 个专家 + 路由器
|
||||||
|
class DeepSeekMoE(nn.Module):
|
||||||
|
def __init__(self, dim, n_routed_experts=256, n_shared_experts=2, top_k=8):
|
||||||
|
super().__init__()
|
||||||
|
self.shared_experts = nn.ModuleList([
|
||||||
|
DeepSeekExpert(dim, dim * 2) for _ in range(n_shared_experts)
|
||||||
|
])
|
||||||
|
self.routed_experts = nn.ModuleList([
|
||||||
|
DeepSeekExpert(dim, dim * 2) for _ in range(n_routed_experts)
|
||||||
|
])
|
||||||
|
self.gate = nn.Linear(dim, n_routed_experts, bias=False)
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
# 共享专家(始终激活)
|
||||||
|
shared_out = sum(e(x) for e in self.shared_experts)
|
||||||
|
# 路由专家(稀疏激活 Top-K)
|
||||||
|
router_logits = self.gate(x)
|
||||||
|
topk_weights, topk_ids = torch.topk(router_logits.softmax(-1), self.top_k)
|
||||||
|
routed_out = 0
|
||||||
|
for i, expert_id in enumerate(topk_ids):
|
||||||
|
routed_out += topk_weights[i] * self.routed_experts[expert_id](x)
|
||||||
|
return shared_out + routed_out
|
||||||
|
```
|
||||||
|
|
||||||
|
> DeepSeek-V3 有 256 个路由专家 + 2 个共享专家,每个专家内部都是 SwiGLU FFN。详见 [[MoE 混合专家架构]]。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、进化总览
|
||||||
|
|
||||||
|
```
|
||||||
|
标准 FFN GLU 系列
|
||||||
|
──────── ────────
|
||||||
|
非线性来源: 激活函数 门控乘法
|
||||||
|
通路数: 单路 双路(值 + 门控)
|
||||||
|
交互阶数: 一阶 二阶(xᵢ·xⱼ)
|
||||||
|
参数效率: 基准 显著更优
|
||||||
|
参数量: 2 × d × d_ff 3 × d × d_ff
|
||||||
|
生产标准: 已过时 SwiGLU(2025年)
|
||||||
|
|
||||||
|
未来方向
|
||||||
|
────────
|
||||||
|
激活函数选择: 可学习、每个神经元不同
|
||||||
|
实现: PolyGLU、动态路由
|
||||||
|
目标: 让模型自主发现最优非线性
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、一句话总结
|
||||||
|
|
||||||
|
```
|
||||||
|
FFN 不是"无聊的全连接层"——
|
||||||
|
它是 Transformer 中参数最密集、负责存储世界知识的核心组件。
|
||||||
|
|
||||||
|
ReLU → GELU → SiLU → SwiGLU → PolyGLU 的进化线,
|
||||||
|
本质上是"从固定非线性到可学习、动态、输入感知的门控机制"的演进。
|
||||||
|
|
||||||
|
你正在用的 LLaMA、DeepSeek、Mistral、Qwen 的每一层中,
|
||||||
|
SwiGLU 正在用乘法门控默默地做着模型 2/3 的"思考"。
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[Transformer 架构详解]] — FFN 在完整架构中的位置
|
||||||
|
- [[大模型架构基础]] — 各组件全景概览
|
||||||
|
- [[MoE 混合专家架构]] — FFN 的稀疏化扩展:用 N 个 SwiGLU 替代 1 个
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新:2026-08-05*
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
# MoE 混合专家架构
|
||||||
|
|
||||||
|
> Mixture of Experts — 用稀疏激活实现"参数量 vs 计算量"的解耦,是 DeepSeek V4、GPT-4、Mixtral 等旗舰模型的核心架构
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、为什么要 MoE?
|
||||||
|
|
||||||
|
### 密集模型的困境
|
||||||
|
|
||||||
|
传统 Transformer 中,每个 Token 流经**所有** FFN [^FFN] 参数:
|
||||||
|
|
||||||
|
```
|
||||||
|
Token → FFN(全部参数参与计算)→ 输出
|
||||||
|
```
|
||||||
|
|
||||||
|
参数量越大 → 每次推理计算量越大 → 训练和推理成本线性增长。
|
||||||
|
|
||||||
|
### MoE 的核心思想
|
||||||
|
|
||||||
|
> **"参数多,但每次只用一小部分"**
|
||||||
|
|
||||||
|
```
|
||||||
|
Token → 路由器 → 选择最相关的几个专家 → 只激活它们 → 输出
|
||||||
|
↑
|
||||||
|
其他专家保持休眠
|
||||||
|
```
|
||||||
|
|
||||||
|
| | 密集模型 | MoE 模型 |
|
||||||
|
|---|---|---|
|
||||||
|
| **总参数量** | 100B | 可以到 1.6T(16倍) |
|
||||||
|
| **每次推理计算量** | 100B | 仅约 36B |
|
||||||
|
| **训练效率** | 基准 | 更高(同算力下能训练更大模型) |
|
||||||
|
| **推理延迟** | 基准 | 需要加载更多权重到显存 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、MoE 层的工作原理
|
||||||
|
|
||||||
|
### 数学公式
|
||||||
|
|
||||||
|
$$
|
||||||
|
\text{MoE}(x) = \sum_{i \in \text{TopK}(G(x), k)} G(x)_i \cdot E_i(x)
|
||||||
|
$$
|
||||||
|
|
||||||
|
其中:
|
||||||
|
|
||||||
|
| 符号 | 含义 |
|
||||||
|
|---|---|
|
||||||
|
| `G(x)` | 路由器/门控网络,输出每个专家的"置信度分数" |
|
||||||
|
| `TopK(G, k)` | 选择分数最高的 k 个专家(通常 k=2~8) |
|
||||||
|
| `E_i(x)` | 第 i 个专家(一个 FFN [^FFN] 子网络) |
|
||||||
|
| `G(x)_i` | Softmax 归一化后的专家权重 |
|
||||||
|
|
||||||
|
### 一句话总结
|
||||||
|
|
||||||
|
> 输入 Token → 路由器打分 → 选 Top-K 专家 → 加权合成输出
|
||||||
|
|
||||||
|
### 结构图解
|
||||||
|
|
||||||
|
```
|
||||||
|
输入 Token x
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────┐
|
||||||
|
│ 路由器 G │ ← 一个小型线性层,输出 N 个分数
|
||||||
|
│ (Gate) │ (N = 专家总数)
|
||||||
|
└─────┬─────┘
|
||||||
|
│ Softmax 归一化
|
||||||
|
│ 选出分数最高的 k 个
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ N 个专家(Expert) │
|
||||||
|
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐│
|
||||||
|
│ │ E₁ │ │ E₂ │ │ E₃ │... │ Eɴ ││
|
||||||
|
│ │💤 │ │🔥 │ │💤 │ │🔥 ││
|
||||||
|
│ └─────┘ └──┬──┘ └─────┘ └──┬──┘│
|
||||||
|
│ │ │ │
|
||||||
|
│ 只激活 k=2 个专家! │ │
|
||||||
|
└─────────────┼─────────────────┼─────┘
|
||||||
|
│ │
|
||||||
|
└─── 加权求和 ────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
输出 MoE(x)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、MoE 层 vs 标准 FFN 层
|
||||||
|
|
||||||
|
```
|
||||||
|
标准 Transformer 块: 使用 MoE 的 Transformer 块:
|
||||||
|
|
||||||
|
注意力层 [^Attn] 注意力层 [^Attn]
|
||||||
|
↓ ↓
|
||||||
|
FFN(全部参数) 路由器 → 选择专家
|
||||||
|
↓ ↓
|
||||||
|
注意力层 [^Attn] 被选中的专家(稀疏激活)
|
||||||
|
↓ ↓
|
||||||
|
FFN(全部参数) 注意力层 [^Attn]
|
||||||
|
↓
|
||||||
|
路由器 → 选择专家
|
||||||
|
↓
|
||||||
|
被选中的专家(稀疏激活)
|
||||||
|
```
|
||||||
|
|
||||||
|
> **只在 FFN 层引入 MoE**,注意力层保持不变(注意力机制本身就负责 Token 间信息交互,无需稀疏化)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、关键设计维度
|
||||||
|
|
||||||
|
### 1. 专家粒度
|
||||||
|
|
||||||
|
| 类型 | 说明 | 示例 |
|
||||||
|
|---|---|---|
|
||||||
|
| **粗粒度** | 少量大专家(如 8 个,每个完整 FFN 大小) | 早期 MoE、Mixtral 8×7B |
|
||||||
|
| **细粒度** | 大量小专家(如 384 个微专家,每个很小) | DeepSeek-V3/V4(64 个微专家/层,激活 6 个) |
|
||||||
|
|
||||||
|
细粒度的优势:
|
||||||
|
- 路由组合更灵活:从 N 选 k 变为 mN 选 mk,组合数暴增
|
||||||
|
- DeepSeek V4 每层约 **3630 万种**可能的专家组合
|
||||||
|
- 同等总参数下,每个专家更小,训练/推理更灵活
|
||||||
|
|
||||||
|
### 2. 共享专家 vs 路由专家
|
||||||
|
|
||||||
|
| 类型 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **共享专家** | 始终激活,捕捉通用模式(语法、基础常识) |
|
||||||
|
| **路由专家** | 按 Token 动态选择,负责特定领域(数学、代码、翻译...) |
|
||||||
|
|
||||||
|
DeepSeekMoE 采用两层设计:
|
||||||
|
- 2 个共享专家(always on)
|
||||||
|
- 62 个路由专家(每个 Token 激活 6 个)
|
||||||
|
|
||||||
|
共享专家提升训练稳定性,但可能降低专家专门化程度。
|
||||||
|
|
||||||
|
### 3. 路由器设计
|
||||||
|
|
||||||
|
```
|
||||||
|
简单线性路由器(当前主流):
|
||||||
|
|
||||||
|
router_logits = W_g · x ← 一个小矩阵,N × d_model
|
||||||
|
topk_experts = TopK(softmax(router_logits), k)
|
||||||
|
```
|
||||||
|
|
||||||
|
实际推理时的路由模式:
|
||||||
|
- 每个 Token **独立**路由(不考虑上下文)
|
||||||
|
- 序列中相邻 Token 可能路由到不同专家
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、负载均衡 — MoE 的核心挑战
|
||||||
|
|
||||||
|
### 问题
|
||||||
|
|
||||||
|
> 如果路由器"偷懒",总是选固定的几个专家 → 其他专家闲置 → 退化为密集模型
|
||||||
|
|
||||||
|
### 传统方案:辅助损失(Auxiliary Loss)
|
||||||
|
|
||||||
|
$$
|
||||||
|
L_{total} = L_{主任务} + \alpha \cdot L_{负载均衡}
|
||||||
|
$$
|
||||||
|
|
||||||
|
强制惩罚专家使用不均匀的情况。**问题**:梯度冲突,可能导致训练不稳定。
|
||||||
|
|
||||||
|
### 2025 前沿:无梯度负载均衡
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 动态偏置调整 — 不干扰主损失梯度
|
||||||
|
logits_i(t+1) = W_g · x + b_i(t) - γ · (f_i(t)/f̄(t) - 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
其中:
|
||||||
|
- `f_i(t)`:当前被路由到专家 i 的 Token 比例
|
||||||
|
- `f̄(t)`:理想平均比例 = 1/N
|
||||||
|
- 效果:专家使用率的变异系数 < 0.1,无梯度冲突
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、2025 年前沿进展
|
||||||
|
|
||||||
|
### 1. DAG-MoE [^DAG](ICML 2026)
|
||||||
|
|
||||||
|
> 不是简单加权平均专家输出,而是把选中的专家排列成**有向无环图(DAG, Directed Acyclic Graph)**,实现结构化的专家聚合(DAG 聚合)
|
||||||
|
|
||||||
|
```
|
||||||
|
传统 MoE: E₁↘
|
||||||
|
E₂ → 加权平均 → 输出
|
||||||
|
E₃↗
|
||||||
|
|
||||||
|
DAG-MoE: E₁ → E₃ ↘
|
||||||
|
E₂ → E₄ → E₆ → 输出(信息流经多个专家)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 允许**单层内多步推理**
|
||||||
|
- 模型学习最优的专家聚合结构(每个输入不同)
|
||||||
|
- 同等 FLOPs 下更强的表达能力
|
||||||
|
|
||||||
|
### 2. MoLE:查找表专家(ICML 2025 Oral)
|
||||||
|
|
||||||
|
> 将训练好的 FFN 专家**重新参数化**为查找表(LUT),专家计算变为查表操作
|
||||||
|
|
||||||
|
- 推理速度接近密集模型
|
||||||
|
- 大幅降低显存占用
|
||||||
|
- 使 MoE 在内存受限设备上部署成为可能
|
||||||
|
|
||||||
|
### 3. MoE + MLA(Multi-head Latent Attention,多头潜在注意力) [^MLA]
|
||||||
|
|
||||||
|
正交瓶颈联合优化:
|
||||||
|
|
||||||
|
| 瓶颈 | 方案 |
|
||||||
|
|---|---|
|
||||||
|
| FFN 计算量大 | MoE 稀疏激活 |
|
||||||
|
| 注意力 KV 缓存大 | MLA 低秩压缩 |
|
||||||
|
|
||||||
|
- ρ = 1/2 时:KV 缓存减少 **68%**,推理加速 **3.2×**
|
||||||
|
- 困惑度仅下降 0.8%
|
||||||
|
- DeepSeek V4 使用此组合
|
||||||
|
|
||||||
|
### 4. MoE-X:可解释 MoE(ICML 2025)
|
||||||
|
|
||||||
|
- 将 MoE 层理解为等效的大型稀疏 MLP
|
||||||
|
- 强制专家内部也做稀疏激活
|
||||||
|
- 可解释性超越 Sparse Autoencoder(SAE)方法
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、主流 MoE 模型对比
|
||||||
|
|
||||||
|
| 模型 | 总参数 | 激活参数 | 专家数 | 激活数 | 特点 |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| **Mixtral 8×7B** | 46.7B | 12.9B | 8 | 2 | 经典粗粒度 MoE |
|
||||||
|
| **DeepSeek-V3** | 671B | 37B | 256 | 8 | 细粒度 + 共享专家 |
|
||||||
|
| **DeepSeek-V4 Pro** | 1600B | 36B | 384/层 | 6 | 细粒度 + MLA + DSpark |
|
||||||
|
| **DeepSeek-V4 Flash** | 284B | 13B | 精简 | 精简 | Pro 的轻量版 |
|
||||||
|
| **GPT-4**(传闻) | 1.8T | ~280B | 16(推测) | 2 | 早批大规模 MoE |
|
||||||
|
|
||||||
|
> 趋势:专家数量越来越多,每个专家越来越小(细粒度),激活参数占比越来越低。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、MoE 的代价
|
||||||
|
|
||||||
|
| 代价 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **显存占用** | 所有专家都在 VRAM 里,即使大部分不激活 → 需要更多 GPU |
|
||||||
|
| **通信开销** | 多 GPU 部署时,Token 需要跨 GPU 路由到专家 |
|
||||||
|
| **训练不稳定** | 负载均衡损失与主损失可能冲突 |
|
||||||
|
| **微调困难** | 稀疏激活 → 梯度更稀疏 → 微调更难收敛 |
|
||||||
|
| **批次大小** | 每个专家实际收到的 Token 少 → 需要较大 batch size |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、总结
|
||||||
|
|
||||||
|
```
|
||||||
|
MoE = 用路由器在大量专家中选择少数激活,实现"参数膨胀但计算可控"
|
||||||
|
|
||||||
|
关键取舍:
|
||||||
|
优势:同等算力下更大的模型容量、更好的性能/成本比
|
||||||
|
代价:更高显存、更复杂的工程、训练和微调挑战
|
||||||
|
|
||||||
|
2025 年趋势:
|
||||||
|
细粒度 → DAG 聚合 → 可解释 → 查找表推理 → 与 MLA 协同
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[Transformer 架构详解]]
|
||||||
|
- [[大模型架构基础]]
|
||||||
|
- [[DeepSeek V4 系列]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 脚注
|
||||||
|
|
||||||
|
[^FFN]: **FFN(Feed-Forward Network,前馈神经网络)**:Transformer 中每个位置的独立全连接子网络。结构为两层 MLP:`W₂ · Act(W₁ · x + b₁) + b₂`,参数量约占整个 Transformer 块的 2/3,是模型"知识存储"的主要位置。现代模型多使用 SwiGLU 激活的变体。详见 [[FFN 前馈网络详解]]。
|
||||||
|
|
||||||
|
[^Attn]: **注意力层(Attention Layer)**:Transformer 的核心机制,负责 Token 之间的信息交互。通过 Q(Query)、K(Key)、V(Value)三个投影矩阵,让每个 Token "看到"并加权所有其他 Token,从而捕获上下文依赖关系。多头注意力(Multi-Head Attention)并行运行多组 Q/K/V,每组关注不同的语义模式。
|
||||||
|
|
||||||
|
[^MLA]: **MLA(Multi-head Latent Attention,多头潜在注意力)**:DeepSeek 提出的注意力压缩技术。核心思路是将 K 和 V 首先投影到一个低维潜在空间(`d_latent << d_model`),再从中展开供注意力计算使用。这大幅减少了 KV 缓存的显存占用——在 ρ = 1/2 时可缩减 68%,且对模型质量影响极小(困惑度仅降 0.8%)。MLA 与 MoE 是正交优化:MoE 省 FFN 计算,MLA 省注意力显存,两者叠加效果倍增。
|
||||||
|
|
||||||
|
[^DAG]: **DAG 聚合(DAG Aggregation)**:将选中的专家按有向无环图(DAG)的结构进行串联/并联组合,而非传统的简单加权平均。每个输入路由到一组专家后,模型学习这些专家之间最优的信息流动路径——例如 E₁ 的输出作为 E₃ 的输入,E₂ 的输出则直接进入最后阶段。这允许在单层 MoE 内完成**多步推理**,表达能力强于传统加权求和,同等 FLOPs 下能取得更好性能。DAG-MoE 发表于 ICML 2026。
|
||||||
@@ -0,0 +1,425 @@
|
|||||||
|
# Transformer 架构详解
|
||||||
|
|
||||||
|
> 2017 年,"Attention Is All You Need" 论文用自注意力取代了 RNN/LSTM,开启了现代大语言模型时代。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、Transformer 之前:RNN 的困境
|
||||||
|
|
||||||
|
```
|
||||||
|
RNN 的处理方式(串行):
|
||||||
|
Token₁ → Token₂ → Token₃ → ... → Tokenₙ
|
||||||
|
5ms 5ms 5ms 5ms = 5×n ms(无法并行)
|
||||||
|
|
||||||
|
Transformer 的处理方式(并行):
|
||||||
|
Token₁ ↘
|
||||||
|
Token₂ → 所有 Token 同时互相"看到" → 并行计算
|
||||||
|
Token₃ ↗ ≈ 5ms(与 n 无关)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 问题 | RNN/LSTM | Transformer |
|
||||||
|
|---|---|---|
|
||||||
|
| **并行性** | 串行,无法并行训练 | 完全并行,GPU 友好 |
|
||||||
|
| **长距离依赖** | 梯度消失/爆炸,远距离信息丢失 | 每个 Token 直接关注任意位置的 Token |
|
||||||
|
| **训练速度** | 慢(序列越长越慢) | 快得多 |
|
||||||
|
| **可解释性** | 难以解释隐藏状态 | 可直接可视化注意力权重 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、整体架构:编码器-解码器
|
||||||
|
|
||||||
|
原始 Transformer 用于机器翻译,包含编码器和解码器两部分。
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ 编码器(Encoder) │
|
||||||
|
│ ┌───────────────────────────┐ │
|
||||||
|
"我 爱 北京" → │ │ Encoder Block × 6 │ │
|
||||||
|
│ │ Self-Attn + FFN │ │
|
||||||
|
│ └───────────────────────────┘ │
|
||||||
|
└──────────────┬──────────────────┘
|
||||||
|
│ 编码后的表示(K, V)
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ 解码器(Decoder) │
|
||||||
|
│ ┌───────────────────────────┐ │
|
||||||
|
│ │ Decoder Block × 6 │ │
|
||||||
|
│ │ ① Masked Self-Attn │ │ → "I love Beijing"
|
||||||
|
│ │ ② Cross-Attn (用 K,V) │ │
|
||||||
|
│ │ ③ FFN │ │
|
||||||
|
│ └───────────────────────────┘ │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 一个 Block 内部(原始设计)
|
||||||
|
|
||||||
|
```
|
||||||
|
输入 x
|
||||||
|
│
|
||||||
|
├──→ Multi-Head Self-Attention ──→ ⊕ ──→ LayerNorm ──→
|
||||||
|
│ ↑ ↑
|
||||||
|
│ 残差连接 x 输出
|
||||||
|
│
|
||||||
|
└──→ Feed-Forward Network ──→ ⊕ ──→ LayerNorm ──→ 输出
|
||||||
|
↑ ↑
|
||||||
|
残差连接 传给下一层
|
||||||
|
```
|
||||||
|
|
||||||
|
### 两种主流归一化位置
|
||||||
|
|
||||||
|
| 方式 | 归一化位置 | 代表模型 | 特点 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Post-LN** | 残差之后 | 原始 Transformer | 训练不稳定,需要 warmup |
|
||||||
|
| **Pre-LN** | 子层之前 | GPT 系列、LLaMA | 训练更稳定,无需大量 warmup |
|
||||||
|
|
||||||
|
```
|
||||||
|
Post-LN:x + Attn(LayerNorm(x)) ← 原始论文
|
||||||
|
Pre-LN: x + Attn(LayerNorm(x)) 错 — 实际上是:
|
||||||
|
Pre-LN:LayerNorm(x + Attn(x)) 错 — Pre-LN 是:
|
||||||
|
|
||||||
|
Pre-LN 实际:x + Attn(LayerNorm(x)) — 等等,让我用图表示清楚:
|
||||||
|
|
||||||
|
Post-LN: x → SubLayer → Norm → + → 输出
|
||||||
|
Pre-LN: x → Norm → SubLayer → + → 输出
|
||||||
|
```
|
||||||
|
|
||||||
|
> Pre-LN 先将输入归一化再送入子层,然后做残差。GPT/LLaMA 全系使用 Pre-LN(或 RMSNorm + Pre-LN 变体)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、自注意力机制:完整推演
|
||||||
|
|
||||||
|
### 3.1 从"查字典"理解 Q/K/V
|
||||||
|
|
||||||
|
| 投影 | 类比 | 数学 | 含义 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Q(Query)** | 你的搜索关键词 | `X · W_Q` | "我在找什么信息?" |
|
||||||
|
| **K(Key)** | 所有条目的索引 | `X · W_K` | "每个词身上有什么标签?" |
|
||||||
|
| **V(Value)** | 条目的实际内容 | `X · W_V` | "每个词的实际信息是什么?" |
|
||||||
|
|
||||||
|
### 3.2 逐步计算示例
|
||||||
|
|
||||||
|
假设输入句子 "我 爱 NLP",模型维度 d=4,头维度 d_k=2:
|
||||||
|
|
||||||
|
**Step 1 — 输入嵌入**
|
||||||
|
```
|
||||||
|
我: [0.1, 0.3, 0.5, 0.2]
|
||||||
|
爱: [0.4, 0.1, 0.3, 0.6]
|
||||||
|
NLP: [0.2, 0.5, 0.1, 0.3]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2 — 计算 K 和 Q(只演示一个头的投影)**
|
||||||
|
```
|
||||||
|
K = X · W_K (3×4)×(4×2) = 3×2 矩阵
|
||||||
|
K_我 = [0.8, 0.2]
|
||||||
|
K_爱 = [0.3, 0.9]
|
||||||
|
K_NLP = [0.5, 0.4]
|
||||||
|
|
||||||
|
Q_爱 = [0.6, 0.3] ("爱"这个位置的 Query)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3 — 计算注意力分数(Q_爱 × K^T)**
|
||||||
|
```
|
||||||
|
Q_爱 · K_我 = 0.6×0.8 + 0.3×0.2 = 0.48 + 0.06 = 0.54
|
||||||
|
Q_爱 · K_爱 = 0.6×0.3 + 0.3×0.9 = 0.18 + 0.27 = 0.45
|
||||||
|
Q_爱 · K_NLP = 0.6×0.5 + 0.3×0.4 = 0.30 + 0.12 = 0.42
|
||||||
|
|
||||||
|
scores = [0.54, 0.45, 0.42]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4 — 缩放 + Softmax**
|
||||||
|
```
|
||||||
|
scaled = scores / √2 = [0.38, 0.32, 0.30]
|
||||||
|
weights = softmax(scaled) = [0.35, 0.33, 0.32]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 5 — 加权求和 V**
|
||||||
|
```
|
||||||
|
V_我 = [0.7, 0.1]
|
||||||
|
V_爱 = [0.2, 0.8]
|
||||||
|
V_NLP = [0.4, 0.5]
|
||||||
|
|
||||||
|
output_爱 = 0.35×[0.7,0.1] + 0.33×[0.2,0.8] + 0.32×[0.4,0.5]
|
||||||
|
= [0.245, 0.035] + [0.066, 0.264] + [0.128, 0.160]
|
||||||
|
= [0.439, 0.459]
|
||||||
|
```
|
||||||
|
|
||||||
|
> 位置"爱"的输出融合了"我"(35%)、"NLP"(32%)和自身(33%)的信息——这正是"理解上下文"的本质。
|
||||||
|
|
||||||
|
### 3.3 矩阵形式(实际实现)
|
||||||
|
|
||||||
|
$$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) V$$
|
||||||
|
|
||||||
|
- **QK^T**:N×N 的注意力矩阵,每对 Token 一个分数
|
||||||
|
- **÷ √d_k**:缩放因子。d_k 越大点积值越大 → softmax 趋向 one-hot → 梯度消失。除以 √d_k 保持方差 ≈ 1
|
||||||
|
- **Softmax**:沿最后维(Key 维度)归一化,每行和为 1
|
||||||
|
- **× V**:用注意力权重对 Value 加权求和
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、多头注意力:并行多个"视角"
|
||||||
|
|
||||||
|
### 4.1 为什么需要多头?
|
||||||
|
|
||||||
|
```
|
||||||
|
单头可能只学到一种注意力模式:
|
||||||
|
"我" → 关注了 "爱"
|
||||||
|
"爱" → 关注了 "北京"
|
||||||
|
所有头都只关注相邻词 ← 浪费了注意力的表达能力
|
||||||
|
|
||||||
|
多头允许并行学习多种模式:
|
||||||
|
头 1:语法结构(主语→谓语)
|
||||||
|
头 2:长距离共指("它"→ 前文的"北京")
|
||||||
|
头 3:语义关联("医生"→ "医院"→ "病人")
|
||||||
|
头 4:位置模式(局部上下文窗口)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 数学公式
|
||||||
|
|
||||||
|
$$\text{head}_i = \text{Attention}(Q W_i^Q, K W_i^K, V W_i^V)$$
|
||||||
|
|
||||||
|
$$\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, ..., \text{head}_h) W^O$$
|
||||||
|
|
||||||
|
每个头有自己独立的投影矩阵 W_Q、W_K、W_V,维度为 d_model × d_k(其中 d_k = d_model / h)。
|
||||||
|
|
||||||
|
### 4.3 计算量并不是 h 倍!
|
||||||
|
|
||||||
|
| | 单头 (d_model=512) | 8头 (每头 d_k=64) |
|
||||||
|
|---|---|---|
|
||||||
|
| Q投影参数 | 512×512 = 262K | 8×512×64 = 262K |
|
||||||
|
| K投影参数 | 同上 | 同上 |
|
||||||
|
| V投影参数 | 同上 | 同上 |
|
||||||
|
| 总参数 | ≈ 786K | ≈ 786K + W_O(512×512) ≈ 1M |
|
||||||
|
|
||||||
|
> 计算量大致相同,只是**把工作分给多个头并行做**,每个头在更小的空间(d_k)中关注不同的模式。
|
||||||
|
|
||||||
|
### 4.4 生产实践中的头数配置
|
||||||
|
|
||||||
|
| 模型 | d_model | 头数 | d_k |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 原始 Transformer | 512 | 8 | 64 |
|
||||||
|
| GPT-3 | 12288 | 96 | 128 |
|
||||||
|
| LLaMA 70B | 8192 | 64 | 128 |
|
||||||
|
| DeepSeek-V3 | — | — | 使用 MLA 替代标准多头 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、位置编码:告诉模型"顺序"
|
||||||
|
|
||||||
|
注意力机制本身是**置换不变**的——打乱输入顺序,注意力分数矩阵只是行列交换,输出值不变。所以必须显式注入位置信息。
|
||||||
|
|
||||||
|
### 方案对比
|
||||||
|
|
||||||
|
| 方案 | 原理 | 优点 | 缺点 | 代表模型 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| **Sinusoidal(正弦)** | 不同频率的正弦/余弦波叠加 | 可外推、无参 | 固定模式 | 原始 Transformer |
|
||||||
|
| **Learned** | 可学习的 pos_embed 表 | 灵活 | 不能超出训练长度 | BERT、ViT |
|
||||||
|
| **RoPE(旋转位置编码)** | 用旋转矩阵编码相对位置 | 天然编码相对位置、可外推 | 长序列扩展需技巧 | LLaMA、Qwen、DeepSeek |
|
||||||
|
| **ALiBi** | 给注意力分数加线性偏置 | 简单、外推最强 | 表达能力有限 | BLOOM |
|
||||||
|
|
||||||
|
### RoPE 核心思想
|
||||||
|
|
||||||
|
> **不是往 embedding 里加位置向量,而是把 Q 和 K "旋转"一个角度,角度大小取决于位置。**
|
||||||
|
|
||||||
|
```
|
||||||
|
位置 m 的 Q:旋转 m×θ
|
||||||
|
位置 n 的 K:旋转 n×θ
|
||||||
|
|
||||||
|
Q·K = (rotated_Q_m)·(rotated_K_n) = 关于 (m-n) 的函数
|
||||||
|
↑
|
||||||
|
只依赖相对位置!
|
||||||
|
```
|
||||||
|
|
||||||
|
RoPE 扩展:
|
||||||
|
- **NTK-aware scaling**:调高基频(如 10000→500000),让旋转更慢,支持更长上下文
|
||||||
|
- **YaRN**:NTK + 额外微调,将 Llama 从 4K 扩展到 128K
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、三种架构变体:选哪种?
|
||||||
|
|
||||||
|
### 6.1 编码器-only(如 BERT)
|
||||||
|
|
||||||
|
```
|
||||||
|
输入:"我 [MASK] 北京" → 编码器 → 每个位置的上下文表示 → 预测 [MASK] = "爱"
|
||||||
|
|
||||||
|
特点:
|
||||||
|
- 双向注意力(能看到整个句子)
|
||||||
|
- 适合:分类、实体识别、语义搜索
|
||||||
|
- 不能做生成(没有解码器)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 解码器-only(如 GPT、LLaMA、DeepSeek V4)
|
||||||
|
|
||||||
|
```
|
||||||
|
输入:"今天天气" → 因果注意力(只看左边)→ 预测下一个 Token "真"
|
||||||
|
"今天天气真" → ... → 预测 "好"
|
||||||
|
|
||||||
|
特点:
|
||||||
|
- 因果掩码(Causal Mask):每个 Token 只能看自己和左边
|
||||||
|
- 适合:对话、代码生成、创意写作
|
||||||
|
- 自回归生成,输入=输出(训练时位移一位即可)
|
||||||
|
- 现代 LLM 几乎全部使用此方案
|
||||||
|
```
|
||||||
|
|
||||||
|
**因果掩码示意**:
|
||||||
|
|
||||||
|
```
|
||||||
|
注意力分数矩阵(× = 被 mask 为 -∞):
|
||||||
|
|
||||||
|
我 爱 北京 天安门
|
||||||
|
我 ✓ × × × ← "我"只能看到自己
|
||||||
|
爱 ✓ ✓ × × ← "爱"能看到"我"和自己
|
||||||
|
北京 ✓ ✓ ✓ × ← ...
|
||||||
|
天安门✓ ✓ ✓ ✓
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 编码器-解码器(如 T5)
|
||||||
|
|
||||||
|
```
|
||||||
|
编码器(双向):处理源语言 → 生成 K、V
|
||||||
|
解码器(因果 + 交叉注意力):用 K、V 辅助生成目标语言
|
||||||
|
|
||||||
|
交叉注意力(Cross-Attention):
|
||||||
|
解码器的 Q ← 来自解码器自身("这句话接下来该说什么?")
|
||||||
|
解码器的 K,V ← 来自编码器("原文说了什么?")
|
||||||
|
```
|
||||||
|
|
||||||
|
| 架构 | 自注意力方式 | 能否生成 | 代表 | 适合任务 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 编码器-only | 双向 | ❌ | BERT | 理解/分类 |
|
||||||
|
| 解码器-only | 因果(单向) | ✅ | GPT, LLaMA | 生成/对话 |
|
||||||
|
| 编码器-解码器 | 双向 + 交叉 | ✅ | T5, BART | 翻译/摘要 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、训练与推理
|
||||||
|
|
||||||
|
### 7.1 训练:Teacher Forcing
|
||||||
|
|
||||||
|
```
|
||||||
|
输入: "今天 天气 真" 目标: "天气 真 好"
|
||||||
|
↑
|
||||||
|
模型被训练来预测每个位置的下一个 Token
|
||||||
|
|
||||||
|
实际一次性计算:
|
||||||
|
输入 [今天, 天气, 真]
|
||||||
|
→ 因果掩码确保"今天"看不到后面
|
||||||
|
→ 输出 [P(天气), P(真), P(好)]
|
||||||
|
→ Loss = CrossEntropy(预测, 实际目标)
|
||||||
|
```
|
||||||
|
|
||||||
|
> 训练时**一次前向**算出所有位置的预测,因为目标已知、且有因果掩码保护。
|
||||||
|
|
||||||
|
### 7.2 推理:自回归生成
|
||||||
|
|
||||||
|
```
|
||||||
|
训练时可以并行(目标已知),推理必须串行(目标未知):
|
||||||
|
|
||||||
|
Step 1: "今天" → 预测 "天气"
|
||||||
|
Step 2: "今天天气" → 预测 "真"
|
||||||
|
Step 3: "今天天气真" → 预测 "好"
|
||||||
|
Step 4: "今天天气真好" → 预测 <eos>
|
||||||
|
|
||||||
|
每次都要重新计算全序列?→ 不,用 KV Cache!
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 KV Cache:推理加速的关键
|
||||||
|
|
||||||
|
```
|
||||||
|
未使用 KV Cache:
|
||||||
|
Step 1:计算 "今天" 的 Q、K、V ──────────── 1个Token
|
||||||
|
Step 2:计算 "今天天气" 的 Q、K、V ──────── 2个Token ← 重新算了"今天"!
|
||||||
|
Step 3:计算 "今天天气真" 的 Q、K、V ────── 3个Token ← 又重算了!
|
||||||
|
...
|
||||||
|
|
||||||
|
使用 KV Cache:
|
||||||
|
Step 1:计算 "今天" → 缓存 K₁、V₁
|
||||||
|
Step 2:只算 "天气" 的 Q、K、V + 用缓存的 K₁、V₁ → 缓存 K₁K₂、V₁V₂
|
||||||
|
Step 3:只算 "真" 的 Q、K、V + 用缓存的 K₁K₂、V₁V₂ → ...
|
||||||
|
...
|
||||||
|
每个 Step 只算 1 个新 Token!开销从 O(n²) 降到 O(n)(单步)。
|
||||||
|
```
|
||||||
|
|
||||||
|
> KV Cache 的代价:显存占用随序列长度线性增长。MLA(多头潜在注意力)通过低秩压缩解决此问题——详见 [[MoE 混合专家架构#MLA(Multi-head Latent Attention,多头潜在注意力)|MLA 详解]]。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、高效注意力变体
|
||||||
|
|
||||||
|
标准自注意力是 **O(n²)** 复杂度(n = 序列长度)。对长序列需优化:
|
||||||
|
|
||||||
|
### 8.1 FlashAttention(事实标准)
|
||||||
|
|
||||||
|
> **IO 感知的精确注意力算法**——数学结果完全等价于标准注意力,但通过算子融合大幅减少显存读写。
|
||||||
|
|
||||||
|
```
|
||||||
|
标准计算: FlashAttention:
|
||||||
|
QK^T → 写回 HBM 将 Q、K、V 分块(tile)
|
||||||
|
Softmax → 写回 HBM 每个块在 SRAM 中完成全部计算
|
||||||
|
乘 V → 写回 HBM 只有最终结果写回 HBM
|
||||||
|
↑ 3次 HBM 读写 ↑ 约 1/n 的 HBM 读写
|
||||||
|
```
|
||||||
|
|
||||||
|
实测效果:相比朴素实现,吞吐量提升 **~32%**(A100),现为 PyTorch 2.0+ 默认后端。
|
||||||
|
|
||||||
|
### 8.2 稀疏/线性注意力(长序列场景)
|
||||||
|
|
||||||
|
| 方案 | 策略 | 复杂度 | 代表 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Longformer** | 局部滑动窗口 + 全局 Token | O(n) | 文档级 NLP |
|
||||||
|
| **BigBird** | 局部 + 全局 + 随机 | O(n) | — |
|
||||||
|
| **Performer** | 随机特征近似 softmax | O(n) | — |
|
||||||
|
| **Mamba/SSM** | 状态空间模型替代注意力 | O(n) | 超长序列 |
|
||||||
|
|
||||||
|
> 经验法则:序列 < 4K Token → 标准注意力 + FlashAttention 即可。长文档/代码库场景才需稀疏注意力或 SSM。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、现代生产优化总览
|
||||||
|
|
||||||
|
| 优化手段 | 效果 | 代价 |
|
||||||
|
|---|---|---|
|
||||||
|
| **混合精度(bf16/fp16)** | 训练/推理速度翻倍 | 质量损失可忽略 |
|
||||||
|
| **梯度检查点** | 显存降低 50%+ | 训练慢 20% |
|
||||||
|
| **FlashAttention** | 推理加速 ~30%,显存降低 | 无(数学等价) |
|
||||||
|
| **算子融合(RMSNorm, xFormers)** | 减少 kernel launch 开销 | 无 |
|
||||||
|
| **序列分桶** | 减少 padding 浪费 | 实现复杂度增加 |
|
||||||
|
| **量化(INT8/INT4)** | 显存降低 4-8× | 轻微质量下降 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、总结
|
||||||
|
|
||||||
|
```
|
||||||
|
Transformer 的核心思想就三条:
|
||||||
|
|
||||||
|
1. 自注意力(Self-Attention)
|
||||||
|
Q·K 算关联 → Softmax 归一化 → ×V 合成上下文
|
||||||
|
每个 Token 直接"看到"所有 Token
|
||||||
|
|
||||||
|
2. 多头(Multi-Head)
|
||||||
|
并行跑多个注意力,每个头学不同的关系模式
|
||||||
|
总计算量不变,表达能力翻倍
|
||||||
|
|
||||||
|
3. 位置编码(Positional Encoding)
|
||||||
|
注意力不感知顺序 → 注入位置信息
|
||||||
|
RoPE 是当前主流:Q/K 旋转角度 = 位置函数
|
||||||
|
|
||||||
|
Transformer 不只是一篇论文——
|
||||||
|
它是整个现代大语言模型时代的起点。
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[大模型架构基础]] — 大模型的各组件总览
|
||||||
|
- [[FFN 前馈网络详解]] — Transformer 中参数量最大的组件
|
||||||
|
- [[MoE 混合专家架构]] — 如何用稀疏专家替代 FFN
|
||||||
|
- [[多模态大模型]] — Transformer 如何扩展到图像/音频
|
||||||
|
- [[DeepSeek V4 系列]] — Transformer + MoE + MLA 的实际应用
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新:2026-08-05*
|
||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
# 多模态大模型(Multimodal LLM, MLLM)
|
||||||
|
|
||||||
|
## 什么是多模态?
|
||||||
|
|
||||||
|
**模态(Modality)** = 数据的感知/表达形式。人类通过多种模态理解世界:
|
||||||
|
|
||||||
|
| 模态 | 示例 |
|
||||||
|
|---|---|
|
||||||
|
| **文本** | 文章、代码、对话 |
|
||||||
|
| **图像** | 照片、图表、截图 |
|
||||||
|
| **音频** | 语音、音乐、环境声 |
|
||||||
|
| **视频** | 连续图像帧 + 音频 |
|
||||||
|
|
||||||
|
**多模态大模型** = 能同时理解和处理**多种模态数据**的 AI 模型,而非仅限于文本。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 为什么需要多模态?
|
||||||
|
|
||||||
|
> 纯文本模型只能"读文字",无法"看图片"、"听声音"。
|
||||||
|
|
||||||
|
现实世界的信息天然是多模态的:
|
||||||
|
- 医生既要看病历(文本),也要看 CT 片(图像)
|
||||||
|
- 自动驾驶需要同时处理摄像头(图像)、雷达(点云)、地图(结构化数据)
|
||||||
|
- 社交媒体帖子包含文字 + 图片 + 视频
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 基本架构(三大组件)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ 视觉编码器 │ ← 处理图像/视频输入
|
||||||
|
│ Vision Encoder │ (如 ViT、SigLIP)
|
||||||
|
└────────┬────────────┘
|
||||||
|
│ 视觉特征
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ 投影器/连接器 │ ← 将视觉特征映射到语言空间
|
||||||
|
│ Projector │ (如 MLP、Q-Former)
|
||||||
|
└────────┬────────────┘
|
||||||
|
│ 对齐后的 token
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ 大语言模型 │ ← 核心推理引擎
|
||||||
|
│ LLM Backbone │ (如 DeepSeek、LLaMA、Qwen)
|
||||||
|
└─────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 工作流程
|
||||||
|
|
||||||
|
1. 图像 → 视觉编码器 → 视觉特征向量
|
||||||
|
2. 视觉特征 → 投影器 → 对齐到语言模型的 token 空间
|
||||||
|
3. 文本 token + 视觉 token → LLM → 生成回复
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心能力
|
||||||
|
|
||||||
|
| 能力 | 说明 | 示例 |
|
||||||
|
|---|---|---|
|
||||||
|
| **视觉问答(VQA)** | 根据图片回答问题 | "这张图里有几只猫?" |
|
||||||
|
| **图像描述** | 自动生成图片文字描述 | 为盲人描述照片内容 |
|
||||||
|
| **多模态对话** | 图文混合交互 | "分析这张财报图表" |
|
||||||
|
| **OCR 理解** | 理解图片中的文字 | 识别截图、海报、PDF |
|
||||||
|
| **视觉推理** | 多步骤逻辑推理 | "如果把这个方块旋转90°会怎样?" |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 主流多模态模型(2025-2026)
|
||||||
|
|
||||||
|
| 模型 | 开发商 | 特点 |
|
||||||
|
|---|---|---|
|
||||||
|
| **GPT-4V / GPT-4o** | OpenAI | 原生多模态,实时语音+视觉 |
|
||||||
|
| **Gemini 系列** | Google | 原生多模态,Ultra/Pro/Flash/Nano 全系覆盖 |
|
||||||
|
| **Claude 系列** | Anthropic | 强大的图像理解、图表分析能力 |
|
||||||
|
| **Qwen-VL 系列** | 阿里通义 | 开源,中英双语 |
|
||||||
|
| **InternVL 系列** | 上海 AI 实验室 | 开源,CVPR 2025 发表 Mono-InternVL |
|
||||||
|
| **DeepSeek-VL** | DeepSeek | 注意:V4 系列目前 **仅文本**,视觉版待发布 |
|
||||||
|
| **LLaVA 系列** | 学术界 | 开源先驱,推动 MLLM 研究方向 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2025 年前沿方向
|
||||||
|
|
||||||
|
### 1. 高效/轻量化 MLLM
|
||||||
|
- 视觉 Token 压缩(降低 Transformer 二次复杂度)
|
||||||
|
- MoE 架构(如 MoE-LLaVA)
|
||||||
|
- 边缘设备部署(MobileVLM、TinyLLaVA、Gemini Nano)
|
||||||
|
|
||||||
|
### 2. 单体式 MLLM(Monolithic MLLM)
|
||||||
|
- **Mono-InternVL**(CVPR 2025):将视觉编码直接集成到 LLM 内部
|
||||||
|
- 减少 67% 首 Token 延迟,解决灾难性遗忘
|
||||||
|
|
||||||
|
### 3. 长链视觉推理
|
||||||
|
- **Insight-V**:多智能体系统(推理 agent + 总结 agent)
|
||||||
|
- 跨 7 个基准平均提升 7.5%
|
||||||
|
|
||||||
|
### 4. 统一多模态表征
|
||||||
|
- **UnifiedMLLM**:单一模型处理多种多模态任务
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 主要挑战
|
||||||
|
|
||||||
|
1. **长序列效率**:一张图 = 数百到数千个 token,多图/视频成本极高
|
||||||
|
2. **幻觉问题**:模型可能"看到"不存在的物体
|
||||||
|
3. **计算成本**:训练和推理资源消耗远超纯文本模型
|
||||||
|
4. **评估困难**:多模态基准测试尚不成熟
|
||||||
|
5. **安全对齐**:视觉输入可能绕过文本安全过滤器
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与纯文本模型对比
|
||||||
|
|
||||||
|
| 维度 | 纯文本 LLM | 多模态 MLLM |
|
||||||
|
|---|---|---|
|
||||||
|
| 输入 | 仅文本 | 文本 + 图像 + 音频 + 视频 |
|
||||||
|
| 参数量 | 较小(相对) | 需额外的视觉编码器参数 |
|
||||||
|
| 推理成本 | 较低 | 较高(视觉 token 开销大) |
|
||||||
|
| 应用范围 | 对话、写作、编程 | 医疗影像、自动驾驶、设计 |
|
||||||
|
| 成熟度 | 较高 | 快速发展中 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
多模态是 AI 走向通用人工智能(AGI)的关键一步。当前的 V4 Pro/Flash 等纯文本模型虽强,但"看不到世界"仍是巨大局限。理解多模态架构和原理,是理解下一代 AI 的必要基础。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[Transformer 架构详解]]
|
||||||
|
- [[DeepSeek V4 系列]]
|
||||||
|
- [[大模型架构基础]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新:2026-08-05*
|
||||||
+248
@@ -0,0 +1,248 @@
|
|||||||
|
# 大模型架构基础
|
||||||
|
|
||||||
|
> 理解现代大语言模型的底层架构 — Transformer、注意力机制与关键组件
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 发展脉络
|
||||||
|
|
||||||
|
```
|
||||||
|
2017 Transformer 论文
|
||||||
|
│ "Attention Is All You Need"
|
||||||
|
▼
|
||||||
|
2018 GPT-1 / BERT
|
||||||
|
│ 解码器-only / 编码器-only
|
||||||
|
▼
|
||||||
|
2020 GPT-3(175B)— Scaling Law 确立
|
||||||
|
▼
|
||||||
|
2022 ChatGPT / GPT-3.5 — RLHF 对齐
|
||||||
|
▼
|
||||||
|
2023 GPT-4 / LLaMA / Claude 2
|
||||||
|
│ 多模态、MoE 兴起
|
||||||
|
▼
|
||||||
|
2024 LLaMA 3 / Qwen 2.5 / DeepSeek-V3
|
||||||
|
▼
|
||||||
|
2025 GPT-5 / Claude Opus 5 / DeepSeek-V4
|
||||||
|
大规模 MoE、混合注意力、推理时扩展
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、Transformer 架构
|
||||||
|
|
||||||
|
现代大语言模型的基石,发表于 2017 年。核心思想:用**自注意力机制**取代循环/卷积,实现并行计算。深度讲解见 [[Transformer 架构详解]]。
|
||||||
|
|
||||||
|
### 架构总览
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┐
|
||||||
|
输入文本 → │ Embedding │ → Token 向量
|
||||||
|
└──────┬───────┘
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────┐
|
||||||
|
│ Transformer Block × N │ ← 重复 N 层(数十到数百层)
|
||||||
|
│ ┌───────────────────────┐ │
|
||||||
|
│ │ Multi-Head Attention │ │ ← 核心:自注意力
|
||||||
|
│ │ + Layer Norm + 残差 │ │
|
||||||
|
│ ├───────────────────────┤ │
|
||||||
|
│ │ Feed-Forward (FFN) │ │ ← 逐位置的全连接网络
|
||||||
|
│ │ + Layer Norm + 残差 │ │
|
||||||
|
│ └───────────────────────┘ │
|
||||||
|
└─────────────┬───────────────┘
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ 输出头 │ → 预测下一个 Token
|
||||||
|
└──────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 三种变体
|
||||||
|
|
||||||
|
| 类型 | 代表模型 | 特点 |
|
||||||
|
|---|---|---|
|
||||||
|
| **编码器-only** | BERT、RoBERTa | 双向注意力,适合理解任务(分类、NER) |
|
||||||
|
| **解码器-only** | GPT 系列、LLaMA、DeepSeek | 因果注意力(只看左边),适合生成任务 |
|
||||||
|
| **编码器-解码器** | T5、BART | 融合两者,适合翻译、摘要 |
|
||||||
|
|
||||||
|
> 现代大语言模型**几乎全部使用解码器-only**(自回归生成)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、自注意力机制(Self-Attention)
|
||||||
|
|
||||||
|
### 直观理解
|
||||||
|
|
||||||
|
> 让每个词"看到"句子中所有其他词,并决定应该关注哪些。
|
||||||
|
|
||||||
|
```
|
||||||
|
"我 爱 北京 天安门"
|
||||||
|
│ │ │ │
|
||||||
|
└─────┼──────┼───────┘
|
||||||
|
│ │
|
||||||
|
每个词都和所有词计算关联度(注意力权重)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 数学过程
|
||||||
|
|
||||||
|
对每个输入的 Token 向量,计算三个投影:
|
||||||
|
|
||||||
|
| | 符号 | 含义 |
|
||||||
|
|---|---|---|
|
||||||
|
| **Q(Query)** | 查询 | "我在找什么?" |
|
||||||
|
| **K(Key)** | 键 | "我有什么?" |
|
||||||
|
| **V(Value)** | 值 | "我的实际内容" |
|
||||||
|
|
||||||
|
$$
|
||||||
|
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) V
|
||||||
|
$$
|
||||||
|
|
||||||
|
步骤:
|
||||||
|
1. **Q × K^T** → 计算每对 token 之间的关联分数(注意力矩阵)
|
||||||
|
2. **÷ √d_k** → 缩放,防止梯度消失
|
||||||
|
3. **Softmax** → 归一化为概率分布
|
||||||
|
4. **× V** → 用注意力权重加权求和,得到输出
|
||||||
|
|
||||||
|
### 多头注意力(Multi-Head Attention)
|
||||||
|
|
||||||
|
> 不是做一次注意力,而是并行做多次(如 8/16/32 个头),每个头关注不同的语义模式。
|
||||||
|
|
||||||
|
- 头 1 可能关注"语法结构"
|
||||||
|
- 头 2 可能关注"实体关系"
|
||||||
|
- 头 3 可能关注"长距离依赖"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、关键组件
|
||||||
|
|
||||||
|
### 1. Token 与 Tokenizer
|
||||||
|
|
||||||
|
| 概念 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **Token** | 文本被拆分的最小语义单元 |
|
||||||
|
| **Tokenizer** | 将文本切分为 Token 的工具(BPE、SentencePiece 等) |
|
||||||
|
| **词表大小** | 通常 32K ~ 256K,DeepSeek V4 使用了更大词表 |
|
||||||
|
|
||||||
|
```
|
||||||
|
"Hello, world!" → ["Hello", ",", " world", "!"]
|
||||||
|
"你好世界" → ["你好", "世界"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 位置编码(Positional Encoding)
|
||||||
|
|
||||||
|
Transformer 本身**不感知顺序**,需要额外注入位置信息:
|
||||||
|
|
||||||
|
| 类型 | 说明 | 代表 |
|
||||||
|
|---|---|---|
|
||||||
|
| **绝对位置编码** | 每个位置有唯一的向量 | 原始 Transformer 的正弦编码 |
|
||||||
|
| **相对位置编码** | 编码 token 之间的相对距离 | T5 的相对偏置 |
|
||||||
|
| **旋转位置编码(RoPE)** | 对 Q/K 做旋转,编码相对位置 | LLaMA、DeepSeek、Qwen 主流方案 |
|
||||||
|
|
||||||
|
### 3. 前馈网络(Feed-Forward Network, FFN)
|
||||||
|
|
||||||
|
```
|
||||||
|
FFN(x) = Act(W₂ · Act(W₁ · x + b₁) + b₂)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 两层全连接,中间有激活函数(GELU/SwiGLU)
|
||||||
|
- 参数量占比最大(约 2/3)
|
||||||
|
- SwiGLU 是现代模型的首选激活函数
|
||||||
|
- 深度讲解见 [[FFN 前馈网络详解]]
|
||||||
|
|
||||||
|
### 4. 残差连接(Residual Connection)
|
||||||
|
|
||||||
|
```
|
||||||
|
输出 = LayerNorm(x + SubLayer(x))
|
||||||
|
```
|
||||||
|
|
||||||
|
- 缓解深层网络的梯度消失
|
||||||
|
- 让模型可以"跳过"不必要的变化
|
||||||
|
- GPT 使用 Pre-LN(层归一化在子层之前)
|
||||||
|
|
||||||
|
### 5. 层归一化(Layer Normalization)
|
||||||
|
|
||||||
|
- 对每个样本的特征维度做归一化
|
||||||
|
- 稳定训练、加速收敛
|
||||||
|
- 现代主流:**RMSNorm**(去掉均值中心化,更快更简单)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、训练范式
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┐
|
||||||
|
│ 1. 预训练 │ 海量互联网文本,无监督学习(预测下一个 Token)
|
||||||
|
│ Pretraining │ 数十 TB 数据,数万 GPU,数周到数月
|
||||||
|
└──────┬───────┘
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ 2. 监督微调 │ 高质量人工标注的指令-回复对
|
||||||
|
│ SFT │ 让模型学会"对话格式"和"遵循指令"
|
||||||
|
└──────┬───────┘
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ 3. 对齐训练 │ RLHF / DPO / RLVR
|
||||||
|
│ Alignment │ 让模型输出更安全、更有用、更符合人类偏好
|
||||||
|
└──────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键概念
|
||||||
|
|
||||||
|
| 概念 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **Scaling Law** | 模型性能随参数量、数据量、计算量幂律增长 |
|
||||||
|
| **涌现能力** | 大模型独有的、小模型没有的能力(如思维链推理) |
|
||||||
|
| **RLHF** | 基于人类反馈的强化学习 — 训练奖励模型指导策略优化 |
|
||||||
|
| **DPO** | 直接偏好优化 — 更简单地对齐方法,不需要单独的奖励模型 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、推理时技术
|
||||||
|
|
||||||
|
### 自回归生成(Autoregressive Generation)
|
||||||
|
|
||||||
|
```
|
||||||
|
输入:"今天天气" → 预测下一个 Token "真"
|
||||||
|
"今天天气真" → 预测下一个 Token "好"
|
||||||
|
"今天天气真好" → 预测下一个 Token "<eos>"(停止)
|
||||||
|
```
|
||||||
|
|
||||||
|
每次生成一个 Token,直到输出结束符或达到最大长度。
|
||||||
|
|
||||||
|
### 关键概念
|
||||||
|
|
||||||
|
| 概念 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **Temperature** | 控制随机性,越高越随机(创造性高),越低越确定 |
|
||||||
|
| **Top-p(核采样)** | 只从累积概率 ≥ p 的最少 Token 集合中采样 |
|
||||||
|
| **Top-k** | 只从概率最高的 k 个 Token 中采样 |
|
||||||
|
| **KV Cache** | 缓存已生成 Token 的 Key/Value,避免重复计算,加速推理 |
|
||||||
|
| **上下文窗口** | 模型能同时"看到"的最大 Token 数(现在主流 128K~1M) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、当前主流架构扩展
|
||||||
|
|
||||||
|
### MoE(混合专家)
|
||||||
|
|
||||||
|
> 详见 [[MoE 混合专家架构]]
|
||||||
|
|
||||||
|
- 不是所有参数都参与每次推理
|
||||||
|
- 每个 Token 只路由到少数"专家"子网络
|
||||||
|
- 总参数极大但计算量可控
|
||||||
|
|
||||||
|
### 多模态扩展
|
||||||
|
|
||||||
|
> 见 [[多模态大模型]]
|
||||||
|
|
||||||
|
- 在 LLM 基础上添加视觉/音频编码器
|
||||||
|
- 通过投影器对齐不同模态的 Token
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 扩展阅读
|
||||||
|
|
||||||
|
- 原始论文:[Attention Is All You Need (2017)](https://arxiv.org/abs/1706.03762)
|
||||||
|
- [The Illustrated Transformer](https://jalammar.github.io/illustrated-transformer/) — 图文详解 Transformer
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新:2026-08-05*
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,67 @@
|
|||||||
|
# VCU控制逻辑(精简版)
|
||||||
|
|
||||||
|
## 一、核心定位
|
||||||
|
VCU是车辆核心控制单元,设计原则:**功能简单、运行稳定**,是整车控制的基石,负责协调各子系统工作。
|
||||||
|
|
||||||
|
## 二、对接子系统
|
||||||
|
VCU通过CAN总线与以下部件通信:
|
||||||
|
- BMS(电池管理系统)、OBC(车载充电机)
|
||||||
|
- 电机控制器、灯光控制系统
|
||||||
|
- ORIN(上层自动驾驶平台)、遥控器、机械臂控制器
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、核心控制逻辑
|
||||||
|
### 1. 充电控制
|
||||||
|
- 检测到OBC可充电后,优先等待ORIN指令,**5分钟超时自动充电**
|
||||||
|
- 电量充满后自动发送停止充电指令
|
||||||
|
- 长时间停在充电区且无上层控制时,**电量低于25%自动充电**,充满自停
|
||||||
|
|
||||||
|
### 2. 驾驶模式控制
|
||||||
|
| 状态 | 控制逻辑 |
|
||||||
|
|------|----------|
|
||||||
|
| 遥控器未开机 | 等待ORIN连接使能,进入自动驾驶模式 |
|
||||||
|
| 遥控器开机-手动模式 | 完全不响应ORIN指令,所有控制以遥控器为准 |
|
||||||
|
| 遥控器开机-自动模式 | ORIN可以接管车辆控制 |
|
||||||
|
|
||||||
|
### 3. 机械臂控制
|
||||||
|
- 通过遥控器E拨杆切换底盘/机械臂模式,**两种模式互斥**
|
||||||
|
- 机械臂手动模式:不响应ORIN机械臂指令,完全由遥控器控制
|
||||||
|
- 遥控器操作完全兼容《履带车T10遥控器协议》,支持5个关节+滚刷控制
|
||||||
|
|
||||||
|
### 4. 高优先级刹车(最高优先级)
|
||||||
|
- 独立刹车摇杆,**全模式生效**,不受手自动模式限制
|
||||||
|
- 拉动幅度对应刹车力度,线性控制减速度,最大不超过系统限值,避免急停
|
||||||
|
- 刹车期间临时上报ORIN为手动模式,屏蔽上层速度指令,释放后自动恢复原模式
|
||||||
|
|
||||||
|
### 5. 电机控制
|
||||||
|
- 支持单摇杆原地转向
|
||||||
|
- 最大加速度/减速度可配置,避免急停
|
||||||
|
- 遥控器速度突降时平滑减速,不直接切断动力
|
||||||
|
|
||||||
|
### 6. 灯光控制
|
||||||
|
- 自动驾驶指示灯:自动驾驶模式点亮,手动模式熄灭
|
||||||
|
- 转向灯:转向指令触发,回正自动关闭
|
||||||
|
- 刹车灯:减速或驻车时点亮
|
||||||
|
- 远近光灯:接收上层/遥控器指令控制
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、控制优先级(从高到低)
|
||||||
|
1. **高优先级刹车摇杆** > 2. 遥控器手动模式 > 3. ORIN自动驾驶
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、关键配置参数
|
||||||
|
| 参数 | 默认值 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| 充电等待超时 | 5分钟 | 检测到可充电后等待上层指令的最长时间 |
|
||||||
|
| 自动充电SOC阈值 | 25% | 低于该值自动启动充电 |
|
||||||
|
| 最大加速度 | 1m/s² | 正向加速度上限 |
|
||||||
|
| 最大减速度 | 1m/s² | 减速上限(刹车力度不超过该值) |
|
||||||
|
| CAN通信超时 | 500ms | 连续未收到报文判定为通信丢失 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、核心安全机制
|
||||||
|
1. 通信丢失保护:对应模式下减速停车,上报故障
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
# VCU(车辆控制单元)控制逻辑文档
|
||||||
|
|
||||||
|
## 1. 概述
|
||||||
|
VCU(Vehicle Control Unit)是车辆的核心控制中心,作为整车控制的基石,设计原则为**功能简单、运行稳定**,负责协调车辆各子系统的工作。
|
||||||
|
|
||||||
|
### 1.1 系统架构
|
||||||
|
VCU通过CAN总线与以下子系统直接通信:
|
||||||
|
- **BMS(电池管理系统)**:电池状态采集
|
||||||
|
- **OBC(车载充电机)**:充电状态监测、充电指令控制
|
||||||
|
- **电机控制器**:速度控制、扭矩输出控制
|
||||||
|
- **灯光控制系统**:远近光灯、转向灯、刹车灯、自动驾驶指示灯控制
|
||||||
|
- **ORIN(上层自动驾驶计算平台)**:接收自动驾驶指令、上报车辆状态
|
||||||
|
- **遥控器**:接收手动驾驶指令、手自动模式切换
|
||||||
|
- **机械臂控制器**:机械臂关节控制、作业工具控制
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
RC --> VCU
|
||||||
|
ARM --> VCU
|
||||||
|
BMS--> VCU
|
||||||
|
VCU[VCU 控制中心] --> BMS[BMS 电池管理系统]
|
||||||
|
VCU --> OBC[OBC 车载充电机]
|
||||||
|
OBC --> VCU
|
||||||
|
ORIN --> VCU
|
||||||
|
VCU --> MOTOR[电机控制器]
|
||||||
|
VCU --> LIGHT[灯光控制系统]
|
||||||
|
VCU --> ORIN[ORIN 自动驾驶平台]
|
||||||
|
VCU --> RC[遥控器]
|
||||||
|
VCU --> ARM[机械臂控制器]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 充电控制逻辑
|
||||||
|
VCU负责整车充电流程的管理,通过CAN总线与BMS和OBC通信,收集两者状态并上报上层系统。
|
||||||
|
|
||||||
|
### 2.1 充电状态机
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> OBC: 待充电状态
|
||||||
|
OBC --> WAIT_FOR_CHARGE_CMD: 检测到OBC可充电
|
||||||
|
ORIN --> CHARGING: 上层发送充电指令
|
||||||
|
WAIT_FOR_CHARGE_CMD --> CHARGING: 收到上层充电指令
|
||||||
|
WAIT_FOR_CHARGE_CMD --> CHARGING: 5分钟超时自动充电
|
||||||
|
|
||||||
|
OBC --> AUTO_CHARGE: 电量<25%且长时间停留在充电区域\n无上层控制
|
||||||
|
AUTO_CHARGE --> CHARGING: 自动执行充电指令
|
||||||
|
CHARGING --> AUTO_STOP_CHARGE: 电量充满
|
||||||
|
AUTO_STOP_CHARGE --> OBC: 自动停止充电
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 充电控制规则
|
||||||
|
1. **充电触发条件**:
|
||||||
|
- 当VCU检测到无线OBC处于可充电状态时,进入等待充电指令状态
|
||||||
|
- 优先等待上层(ORIN)发送充电开始指令
|
||||||
|
- 若等待超时(5分钟),自动进入充电状态
|
||||||
|
|
||||||
|
2. **充电停止条件**:
|
||||||
|
- BMS上报电量充满后,VCU自动向OBC发送停止充电指令
|
||||||
|
- 收到上层停止充电指令时,立即停止充电
|
||||||
|
|
||||||
|
3. **自动充电策略**:
|
||||||
|
- 车辆长时间停留在可充电区域且无上层控制指令时
|
||||||
|
- 当电池电量低于25%时,自动执行充电指令
|
||||||
|
- 电量充满后自动执行停止充电指令
|
||||||
|
|
||||||
|
## 3. 驾驶控制逻辑
|
||||||
|
VCU支持两种驾驶模式:**自动驾驶模式**(上层ORIN控制)和**手动驾驶模式**(遥控器控制),遥控器控制优先级高于上层控制。
|
||||||
|
|
||||||
|
### 3.1 模式切换逻辑
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> SBUS_WAIT: 遥控器未开机
|
||||||
|
SBUS_WAIT --> AUTO_MODE: 上层ORIN连接并使能\n进入自动驾驶模式
|
||||||
|
AUTO_MODE --> SBUS_CONNECTED: 遥控器开机
|
||||||
|
SBUS_CONNECTED --> MANUAL_MODE: 遥控器手动模式\n不响应上层任何指令
|
||||||
|
SBUS_CONNECTED --> AUTO_MODE: 遥控器自动模式\n上层可接管控制
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 控制优先级规则
|
||||||
|
1. **遥控器未开机时**:
|
||||||
|
- 等待上层ORIN连接并发送使能指令
|
||||||
|
- 进入自动驾驶模式,响应ORIN的控制指令
|
||||||
|
|
||||||
|
2. **遥控器开机后**:
|
||||||
|
- 优先读取遥控器的手自动模式状态
|
||||||
|
- **手动模式**:完全不响应上层ORIN的任何指令,所有控制以遥控器为准
|
||||||
|
- **自动模式**:上层ORIN可以接管车辆控制
|
||||||
|
|
||||||
|
3. **高优先级刹车最高优先级**:遥控器独立刹车摇杆优先级高于所有其他控制指令,无论当前处于自动驾驶模式还是手动模式,只要拉动刹车摇杆,立即响应刹车指令,不受模式限制。
|
||||||
|
|
||||||
|
### 3.3 指令接收处理
|
||||||
|
VCU通过CAN总线接收两类控制指令:
|
||||||
|
|
||||||
|
#### 3.3.1 上层ORIN指令
|
||||||
|
- 速度控制指令
|
||||||
|
- 使能控制指令
|
||||||
|
- 灯光控制指令(远近光灯)
|
||||||
|
- 驻车控制指令
|
||||||
|
|
||||||
|
#### 3.3.2 遥控器指令
|
||||||
|
- 速度控制指令(单摇杆)
|
||||||
|
- 方向控制(单摇杆)
|
||||||
|
- 使能控制指令
|
||||||
|
- 灯光控制指令
|
||||||
|
- 手自动切换指令
|
||||||
|
- 驻车控制指令
|
||||||
|
- 模式切换指令
|
||||||
|
- 机械臂各关节控制指令
|
||||||
|
- 作业工具(滚刷)控制指令
|
||||||
|
- 高优先级刹车控制指令
|
||||||
|
|
||||||
|
## 4. 电机控制逻辑
|
||||||
|
### 4.1 遥控器单摇杆控制
|
||||||
|
- 支持**原地转向**功能:摇杆左右方向控制转向,前后方向控制速度
|
||||||
|
- 左右摇杆量直接对应转向角度,前后摇杆量对应目标速度
|
||||||
|
|
||||||
|
### 4.2 加减速限制
|
||||||
|
为保证行驶平稳性,对电机输出进行如下限制:
|
||||||
|
1. **最大加速度限制**:加速度不超过预设最大值(可配置,默认0.5g)
|
||||||
|
2. **最大减速度限制**:减速度不超过预设最大值(可配置,默认0.3g)
|
||||||
|
3. **避免急停**:当遥控器速度指令突然变为0时,不直接切断动力输出,而是按照最大减速度平滑减速至停止
|
||||||
|
|
||||||
|
### 4.3 高优先级刹车控制
|
||||||
|
遥控器配备独立高优先级刹车摇杆,为最高优先级控制输入,逻辑如下:
|
||||||
|
1. **全模式生效**:无论车辆当前处于自动驾驶模式还是手动驾驶模式,刹车摇杆指令均生效,不受当前控制模式限制
|
||||||
|
2. **力度线性控制**:刹车摇杆拉动幅度对应刹车力度,幅度越大减速度越大,最大减速度不超过系统预设的最大减速度限值,实现缓慢刹车,避免急停
|
||||||
|
3. **临时状态上报**:拉动刹车摇杆期间,VCU临时向上层ORIN上报车辆处于**手动模式**,同时屏蔽上层ORIN的速度控制指令,仅响应刹车指令
|
||||||
|
4. **释放自动恢复**:刹车摇杆完全释放后,立即恢复原运行模式,向ORIN上报实际模式状态,恢复响应上层速度控制指令
|
||||||
|
5. **不干涉其他控制**:刹车控制仅干预速度控制相关指令,不影响灯光、驻车、机械臂等其他控制功能
|
||||||
|
|
||||||
|
## 5. 灯光控制逻辑
|
||||||
|
灯光控制暂时由VCU自主判断处理,无需上层系统干预。
|
||||||
|
|
||||||
|
### 5.1 控制列表
|
||||||
|
| 灯光类型 | 控制逻辑 |
|
||||||
|
| -------- | -------------------- |
|
||||||
|
| 自动驾驶指示灯 | 自动驾驶模式开启时点亮,手动模式时熄灭 |
|
||||||
|
| 转向灯(左/右) | 根据转向指令自动开启,转向回正后自动关闭 |
|
||||||
|
| 刹车灯 | 车辆处于减速状态或驻车状态时点亮 |
|
||||||
|
| 远近光灯 | 接收上层或遥控器指令控制,默认不开启 |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
## 6. 通信协议规范
|
||||||
|
### 6.1 CAN通信矩阵(摘要)
|
||||||
|
|
||||||
|
待补充
|
||||||
|
|
||||||
|
## 7. 故障处理与安全机制
|
||||||
|
### 7.1 通信故障处理
|
||||||
|
- 与BMS通信丢失:立即禁止充电,上报故障
|
||||||
|
- 与OBC通信丢失:终止当前充电流程,上报故障
|
||||||
|
- 与ORIN通信丢失:自动驾驶模式下减速停车,切换到待机状态
|
||||||
|
- 与遥控器通信丢失:手动模式下减速停车,开启危险报警灯;机械臂手动模式下停止机械臂所有运动并锁定
|
||||||
|
|
||||||
|
### 7.2 安全保护机制
|
||||||
|
待补充
|
||||||
|
## 8. 配置参数(可调整)
|
||||||
|
| 参数名称 | 默认值 | 说明 |
|
||||||
|
| --------- | ----- | ------------------- |
|
||||||
|
| 充电指令等待超时 | 5分钟 | 检测到可充电后等待上层指令的最长时间 |
|
||||||
|
| 自动充电SOC阈值 | 25% | 低于该值时自动启动充电 |
|
||||||
|
| 最大加速度 | 1m/s² | 正向加速度上限 |
|
||||||
|
| 最大减速度 | 1m/s² | 反向加速度(减速)上限 |
|
||||||
|
| CAN通信超时阈值 | 500ms | 连续500ms未收到报文判定为通信丢失 |
|
||||||
|
|
||||||
|
## 9. 机械臂控制逻辑
|
||||||
|
VCU支持机械臂手动控制功能,通过遥控器切换操作模式,实现底盘控制与机械臂控制的复用,遵循**手动优先**的控制原则。
|
||||||
|
|
||||||
|
### 9.1 模式切换逻辑
|
||||||
|
机械臂控制与底盘控制通过遥控器E拨杆进行切换,完全兼容《履带车T10遥控器协议与操作说明》:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> CHASSIS_MODE: E拨杆最左侧\n底盘控制模式
|
||||||
|
CHASSIS_MODE --> ARM_MODE: E拨杆拨到最右侧\n切换到机械臂控制模式
|
||||||
|
ARM_MODE --> CHASSIS_MODE: E拨杆拨到最左侧\n切换到底盘控制模式
|
||||||
|
|
||||||
|
state CHASSIS_MODE {
|
||||||
|
[*] --> CHASSIS_MANUAL: 手动模式
|
||||||
|
[*] --> CHASSIS_AUTO: 自动模式
|
||||||
|
}
|
||||||
|
|
||||||
|
state ARM_MODE {
|
||||||
|
[*] --> ARM_MANUAL: 手动模式(默认)
|
||||||
|
ARM_MANUAL --> ARM_AUTO: A按键切换到自动模式\n上层可控制机械臂
|
||||||
|
ARM_AUTO --> ARM_MANUAL: A按键切换到手动模式\n不响应上层指令
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 控制优先级规则
|
||||||
|
1. **手动模式优先**:无论机械臂处于何种状态,只要遥控器切换到机械臂手动控制模式,立即停止响应上层ORIN的机械臂控制指令
|
||||||
|
2. **模式互斥**:E拨杆同一时间只能处于一种模式,底盘控制与机械臂控制不可同时操作
|
||||||
|
3. **自动模式使能**:机械臂自动模式下,上层ORIN可以发送机械臂控制指令,VCU转发给机械臂控制器
|
||||||
|
|
||||||
|
### 9.3 遥控器机械臂操作映射(E拨杆最右侧)
|
||||||
|
完全遵循《履带车T10遥控器协议与操作说明》定义的操作逻辑:
|
||||||
|
|
||||||
|
| 控制部件 | 功能 | 通道映射 |
|
||||||
|
|---------------|--------------------------|----------|
|
||||||
|
| 右摇杆X轴(x2) | 控制回转关节(joint1) | CH1 |
|
||||||
|
| 右摇杆Y轴(y2) | 控制动臂关节(joint4) | CH2 |
|
||||||
|
| 左摇杆Y轴(y1) | 控制横梁关节(joint3) | CH3 |
|
||||||
|
| 左摇杆X轴(x1) | 控制力臂关节(joint2) | CH4 |
|
||||||
|
| A按键 | 切换机械臂自动/手动控制模式 | CH7 |
|
||||||
|
| F拨杆 | 控制刷头上下移动(joint5) | CH6 |
|
||||||
|
| D轮盘 | 控制滚刷启停/转速 | CH10 |
|
||||||
|
|
||||||
|
### 9.4 机械臂控制处理流程
|
||||||
|
1. VCU实时接收遥控器CAN报文(ID范围:0x187~0x18A)
|
||||||
|
2. 解析E拨杆(CH5)数值判断当前操作模式
|
||||||
|
3. **机械臂模式下**:
|
||||||
|
- 解析各通道摇杆量,转换为对应关节的目标角度/速度
|
||||||
|
- 将控制指令通过CAN总线发送给机械臂控制器
|
||||||
|
- 手动模式下直接转发遥控器指令,自动模式下转发上层ORIN指令
|
||||||
|
4. **底盘模式下**:
|
||||||
|
- 忽略机械臂相关通道数据,保持机械臂当前状态
|
||||||
|
- 执行底盘控制逻辑
|
||||||
|
|
||||||
|
### 9.5 安全保护机制
|
||||||
|
1. **模式切换保护**:在机械臂运行过程中切换到底盘模式时,立即停止机械臂所有运动,保持当前位置
|
||||||
|
2. **通信丢失保护**:遥控器通信丢失时,立即停止机械臂所有运动,进入锁定状态
|
||||||
|
3. **急停保护**:收到急停指令时,立即切断机械臂动力输出
|
||||||
|
|
||||||
|
## 10. 通信协议补充
|
||||||
|
### 10.1 遥控器CAN通信扩展
|
||||||
|
| CAN ID | 发送方 | 接收方 | 报文内容 | 周期 |
|
||||||
|
|--------|--------|--------|----------|------|
|
||||||
|
| 0x187 | 遥控器 | VCU | 通道1-4数据(摇杆) | 10ms |
|
||||||
|
| 0x188 | 遥控器 | VCU | 通道5-8数据(拨杆、按键) | 10ms |
|
||||||
|
| 0x189 | 遥控器 | VCU | 通道9-10数据(轮盘) | 10ms |
|
||||||
|
| 0x18A | 遥控器 | VCU | 保留 | 10ms |
|
||||||
|
| 0x18B | 遥控器 | VCU | 校验帧 | 10ms |
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
控制相关参数没有按速度区间机制,需要自己实现
|
||||||
|
rtk精度行走是够的,但是目前看会有5-8cm的跳变,所以充电还是需要用docking server配合视觉或者雷达精确定位,加上限位和触点开关之类的。
|
||||||
|
|
||||||
|
体量小,开发快,资料够多。
|
||||||
|
|
||||||
|
route server支持大地图
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
## 1. 硬件概述
|
||||||
|
本文档描述云卓T10遥控器通过SBUS转CAN模块输出的CAN通信协议及操作逻辑。遥控器布局参考下图:
|
||||||
|
|
||||||
|
![[Pasted image 20260402112914.png|350]]
|
||||||
|
![[Pasted image 20260402112951.png|369]]
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. CAN通信协议规范
|
||||||
|
### 2.1 基础参数
|
||||||
|
- CAN ID范围:`0x187` ~ `0x18A`(共4个ID,每个ID对应4个通道数据)
|
||||||
|
- 比特率:500K
|
||||||
|
- 数据长度:每帧8字节,包含4个通道值,每个通道占2字节
|
||||||
|
- 字节序:大端模式(第一字节为高位字节)
|
||||||
|
- 通道值范围:
|
||||||
|
- 最小值:`0x011A` (十进制 282)
|
||||||
|
- 中间值:`0x03EA` (十进制 1002)
|
||||||
|
- 最大值:`0x06BA` (十进制 1722)
|
||||||
|
- 开关量特性:A/B按键为开关量,开关打开时输出最大值,关闭时输出最小值
|
||||||
|
|
||||||
|
### 2.2 帧结构
|
||||||
|
|
||||||
|
| CAN ID | 0-1 | 2-3 | 4-5 | 6-7 |
|
||||||
|
| ------ | --- | ---- | --- | --- |
|
||||||
|
| 0x187 | CH1 | CH2 | CH3 | CH4 |
|
||||||
|
| 0x188 | CH5 | CH6 | CH7 | CH8 |
|
||||||
|
| 0x189 | CH9 | CH10 | 保留 | 保留 |
|
||||||
|
| 0x18A | 保留 | 保留 | 保留 | 保留 |
|
||||||
|
| 0x18B | 校验 | | | |
|
||||||
|
18B高位为数字通道和状态位,低位为前33位累加和校验。
|
||||||
|
|
||||||
|
## 3. 遥控器通道映射表
|
||||||
|
| 控制部件 | 通道编号 | 说明 |
|
||||||
|
| --------- | ---- | --------- |
|
||||||
|
| 右摇杆X轴(x2) | CH1 | 横向数值,左小右大 |
|
||||||
|
| 右摇杆Y轴(y2) | CH2 | 纵向数值,上小下大 |
|
||||||
|
| 左摇杆Y轴(y1) | CH3 | 纵向数值,下小上大 |
|
||||||
|
| 左摇杆X轴(x1) | CH4 | 横向数值,左小右大 |
|
||||||
|
| E拨杆 | CH5 | 三档,左小右大 |
|
||||||
|
| F拨杆 | CH6 | 三档,左小右大 |
|
||||||
|
| A按键 | CH7 | 开关量 |
|
||||||
|
| B按键 | CH8 | 开关量 |
|
||||||
|
| C轮盘 | CH9 | 左小右大 |
|
||||||
|
| D轮盘 | CH10 | 左小右大 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 操作模式说明
|
||||||
|
遥控器由E拨杆位置切换两种工作模式:
|
||||||
|
|
||||||
|
### 4.1 底盘控制模式(E拨杆拨到最左侧,通道5输出最小值)
|
||||||
|
| 控制部件 | 功能 |
|
||||||
|
| --------- | ----------- |
|
||||||
|
| 左摇杆X轴(x1) | 控制底盘左右转向 |
|
||||||
|
| 左摇杆Y轴(y1) | 控制底盘前后移动 |
|
||||||
|
| A按键 | 切换自动/手动控制模式 |
|
||||||
|
| B按键 | 切换驻车状态 |
|
||||||
|
| F拨杆 | 切换前灯远近光 |
|
||||||
|
|
||||||
|
### 4.2 机械臂控制模式(E拨杆拨到最右侧,通道5输出最大值)
|
||||||
|
| 控制部件 | 功能 |
|
||||||
|
| --------- | ---------------- |
|
||||||
|
| 右摇杆X轴(x2) | 控制回转关节(joint1) |
|
||||||
|
| 右摇杆Y轴(y2) | 控制动臂关节(joint4) |
|
||||||
|
| 左摇杆Y轴(y1) | 控制横梁关节(joint3) |
|
||||||
|
| 左摇杆X轴(x1) | 控制力臂关节(joint2) |
|
||||||
|
| A按键 | 切换自动/手动控制模式 |
|
||||||
|
| F拨杆 | 控制刷头上下移动(joint5) |
|
||||||
|
| D轮盘 | 控制滚刷启停/转速 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 版本信息
|
||||||
|
- 文档版本:V1.0
|
||||||
|
- 最后更新:2026-04-02
|
||||||
Binary file not shown.
@@ -0,0 +1,182 @@
|
|||||||
|
# AI 编译器现状与前景
|
||||||
|
|
||||||
|
> 2026-08-05 分析笔记。源自一个判断:大模型时代模型结构收敛、数量变少,传统 AI 编译器必要性下降,"只需适配特定子网络深入优化即可"——这个判断对一半。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 背景:原判断
|
||||||
|
|
||||||
|
作者背景:做过编译器工作,TVM 0.6 魔改 + 接触过 MLIR。
|
||||||
|
|
||||||
|
原判断:
|
||||||
|
- 大模型时代,模型结构越来越固定(decoder-only Transformer 一统)
|
||||||
|
- 模型数量远少于传统 CNN 时代
|
||||||
|
- 传统 AI 编译器(通用图级自动优化)必要性下降
|
||||||
|
- 只需适配特定子网络,深入优化即可
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、判断对的部分:通用图编译器退潮
|
||||||
|
|
||||||
|
在**图级通用编译**这一层,判断成立,有实证:
|
||||||
|
|
||||||
|
### OctoML 案例(最重要的证据)
|
||||||
|
|
||||||
|
- NVIDIA 2024年5月收购 OctoML(TVM 团队),官方理由是"拿到能把固定硅片上最后几个点性能挤出来的人"
|
||||||
|
- **结果相反**:编译流水线产品被逐步废弃,客户流向 vLLM 等 serving-first 引擎
|
||||||
|
- **结论:编译优先输给了服务优先**——生产 LLM 系统真正花时间的是低 TTFT、持续吞吐、API 契约,而不是"把模型编译成最优 artifact"
|
||||||
|
|
||||||
|
### AOT → JIT 的转移
|
||||||
|
|
||||||
|
| | AOT(传统编译器) | JIT(2026 主流) |
|
||||||
|
|---|---|---|
|
||||||
|
| 模式 | 模型进 → 优化 passes → 编译产物出 | 运行时按需编译 kernel,首次启动缓存 |
|
||||||
|
| 代表 | TVM、TensorRT-LLM | FlashInfer、DeepGEMM、Triton |
|
||||||
|
| 部署速度 | TensorRT-LLM 构建 engine 需数小时 | vLLM 加载 HF 模型只需几分钟 |
|
||||||
|
|
||||||
|
### CNN vs LLM 的模型量
|
||||||
|
|
||||||
|
- CNN 时代:几百上千种网络结构 → 通用图编译"一套处理任意图"有价值
|
||||||
|
- LLM 时代:decoder-only 一统,结构高度收敛 → 为"任意图"做的通用优化确实浪费
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、判断的偏差:"AI 编译器"分裂成了四个层
|
||||||
|
|
||||||
|
> 核心偏差:把"AI 编译器"等同于 TVM 0.6 式的通用图编译器。
|
||||||
|
> 实际 2026 年编译器工作量没有变少,而是转移到四个更深更专的层。
|
||||||
|
|
||||||
|
### 层 1:Kernel 层——最热战场
|
||||||
|
|
||||||
|
LLM 时代性能关键算子的集合**比 CNN 时代更丰富**:
|
||||||
|
|
||||||
|
| 算子/技术 | 为什么难 |
|
||||||
|
|---|---|
|
||||||
|
| FlashAttention / MLA | 每次新注意力变体 = 新 kernel 的数月专家工作 |
|
||||||
|
| MoE 路由 + GEMM | 专家调度、跨卡通信;vLLM 的 MoE backend 从 FlashInfer 切到 Triton(H200 更快) |
|
||||||
|
| FP8 / FP4 / NVFP4 量化 GEMM | 新数值格式把旧 cost model 和调度规则**全部作废** |
|
||||||
|
| 长上下文 / PagedAttention | 变长序列、内存受限的 kernel 调度 |
|
||||||
|
|
||||||
|
当前 Kernel 层的生态谱系(从高层 DSL 到底层):
|
||||||
|
|
||||||
|
```
|
||||||
|
Triton(事实标准,高层 tile 抽象)
|
||||||
|
↓
|
||||||
|
TileLang / Helion(布局自动推断)
|
||||||
|
↓
|
||||||
|
CuTe DSL(CUTLASS v4,可组合布局抽象)
|
||||||
|
↓
|
||||||
|
TIRx / TLX(硬件原生,显式 orchestration)
|
||||||
|
↓
|
||||||
|
CUDA / PTX(手工极限优化)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 层 2:推理引擎层——"编译器/运行时边界模糊"
|
||||||
|
|
||||||
|
**LLM 推理编译已被定义为独立学科**:传统编译器五层框架(图→kernel→内存→运行时调度)被在线调度吸收。
|
||||||
|
|
||||||
|
- 动态形状(变长序列、KV cache)
|
||||||
|
- chunked prefill、continuous batching
|
||||||
|
- 这些调度问题**本质上变成了编译问题**
|
||||||
|
|
||||||
|
代表:vLLM、SGLang、TensorRT-LLM、llama.cpp。
|
||||||
|
|
||||||
|
2026 实战数据:
|
||||||
|
- vLLM V1 引擎比 V0 快 1.5~2×(异步调度、chunked prefill、torch.compile 集成)
|
||||||
|
- vLLM 默认 MoE backend 从 FlashInfer 切到 Triton:H200 上 57,821 vs 55,700 tokens/s
|
||||||
|
- TensorRT-LLM 高并发(32+ 并发)时仍快 10~30%,但需数小时 build engine
|
||||||
|
|
||||||
|
### 层 3:硬件使能层——传统编译器反而吃香
|
||||||
|
|
||||||
|
反转点:**通用模型少,但硬件爆发式碎片化**。
|
||||||
|
|
||||||
|
- NVIDIA Blackwell、AMD MI300X、华为昇腾、寒武纪、国产 ASIC
|
||||||
|
- 非 NVIDIA 芯片没有厂商 kernel 库 → **编译栈是必需的**
|
||||||
|
- 国内芯片编译团队从"建设期"进入"换血期":要求 codegen 优化、内存规划、target-specific 调度的深度人才
|
||||||
|
- TVM/MLIR"一套栈、多后端"思路在这一层真正兑现价值
|
||||||
|
|
||||||
|
### 层 4:LLM 生成 kernel——角色重塑
|
||||||
|
|
||||||
|
2025-2026 最大变量:**LLM agent 成为 kernel 生成器和编译器优化器**。
|
||||||
|
|
||||||
|
| 系统 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| **KernelEvolve**(Meta,已部署) | 480 个算子-平台组合 100% 正确率,1.25~17× 加速,开发时间从数周降到数小时 |
|
||||||
|
| **KernelBench** | LLM kernel 能力基准 |
|
||||||
|
| **AutoTriton / TritonRL / KernelLLM** | RL 驱动的 Triton 生成 |
|
||||||
|
| **Compiler-R1 / REASONING COMPILER**(NeurIPS 2025) | RL 驱动的编译自动调优 |
|
||||||
|
|
||||||
|
> 意义:未来编译器工程师核心技能从"手写 kernel"变为"**引导 agent 搜索 + 验证正确性 + 设计搜索空间**"。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、反驳"只需适配特定子网络"
|
||||||
|
|
||||||
|
策略对,深度被低估:
|
||||||
|
|
||||||
|
- **"只优化少量关键算子"是对的**——这正是 vLLM/TensorRT-LLM 的做法
|
||||||
|
- 但"只需"严重低估深度:把 FlashAttention-4 或 MoE kernel 在 B200 调到峰值是**数周专家工作**
|
||||||
|
- **动态形状是关键分水岭**:静态形状下融合是"规则问题",动态形状下是"开放问题"(广播开销、索引计算、codegen 分支)。2026 人才市场把"动态形状编译"列为 LLM 推理团队硬性要求
|
||||||
|
- 值钱的是**精通动态形状 pass 设计、memory-bound 优化、新数值格式**的人,不是"会写 dialect 定义和基本 lowering"的人
|
||||||
|
|
||||||
|
MLIR 生态(2026 年已是"编译器基础设施的 Linux"):
|
||||||
|
- torch.compile (Inductor) 是 MLIR 思想设计
|
||||||
|
- Google XLA 已迁移到 MLIR 底层
|
||||||
|
- IREE 是纯 MLIR 栈
|
||||||
|
- 需求已从"懂 dialect 机制"转向"**自定义 pass 流水线设计、图融合策略、跨 IR 优化**"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、前景判断(2026)
|
||||||
|
|
||||||
|
```
|
||||||
|
通用图编译器(TVM 全自动调优式) ↘ 退潮,仅存于特定 niche
|
||||||
|
Kernel DSL(Triton/CuTe/TileLang) ↗ 繁荣,LLM 推理事实标准
|
||||||
|
推理引擎内部编译(vLLM/SGLang) ↗ 最热,编译器×分布式交叉岗位稀缺
|
||||||
|
硬件使能编译栈(昇腾/AMD/寒武纪) ↗ 确定性增长,国产芯片刚需
|
||||||
|
LLM agent 生成 kernel ↗ 爆发前夜,重塑工程师角色
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键结论
|
||||||
|
|
||||||
|
> **AI 编译器没有死,死的是"通用图编译"这个窄定义。**
|
||||||
|
|
||||||
|
- AI 推理支出 2026 年已超过训练
|
||||||
|
- 编译器工程师是 AI 基础设施链上最稀缺岗位之一
|
||||||
|
- 能力栈从"覆盖任意图"转向"**少量关键算子做到极致的深度 + 动态形状 + 新硬件 + 新数值格式**"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、职业建议(针对本笔记作者背景)
|
||||||
|
|
||||||
|
作者技能:TVM 0.6(Relay/TIR/AutoTVM 时代)+ MLIR。
|
||||||
|
|
||||||
|
| 技能 | 2026 年变现路径 |
|
||||||
|
|---|---|
|
||||||
|
| MLIR 了解 | 深入 torch.compile/Inductor 的 pass 设计、动态形状融合 |
|
||||||
|
| TVM 调度/调优思想 | 转向 Triton/CUTLASS——AutoTVM/Ansor 的调优心智模型可迁移 |
|
||||||
|
| 编译原理底子(IR/pass/调度) | vLLM/SGLang 内部,编译器×分布式调度是稀缺交叉 |
|
||||||
|
| 多后端思维 | 国产芯片(昇腾 CANN、寒武纪)使能,"适配子网络"直觉在此是核心竞争力 |
|
||||||
|
|
||||||
|
**一句话建议**:
|
||||||
|
> 不守"通用编译框架"这条船;把"适配特定子网络深入优化"做深到极致——但"深"是指**动态形状 + 新数值格式 + 新硬件架构**三个维度,而不是 TVM 0.6 时代的静态图自动调优。编译功底在这三个维度上直接可迁移,是"只会写 PyTorch 的 ML 工程师"够不着的护城河。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参考资料
|
||||||
|
|
||||||
|
- [LLM Inference Compiler Panorama(推理编译独立成领域)](https://arxiv.org/pdf/2512.23236v1)
|
||||||
|
- [TIRx:TVM 上的新 kernel DSL(2026-06)](https://tvm.apache.org/2026/06/22/tirx)
|
||||||
|
- [vLLM 切换 Triton MoE backend(PR #44220)](https://github.com/vllm-project/vllm/pull/44220)
|
||||||
|
- [AI Inference Engines 2026 全景](https://www.youngju.dev/blog/culture/2026-05-16-ai-inference-engines-2026-vllm-sglang-llama-cpp-tgi-tensorrt-llm-mlx-mistralrs-deepspeed-aphrodite-deep-dive.en)
|
||||||
|
- [KernelEvolve:Meta 生产级 LLM kernel 生成](https://www.ivoox.com/llm-inference-compiler-panorama-research-and-engineering-evolution-audios-mp3_rf_176267639_1.html)
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[大模型架构基础]] — 编译的对象:Transformer 结构
|
||||||
|
- [[DeepSeek V4 系列]] — 最新模型的 FP8/NVFP4、DSpark 都是 kernel 层优化
|
||||||
|
- [[FFN 前馈网络详解]] — MoE/SwiGLU 是最热的 kernel 优化对象
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新:2026-08-05*
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# Gitea 部署指南
|
||||||
|
|
||||||
|
> 2026-08-13 记录。自托管轻量 Git 服务,个人代码仓库,Web 用 Caddy 反代套 HTTPS。域名域名 `git.hyonglin.top`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 选型
|
||||||
|
|
||||||
|
| 方案 | 是否选用 | 原因 |
|
||||||
|
|---|---|---|
|
||||||
|
| **Gitea** | ✅ | Go 单二进制,轻量(~50–100MB),功能全(仓库/Issue/PR/Actions/Package),社区活跃、安全更新及时 |
|
||||||
|
| Gogs | ❌ | Gitea 的 fork 前身,开发停滞,新项目不推荐 |
|
||||||
|
| 裸仓库+SSH | ❌ | 无 Web 界面 |
|
||||||
|
|
||||||
|
> Gitea 是 Gogs 的 fork(社区驱动),新项目无脑选 Gitea;若更在意「纯社区治理」可选 Forgejo。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## docker-compose 服务
|
||||||
|
|
||||||
|
`silverbullet/docker-compose.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:latest
|
||||||
|
container_name: gitea
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
- GITEA__server__ROOT_URL=https://git.hyonglin.top/
|
||||||
|
- GITEA__server__DOMAIN=git.hyonglin.top
|
||||||
|
- GITEA__server__SSH_DOMAIN=git.hyonglin.top
|
||||||
|
- GITEA__server__SSH_PORT=2222
|
||||||
|
ports:
|
||||||
|
- "2222:22" # SSH clone 用(服务器 22 已被 SSH 占用,故映射 2222)
|
||||||
|
volumes:
|
||||||
|
- ./gitea:/data
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
- Web(3000)不映射端口,由 Caddy 反代 `gitea:3000`
|
||||||
|
- SSH 需映射 `2222:22`,因为宿主机 22 被 OpenSSH 占用
|
||||||
|
|
||||||
|
## Caddy 反代
|
||||||
|
|
||||||
|
`silverbullet/Caddyfile` 加一段:
|
||||||
|
|
||||||
|
```caddyfile
|
||||||
|
# Git 服务
|
||||||
|
git.hyonglin.top {
|
||||||
|
tls {
|
||||||
|
dns cloudflare {env.CF_API_TOKEN}
|
||||||
|
}
|
||||||
|
reverse_proxy gitea:3000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## compose 部署
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d gitea
|
||||||
|
docker compose up -d --force-recreate caddy # 让 caddy 加载新站点
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 首次安装(web 向导)
|
||||||
|
|
||||||
|
打开 `https://git.hyonglin.top` 走安装向导:
|
||||||
|
|
||||||
|
- **数据库**:默认 `SQLite3`(个人用足够)
|
||||||
|
- **域名/URL**:环境变量已预设(`git.hyonglin.top`),保持默认
|
||||||
|
- **SSH 端口**:`2222`
|
||||||
|
- **管理员账号**:设置用户名/邮箱/密码
|
||||||
|
- 点「安装 Gitea」
|
||||||
|
|
||||||
|
验证安装完成:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# app.ini 应已锁定安装
|
||||||
|
grep INSTALL_LOCK /home/ubuntu/silverbullet/gitea/gitea/conf/app.ini # → true
|
||||||
|
|
||||||
|
# 确认管理员存在
|
||||||
|
docker compose exec -T gitea su git -c "gitea admin user list"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
|
||||||
|
- **Web**:登录 `https://git.hyonglin.top` 建仓库
|
||||||
|
- **HTTPS clone**:`git clone https://git.hyonglin.top/用户名/仓库.git`
|
||||||
|
- **SSH clone**:`git clone git@git.hyonglin.top:2222/用户名/仓库.git`(需安全组放行 TCP 2222)
|
||||||
|
- **备份**:备份 `silverbullet/gitea` 目录(含数据库和所有仓库)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[主页与Caddy反向代理]] — git.hyonglin.top 的 HTTPS 入口
|
||||||
|
- [[frp内网穿透部署指南]] — 本服务器其他自建服务
|
||||||
|
- [Gitea 官方文档](https://docs.gitea.com/zh-cn/)
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
# Silverbullet 部署指南
|
||||||
|
|
||||||
|
> 2026-08-05 记录。目标:在远程 Linux 服务器上用 Docker 部署自托管笔记服务,实现"随时随地在任意设备用浏览器查看编辑笔记"。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 背景与选型
|
||||||
|
|
||||||
|
**需求**:远程服务器部署,随时随地任意设备查看、编辑笔记。
|
||||||
|
|
||||||
|
**选型结论**:Silverbullet(浏览器直接编辑 + Linux/Docker)。
|
||||||
|
|
||||||
|
### 为什么选 Silverbullet
|
||||||
|
|
||||||
|
- 任何设备浏览器打开网址即可**查看 + 编辑**,无需安装 App
|
||||||
|
- 支持 `[[]]` 双链、反向链接(**与 Obsidian 语法兼容**,现有笔记可直接用)
|
||||||
|
- 笔记是纯 Markdown 文件,存在服务器目录,备份 = 复制文件夹
|
||||||
|
- PWA 支持,手机浏览器可离线编辑
|
||||||
|
- Docker 一条命令部署,开源
|
||||||
|
|
||||||
|
### 备选:code-server(VS Code Web)
|
||||||
|
|
||||||
|
如果更想要完整 VS Code 体验,用 codercom/code-server。缺点:移动端体验差、无双链支持。**先用 Silverbullet,不够再补。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、服务器部署
|
||||||
|
|
||||||
|
### 创建 docker-compose.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
silverbullet:
|
||||||
|
image: ghcr.io/silverbulletmd/silverbullet:latest
|
||||||
|
container_name: silverbullet
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
- ./space:/space # 笔记存储目录,备份就是复制这个文件夹
|
||||||
|
environment:
|
||||||
|
- SB_USER=admin:改成你的强密码 # 登录认证,必填!
|
||||||
|
```
|
||||||
|
|
||||||
|
### 启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
访问 `http://服务器IP:3000` → 输入 admin/密码 → 完成。
|
||||||
|
|
||||||
|
### 常用环境变量
|
||||||
|
|
||||||
|
| 变量 | 说明 | 默认 |
|
||||||
|
|---|---|---|
|
||||||
|
| `SB_FOLDER` | Markdown 文件目录 | `/space` |
|
||||||
|
| `SB_PORT` | 内部端口 | `3000` |
|
||||||
|
| `SB_USER` | Basic auth(`user:pass`) | 无认证 |
|
||||||
|
| `SB_AUTH_TOKEN` | Bearer token API 访问 | 无 |
|
||||||
|
| `SB_READ_ONLY` | 只读模式 | `0` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、迁移现有笔记
|
||||||
|
|
||||||
|
本机笔记在 `d:\onedrive\note`(Windows),用 Git Bash 一次性传到服务器:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 服务器上先建目录
|
||||||
|
ssh user@server "mkdir -p /path/to/space"
|
||||||
|
|
||||||
|
# rsync 上传(排除 Obsidian 配置目录,Silverbullet 用不上)
|
||||||
|
rsync -avP --exclude ".obsidian" "/d/onedrive/note/" user@server:/path/to/space/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、HTTPS + 域名(强烈建议)
|
||||||
|
|
||||||
|
裸 HTTP 下密码明文传输,不安全。用 Caddy 做反向代理 + 自动 TLS 证书(Let's Encrypt)。
|
||||||
|
|
||||||
|
### 前提条件
|
||||||
|
|
||||||
|
- 一个已备案/可用的域名,如 `notes.yourdomain.com`
|
||||||
|
- 域名 A 记录已指向服务器公网 IP
|
||||||
|
- 服务器 80 和 443 端口未被占用(云服务器需在安全组放行这两个端口)
|
||||||
|
|
||||||
|
### 整合后的 docker-compose.yml
|
||||||
|
|
||||||
|
将 Caddy 和 Silverbullet 放在同一个 compose 文件中,让它们共享同一个 Docker 网络,容器间用服务名互相访问:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
silverbullet:
|
||||||
|
image: ghcr.io/silverbulletmd/silverbullet:latest
|
||||||
|
container_name: silverbullet
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./space:/space
|
||||||
|
environment:
|
||||||
|
- SB_USER=admin:改成你的强密码
|
||||||
|
# 不暴露 ports,只允许 Caddy 通过内部网络访问
|
||||||
|
|
||||||
|
caddy:
|
||||||
|
image: caddy:latest
|
||||||
|
container_name: caddy
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile
|
||||||
|
- caddy_data:/data # 证书和密钥持久化,避免重启重新申请
|
||||||
|
- caddy_config:/config # Caddy 自身配置
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
|
```
|
||||||
|
|
||||||
|
> **关键**:`caddy_data` 和 `caddy_config` 用 named volume 而非 bind mount,避免权限问题,且证书重启不丢失。
|
||||||
|
|
||||||
|
### Caddyfile 配置
|
||||||
|
|
||||||
|
在 `docker-compose.yml` 同级目录创建 `Caddyfile`(纯文本,无后缀):
|
||||||
|
|
||||||
|
```caddyfile
|
||||||
|
# 基础版:自动 HTTPS + 反向代理
|
||||||
|
notes.yourdomain.com {
|
||||||
|
reverse_proxy silverbullet:3000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**常用增强配置**:
|
||||||
|
|
||||||
|
```caddyfile
|
||||||
|
notes.yourdomain.com {
|
||||||
|
# 反向代理
|
||||||
|
reverse_proxy silverbullet:3000
|
||||||
|
|
||||||
|
# 访问日志(排查问题时打开)
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/access.log
|
||||||
|
}
|
||||||
|
|
||||||
|
# 限制请求体大小(上传大文件时调大)
|
||||||
|
request_body {
|
||||||
|
max_size 50MB
|
||||||
|
}
|
||||||
|
|
||||||
|
# 安全头(可选)
|
||||||
|
header {
|
||||||
|
X-Content-Type-Options nosniff
|
||||||
|
X-Frame-Options DENY
|
||||||
|
-Server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 启动与验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 启动
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# 查看 Caddy 日志(确认证书申请是否成功)
|
||||||
|
docker compose logs caddy -f
|
||||||
|
```
|
||||||
|
|
||||||
|
正常日志中应能看到类似 `certificate obtained successfully` 的输出。然后浏览器访问 `https://notes.yourdomain.com` 即可。
|
||||||
|
|
||||||
|
### 排错
|
||||||
|
|
||||||
|
| 问题 | 检查项 |
|
||||||
|
|---|---|
|
||||||
|
| 证书申请失败 | 确认域名 A 记录已生效(`dig notes.yourdomain.com` 或 `nslookup`),且 80 端口能从公网访问 |
|
||||||
|
| 502 Bad Gateway | `docker compose ps` 确认 silverbullet 容器在运行;确认 Caddyfile 中 `reverse_proxy` 的目标容器名与 compose 中 service 名一致 |
|
||||||
|
| 端口被占用 | 如果服务器已有 nginx/apache,先停掉再启 Caddy,或让 Caddy 监听其他端口 |
|
||||||
|
| 国内服务器 | 80/443 端口需备案;若无备案可用非标端口 + DNS 验证,但 Caddy 默认 HTTP-01 验证仍需 80 端口可达 |
|
||||||
|
|
||||||
|
> 无域名临时方案:frp / 路由侠等内网穿透工具把 3000 端口暴露出去。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、数据备份
|
||||||
|
|
||||||
|
笔记是纯 Markdown → 备份 = 压缩目录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 手动备份
|
||||||
|
tar czf notes-backup-$(date +%F).tar.gz /path/to/space/
|
||||||
|
|
||||||
|
# cron 定时备份 + 保留最近 7 份
|
||||||
|
0 3 * * * tar czf /backup/notes-$(date +%F).tar.gz /path/to/space/ && ls -t /backup/notes-*.tar.gz | tail -n +8 | xargs rm -f
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、使用方式转变(关键)
|
||||||
|
|
||||||
|
选浏览器编辑 → **服务器目录成为唯一权威版本**,本地 OneDrive 降级为离线备份:
|
||||||
|
|
||||||
|
| 场景 | 操作 |
|
||||||
|
|---|---|
|
||||||
|
| 日常编辑 | 浏览器打开 Silverbullet,直接改服务器文件 |
|
||||||
|
| 本地离线备份 | `rsync user@server:/path/to/space/ /d/onedrive/note/` |
|
||||||
|
| 多设备 | 全部走浏览器,无需装任何东西 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[大模型架构基础]] — 本笔记库的正式学习内容
|
||||||
|
- [[AI编译器现状与前景]] — 技术趋势分析
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新:2026-08-05*
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
# frp 内网穿透部署指南
|
||||||
|
|
||||||
|
> 2026-08-13 更新。目标:通过云服务器(公网 IP `58.87.87.208`)随时随地访问家里多台机器的 SSH 和 RDP,统一用域名 `hyonglin.top` + 端口区分。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 背景与方案
|
||||||
|
|
||||||
|
**需求**:家里机器在 NAT 内网、没有公网 IP,想在任意地点 SSH 进去、远程桌面操作。
|
||||||
|
|
||||||
|
**选型结论**:frp(Fast Reverse Proxy),成熟的内网穿透工具。
|
||||||
|
|
||||||
|
- 家里机器(内网)主动反向连到云服务器,云服务器监听公网端口转发进来
|
||||||
|
- 一个服务端(frps)对多个客户端(frpc),加机器只需加端口,服务端不用动
|
||||||
|
- Go 编写,单文件二进制,Linux/Windows 通用,systemd 管理开机自启
|
||||||
|
|
||||||
|
### 架构
|
||||||
|
|
||||||
|
```
|
||||||
|
你(任意地点) 云服务器 frps 家里机器 frpc(可多台)
|
||||||
|
│ │ │
|
||||||
|
├─SSH hyonglin.top:2201──▶│─监听 2201───────────▶│─▶ pc01:22
|
||||||
|
├─SSH hyonglin.top:2202──▶│─监听 2202───────────▶│─▶ pc02:22
|
||||||
|
├─RDP hyonglin.top:3389──▶│─监听 3389───────────▶│─▶ pc01:3389
|
||||||
|
├─RDP hyonglin.top:3390──▶│─监听 3390───────────▶│─▶ pc02:3389
|
||||||
|
│ └─frpc 主动连 bindPort 7000◀─┘
|
||||||
|
```
|
||||||
|
|
||||||
|
> 域名只解析到 IP,**端口才是区分机器的关键**。RDP 不能共用 3389(TCP 层没有域名概念),但 frp 的 `remotePort` 独立于本机 `localPort`,本机 RDP 端口保持 3389 不用改。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 端口规划
|
||||||
|
|
||||||
|
| 机器 | SSH(remotePort) | RDP(remotePort) | 本机端口 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| pc01 | 2201 | 3389 | 22 / 3389 |
|
||||||
|
| pc02 | 2202 | 3390 | 22 / 3389 |
|
||||||
|
| 新增机器 | 2203 | 3391 | … |
|
||||||
|
|
||||||
|
固定端口:frps 客户端连接 `7000`、管理面板 `7500`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、服务端 frps 部署(云服务器)
|
||||||
|
|
||||||
|
### 下载与安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 下载(GitHub 慢时走镜像 ghfast.top)
|
||||||
|
wget https://ghfast.top/https://github.com/fatedier/frp/releases/download/v0.65.0/frp_0.65.0_linux_amd64.tar.gz
|
||||||
|
tar xzf frp_0.65.0_linux_amd64.tar.gz
|
||||||
|
|
||||||
|
sudo cp frp_0.65.0_linux_amd64/frps /usr/local/bin/
|
||||||
|
sudo mkdir -p /etc/frp
|
||||||
|
```
|
||||||
|
|
||||||
|
### 服务端配置 `/etc/frp/frps.toml`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
bindPort = 7000 # frpc 连接端口
|
||||||
|
auth.token = "0ae2664b411c41645e5c9ab6779724d4" # 客户端认证令牌(frpc 必须一致)
|
||||||
|
|
||||||
|
# 管理面板
|
||||||
|
webServer.addr = "0.0.0.0"
|
||||||
|
webServer.port = 7500
|
||||||
|
webServer.user = "admin"
|
||||||
|
webServer.password = "Admin-0ae2664b"
|
||||||
|
|
||||||
|
# 日志
|
||||||
|
log.to = "/var/log/frps.log"
|
||||||
|
log.level = "info"
|
||||||
|
log.maxDays = 7
|
||||||
|
```
|
||||||
|
|
||||||
|
### systemd 服务 `/etc/systemd/system/frps.service`
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=frp server
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable --now frps
|
||||||
|
systemctl status frps # active (running)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、客户端 frpc 部署(家里机器)
|
||||||
|
|
||||||
|
### 客户端配置 `/etc/frp/frpc.toml`
|
||||||
|
|
||||||
|
以 pc01 为例:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
serverAddr = "hyonglin.top"
|
||||||
|
serverPort = 7000
|
||||||
|
auth.token = "0ae2664b411c41645e5c9ab6779724d4"
|
||||||
|
|
||||||
|
# SSH:服务器 2201 → 本机 22
|
||||||
|
[[proxies]]
|
||||||
|
name = "pc01-ssh"
|
||||||
|
type = "tcp"
|
||||||
|
localIP = "127.0.0.1"
|
||||||
|
localPort = 22
|
||||||
|
remotePort = 2201
|
||||||
|
|
||||||
|
# RDP:服务器 3389 → 本机 3389
|
||||||
|
[[proxies]]
|
||||||
|
name = "pc01-rdp"
|
||||||
|
type = "tcp"
|
||||||
|
localIP = "127.0.0.1"
|
||||||
|
localPort = 3389
|
||||||
|
remotePort = 3389
|
||||||
|
```
|
||||||
|
|
||||||
|
> 加第二台(pc02):把 `name` 换成 `pc02-*`、`remotePort` 换成 `2202`/`3390`,`serverAddr`/`token` 不变即可。
|
||||||
|
|
||||||
|
### 安装(frpc 二进制 + systemd)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo install -m 755 ~/frpc /usr/local/bin/frpc
|
||||||
|
sudo mkdir -p /etc/frp
|
||||||
|
sudo cp ~/frpc.toml /etc/frp/frpc.toml
|
||||||
|
sudo cp ~/frpc.service /etc/systemd/system/frpc.service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable --now frpc
|
||||||
|
systemctl status frpc # active (running)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、家里开启 SSH 和 RDP 服务
|
||||||
|
|
||||||
|
### SSH
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt install -y openssh-server
|
||||||
|
sudo systemctl enable --now ssh
|
||||||
|
```
|
||||||
|
|
||||||
|
### RDP(Ubuntu 内置,无需装 xrdp)
|
||||||
|
|
||||||
|
- 打开 **设置 → 系统 → 远程桌面**
|
||||||
|
- 开启 **远程登录**(Remote Desktop / RDP)开关,记下用户名密码
|
||||||
|
- 端口默认 3389
|
||||||
|
|
||||||
|
> ⚠️ Ubuntu 内置 RDP 依赖**已登录的图形会话**。重启后停在登录界面、无人登录时 RDP 连不上。若要无人值守,需换 xrdp 方案。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、云安全组放行端口(关键坑)
|
||||||
|
|
||||||
|
**最容易漏的一步**:云服务商控制台的「防火墙/安全组」默认只开 22/80/443,需手动放行 TCP:
|
||||||
|
|
||||||
|
```
|
||||||
|
7000(frps 连接)、2201/2202(SSH 转发)、3389/3390(RDP 转发)
|
||||||
|
```
|
||||||
|
|
||||||
|
> 服务器内部 `ufw` 是 inactive,iptables 只黑名单了若干恶意 IP,不影响端口;问题出在**云控制台安全组**,与服务器内防火墙无关。
|
||||||
|
|
||||||
|
> 7500(frps 管理面板)走 `frp.hyonglin.top` HTTPS 后,建议在安全组**撤销 7500 的公网放行**,避免明文暴露。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、验证与使用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 服务器端确认 frpc 已登录、代理已监听
|
||||||
|
ss -tlnp | grep -E '2201|2202|3389|3390'
|
||||||
|
sudo tail -f /var/log/frps.log # 应看到 client login / new proxy success
|
||||||
|
```
|
||||||
|
|
||||||
|
连接方式(统一 hyonglin.top + 端口):
|
||||||
|
|
||||||
|
| 目标 | 命令 |
|
||||||
|
|---|---|
|
||||||
|
| pc01 SSH | `ssh 用户名@hyonglin.top -p 2201` |
|
||||||
|
| pc01 RDP | 远程桌面连 `hyonglin.top:3389` |
|
||||||
|
| pc02 SSH | `ssh 用户名@hyonglin.top -p 2202` |
|
||||||
|
| pc02 RDP | 远程桌面连 `hyonglin.top:3390` |
|
||||||
|
|
||||||
|
管理面板:`https://frp.hyonglin.top`(admin / Admin-0ae2664b)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 排错记录
|
||||||
|
|
||||||
|
| 症状 | 原因 | 解决 |
|
||||||
|
|---|---|---|
|
||||||
|
| frpc 状态 active 但 frps 日志无 login 记录 | 云安全组没放行 7000 | 控制台放行 7000 及转发端口 |
|
||||||
|
| `login to server failed` | token 不一致 | 检查 frpc/frps 的 auth.token 是否相同 |
|
||||||
|
| 2201 没监听 | frpc 没启动或代理注册失败 | `journalctl -u frpc -n 50` 看报错 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[主页与Caddy反向代理]] — 主页/面板的 HTTPS 入口
|
||||||
|
- [[sshwifty网页SSH终端]] — 浏览器里连 SSH
|
||||||
|
- [[Silverbullet部署指南]] — 本服务器自建服务
|
||||||
|
- [frp官方文档](https://gofrp.org/zh-cn/)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新:2026-08-13*
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# sshwifty 网页 SSH 终端
|
||||||
|
|
||||||
|
> 2026-08-13 记录。网页版通用 SSH 客户端,浏览器里填主机/端口/账号即可连接任意机器。Go 单二进制,内存占用 ~10–30MB。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## docker-compose 服务
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
sshwifty:
|
||||||
|
image: niruix/sshwifty:latest
|
||||||
|
container_name: sshwifty
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- SSHWIFTY_CONFIG=/etc/sshwifty.conf.json # 指向配置文件
|
||||||
|
volumes:
|
||||||
|
- ./sshwifty.conf.json:/etc/sshwifty.conf.json
|
||||||
|
```
|
||||||
|
|
||||||
|
不暴露端口,由 Caddy 反代 `sshwifty:8182`(WebSocket,Caddy 默认支持),入口 `https://ssh.hyonglin.top`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 配置文件 sshwifty.conf.json(含预设主机)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"SharedKey": "hylssh0813",
|
||||||
|
"Servers": [
|
||||||
|
{ "ListenInterface": "0.0.0.0", "ListenPort": 8182 }
|
||||||
|
],
|
||||||
|
"Presets": [
|
||||||
|
{
|
||||||
|
"Title": "pc01",
|
||||||
|
"Type": "SSH",
|
||||||
|
"Host": "hyonglin.top:2201",
|
||||||
|
"Meta": { "User": "ylhan", "Encoding": "utf-8", "Authentication": "Password" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Title": "pc02",
|
||||||
|
"Type": "SSH",
|
||||||
|
"Host": "hyonglin.top:2202",
|
||||||
|
"Meta": { "User": "ylhan", "Encoding": "utf-8", "Authentication": "Password" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Title": "云服务器",
|
||||||
|
"Type": "SSH",
|
||||||
|
"Host": "hyonglin.top:22",
|
||||||
|
"Meta": { "User": "ubuntu", "Encoding": "utf-8", "Authentication": "Password" }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"OnlyAllowPresetRemotes": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 端口写在 `Host` 里用 `host:port`,没有单独的 Port 字段。`OnlyAllowPresetRemotes: true` 可限制只连预设主机。改完配置 `docker compose up -d sshwifty` 重启生效。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
|
||||||
|
1. 打开 `https://ssh.hyonglin.top`,输入 SharedKey 密码
|
||||||
|
2. 预设主机点一下即连,也可手动填任意主机:
|
||||||
|
|
||||||
|
| 预设 | 目标 |
|
||||||
|
|---|---|
|
||||||
|
| pc01 | `hyonglin.top:2201` |
|
||||||
|
| pc02 | `hyonglin.top:2202` |
|
||||||
|
| 云服务器 | `hyonglin.top:22` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 坑:Known Remotes 不跨设备
|
||||||
|
|
||||||
|
Known Remotes(已知主机)存在浏览器 `localStorage`,换机器/换浏览器/清缓存都会丢,**没有服务端存储**。
|
||||||
|
|
||||||
|
要跨设备固定入口,就用上面的 **Presets**(服务端配置,所有机器通用)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[frp内网穿透部署指南]] — SSH/RDP 端口转发
|
||||||
|
- [[主页与Caddy反向代理]] — ssh.hyonglin.top 的 HTTPS 入口
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
# 主页与 Caddy 反向代理
|
||||||
|
|
||||||
|
> 2026-08-13 记录。用 Caddy 给自建服务套 HTTPS,并做一个主页统一列出服务链接。域名都在 Cloudflare 管理,用 DNS challenge 自动签证书。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 域名规划
|
||||||
|
|
||||||
|
所有域名 A 记录统一指向 `58.87.87.208`:
|
||||||
|
|
||||||
|
| 域名 | 用途 |
|
||||||
|
|---|---|
|
||||||
|
| `hyonglin.top` | 主页(导航)+ SSH/RDP 直连(纯 DNS 不经 Caddy) |
|
||||||
|
| `www.hyonglin.top` | 301 重定向到 hyonglin.top |
|
||||||
|
| `note.hyonglin.top` | 笔记 Silverbullet |
|
||||||
|
| `frp.hyonglin.top` | frp 管理面板 |
|
||||||
|
| `ssh.hyonglin.top` | 网页 SSH 终端 |
|
||||||
|
| `git.hyonglin.top` | Git 服务(Gitea) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 主页
|
||||||
|
|
||||||
|
静态页 `silverbullet/homepage/index.html`,导航分「自建服务」「常用链接」两组;以后加服务在 `<ul class="links">` 里加一行即可(目录挂载,改完实时生效)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Caddyfile
|
||||||
|
|
||||||
|
`silverbullet/Caddyfile`:
|
||||||
|
|
||||||
|
```caddyfile
|
||||||
|
# www → 主域名 301
|
||||||
|
www.hyonglin.top {
|
||||||
|
tls {
|
||||||
|
dns cloudflare {env.CF_API_TOKEN}
|
||||||
|
}
|
||||||
|
redir https://hyonglin.top{path} 301
|
||||||
|
}
|
||||||
|
|
||||||
|
# 主页
|
||||||
|
hyonglin.top {
|
||||||
|
tls {
|
||||||
|
dns cloudflare {env.CF_API_TOKEN}
|
||||||
|
}
|
||||||
|
root * /srv/homepage
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
# frp 管理面板
|
||||||
|
frp.hyonglin.top {
|
||||||
|
tls {
|
||||||
|
dns cloudflare {env.CF_API_TOKEN}
|
||||||
|
}
|
||||||
|
reverse_proxy host.docker.internal:7500
|
||||||
|
}
|
||||||
|
|
||||||
|
# 笔记
|
||||||
|
note.hyonglin.top {
|
||||||
|
tls {
|
||||||
|
dns cloudflare {env.CF_API_TOKEN}
|
||||||
|
}
|
||||||
|
reverse_proxy silverbullet:3000
|
||||||
|
}
|
||||||
|
|
||||||
|
# 网页 SSH 终端
|
||||||
|
ssh.hyonglin.top {
|
||||||
|
tls {
|
||||||
|
dns cloudflare {env.CF_API_TOKEN}
|
||||||
|
}
|
||||||
|
reverse_proxy sshwifty:8182
|
||||||
|
}
|
||||||
|
|
||||||
|
# Git 服务
|
||||||
|
git.hyonglin.top {
|
||||||
|
tls {
|
||||||
|
dns cloudflare {env.CF_API_TOKEN}
|
||||||
|
}
|
||||||
|
reverse_proxy gitea:3000
|
||||||
|
}
|
||||||
|
|
||||||
|
# 备案期间 IP 直连主页(HTTP,非标端口绕过备案拦 80/443)
|
||||||
|
:8080 {
|
||||||
|
root * /srv/homepage
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## compose 关键改动
|
||||||
|
|
||||||
|
Caddy 在 Docker 里,要访问宿主机上的 frps(7500),需加 `extra_hosts`;主页则挂载目录:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
caddy:
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway" # 让容器访问宿主机 frps:7500
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile
|
||||||
|
- ./homepage:/srv/homepage # 主页静态文件
|
||||||
|
```
|
||||||
|
|
||||||
|
改完 `docker compose up -d` 重建 Caddy,证书自动签发(DNS challenge)。frps 面板仍保留自身 basic auth,HTTPS + 面板认证双重保护。
|
||||||
|
|
||||||
|
主页导航:`silverbullet/homepage/index.html`,分「自建服务」「常用链接」两组;加服务在 `<ul class="links">` 里加一行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 坑:单文件 bind mount
|
||||||
|
|
||||||
|
Caddyfile 是**单文件 bind mount**,用编辑器「重命名替换」改完后容器内不生效(inode 变化),必须重建:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d --force-recreate caddy
|
||||||
|
```
|
||||||
|
|
||||||
|
(主页 index.html 是**目录挂载**,改完实时生效,无需重建。)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [[frp内网穿透部署指南]] — frp 端口与转发
|
||||||
|
- [[Gitea部署指南]] — git.hyonglin.top 后端
|
||||||
|
- [[sshwifty网页SSH终端]] — ssh.hyonglin.top 后端
|
||||||
|
- [[Silverbullet部署指南]] — note.hyonglin.top 后端
|
||||||
Reference in New Issue
Block a user