mirror of
https://github.com/orbbec/OrbbecSDK_ROS2.git
synced 2026-10-03 19:47:46 +08:00
add Chinese Document
This commit is contained in:
@@ -22,10 +22,23 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install sphinx recommonmark sphinx-rtd-theme sphinx-markdown-tables
|
pip install -r docs/en/requirements.txt
|
||||||
|
|
||||||
- name: Build HTML
|
- name: Build English Docs
|
||||||
run: sphinx-build -b html docs docs/_build/html
|
run: |
|
||||||
|
cd docs/en
|
||||||
|
sphinx-build -b html . _build/html
|
||||||
|
|
||||||
|
- name: Build Chinese Docs
|
||||||
|
run: |
|
||||||
|
cd docs/zh
|
||||||
|
sphinx-build -b html . _build/html
|
||||||
|
|
||||||
|
- name: Prepare deployment directory
|
||||||
|
run: |
|
||||||
|
mkdir -p _deploy
|
||||||
|
cp -r docs/en/_build/html/* _deploy/
|
||||||
|
cp -r docs/zh/_build/html _deploy/zh
|
||||||
|
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
uses: peaceiris/actions-gh-pages@v4
|
uses: peaceiris/actions-gh-pages@v4
|
||||||
@@ -33,4 +46,4 @@ jobs:
|
|||||||
deploy_key: ${{ secrets.DEPLOY_KEY }}
|
deploy_key: ${{ secrets.DEPLOY_KEY }}
|
||||||
external_repository: orbbec/OrbbecSDK_ROS2
|
external_repository: orbbec/OrbbecSDK_ROS2
|
||||||
publish_branch: gh-pages
|
publish_branch: gh-pages
|
||||||
publish_dir: docs/_build/html
|
publish_dir: _deploy
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
# 双语文档语言切换指南
|
||||||
|
|
||||||
|
## GitHub Pages 部署结构
|
||||||
|
|
||||||
|
当推送到 GitHub 后,文档将自动构建并部署到以下结构:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://orbbec.github.io/OrbbecSDK_ROS2/
|
||||||
|
├── index.html # 英文版首页(默认)
|
||||||
|
├── _static/ # 英文版静态资源
|
||||||
|
├── 1_overview/ # 英文版内容
|
||||||
|
├── 2_installation/
|
||||||
|
├── ...
|
||||||
|
└── zh/ # 中文版
|
||||||
|
├── index.html # 中文版首页
|
||||||
|
├── _static/ # 中文版静态资源
|
||||||
|
├── 1_overview/ # 中文版内容
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 访问地址
|
||||||
|
|
||||||
|
- **英文版(默认)**: `https://orbbec.github.io/OrbbecSDK_ROS2/`
|
||||||
|
- **中文版**: `https://orbbec.github.io/OrbbecSDK_ROS2/zh/`
|
||||||
|
|
||||||
|
## 如何添加语言切换链接
|
||||||
|
|
||||||
|
### 方法 1:在自定义 CSS 中添加语言切换按钮(推荐)
|
||||||
|
|
||||||
|
编辑 `docs/en/source/_static/custom.css` 和 `docs/zh/source/_static/custom.css`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* 在页面右上角添加语言切换链接 */
|
||||||
|
.wy-nav-top::after {
|
||||||
|
content: "中文";
|
||||||
|
position: absolute;
|
||||||
|
right: 60px;
|
||||||
|
top: 0;
|
||||||
|
height: 45px;
|
||||||
|
line-height: 45px;
|
||||||
|
padding: 0 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 为链接添加点击事件 */
|
||||||
|
.wy-nav-top {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方法 2:在自定义 JavaScript 中添加(更灵活)
|
||||||
|
|
||||||
|
创建或编辑 `docs/en/source/_static/language-switch.js`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// 创建语言切换链接
|
||||||
|
var langSwitch = document.createElement('a');
|
||||||
|
langSwitch.href = '/OrbbecSDK_ROS2/zh/';
|
||||||
|
langSwitch.textContent = '中文';
|
||||||
|
langSwitch.style.cssText = 'position: fixed; top: 10px; right: 60px; z-index: 1000; color: #fff; background: #2980b9; padding: 5px 15px; border-radius: 3px; text-decoration: none;';
|
||||||
|
|
||||||
|
document.body.appendChild(langSwitch);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
然后在 `docs/en/conf.py` 中添加:
|
||||||
|
|
||||||
|
```python
|
||||||
|
html_js_files = [
|
||||||
|
'language-switch.js',
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
对应的中文版 `docs/zh/source/_static/language-switch.js`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var langSwitch = document.createElement('a');
|
||||||
|
langSwitch.href = '/OrbbecSDK_ROS2/';
|
||||||
|
langSwitch.textContent = 'English';
|
||||||
|
langSwitch.style.cssText = 'position: fixed; top: 10px; right: 60px; z-index: 1000; color: #fff; background: #2980b9; padding: 5px 15px; border-radius: 3px; text-decoration: none;';
|
||||||
|
|
||||||
|
document.body.appendChild(langSwitch);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方法 3:修改 Sphinx 主题模板(最专业)
|
||||||
|
|
||||||
|
1. 创建自定义模板覆盖 `docs/en/source/_templates/layout.html`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
{% extends "!layout.html" %}
|
||||||
|
|
||||||
|
{% block extrahead %}
|
||||||
|
{{ super() }}
|
||||||
|
<style>
|
||||||
|
.language-switch {
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
right: 60px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.language-switch a {
|
||||||
|
color: #fff;
|
||||||
|
background: #2980b9;
|
||||||
|
padding: 5px 15px;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.language-switch a:hover {
|
||||||
|
background: #3498db;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block menu %}
|
||||||
|
{{ super() }}
|
||||||
|
<div class="language-switch">
|
||||||
|
<a href="/OrbbecSDK_ROS2/zh/">中文</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 对应的中文版 `docs/zh/source/_templates/layout.html`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
{% extends "!layout.html" %}
|
||||||
|
|
||||||
|
{% block extrahead %}
|
||||||
|
{{ super() }}
|
||||||
|
<style>
|
||||||
|
.language-switch {
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
right: 60px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.language-switch a {
|
||||||
|
color: #fff;
|
||||||
|
background: #2980b9;
|
||||||
|
padding: 5px 15px;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.language-switch a:hover {
|
||||||
|
background: #3498db;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block menu %}
|
||||||
|
{{ super() }}
|
||||||
|
<div class="language-switch">
|
||||||
|
<a href="/OrbbecSDK_ROS2/">English</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 在 conf.py 中配置主题选项(可选)
|
||||||
|
|
||||||
|
你也可以在 `conf.py` 中配置 RTD 主题的自定义选项:
|
||||||
|
|
||||||
|
```python
|
||||||
|
html_theme_options = {
|
||||||
|
# ...existing options...
|
||||||
|
'display_version': True,
|
||||||
|
'prev_next_buttons_location': 'bottom',
|
||||||
|
'style_external_links': False,
|
||||||
|
# 可以添加自定义 HTML
|
||||||
|
# 'canonical_url': '',
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 本地测试
|
||||||
|
|
||||||
|
在推送到 GitHub 之前,建议先本地测试:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 构建英文版
|
||||||
|
cd docs/en
|
||||||
|
make html
|
||||||
|
# 在浏览器中打开:docs/en/_build/html/index.html
|
||||||
|
|
||||||
|
# 构建中文版
|
||||||
|
cd docs/zh
|
||||||
|
make html
|
||||||
|
# 在浏览器中打开:docs/zh/_build/html/index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
## GitHub Actions 工作流程
|
||||||
|
|
||||||
|
当你推送代码到 `Document` 分支时,GitHub Actions 会自动:
|
||||||
|
|
||||||
|
1. ✅ 安装 Python 和依赖
|
||||||
|
2. ✅ 构建英文版文档到 `docs/en/_build/html/`
|
||||||
|
3. ✅ 构建中文版文档到 `docs/zh/_build/html/`
|
||||||
|
4. ✅ 将英文版作为根目录
|
||||||
|
5. ✅ 将中文版复制到 `/zh/` 子目录
|
||||||
|
6. ✅ 部署到 `gh-pages` 分支
|
||||||
|
|
||||||
|
## 推荐的实现方式
|
||||||
|
|
||||||
|
我推荐使用 **方法 2(JavaScript)** 或 **方法 3(模板)**,因为:
|
||||||
|
|
||||||
|
- ✅ 更灵活,易于维护
|
||||||
|
- ✅ 可以动态调整样式
|
||||||
|
- ✅ 不依赖于特定主题的 CSS 类名
|
||||||
|
- ✅ 可以添加更多交互功能(如自动检测浏览器语言)
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **链接路径**:注意区分相对路径和绝对路径
|
||||||
|
- 英文版链接到中文版:`/OrbbecSDK_ROS2/zh/`
|
||||||
|
- 中文版链接到英文版:`/OrbbecSDK_ROS2/`
|
||||||
|
|
||||||
|
2. **测试链接**:在部署后测试所有语言切换链接是否正常工作
|
||||||
|
|
||||||
|
3. **SEO 优化**:可以在 HTML head 中添加 `hreflang` 标签:
|
||||||
|
```html
|
||||||
|
<link rel="alternate" hreflang="en" href="/OrbbecSDK_ROS2/" />
|
||||||
|
<link rel="alternate" hreflang="zh-CN" href="/OrbbecSDK_ROS2/zh/" />
|
||||||
|
```
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
# 文档项目结构检查与修复总结
|
||||||
|
|
||||||
|
## 项目目标
|
||||||
|
创建英文版和中文版两个独立的 Sphinx 文档站点。
|
||||||
|
|
||||||
|
## 原始问题
|
||||||
|
|
||||||
|
### 1. 中文版缺失的关键文件
|
||||||
|
- ❌ `conf.py` - Sphinx 配置文件
|
||||||
|
- ❌ `index.rst` - 主索引文件
|
||||||
|
- ❌ `Makefile` - Linux/Mac 构建脚本
|
||||||
|
- ❌ `make.bat` - Windows 构建脚本
|
||||||
|
- ❌ `requirements.txt` - Python 依赖列表
|
||||||
|
|
||||||
|
### 2. 配置文件中的错误
|
||||||
|
- ❌ 英文版 `conf.py` 中 `github_doc_root` 未定义但被引用
|
||||||
|
- ❌ 英文版 `conf.py` 中路径使用 `source/images` 但实际目录是 `source/image`
|
||||||
|
|
||||||
|
## 修复内容
|
||||||
|
|
||||||
|
### ✅ 为中文版创建的文件
|
||||||
|
|
||||||
|
#### 1. `/docs/zh/conf.py`
|
||||||
|
- 项目名称:`OrbbecSDK V2 ROS2 封装`
|
||||||
|
- 语言设置:`language = 'zh_CN'`
|
||||||
|
- 版权信息:`奥比中光科技集团股份有限公司`
|
||||||
|
- 时间格式:`%Y年%m月%d日 %H:%M:%S`
|
||||||
|
- 图片路径:`source/image`(与实际目录结构一致)
|
||||||
|
- 修复了 `github_doc_root` 未定义的问题
|
||||||
|
|
||||||
|
#### 2. `/docs/zh/index.rst`
|
||||||
|
- 主文档标题:`OrbbecSDK V2 ROS2 封装文档`
|
||||||
|
- 包含所有章节的 toctree:
|
||||||
|
- 1_overview - 概览
|
||||||
|
- 2_installation - 安装
|
||||||
|
- 3_quickstarts - 快速入门
|
||||||
|
- 4_application_guide - 应用指南
|
||||||
|
- 5_advanced_guide - 高级指南
|
||||||
|
- 6_benchmark - 基准测试
|
||||||
|
- 7_developer_guide - 开发者指南
|
||||||
|
- 8_FAQ - 常见问题
|
||||||
|
|
||||||
|
#### 3. `/docs/zh/Makefile`
|
||||||
|
- Linux/Mac 下构建文档的标准 Makefile
|
||||||
|
|
||||||
|
#### 4. `/docs/zh/make.bat`
|
||||||
|
- Windows 下构建文档的批处理脚本
|
||||||
|
|
||||||
|
#### 5. `/docs/zh/requirements.txt`
|
||||||
|
- 包含必需的 Python 依赖包:
|
||||||
|
- sphinx>=4.0.0
|
||||||
|
- sphinx_rtd_theme>=1.0.0
|
||||||
|
- recommonmark>=0.7.1
|
||||||
|
- sphinx-markdown-tables>=0.0.15
|
||||||
|
- myst-parser>=0.18.0
|
||||||
|
|
||||||
|
### ✅ 修复英文版的问题
|
||||||
|
|
||||||
|
#### 1. `/docs/en/conf.py`
|
||||||
|
- 修复 `html_static_path` 和 `html_extra_path` 从 `source/images` 改为 `source/image`
|
||||||
|
- 注释掉未定义的 `github_doc_root` 相关代码
|
||||||
|
|
||||||
|
## 当前目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
├── en/ # 英文文档
|
||||||
|
│ ├── conf.py # ✅ Sphinx 配置(已修复)
|
||||||
|
│ ├── index.rst # ✅ 主索引
|
||||||
|
│ ├── Makefile # ✅ 构建脚本
|
||||||
|
│ ├── make.bat # ✅ Windows 脚本
|
||||||
|
│ ├── requirements.txt # ✅ 依赖列表
|
||||||
|
│ └── source/ # 源文件目录
|
||||||
|
│ ├── _static/ # 静态资源
|
||||||
|
│ ├── _templates/ # 模板
|
||||||
|
│ ├── image/ # 图片目录
|
||||||
|
│ ├── 1_overview/ # 概览章节
|
||||||
|
│ ├── 2_installation/ # 安装章节
|
||||||
|
│ ├── 3_quickstarts/ # 快速入门
|
||||||
|
│ ├── 4_application_guide/ # 应用指南
|
||||||
|
│ ├── 5_advanced_guide/ # 高级指南
|
||||||
|
│ ├── 6_benchmark/ # 基准测试
|
||||||
|
│ ├── 7_developer_guide/ # 开发者指南
|
||||||
|
│ └── 8_FAQ/ # 常见问题
|
||||||
|
│
|
||||||
|
└── zh/ # 中文文档
|
||||||
|
├── conf.py # ✅ Sphinx 配置(新建)
|
||||||
|
├── index.rst # ✅ 主索引(新建)
|
||||||
|
├── Makefile # ✅ 构建脚本(新建)
|
||||||
|
├── make.bat # ✅ Windows 脚本(新建)
|
||||||
|
├── requirements.txt # ✅ 依赖列表(新建)
|
||||||
|
└── source/ # 源文件目录
|
||||||
|
├── _static/ # 静态资源
|
||||||
|
├── _templates/ # 模板
|
||||||
|
├── image/ # 图片目录
|
||||||
|
├── 1_overview/ # 概览章节
|
||||||
|
├── 2_installation/ # 安装章节
|
||||||
|
├── 3_quickstarts/ # 快速入门
|
||||||
|
├── 4_application_guide/ # 应用指南
|
||||||
|
├── 5_advanced_guide/ # 高级指南
|
||||||
|
├── 6_benchmark/ # 基准测试
|
||||||
|
├── 7_developer_guide/ # 开发者指南
|
||||||
|
└── 8_FAQ/ # 常见问题
|
||||||
|
```
|
||||||
|
|
||||||
|
## 如何构建文档
|
||||||
|
|
||||||
|
### 安装依赖
|
||||||
|
```bash
|
||||||
|
# 英文版
|
||||||
|
cd docs/en
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 中文版
|
||||||
|
cd docs/zh
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 构建 HTML 文档
|
||||||
|
|
||||||
|
#### Linux/Mac
|
||||||
|
```bash
|
||||||
|
# 英文版
|
||||||
|
cd docs/en
|
||||||
|
make html
|
||||||
|
|
||||||
|
# 中文版
|
||||||
|
cd docs/zh
|
||||||
|
make html
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
```bash
|
||||||
|
# 英文版
|
||||||
|
cd docs/en
|
||||||
|
make.bat html
|
||||||
|
|
||||||
|
# 中文版
|
||||||
|
cd docs/zh
|
||||||
|
make.bat html
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查看生成的文档
|
||||||
|
- 英文版:`docs/en/_build/html/index.html`
|
||||||
|
- 中文版:`docs/zh/_build/html/index.html`
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **目录结构正确**:英文版和中文版都采用相同的目录结构,便于维护
|
||||||
|
2. **独立配置**:两个版本有独立的配置文件,可以分别自定义
|
||||||
|
3. **共享资源**:_static 和 image 目录在两个版本间共享相同的资源
|
||||||
|
4. **语言设置**:
|
||||||
|
- 英文版:`language = 'en'`
|
||||||
|
- 中文版:`language = 'zh_CN'`
|
||||||
|
|
||||||
|
## 后续建议
|
||||||
|
|
||||||
|
1. 如果需要配置 GitHub 仓库链接,可以在 `conf.py` 中取消注释并设置 `github_doc_root` 变量
|
||||||
|
2. 考虑添加自动化构建脚本,同时构建两个版本
|
||||||
|
3. 可以在项目根目录添加一个主 README 文件,说明如何访问两个语言版本的文档
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Add language switcher buttons to all markdown pages in source and source_zh directories.
|
|
||||||
The buttons will be placed at the beginning of each file with relative path links.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
def get_relative_path(from_path, to_path):
|
|
||||||
"""Calculate relative path from one file to another."""
|
|
||||||
from_dir = os.path.dirname(from_path)
|
|
||||||
rel_path = os.path.relpath(to_path, from_dir)
|
|
||||||
return rel_path
|
|
||||||
|
|
||||||
def has_language_switcher(content):
|
|
||||||
"""Check if the file already has a language switcher."""
|
|
||||||
patterns = [
|
|
||||||
r'\[.*?English.*?\]',
|
|
||||||
r'\[.*?中文.*?\]',
|
|
||||||
r'\[.*?EN.*?\]',
|
|
||||||
r'\[.*?ZH.*?\]',
|
|
||||||
]
|
|
||||||
for pattern in patterns:
|
|
||||||
if re.search(pattern, content[:500]): # Check first 500 chars
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def add_language_switcher(file_path, is_chinese=False):
|
|
||||||
"""Add language switcher to a markdown file."""
|
|
||||||
|
|
||||||
# Read the file
|
|
||||||
with open(file_path, 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Check if already has switcher
|
|
||||||
if has_language_switcher(content):
|
|
||||||
print(f" ⏭️ Skipping {file_path} (already has switcher)")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Get relative path to the corresponding file in the other language
|
|
||||||
if is_chinese:
|
|
||||||
# source_zh -> source
|
|
||||||
en_path = str(file_path).replace('/source_zh/', '/source/')
|
|
||||||
if os.path.exists(en_path):
|
|
||||||
rel_path = get_relative_path(file_path, en_path)
|
|
||||||
switcher = f"[English]({rel_path}) | **中文**\n\n---\n\n"
|
|
||||||
else:
|
|
||||||
print(f" ⚠️ Warning: English version not found for {file_path}")
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
# source -> source_zh
|
|
||||||
zh_path = str(file_path).replace('/source/', '/source_zh/')
|
|
||||||
if os.path.exists(zh_path):
|
|
||||||
rel_path = get_relative_path(file_path, zh_path)
|
|
||||||
switcher = f"**English** | [中文]({rel_path})\n\n---\n\n"
|
|
||||||
else:
|
|
||||||
print(f" ⚠️ Warning: Chinese version not found for {file_path}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Add switcher at the beginning
|
|
||||||
new_content = switcher + content
|
|
||||||
|
|
||||||
# Write back
|
|
||||||
with open(file_path, 'w', encoding='utf-8') as f:
|
|
||||||
f.write(new_content)
|
|
||||||
|
|
||||||
print(f" ✅ Added switcher to {file_path}")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def process_directory(base_dir, is_chinese=False):
|
|
||||||
"""Process all markdown files in a directory."""
|
|
||||||
print(f"\n{'='*60}")
|
|
||||||
print(f"Processing {'Chinese' if is_chinese else 'English'} files in: {base_dir}")
|
|
||||||
print(f"{'='*60}")
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
for root, dirs, files in os.walk(base_dir):
|
|
||||||
for file in files:
|
|
||||||
if file.endswith('.md'):
|
|
||||||
file_path = os.path.join(root, file)
|
|
||||||
if add_language_switcher(file_path, is_chinese):
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
print(f"\n✨ Processed {count} files in {base_dir}")
|
|
||||||
return count
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Main function."""
|
|
||||||
script_dir = Path(__file__).parent.resolve()
|
|
||||||
|
|
||||||
source_dir = script_dir / 'source'
|
|
||||||
source_zh_dir = script_dir / 'source_zh'
|
|
||||||
|
|
||||||
print("🚀 Adding language switchers to all markdown pages...")
|
|
||||||
print(f"📁 Base directory: {script_dir}")
|
|
||||||
|
|
||||||
# Check if directories exist
|
|
||||||
if not source_dir.exists():
|
|
||||||
print(f"❌ Error: {source_dir} does not exist!")
|
|
||||||
return
|
|
||||||
|
|
||||||
if not source_zh_dir.exists():
|
|
||||||
print(f"❌ Error: {source_zh_dir} does not exist!")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Process English files
|
|
||||||
en_count = process_directory(source_dir, is_chinese=False)
|
|
||||||
|
|
||||||
# Process Chinese files
|
|
||||||
zh_count = process_directory(source_zh_dir, is_chinese=True)
|
|
||||||
|
|
||||||
print(f"\n{'='*60}")
|
|
||||||
print(f"🎉 Done!")
|
|
||||||
print(f" Total English files processed: {en_count}")
|
|
||||||
print(f" Total Chinese files processed: {zh_count}")
|
|
||||||
print(f" Total files processed: {en_count + zh_count}")
|
|
||||||
print(f"{'='*60}\n")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Add language switcher buttons to all RST chapter index files in source and source_zh directories.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
def get_relative_path(from_path, to_path):
|
|
||||||
"""Calculate relative path from one file to another."""
|
|
||||||
from_dir = os.path.dirname(from_path)
|
|
||||||
rel_path = os.path.relpath(to_path, from_dir)
|
|
||||||
return rel_path
|
|
||||||
|
|
||||||
def has_language_switcher(content):
|
|
||||||
"""Check if the file already has a language switcher."""
|
|
||||||
# Check for common language switcher patterns in first few lines
|
|
||||||
first_lines = '\n'.join(content.split('\n')[:10])
|
|
||||||
patterns = [
|
|
||||||
r'English.*中文',
|
|
||||||
r'中文.*English',
|
|
||||||
r'\*\*English\*\*',
|
|
||||||
r'\*\*中文\*\*',
|
|
||||||
]
|
|
||||||
for pattern in patterns:
|
|
||||||
if re.search(pattern, first_lines, re.IGNORECASE):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def add_language_switcher_to_rst(file_path, is_chinese=False):
|
|
||||||
"""Add language switcher to an RST file."""
|
|
||||||
|
|
||||||
# Read the file
|
|
||||||
with open(file_path, 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Check if already has switcher
|
|
||||||
if has_language_switcher(content):
|
|
||||||
print(f" ⏭️ Skipping {file_path} (already has switcher)")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Get relative path to the corresponding file in the other language
|
|
||||||
if is_chinese:
|
|
||||||
# source_zh -> source
|
|
||||||
en_path = str(file_path).replace('/source_zh/', '/source/')
|
|
||||||
if os.path.exists(en_path):
|
|
||||||
rel_path = get_relative_path(file_path, en_path)
|
|
||||||
# For RST files, convert path to HTML
|
|
||||||
rel_path_html = rel_path.replace('.rst', '.html')
|
|
||||||
switcher = f"`English <{rel_path_html}>`_ | **中文**\n\n----\n\n"
|
|
||||||
else:
|
|
||||||
print(f" ⚠️ Warning: English version not found for {file_path}")
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
# source -> source_zh
|
|
||||||
zh_path = str(file_path).replace('/source/', '/source_zh/')
|
|
||||||
if os.path.exists(zh_path):
|
|
||||||
rel_path = get_relative_path(file_path, zh_path)
|
|
||||||
# For RST files, convert path to HTML
|
|
||||||
rel_path_html = rel_path.replace('.rst', '.html')
|
|
||||||
switcher = f"**English** | `中文 <{rel_path_html}>`_\n\n----\n\n"
|
|
||||||
else:
|
|
||||||
print(f" ⚠️ Warning: Chinese version not found for {file_path}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Add switcher at the beginning
|
|
||||||
new_content = switcher + content
|
|
||||||
|
|
||||||
# Write back
|
|
||||||
with open(file_path, 'w', encoding='utf-8') as f:
|
|
||||||
f.write(new_content)
|
|
||||||
|
|
||||||
print(f" ✅ Added switcher to {file_path}")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def process_rst_files(base_dir, is_chinese=False):
|
|
||||||
"""Process all RST chapter index files in a directory."""
|
|
||||||
print(f"\n{'='*60}")
|
|
||||||
print(f"Processing {'Chinese' if is_chinese else 'English'} RST files in: {base_dir}")
|
|
||||||
print(f"{'='*60}")
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
# List of RST chapter index files to process
|
|
||||||
rst_files = [
|
|
||||||
'1_overview/overview.rst',
|
|
||||||
'2_installation/installation.rst',
|
|
||||||
'3_quickstarts/quickstarts.rst',
|
|
||||||
'4_application_guide/application_guide.rst',
|
|
||||||
'5_advanced_guide/advanced_guide.rst',
|
|
||||||
'6_benchmark/benchmark.rst',
|
|
||||||
'7_developer_guide/developer_guide.rst',
|
|
||||||
'8_FAQ/FAQ.rst',
|
|
||||||
]
|
|
||||||
|
|
||||||
for rst_file in rst_files:
|
|
||||||
file_path = os.path.join(base_dir, rst_file)
|
|
||||||
if os.path.exists(file_path):
|
|
||||||
if add_language_switcher_to_rst(file_path, is_chinese):
|
|
||||||
count += 1
|
|
||||||
else:
|
|
||||||
print(f" ⚠️ File not found: {file_path}")
|
|
||||||
|
|
||||||
print(f"\n✨ Processed {count} RST files in {base_dir}")
|
|
||||||
return count
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Main function."""
|
|
||||||
script_dir = Path(__file__).parent.resolve()
|
|
||||||
|
|
||||||
source_dir = script_dir / 'source'
|
|
||||||
source_zh_dir = script_dir / 'source_zh'
|
|
||||||
|
|
||||||
print("🚀 Adding language switchers to RST chapter index files...")
|
|
||||||
print(f"📁 Base directory: {script_dir}")
|
|
||||||
|
|
||||||
# Check if directories exist
|
|
||||||
if not source_dir.exists():
|
|
||||||
print(f"❌ Error: {source_dir} does not exist!")
|
|
||||||
return
|
|
||||||
|
|
||||||
if not source_zh_dir.exists():
|
|
||||||
print(f"❌ Error: {source_zh_dir} does not exist!")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Process English RST files
|
|
||||||
en_count = process_rst_files(source_dir, is_chinese=False)
|
|
||||||
|
|
||||||
# Process Chinese RST files
|
|
||||||
zh_count = process_rst_files(source_zh_dir, is_chinese=True)
|
|
||||||
|
|
||||||
print(f"\n{'='*60}")
|
|
||||||
print(f"🎉 Done!")
|
|
||||||
print(f" Total English RST files processed: {en_count}")
|
|
||||||
print(f" Total Chinese RST files processed: {zh_count}")
|
|
||||||
print(f" Total RST files processed: {en_count + zh_count}")
|
|
||||||
print(f"{'='*60}\n")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
+9
-8
@@ -91,9 +91,9 @@ html_favicon = "source/_static/orbbec_footerlogo_3d_world.svg"
|
|||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ['source/_static','source/images']
|
html_static_path = ['source/_static','source/image']
|
||||||
|
|
||||||
html_extra_path = ['source/images']
|
html_extra_path = ['source/image']
|
||||||
|
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
# 'analytics_id': 'G-EVD5Z6G6NH',
|
# 'analytics_id': 'G-EVD5Z6G6NH',
|
||||||
@@ -192,9 +192,10 @@ def copy_videos(app, exception):
|
|||||||
shutil.copytree(src_dir, dest_dir)
|
shutil.copytree(src_dir, dest_dir)
|
||||||
|
|
||||||
# 20201030
|
# 20201030
|
||||||
def setup(app):
|
# github_doc_root = 'https://github.com/yourusername/yourrepo/blob/main/'
|
||||||
app.add_config_value('recommonmark_config', {
|
# def setup(app):
|
||||||
'url_resolver': lambda url: github_doc_root + url,
|
# app.add_config_value('recommonmark_config', {
|
||||||
'auto_toc_tree_section': 'Contents',
|
# 'url_resolver': lambda url: github_doc_root + url,
|
||||||
}, True)
|
# 'auto_toc_tree_section': 'Contents',
|
||||||
app.add_transform(AutoStructify)
|
# }, True)
|
||||||
|
# app.add_transform(AutoStructify)
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// Language switch for English version
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Create language switch link
|
||||||
|
var langSwitch = document.createElement('div');
|
||||||
|
langSwitch.className = 'language-switch';
|
||||||
|
langSwitch.innerHTML = '<a href="/OrbbecSDK_ROS2/zh/" title="切换到中文">中文</a>';
|
||||||
|
|
||||||
|
// Add styles
|
||||||
|
var style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
.language-switch {
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
right: 60px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.language-switch a {
|
||||||
|
color: #fff;
|
||||||
|
background: #2980b9;
|
||||||
|
padding: 5px 15px;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
.language-switch a:hover {
|
||||||
|
background: #3498db;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.language-switch {
|
||||||
|
top: 5px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.head.appendChild(style);
|
||||||
|
document.body.appendChild(langSwitch);
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line, and also
|
||||||
|
# from the environment for the first two.
|
||||||
|
SPHINXOPTS ?=
|
||||||
|
SPHINXBUILD ?= sphinx-build
|
||||||
|
SOURCEDIR = .
|
||||||
|
BUILDDIR = _build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
+199
@@ -0,0 +1,199 @@
|
|||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# This file only contains a selection of the most common options. For a full
|
||||||
|
# list see the documentation:
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sphinx
|
||||||
|
|
||||||
|
import recommonmark
|
||||||
|
from recommonmark.transform import AutoStructify
|
||||||
|
|
||||||
|
# import sphinx_book_theme
|
||||||
|
# import sphinx_rtd_theme
|
||||||
|
# import furo
|
||||||
|
|
||||||
|
|
||||||
|
#choice theme default
|
||||||
|
# html_theme = 'sphinx_book_theme'
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
# html_theme = "furo"
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
project = 'OrbbecSDK V2 ROS2 封装'
|
||||||
|
# project = """
|
||||||
|
# OrbbecSDK ROS2 文档
|
||||||
|
# """
|
||||||
|
copyright = '2025, 奥比中光科技集团股份有限公司 www.orbbec.com.'
|
||||||
|
author = '奥比中光科技集团股份有限公司 www.orbbec.com.'
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = ['recommonmark',
|
||||||
|
'sphinx_markdown_tables',
|
||||||
|
|
||||||
|
'sphinx.ext.autosectionlabel',
|
||||||
|
|
||||||
|
# 'myst_parser',
|
||||||
|
]
|
||||||
|
|
||||||
|
# The suffix(es) of source filenames.
|
||||||
|
# You can specify multiple suffix as a list of string:
|
||||||
|
source_suffix = ['.rst', 'rest', '.md', '.MD']
|
||||||
|
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = 'zh_CN'
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
# html_logo = "source/_static/orbbec_logo2.png"
|
||||||
|
# html_favicon = "source/_static/orbbec_logo2.png"
|
||||||
|
|
||||||
|
#html_logo = "source/_static/orbbec-light_no_colour.svg"
|
||||||
|
html_favicon = "source/_static/orbbec_footerlogo_3d_world.svg"
|
||||||
|
# html_logo = "source/_static/orbbec_footerlogo_3d_world.svg"
|
||||||
|
# html_favicon = "source/_static/orbbec_footerlogo_3d_world.svg"
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['source/_static','source/image']
|
||||||
|
|
||||||
|
html_extra_path = ['source/image']
|
||||||
|
|
||||||
|
html_theme_options = {
|
||||||
|
# 'analytics_id': 'G-EVD5Z6G6NH',
|
||||||
|
'collapse_navigation': False,
|
||||||
|
# 启用导航栏的"粘性"头部,这样导航栏会固定在页面顶部
|
||||||
|
'sticky_navigation': True,
|
||||||
|
# 配置导航栏的深度,-1 表示显示所有层级的标题
|
||||||
|
'navigation_depth': 5,
|
||||||
|
# 'show_navbar_depth': 4,
|
||||||
|
# 导航栏显示+号
|
||||||
|
'collapse_navigation': False,
|
||||||
|
|
||||||
|
# 'analytics_anonymize_ip': False,
|
||||||
|
# 'logo_only': False,
|
||||||
|
# 'display_version': True,
|
||||||
|
# 'prev_next_buttons_location': 'bottom',
|
||||||
|
# 'style_external_links': False,
|
||||||
|
# 'vcs_pageview_mode': '',
|
||||||
|
# 'style_nav_header_background': 'white',
|
||||||
|
# # Toc options
|
||||||
|
# 'collapse_navigation': True,
|
||||||
|
# 'sticky_navigation': True,
|
||||||
|
# 'navigation_depth': 5,
|
||||||
|
# 'includehidden': True,
|
||||||
|
# 'titles_only': False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# # 添加自定义的 JavaScript 文件
|
||||||
|
|
||||||
|
|
||||||
|
# #不需要添加_static目录,加了会不起作用
|
||||||
|
html_css_files = ["custom.css"]
|
||||||
|
|
||||||
|
# 与文档无关的其他资源的路径,由于无需构建此文件夹的文件,会自动忽略
|
||||||
|
# 默认情况下,此路径下的文件会输出到生成的html的根目录
|
||||||
|
# html_extra_path = ["_extra"]
|
||||||
|
|
||||||
|
# 在页面底部显示上一次更新于某某时间
|
||||||
|
html_last_updated_fmt = "%Y年%m月%d日 %H:%M:%S"
|
||||||
|
|
||||||
|
# 以下为 sphinx_book_theme 的主题配置/定制(sphinx_book_theme)
|
||||||
|
# html_theme_options = {
|
||||||
|
# # ----------------主题内容中导航栏的功能按钮配置--------
|
||||||
|
# # 添加存储库链接
|
||||||
|
# "repository_url": "https://github.com/Eugene-Forest/NoteBook",
|
||||||
|
# # 添加按钮以链接到存储库
|
||||||
|
# "use_repository_button": True,
|
||||||
|
# # 要添加按钮以打开有关当前页面的问题
|
||||||
|
# "use_issues_button": True,
|
||||||
|
# # 添加一个按钮来建议编辑
|
||||||
|
# "use_edit_page_button": True,
|
||||||
|
# # 默认情况下,编辑按钮将指向master分支,但如果您想更改此设置,请使用以下配置
|
||||||
|
# "repository_branch": "main",
|
||||||
|
# # 默认情况下,编辑按钮将指向存储库的根目录;而我们 sphinx项目的 doc文件其实是在 source 文件夹下的,包括 conf.py 和 index(.rst) 主目录
|
||||||
|
# "path_to_docs": "source",
|
||||||
|
# # 您可以添加 use_download_button 按钮,允许用户以多种格式下载当前查看的页面
|
||||||
|
# "use_download_button": True,
|
||||||
|
|
||||||
|
# # --------------------------右侧辅助栏配置---------
|
||||||
|
# # 重命名右侧边栏页内目录名,标题的默认值为Contents。
|
||||||
|
# "toc_title": "页内目录",
|
||||||
|
# # 通常,右侧边栏页内目录中仅显示页面的第 2 级标题,只有当它们是活动部分的一部分时(在屏幕上滚动时),才会显示更深的级别。可以使用以下配置显示更深的级别,指示应显示多少级别
|
||||||
|
# "show_toc_level": 2,
|
||||||
|
|
||||||
|
# # --------------------------左侧边栏配置--------------
|
||||||
|
# # logo 配置
|
||||||
|
# "logo_only": True,
|
||||||
|
# # 控制左侧边栏列表的深度展开,默认值为1,它仅显示文档的顶级部分
|
||||||
|
# "show_navbar_depth": 1,
|
||||||
|
# # 自定义侧边栏页脚,默认为 Theme by the Executable Book Project
|
||||||
|
# # "extra_navbar": "<p>Your HTML</p>",
|
||||||
|
# "home_page_in_toc": True,
|
||||||
|
# # ------------------------- 单页模式 -----------------
|
||||||
|
# # 如果您的文档只有一个页面,并且您不需要左侧导航栏,那么您可以 使用以下配置将其配置sphinx-book-theme 为以单页模式运行
|
||||||
|
# # "single_page": True,
|
||||||
|
# }
|
||||||
|
|
||||||
|
# 是否显示页面下方的由sphinx创建, 默认为True
|
||||||
|
html_show_sphinx = False
|
||||||
|
|
||||||
|
# Function to copy video files to output directory
|
||||||
|
def setup(app):
|
||||||
|
app.connect('build-finished', copy_videos)
|
||||||
|
|
||||||
|
def copy_videos(app, exception):
|
||||||
|
if exception is None: # Only copy if build succeeded
|
||||||
|
src_dir = os.path.join(app.srcdir, '_static/videos')
|
||||||
|
dest_dir = os.path.join(app.outdir, '_static/videos')
|
||||||
|
if os.path.exists(src_dir):
|
||||||
|
shutil.copytree(src_dir, dest_dir)
|
||||||
|
|
||||||
|
# 20201030
|
||||||
|
# github_doc_root = 'https://github.com/yourusername/yourrepo/blob/main/'
|
||||||
|
# def setup(app):
|
||||||
|
# app.add_config_value('recommonmark_config', {
|
||||||
|
# 'url_resolver': lambda url: github_doc_root + url,
|
||||||
|
# 'auto_toc_tree_section': 'Contents',
|
||||||
|
# }, True)
|
||||||
|
# app.add_transform(AutoStructify)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
.. OrbbecSDK V2 ROS2 封装文档主文件,由
|
||||||
|
sphinx-quickstart 于 Tue Sep 9 21:55:16 2025 创建。
|
||||||
|
您可以完全按照自己的喜好调整此文件,但至少应包含根 `toctree` 指令。
|
||||||
|
|
||||||
|
OrbbecSDK V2 ROS2 封装文档
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 3
|
||||||
|
:numbered:
|
||||||
|
|
||||||
|
source/1_overview/overview.rst
|
||||||
|
source/2_installation/installation.rst
|
||||||
|
source/3_quickstarts/quickstarts.rst
|
||||||
|
source/4_application_guide/application_guide.rst
|
||||||
|
source/5_advanced_guide/advanced_guide.rst
|
||||||
|
source/6_benchmark/benchmark.rst
|
||||||
|
source/7_developer_guide/developer_guide.rst
|
||||||
|
source/8_FAQ/FAQ.rst
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
|
if "%SPHINXBUILD%" == "" (
|
||||||
|
set SPHINXBUILD=sphinx-build
|
||||||
|
)
|
||||||
|
set SOURCEDIR=.
|
||||||
|
set BUILDDIR=_build
|
||||||
|
|
||||||
|
%SPHINXBUILD% >NUL 2>NUL
|
||||||
|
if errorlevel 9009 (
|
||||||
|
echo.
|
||||||
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
|
echo.may add the Sphinx directory to PATH.
|
||||||
|
echo.
|
||||||
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
|
echo.https://www.sphinx-doc.org/
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "" goto help
|
||||||
|
|
||||||
|
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:help
|
||||||
|
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||||
|
|
||||||
|
:end
|
||||||
|
popd
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
sphinx>=4.0.0
|
||||||
|
sphinx_rtd_theme>=1.0.0
|
||||||
|
recommonmark>=0.7.1
|
||||||
|
sphinx-markdown-tables>=0.0.15
|
||||||
|
myst-parser>=0.18.0
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# 概述
|
||||||
|
|
||||||
|
## 关于 OrbbecSDK ROS2 包装器
|
||||||
|
|
||||||
|
OrbbecSDK ROS2 包装器是奥比中光科技集团为 ROS2(Robot Operating System 2)开发的官方软件包。它为 Orbbec 3D 相机提供完整的接口支持,使开发者能够轻松地在机器人应用中集成深度感知和 3D 视觉功能。
|
||||||
|
|
||||||
|
## 主要特性
|
||||||
|
|
||||||
|
- ✅ **完整的相机支持**: 支持所有 Orbbec 3D 相机型号
|
||||||
|
- 🚀 **高性能**: 优化的数据流处理和低延迟
|
||||||
|
- 🎯 **易于使用**: 简单的 ROS2 接口和丰富的示例
|
||||||
|
- 🔧 **可配置**: 灵活的启动参数和配置选项
|
||||||
|
- 📊 **丰富的数据流**: 深度、彩色、红外、点云等
|
||||||
|
- 🌐 **跨平台**: 支持 Linux、Windows 和 ARM 平台
|
||||||
|
|
||||||
|
## 支持的设备
|
||||||
|
|
||||||
|
本 ROS2 包装器支持以下 Orbbec 3D 相机系列:
|
||||||
|
|
||||||
|
- Astra 系列
|
||||||
|
- Gemini 系列
|
||||||
|
- Femto 系列
|
||||||
|
- Persee 系列
|
||||||
|
|
||||||
|
详细的设备兼容性列表请参考产品文档。
|
||||||
|
|
||||||
|
## 快速链接
|
||||||
|
|
||||||
|
- [安装指南](../2_installation/installation.rst)
|
||||||
|
- [快速开始](../3_quickstarts/quickstarts.rst)
|
||||||
|
- [应用指南](../4_application_guide/application_guide.rst)
|
||||||
|
|
||||||
|
## 技术支持
|
||||||
|
|
||||||
|
如需技术支持,请访问:
|
||||||
|
- 官方网站: https://www.orbbec.com
|
||||||
|
- GitHub 仓库: https://github.com/orbbec/OrbbecSDK_ROS2
|
||||||
|
- 技术支持: support@orbbec.com
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
# Orbbec SDK 概述
|
||||||
|
|
||||||
|
本节介绍 C++ 版本的 Orbbec SDK。其架构和概念与 Python 包装器一致。
|
||||||
|
|
||||||
|
## 术语
|
||||||
|
|
||||||
|
| 序号 | 名称 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1 | USB | 通用串行总线(Universal Serial Bus) |
|
||||||
|
| 2 | UVC | USB 视频类(USB Video Class) |
|
||||||
|
| 3 | Firmware | 3D 相机的固件 |
|
||||||
|
| 4 | Disparity | 视差是指从两个有一定距离的点观察同一目标时的方向差异。 |
|
||||||
|
| 5 | D2D (Disparity to depth) | 视差转深度是一种图像处理技术,用于将视差信息转换为深度信息。 |
|
||||||
|
| 6 | Hardware D2D | 视差转深度在设备内部实现,不占用主机的计算能力。 |
|
||||||
|
| 7 | Software D2D | 视差转深度,在 Orbbec SDK 中实现 |
|
||||||
|
| 8 | Depth point cloud | 深度点云,三维世界坐标系中点的坐标,可以使用深度相机的内参转换为点云。 |
|
||||||
|
| 9 | RGBD point cloud | 叠加了 RGB 信息的点云 |
|
||||||
|
| 10 | D2C | "深度到彩色"(Depth to Color)是一种对深度图像进行逐像素几何变换的功能。其结果是通过 D2C 变换将深度图像与其对应的彩色图像对齐,使我们能够通过在变换后的深度图像中使用相同图像坐标位置来定位彩色像素的深度信息。经过 D2C 变换后,我们生成一个与目标彩色图像大小相同的深度图像,其中图像内容表示彩色相机坐标系中的深度数据。换句话说,它重建了一个使用彩色相机的原点和尺寸"拍摄"的深度图像,其中每个像素与彩色相机的相应像素坐标匹配。 |
|
||||||
|
| 11 | Hardware D2C | 硬件 D2C 是指在相机内部执行深度到彩色变换的功能,相机直接输出 D2C 变换的结果。 |
|
||||||
|
| 12 | Software D2C | 使用 SDK 在主机端执行 D2C 计算。 |
|
||||||
|
| 13 | Frame aggregation (FrameSet) | 帧聚合,将深度、红外和彩色帧组合成一个帧集(Frameset),并通过管道调用。 |
|
||||||
|
| 14 | C2D | "彩色到深度"(Color to Depth)是一种对彩色图像进行逐像素几何变换的功能。其结果是通过 C2D 变换将彩色图像与其对应的深度图像对齐。 |
|
||||||
|
| 15 | MetaData | 帧元数据是一组参数(或属性),提供了帧生成时传感器配置和/或系统状态的快照。 |
|
||||||
|
| 16 | HDR | 高动态范围(High Dynamic Range,HDR)成像允许成像系统在极暗和极亮的场景中拍摄图像。我们提出了一种在主机 CPU 上运行的软件解决方案来实现此功能。它利用两个连续帧的数据,直接合成这两个深度图像,从而增强 16 位深度图像的动态范围。 |
|
||||||
|
| 17 | LDP | 激光近距离保护(Laser close-range protection) |
|
||||||
|
|
||||||
|
## Orbbec SDK v2 架构概述
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 应用层(Application)
|
||||||
|
|
||||||
|
OrbbecViewer、示例程序和用户应用程序实现。
|
||||||
|
|
||||||
|
- 接口和封装层(Interfaces and Encapsulation Layer)
|
||||||
|
|
||||||
|
OrbbecSDK 接口封装和包装器封装。
|
||||||
|
|
||||||
|
- 高级层(High-level Layer)
|
||||||
|
|
||||||
|
HighLevel 封装了核心业务组件,并使用管道(pipeline)向外部提供接口。
|
||||||
|
|
||||||
|
- 基础业务层(Basic business layer)
|
||||||
|
|
||||||
|
核心业务逻辑框架的实现。
|
||||||
|
|
||||||
|
- 平台抽象层(Platform abstraction layer)
|
||||||
|
|
||||||
|
跨平台组件抽象操作系统差异,提供统一的访问接口。
|
||||||
|
|
||||||
|
- 平台实现层(Platform implementation layer)
|
||||||
|
|
||||||
|
各平台的驱动实现。
|
||||||
|
|
||||||
|
## SDK 概念概述
|
||||||
|
|
||||||
|
- Context(上下文)
|
||||||
|
|
||||||
|
上下文提供一组设置,包括设备状态更改回调、日志级别等设置。Context 可以访问多个设备。
|
||||||
|
|
||||||
|
- Device(设备)
|
||||||
|
|
||||||
|
一个实际的硬件设备对应一个 Device 对象,用于获取设备的相关信息并控制其属性。
|
||||||
|
|
||||||
|
- Pipeline(管道)
|
||||||
|
|
||||||
|
HighLevel 对应的对象,封装了快速访问 SDK 的接口。它具有简单的功能,使用户能够快速上手并使用 SDK。
|
||||||
|
|
||||||
|
- Config(配置)
|
||||||
|
|
||||||
|
提供启用数据流、对齐模式和帧聚合模式的配置,用于控制数据输出的行为。
|
||||||
|
|
||||||
|
- StreamProfile(流配置)
|
||||||
|
|
||||||
|
流配置定义分辨率、帧率和编码格式等参数,还提供相机参数的管理。
|
||||||
|
|
||||||
|
- Frame(帧)
|
||||||
|
|
||||||
|
表示流中的一帧数据,还包含该帧数据的相关信息,如时间戳、类型等。
|
||||||
|
|
||||||
|
- Filter(滤镜)
|
||||||
|
|
||||||
|
主要指用于复合流 FrameSet 的一些算法处理模块,如点云算法处理。
|
||||||
|
|
||||||
|
- Record(录制)
|
||||||
|
|
||||||
|
录制功能,捕获数据流并将其保存为文件,以便后续分析或回放。
|
||||||
|
|
||||||
|
- Playback(回放)
|
||||||
|
|
||||||
|
回放功能,播放录制的文件,并支持控制回放速度和其他相关参数。
|
||||||
|
|
||||||
|
## SDK 编程模型
|
||||||
|
|
||||||
|
以下是 C++ 编程逻辑流程图。Python 的编程逻辑与之相同。
|
||||||
|
|
||||||
|
- 标准流程图:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
标准流程图演示了如何从设备列表创建设备、设置和获取参数,以及应用后处理滤镜。
|
||||||
|
|
||||||
|
- 使用默认配置的流程图(基于 OrbbecSDKConfig.xml 中的默认设置获取流):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
概述
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
本章节提供 Orbbec SDK 的概述,包括支持的产品、主要功能和架构。
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
introduction.md
|
||||||
|
orbbecsdk_overview.md
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
### 从源码构建
|
||||||
|
|
||||||
|
#### 环境配置
|
||||||
|
|
||||||
|
根据官方指南安装 ROS 2:
|
||||||
|
|
||||||
|
* [ROS 2 安装指南(Ubuntu)](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html)
|
||||||
|
|
||||||
|
启用 ROS 2 自动补全:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
eval "$(register-python-argcomplete3 ros2)"
|
||||||
|
eval "$(register-python-argcomplete3 colcon)"
|
||||||
|
```
|
||||||
|
|
||||||
|
创建 `colcon` 工作空间:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/ros2_ws/src
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Linux ROS2 包装器编译
|
||||||
|
|
||||||
|
克隆源代码并切换到 `v2-main` 分支:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ros2_ws/src
|
||||||
|
git clone https://github.com/orbbec/OrbbecSDK_ROS2.git
|
||||||
|
cd OrbbecSDK_ROS2
|
||||||
|
git checkout v2-main
|
||||||
|
```
|
||||||
|
|
||||||
|
安装依赖项:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install libgflags-dev nlohmann-json3-dev \
|
||||||
|
ros-$ROS_DISTRO-image-transport ros-${ROS_DISTRO}-image-transport-plugins ros-${ROS_DISTRO}-compressed-image-transport \
|
||||||
|
ros-$ROS_DISTRO-image-publisher ros-$ROS_DISTRO-camera-info-manager \
|
||||||
|
ros-$ROS_DISTRO-diagnostic-updater ros-$ROS_DISTRO-diagnostic-msgs ros-$ROS_DISTRO-statistics-msgs \
|
||||||
|
ros-$ROS_DISTRO-backward-ros libdw-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
可选依赖项:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 435Le writeCustomerDate 功能:
|
||||||
|
sudo apt install libssl-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
构建:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ros2_ws
|
||||||
|
colcon build --event-handlers console_direct+ --cmake-args -DCMAKE_BUILD_TYPE=Release
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
安装
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
本章节说明如何安装 Orbbec ROS2 Python SDK,包括从源码构建、安装依赖项以及使用注册脚本。
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
build_the_package.md
|
||||||
|
registration_script.md
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
## 注册脚本(必需)
|
||||||
|
|
||||||
|
为了让 Orbbec 相机在 Linux 上被正确识别,请安装 udev 规则:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ros2_ws/src/OrbbecSDK_ROS2/orbbec_camera/scripts
|
||||||
|
sudo bash install_udev_rules.sh
|
||||||
|
sudo udevadm control --reload-rules && sudo udevadm trigger
|
||||||
|
```
|
||||||
|
|
||||||
|
此步骤对于 Linux 用户是**必需的**。
|
||||||
|
|
||||||
|
`注意:` 如果不执行此脚本,由于权限问题,打开设备将会失败。您需要使用 sudo(管理员权限)运行示例程序。
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# OrbbecViewer 快速入门
|
||||||
|
|
||||||
|
> **注意:** 此 ROS 包的参数和功能与 **Orbbec Viewer** 保持一致;有关参数使用或设备型号支持的任何问题,请参考 Orbbec Viewer。
|
||||||
|
|
||||||
|
## 下载
|
||||||
|
|
||||||
|
**仓库链接:**[OrbbecViewer 下载](https://github.com/orbbec/OrbbecSDK_v2/releases)
|
||||||
|
|
||||||
|
根据您的设备类型选择合适版本的 OrbbecViewer。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 连接设备
|
||||||
|
|
||||||
|
当 Orbbec Viewer 打开时,当前设备连接状态将显著地显示在应用程序窗口的左上角。此区域提供关于相机是否已连接并正常工作的即时反馈。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 相机控制
|
||||||
|
|
||||||
|
您可以使用窗口顶部的按钮快速查看图像,并在窗口左侧的相机面板中调整图像参数。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 设备信息和固件升级
|
||||||
|
|
||||||
|
点击窗口左下角的图标以查看当前相机信息并升级固件。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
请参考下面的列表获取最新的相机固件。[更多信息请点击这里。](https://www.orbbec.com/docs/g330-explore-camera-functions-in-orbbec-viewer/)
|
||||||
|
|
||||||
|
**仓库链接:**[固件下载](https://github.com/orbbec/OrbbecFirmware?tab=readme-ov-file#firmware-download)
|
||||||
|
|
||||||
|
| **产品列表** | **下载链接** | 最新版本 |
|
||||||
|
| ------------------ | -------------------------------------------------------------------------------------------------- | ---------- |
|
||||||
|
| Femto Bolt | [Femto Bolt 固件](https://github.com/orbbec/OrbbecFirmware/releases/tag/Femto-Bolt-Firmware) | v1.1.2 |
|
||||||
|
| Femto Mega | [Femto Mega 固件](https://github.com/orbbec/OrbbecFirmware/releases/tag/Femto-Mega-Firmware) | v1.3.1 |
|
||||||
|
| Gemini 2 | [Gemini 2 固件](https://github.com/orbbec/OrbbecFirmware/releases/tag/Gemini2-Firmware) | v1.4.98 |
|
||||||
|
| Gemini 2 L | [Gemini 2L 固件](https://github.com/orbbec/OrbbecFirmware/releases/tag/Gemini2L-Firmware) | v1.5.02 |
|
||||||
|
| Femto Mega I | [Femto Mega I 固件](https://github.com/orbbec/OrbbecFirmware/releases/tag/Femto-Mega-I-Firmware) | v2.0.4 |
|
||||||
|
| Gemini 330 系列 | [Gemini 330 系列固件](https://www.orbbec.com/docs/g330-firmware-release/?_gl=1) | |
|
||||||
|
| Gemini 215 | [Gemini 215](https://github.com/orbbec/OrbbecFirmware/releases/tag/Gemini215-Firmware) | v1.0.9 |
|
||||||
|
| Gemini 210 | [Gemini 210](https://github.com/orbbec/OrbbecFirmware/releases/tag/Gemini210-Firmware) | v1.0.9 |
|
||||||
|
| Gemini 435Le | [Gemini 435Le](https://github.com/orbbec/OrbbecFirmware/releases/tag/Gemin435Le-Firmware) | v1.3.2 |
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
## ROS 包快速入门
|
||||||
|
|
||||||
|
### 简介
|
||||||
|
|
||||||
|
本节提供 Orbbec ROS 2 包装器的快速入门指南。
|
||||||
|
您将学习如何:
|
||||||
|
|
||||||
|
* 启动相机节点。
|
||||||
|
* 在 **RViz2** 中可视化深度/彩色流。
|
||||||
|
* 使用 **ROS 2 CLI 工具**与话题和服务交互。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 构建您的第一个相机应用
|
||||||
|
|
||||||
|
#### 步骤 1:配置 ROS 2 和工作空间环境
|
||||||
|
|
||||||
|
确保已配置 ROS 2 和工作空间环境:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source /opt/ros/$ROS_DISTRO/setup.bash
|
||||||
|
source ~/ros2_ws/install/setup.bash
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 步骤 2:启动相机节点
|
||||||
|
|
||||||
|
- 在终端 1 中
|
||||||
|
|
||||||
|
```bash
|
||||||
|
. ./install/setup.bash
|
||||||
|
ros2 run orbbec_camera list_devices_node #检查相机是否已连接
|
||||||
|
ros2 launch orbbec_camera gemini_330_series.launch.py # 或其他启动文件,见下表
|
||||||
|
```
|
||||||
|
|
||||||
|
如果您连接了多个相机,可以指定**序列号**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 launch orbbec_camera gemini_330_series.launch.py serial_number:=<您的相机序列号>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 步骤 3:在 RViz2 中可视化
|
||||||
|
|
||||||
|
启动 RViz2 并加载默认配置:
|
||||||
|
|
||||||
|
- 在终端 2 中
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rviz2
|
||||||
|
```
|
||||||
|
|
||||||
|
* 添加一个 **Image** 显示,将话题设置为 `/camera/color/image_raw`。
|
||||||
|
* 为 `/camera/depth/image_raw` 添加另一个 **Image** 显示。
|
||||||
|
* 可选:为 `/camera/depth/points` 添加 **PointCloud2** 显示。
|
||||||
|
|
||||||
|
现在您应该能在 RViz2 中看到彩色流、深度流和 3D 点云。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 示例功能
|
||||||
|
|
||||||
|
节点运行后,尝试一些 ROS 2 CLI 命令:
|
||||||
|
|
||||||
|
#### 列出可用的话题/服务/参数
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 topic list
|
||||||
|
ros2 service list
|
||||||
|
ros2 param list
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 回显话题
|
||||||
|
|
||||||
|
查看深度相机数据:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 topic echo /camera/depth/camera_info
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 调用服务
|
||||||
|
|
||||||
|
例如,获取设备信息:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/get_device_info orbbec_camera_msgs/srv/GetDeviceInfo '{}'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 使用 rosbag2 录制
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 bag record /camera/color/image_raw /camera/depth/image_raw
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
快速开始
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
本章节提供 SDK 的快速入门指南,帮助用户快速运行基本示例程序。
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
quickstart.md
|
||||||
|
orbbecviewer.md
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
应用指南
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
本章介绍使用SDK进行应用开发,包括启动参数配置、ROS2服务和话题使用。
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
launch_parameters.md
|
||||||
|
services.md
|
||||||
|
topics.md
|
||||||
|
coordinate_systems.md
|
||||||
|
camera_sensor_structure.md
|
||||||
|
tf_transformations.md
|
||||||
|
compressed_image.md
|
||||||
|
point_cloud.md
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
### 相机传感器结构
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
### 压缩图像
|
||||||
|
|
||||||
|
您可以使用 `image_transport` 通过 `jpeg` 压缩图像。以下是使用示例:
|
||||||
|
|
||||||
|
要访问压缩的彩色图像,可以使用以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 topic echo /camera/color/image_raw/compressed --no-arr
|
||||||
|
```
|
||||||
|
|
||||||
|
此命令将允许您从指定话题接收压缩的彩色图像。
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
### ROS2机器人坐标系 vs 相机光学坐标系
|
||||||
|
|
||||||
|
* 视角:
|
||||||
|
* 想象我们站在相机后面,向前看。
|
||||||
|
* 在讨论坐标、左右红外、传感器位置等时,始终使用此视角。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
* ROS2坐标系:(X: 向前,Y: 向左,Z: 向上)
|
||||||
|
* 相机光学坐标系:(X: 向右,Y: 向下,Z: 向前)
|
||||||
|
* 我们封装器话题中发布的所有数据都是直接从相机传感器获取的光学数据。
|
||||||
|
* 静态和动态TF话题发布光学坐标系和ROS坐标系,使用户能够在两个坐标系之间转换。
|
||||||
|
|||||||
@@ -0,0 +1,274 @@
|
|||||||
|
# 启动参数
|
||||||
|
|
||||||
|
> 如果您不确定如何设置参数,可以连接orbbec相机并打开 [OrbbecViewer](https://github.com/orbbec/OrbbecSDK/releases)。
|
||||||
|
|
||||||
|
以下是可用的启动参数:
|
||||||
|
|
||||||
|
### 核心与数据流配置
|
||||||
|
|
||||||
|
* **`camera_name`**
|
||||||
|
* 启动节点的命名空间。
|
||||||
|
* **`serial_number`**
|
||||||
|
* 相机的序列号。当使用多个相机时需要此参数。
|
||||||
|
* **`usb_port`**
|
||||||
|
* 相机的USB端口。当使用多个相机时需要此参数。
|
||||||
|
* **`device_num`**
|
||||||
|
* 设备数量。如果需要多个相机,必须填写此参数。
|
||||||
|
* **`[color|depth|left_ir|right_ir|ir]_[width|height|fps|format]`**
|
||||||
|
* 传感器流的分辨率和帧率。
|
||||||
|
* **`[color|depth|left_ir|right_ir|ir]_rotation`**
|
||||||
|
* 设置流图像旋转。
|
||||||
|
* 可能的值为 `0`、`90`、`180`、`270`。
|
||||||
|
* **`[color|depth|left_ir|right_ir|ir]_flip`**
|
||||||
|
* 启用流图像翻转。
|
||||||
|
* **`[color|depth|left_ir|right_ir|ir]_mirror`**
|
||||||
|
* 启用流图像镜像。
|
||||||
|
* **`enable_point_cloud`**
|
||||||
|
* 启用点云。
|
||||||
|
* **`enable_colored_point_cloud`**
|
||||||
|
* 启用RGB点云。
|
||||||
|
* **`cloud_frame_id`**
|
||||||
|
* 修改ros消息中的 `frame_id` 名称。
|
||||||
|
* **`ordered_pc`**
|
||||||
|
* 启用无效点云过滤。
|
||||||
|
* **`point_cloud_qos`、`[stream]_qos`、`[stream]_camera_info_qos`**
|
||||||
|
* ROS 2消息服务质量(QoS)设置。可能的值为 `SYSTEM_DEFAULT`、`DEFAULT`、`PARAMETER_EVENTS`、`SERVICES_DEFAULT`、`PARAMETERS`、`SENSOR_DATA`,不区分大小写。这些分别对应 `rmw_qos_profile_system_default`、`rmw_qos_profile_default`、`rmw_qos_profile_parameter_events`、`rmw_qos_profile_services_default`、`rmw_qos_profile_parameters` 和 `SENSOR_DATA`。
|
||||||
|
|
||||||
|
### 传感器控制
|
||||||
|
|
||||||
|
#### 彩色流
|
||||||
|
* **`enable_color_auto_exposure`**
|
||||||
|
* 启用彩色自动曝光。
|
||||||
|
* **`enable_color_auto_exposure_priority`**
|
||||||
|
* 启用彩色自动曝光优先级。
|
||||||
|
* **`color_exposure`**
|
||||||
|
* 设置彩色曝光。
|
||||||
|
* **`color_gain`**
|
||||||
|
* 设置彩色增益。
|
||||||
|
* **`enable_color_auto_white_balance`**
|
||||||
|
* 启用彩色自动白平衡。
|
||||||
|
* **`color_white_balance`**
|
||||||
|
* 设置彩色白平衡。
|
||||||
|
* **`color_ae_max_exposure`**
|
||||||
|
* 设置彩色自动曝光的最大曝光值。
|
||||||
|
* **`color_brightness`**、**`color_sharpness`**、**`color_gamma`**、**`color_saturation`**、**`color_contrast`**、**`color_hue`**
|
||||||
|
* 设置彩色亮度、锐度、伽马、饱和度、对比度和色调。
|
||||||
|
* **`color_backlight_compensation`**
|
||||||
|
* 启用彩色相机的背光补偿功能。**范围**:`0–6`,**默认值**:`3`。
|
||||||
|
* **`color_powerline_freq`**
|
||||||
|
* 设置电源线频率。可能的值为 `disable`、`50hz`、`60hz`、`auto`。
|
||||||
|
* **`enable_color_decimation_filter`** / **`color_decimation_filter_scale`**
|
||||||
|
* 启用彩色抽取滤波器并设置其比例。
|
||||||
|
* **`color_ae_roi_[left|right|top|bottom]`**
|
||||||
|
* 设置彩色自动曝光ROI。
|
||||||
|
* **`color_denoising_level`**
|
||||||
|
* 启用Gemini 330系列设备的ISP降噪功能。**范围:** `0–8`,**默认值:** `0`(自动)。
|
||||||
|
|
||||||
|
|
||||||
|
#### 深度流
|
||||||
|
* **`enable_depth_auto_exposure_priority`**
|
||||||
|
|
||||||
|
* 启用深度自动曝光优先级。
|
||||||
|
* **`mean_intensity_set_point`**
|
||||||
|
* 设置深度图像的目标平均强度。例如:`mean_intensity_set_point:=100`。
|
||||||
|
> **注意:** 这取代了已弃用的 `depth_brightness`,后者仍支持以保持向后兼容性。
|
||||||
|
* **`enable_depth_scale`**
|
||||||
|
* 启用深度缩放。
|
||||||
|
* **`depth_precision`**
|
||||||
|
* 深度精度应为 `1mm` 格式。默认值为 `1mm`。
|
||||||
|
* **`depth_ae_roi_[left|right|top|bottom]`**
|
||||||
|
* 设置深度自动曝光ROI。
|
||||||
|
|
||||||
|
#### 红外流
|
||||||
|
* **`enable_ir_auto_exposure`**
|
||||||
|
* 启用红外自动曝光。
|
||||||
|
* **`ir_exposure`** / **`ir_gain`**
|
||||||
|
* 设置红外曝光和增益。
|
||||||
|
* **`ir_ae_max_exposure`**
|
||||||
|
* 设置红外自动曝光的最大曝光值。
|
||||||
|
* **`ir_brightness`**
|
||||||
|
* 设置红外亮度。
|
||||||
|
|
||||||
|
#### 激光 / LDP
|
||||||
|
* **`enable_laser`**
|
||||||
|
* 启用激光。默认值为 `true`。
|
||||||
|
* **`laser_energy_level`**
|
||||||
|
* 设置激光能量级别。
|
||||||
|
* **`enable_ldp`** / **`ldp_power_level`**
|
||||||
|
* 启用LDP并设置其功率级别。
|
||||||
|
|
||||||
|
### 设备、同步与高级功能
|
||||||
|
|
||||||
|
#### 多相机同步
|
||||||
|
* **`sync_mode`**
|
||||||
|
* 设置同步模式。默认值为 `standalone`。
|
||||||
|
* **`depth_delay_us`** / **`color_delay_us`**
|
||||||
|
* 接收捕获命令或触发信号后深度/彩色图像捕获的延迟时间(微秒)。
|
||||||
|
* **`trigger2image_delay_us`**
|
||||||
|
* 接收捕获命令或触发信号后图像捕获的延迟时间(微秒)。
|
||||||
|
* **`trigger_out_delay_us`**
|
||||||
|
* 接收捕获命令或触发信号后触发信号输出的延迟时间(微秒)。
|
||||||
|
* **`trigger_out_enabled`**
|
||||||
|
* 启用触发输出信号。
|
||||||
|
* **`software_trigger_enabled`** / **`software_trigger_period`**
|
||||||
|
* 启用软件触发输出信号 / 设置软件触发周期(毫秒)。
|
||||||
|
* **`frames_per_trigger`**
|
||||||
|
* 触发模式下每次触发后每个流的帧数。
|
||||||
|
|
||||||
|
> 用于 [多相机同步](../5_advanced_guide/multi_camera/multi_camera_synced.md)。
|
||||||
|
|
||||||
|
#### 网络相机
|
||||||
|
* **`enumerate_net_device`**
|
||||||
|
* 启用自动枚举网络设备。
|
||||||
|
* **`net_device_ip`** / **`net_device_port`**
|
||||||
|
* 设置网络设备的IP地址和端口(通常为 `8090`)。
|
||||||
|
* **`force_ip_enable`**
|
||||||
|
* 启用强制IP功能。**默认值:** `false`
|
||||||
|
|
||||||
|
* **`force_ip_mac`**
|
||||||
|
* 连接多个相机时的目标设备MAC地址(例如,`"54:14:FD:06:07:DA"`)。您可以使用 `list_devices_node` 查找每个设备的MAC。**默认值:** `""`
|
||||||
|
|
||||||
|
* **`force_ip_address`**
|
||||||
|
* 要分配的静态IP地址。**默认值:** `192.168.1.10`
|
||||||
|
|
||||||
|
* **`force_ip_subnet_mask`**
|
||||||
|
* 静态IP的子网掩码。**默认值:** `255.255.255.0`
|
||||||
|
|
||||||
|
* **`force_ip_gateway`**
|
||||||
|
* 静态IP的网关地址。**默认值:** `192.168.1.1`
|
||||||
|
|
||||||
|
> 用于 [网络相机](../5_advanced_guide/configuration/net_camera.md)。
|
||||||
|
|
||||||
|
#### 设备特定
|
||||||
|
* **`device_preset`**
|
||||||
|
* 默认值为 `Default`。仅支持G330系列。有关更多信息,请参阅 [G330文档](https://www.orbbec.com/docs/g330-use-depth-presets/)。该值应为 [表中列出](../5_advanced_guide/configuration/predefined_presets.md) 的预设名称之一。
|
||||||
|
* **`enable_gmsl_trigger`** / **`gmsl_trigger_fps`**
|
||||||
|
* 启用gmsl触发输出信号 / 设置gmsl触发fps。用于 [gmsl相机](../5_advanced_guide/multi_camera/gmsl_camera.md)。
|
||||||
|
|
||||||
|
|
||||||
|
#### 视差
|
||||||
|
* **`disparity_to_depth_mode`**
|
||||||
|
* `HW`:使用硬件视差到深度转换。`SW`:使用软件视差到深度转换。
|
||||||
|
* **`disparity_range_mode`**、**`disparity_search_offset`**、**`disparity_offset_config`**
|
||||||
|
* 视差搜索偏移参数。用于 [视差搜索偏移](../5_advanced_guide/configuration/disparity_search_offset.md)。
|
||||||
|
|
||||||
|
#### 交错AE模式
|
||||||
|
* **`interleave_ae_mode`**
|
||||||
|
* 设置 `laser` 或 `hdr` 交错。
|
||||||
|
* **`interleave_frame_enable`**、**`interleave_skip_enable`**、**`interleave_skip_index`**
|
||||||
|
* 控制交错帧模式的参数。
|
||||||
|
* **`[hdr|laser]_index[0|1]_[...]`**
|
||||||
|
* 在交错帧模式下,设置hdr或laser交错帧的第0和第1帧参数。
|
||||||
|
* *所有交错参数用于 [交错ae模式](../5_advanced_guide/configuration/interleave_ae_mode.md)。*
|
||||||
|
|
||||||
|
#### 相机内同步
|
||||||
|
|
||||||
|
- **`depth_registration`**
|
||||||
|
* 启用深度帧与彩色帧的对齐。当 `enable_colored_point_cloud` 设置为 `true` 时需要此字段。
|
||||||
|
- **`align_mode`**
|
||||||
|
* 要使用的对齐模式。选项为 `HW`(硬件对齐)和 `SW`(软件对齐)。
|
||||||
|
- **`align_target_stream`**
|
||||||
|
* 设置对齐目标流模式。
|
||||||
|
* 可能的值为 `COLOR`、`DEPTH`。
|
||||||
|
* `COLOR`:将深度对齐到彩色。
|
||||||
|
* `DEPTH`:将彩色对齐到深度。
|
||||||
|
- **`intra_camera_sync_reference`**
|
||||||
|
- 设置相机内同步的参考点。适用于Gemini 330系列设备,当 `sync_mode` 设置为**软件**或**硬件触发**模式时。**选项:** `Start`、`Middle`、`End`。**默认值:** `Middle`
|
||||||
|
|
||||||
|
### 基础与通用参数
|
||||||
|
|
||||||
|
#### 固件与后端
|
||||||
|
* **`upgrade_firmware`**
|
||||||
|
* 输入参数为固件路径。
|
||||||
|
* **`preset_firmware_path`**
|
||||||
|
* 输入参数为预设固件路径。如果输入多个路径,每个路径需要用 `,` 分隔,最多可输入3个固件路径。
|
||||||
|
* **`uvc_backend`**
|
||||||
|
* 可选值:`v4l2`、`libuvc`。
|
||||||
|
* **`connection_delay`**
|
||||||
|
* 重新打开设备的延迟时间(毫秒)。某些设备(如Astra mini)需要较长时间初始化,热插拔时立即重新打开设备可能导致固件崩溃。
|
||||||
|
* **`retry_on_usb3_detection_failure`**
|
||||||
|
* 如果相机连接到USB 2.0端口且未检测到,系统将尝试重置相机最多三次。使用USB 2.0连接时建议将此参数设置为 `false`,以避免不必要的重置。
|
||||||
|
|
||||||
|
#### TF、外参与校准
|
||||||
|
* **`publish_tf`** / **`tf_publish_rate`**
|
||||||
|
* 启用TF发布并设置其发布速率。
|
||||||
|
* **`enable_publish_extrinsic`**
|
||||||
|
* 启用外参发布。
|
||||||
|
* **`ir_info_url`** / **`color_info_url`**
|
||||||
|
* 设置IR/彩色相机信息的URL。
|
||||||
|
* **`enable_color_undistortion`**
|
||||||
|
* 启用彩色去畸变。
|
||||||
|
|
||||||
|
#### 时间同步
|
||||||
|
* **`enable_sync_host_time`**
|
||||||
|
* 启用主机时间与相机时间的同步。默认值为 `true`。如果使用全局时间,设置为 `false`。
|
||||||
|
* **`time_domain`**
|
||||||
|
* 选择时间戳类型:`device`、`global` 和 `system`。
|
||||||
|
* **`time_sync_period`**
|
||||||
|
|
||||||
|
* 相机时间与主机系统同步的间隔(秒)。
|
||||||
|
> **注意**:仅当 **`enable_sync_host_time = true`** 且 **`time_domain = device`** 时需要设置此参数。
|
||||||
|
* **`enable_ptp_config`**
|
||||||
|
* 启用PTP时间同步。仅适用于Gemini 335Le。需要 `enable_sync_host_time` 设置为 `false`。
|
||||||
|
* **`enable_frame_sync`**
|
||||||
|
* 启用帧同步。
|
||||||
|
|
||||||
|
#### 日志与诊断
|
||||||
|
* **`log_level`**
|
||||||
|
* SDK日志级别。默认为 `info`。可选值:`debug`、`info`、`warn`、`error`、`fatal`。
|
||||||
|
* **`diagnostic_period`**
|
||||||
|
* 诊断周期(秒)。
|
||||||
|
* **`enable_heartbeat`**
|
||||||
|
* 启用心跳功能。默认为 `false`。如果为 `true`,相机节点将向固件发送心跳信号。
|
||||||
|
|
||||||
|
#### 其他
|
||||||
|
* **`config_file_path`**
|
||||||
|
* YAML配置文件的路径。默认为 `""`。如果未指定,将使用启动文件中的默认参数。
|
||||||
|
* **`frame_aggregate_mode`**
|
||||||
|
* 设置帧聚合输出模式。可选值:`full_frame`、`color_frame`、`ANY`、`disable`。
|
||||||
|
* **`enable_d2c_viewer`**
|
||||||
|
* 发布D2C叠加图像(仅用于测试)。
|
||||||
|
|
||||||
|
### IMU
|
||||||
|
|
||||||
|
* **`enable_accel`** / **`enable_gyro`**
|
||||||
|
* 启用加速度计/陀螺仪并输出其信息话题数据。
|
||||||
|
* **`enable_sync_output_accel_gyro`**
|
||||||
|
* 启用同步 `accel_gyro`,并输出IMU话题实时数据。
|
||||||
|
* **`accel_rate`** / **`gyro_rate`**
|
||||||
|
* 加速度计/陀螺仪的频率。值范围从 `1.5625hz` 到 `32khz`。
|
||||||
|
* **`accel_range`** / **`gyro_range`**
|
||||||
|
* 加速度计(`2g`、`4g`、`8g`、`16g`)和陀螺仪(`16dps` 到 `2000dps`)的范围。
|
||||||
|
* **`enable_accel_data_correction`** / **`enable_gyro_data_correction`**
|
||||||
|
* 启用加速度计/陀螺仪的数据校正。
|
||||||
|
* **`linear_accel_cov`** / **`angular_vel_cov`**
|
||||||
|
* 线性加速度和角速度的协方差。
|
||||||
|
|
||||||
|
### 深度滤波器
|
||||||
|
|
||||||
|
* **`enable_decimation_filter`**
|
||||||
|
* 启用深度抽取滤波器。使用 `decimation_filter_scale` 设置。
|
||||||
|
* **`enable_hdr_merge`**
|
||||||
|
* 启用深度hdr合并滤波器。使用 `hdr_merge_exposure_1` 等设置。
|
||||||
|
* **`enable_sequence_id_filter`**
|
||||||
|
* 启用深度序列id滤波器。使用 `sequence_id_filter_id` 设置。
|
||||||
|
* **`enable_threshold_filter`**
|
||||||
|
* 启用深度阈值滤波器。使用 `threshold_filter_max`、`threshold_filter_min` 设置。
|
||||||
|
* **`enable_hardware_noise_removal_filter`**
|
||||||
|
* 启用深度硬件降噪滤波器。
|
||||||
|
* **`enable_noise_removal_filter`**
|
||||||
|
* 启用深度软件降噪滤波器。使用 `noise_removal_filter_min_diff` 等设置。
|
||||||
|
* **`enable_spatial_filter`**
|
||||||
|
* 启用深度空间滤波器。使用 `spatial_filter_alpha` 等设置。
|
||||||
|
* **`enable_temporal_filter`**
|
||||||
|
* 启用深度时间滤波器。使用 `temporal_filter_diff_threshold` 等设置。
|
||||||
|
* **`enable_hole_filling_filter`**
|
||||||
|
* 启用深度孔洞填充滤波器。使用 `hole_filling_filter_mode` 设置。
|
||||||
|
* **`enable_spatial_fast_filter`**
|
||||||
|
* 启用深度空间快速滤波器。使用 `spatial_fast_filter_radius` 设置。
|
||||||
|
* **`enable_spatial_moderate_filter`**
|
||||||
|
* 启用深度空间中等滤波器。使用 `spatial_moderate_filter_diff_threshold` 等设置。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> **_重要_**:请仔细阅读 [此链接](https://www.orbbec.com/docs/g330-use-depth-post-processing-blocks/) 中有关软件滤波设置的说明。如果不确定,请勿修改这些设置。
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
## 在ROS 2中启用和可视化点云
|
||||||
|
|
||||||
|
本节演示如何从相机节点启用点云数据输出并使用RViz2进行可视化。
|
||||||
|
|
||||||
|
### 启用深度点云
|
||||||
|
|
||||||
|
#### 启用深度点云的命令
|
||||||
|
|
||||||
|
要激活深度信息的点云数据流,使用以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 launch orbbec_camera gemini_330_series.launch.py enable_point_cloud:=true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 在RViz2中可视化深度点云
|
||||||
|
|
||||||
|
运行上述命令后,执行以下步骤可视化深度点云:
|
||||||
|
|
||||||
|
1. 打开RViz2。
|
||||||
|
2. 添加 `PointCloud2` 显示。
|
||||||
|
3. 选择 `/camera/depth/points` 话题进行可视化。
|
||||||
|
4. 将固定帧设置为 `camera_link` 以正确对齐数据。
|
||||||
|
|
||||||
|
- **可视化示例**
|
||||||
|
|
||||||
|
深度点云在RViz2中可能如下所示:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 启用彩色点云
|
||||||
|
|
||||||
|
#### 启用彩色点云的命令
|
||||||
|
|
||||||
|
要启用彩色点云功能,输入以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 launch orbbec_camera gemini_330_series.launch.py enable_colored_point_cloud:=true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 在RViz2中可视化彩色点云
|
||||||
|
|
||||||
|
要可视化彩色点云数据:
|
||||||
|
|
||||||
|
1. 执行命令后启动RViz2。
|
||||||
|
2. 添加 `PointCloud2` 显示面板。
|
||||||
|
3. 从列表中选择 `/camera/depth_registered/points` 话题。
|
||||||
|
4. 确保固定帧设置为 `camera_link`。
|
||||||
|
|
||||||
|
- **可视化示例**
|
||||||
|
|
||||||
|
RViz2中彩色点云的结果应该如下所示:
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@@ -0,0 +1,210 @@
|
|||||||
|
# 所有可用的相机控制服务
|
||||||
|
|
||||||
|
> **注意:** 与特定数据流相关的服务(例如 `/camera/set_color_*`)仅在启动文件中启用该数据流时可用(例如 `enable_color:=true`)。
|
||||||
|
|
||||||
|
### 数据流控制
|
||||||
|
|
||||||
|
#### 彩色流
|
||||||
|
* `/camera/toggle_color`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/toggle_color std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/get_color_exposure` & `/camera/get_color_gain`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/get_color_exposure orbbec_camera_msgs/srv/GetInt32 '{}'
|
||||||
|
ros2 service call /camera/get_color_gain orbbec_camera_msgs/srv/GetInt32 '{}'
|
||||||
|
```
|
||||||
|
* `/camera/set_color_auto_exposure`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_color_auto_exposure std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/set_color_exposure` & `/camera/set_color_gain`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_color_exposure orbbec_camera_msgs/srv/SetInt32 '{data: 1}'
|
||||||
|
ros2 service call /camera/set_color_gain orbbec_camera_msgs/srv/SetInt32 '{data: 64}'
|
||||||
|
```
|
||||||
|
* `/camera/set_color_mirror`, `/camera/set_color_flip`, `/camera/set_color_rotation`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_color_mirror std_srvs/srv/SetBool '{data: true}'
|
||||||
|
ros2 service call /camera/set_color_flip std_srvs/srv/SetBool '{data: true}'
|
||||||
|
ros2 service call /camera/set_color_rotation orbbec_camera_msgs/srv/SetInt32 '{data: 180}'
|
||||||
|
```
|
||||||
|
* `/camera/set_color_ae_roi`
|
||||||
|
```bash
|
||||||
|
# data_param: [左, 右, 上, 下]
|
||||||
|
ros2 service call /camera/set_color_ae_roi orbbec_camera_msgs/srv/SetArrays '{data_param: [0,1279,0,719]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 深度流
|
||||||
|
* `/camera/toggle_depth`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/toggle_depth std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/get_depth_exposure` & `/camera/get_depth_gain`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/get_depth_exposure orbbec_camera_msgs/srv/GetInt32 '{}'
|
||||||
|
ros2 service call /camera/get_depth_gain orbbec_camera_msgs/srv/GetInt32 '{}'
|
||||||
|
```
|
||||||
|
* `/camera/set_depth_auto_exposure`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_depth_auto_exposure std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/set_depth_exposure` & `/camera/set_depth_gain`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_depth_exposure orbbec_camera_msgs/srv/SetInt32 '{data: 3000}'
|
||||||
|
ros2 service call /camera/set_depth_gain orbbec_camera_msgs/srv/SetInt32 '{data: 64}'
|
||||||
|
```
|
||||||
|
* `/camera/set_depth_mirror`, `/camera/set_depth_flip`, `/camera/set_depth_rotation`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_depth_mirror std_srvs/srv/SetBool '{data: true}'
|
||||||
|
ros2 service call /camera/set_depth_flip std_srvs/srv/SetBool '{data: true}'
|
||||||
|
ros2 service call /camera/set_depth_rotation orbbec_camera_msgs/srv/SetInt32 '{data: 180}'
|
||||||
|
```
|
||||||
|
* `/camera/set_depth_ae_roi`
|
||||||
|
```bash
|
||||||
|
# data_param: [左, 右, 上, 下]
|
||||||
|
ros2 service call /camera/set_depth_ae_roi orbbec_camera_msgs/srv/SetArrays '{data_param: [0,847,0,479]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 红外流
|
||||||
|
* `/camera/toggle_ir`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/toggle_ir std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/get_ir_exposure` & `/camera/get_ir_gain`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/get_ir_exposure orbbec_camera_msgs/srv/GetInt32 '{}'
|
||||||
|
ros2 service call /camera/get_ir_gain orbbec_camera_msgs/srv/GetInt32 '{}'
|
||||||
|
```
|
||||||
|
* `/camera/set_ir_auto_exposure`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_ir_auto_exposure std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/set_ir_exposure` & `/camera/set_ir_gain`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_ir_exposure orbbec_camera_msgs/srv/SetInt32 '{data: 3000}'
|
||||||
|
ros2 service call /camera/set_ir_gain orbbec_camera_msgs/srv/SetInt32 '{data: 64}'
|
||||||
|
```
|
||||||
|
* `/camera/switch_ir`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/switch_ir orbbec_camera_msgs/srv/SetString '{data: left}'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 所有数据流
|
||||||
|
* `/camera/get_streams_enable` & `/camera/set_streams_enable`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/get_streams_enable orbbec_camera_msgs/srv/GetBool '{}'
|
||||||
|
ros2 service call /camera/set_streams_enable std_srvs/srv/SetBool '{data: false}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 传感器与发射器控制
|
||||||
|
|
||||||
|
* `/camera/set_auto_white_balance` & `/camera/get_auto_white_balance`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_auto_white_balance std_srvs/srv/SetBool '{data: true}'
|
||||||
|
ros2 service call /camera/get_auto_white_balance orbbec_camera_msgs/srv/GetInt32 '{}'
|
||||||
|
```
|
||||||
|
* `/camera/set_white_balance` & `/camera/get_white_balance`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_white_balance orbbec_camera_msgs/srv/SetInt32 '{data: 2800}'
|
||||||
|
ros2 service call /camera/get_white_balance orbbec_camera_msgs/srv/GetInt32 '{}'
|
||||||
|
```
|
||||||
|
* `/camera/set_laser_enable`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_laser_enable std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/set_ldp_enable` & `/camera/get_ldp_status`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_ldp_enable std_srvs/srv/SetBool '{data: true}'
|
||||||
|
ros2 service call /camera/get_ldp_status orbbec_camera_msgs/srv/GetBool '{}'
|
||||||
|
```
|
||||||
|
* `/camera/set_fan_work_mode`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_fan_work_mode orbbec_camera_msgs/srv/SetInt32 '{data: 0}'
|
||||||
|
```
|
||||||
|
* `/camera/set_floor_enable`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_floor_enable std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 设备信息与管理
|
||||||
|
|
||||||
|
* `/camera/get_device_info`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/get_device_info orbbec_camera_msgs/srv/GetDeviceInfo
|
||||||
|
```
|
||||||
|
* `/camera/get_sdk_version`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/get_sdk_version orbbec_camera_msgs/srv/GetString
|
||||||
|
```
|
||||||
|
* `/camera/reboot_device`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/reboot_device std_srvs/srv/Empty '{}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 同步与触发
|
||||||
|
|
||||||
|
* `/camera/send_software_trigger`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/send_software_trigger std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/set_reset_timestamp`
|
||||||
|
```bash
|
||||||
|
# 仅在time_domain参数设置为device时可用
|
||||||
|
ros2 service call /camera/set_reset_timestamp std_srvs/srv/SetBool '{data: true}'
|
||||||
|
```
|
||||||
|
* `/camera/set_sync_interleaverlaser`
|
||||||
|
```bash
|
||||||
|
# 仅在interleave_ae_mode为'laser'且interleave_frame_enable为true时可用
|
||||||
|
ros2 service call /camera/set_sync_interleaverlaser orbbec_camera_msgs/srv/SetInt32 '{data: 0}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 深度滤波器配置
|
||||||
|
|
||||||
|
* `/camera/set_filter`
|
||||||
|
```bash
|
||||||
|
# 设置DecimationFilter
|
||||||
|
ros2 service call /camera/set_filter orbbec_camera_msgs/srv/SetFilter '{filter_name: DecimationFilter, filter_enable: false, filter_param: [5]}'
|
||||||
|
# 设置SpatialAdvancedFilter
|
||||||
|
ros2 service call /camera/set_filter orbbec_camera_msgs/srv/SetFilter '{filter_name: SpatialAdvancedFilter, filter_enable: true, filter_param: [0.5,160,1,8]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 数据捕获与校准管理
|
||||||
|
|
||||||
|
* `/camera/save_images`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/save_images std_srvs/srv/Empty '{}'
|
||||||
|
```
|
||||||
|
* `/camera/save_point_cloud`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/save_point_cloud std_srvs/srv/Empty '{}'
|
||||||
|
```
|
||||||
|
|
||||||
|
> **注意**:以下服务目前仅支持435Le模块。每个服务一次只能存储一组数据或字符串。
|
||||||
|
|
||||||
|
* `/camera/write_customer_data` & `/camera/read_customer_data`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/write_customer_data orbbec_camera_msgs/srv/SetString '{data: "string"}'
|
||||||
|
ros2 service call /camera/read_customer_data orbbec_camera_msgs/srv/GetString '{}'
|
||||||
|
```
|
||||||
|
* `/camera/set_user_calib_params` & `/camera/get_user_calib_params`
|
||||||
|
```bash
|
||||||
|
ros2 service call /camera/set_user_calib_params orbbec_camera_msgs/srv/SetUserCalibParams \
|
||||||
|
'{k: [614.9613647460938, 0.0, 634.91552734375,
|
||||||
|
0.0, 614.65771484375, 391.407470703125,
|
||||||
|
0.0, 0.0, 1.0],
|
||||||
|
d: [-0.03131488710641861,
|
||||||
|
0.032955970615148544,
|
||||||
|
9.096559369936585e-05,
|
||||||
|
-0.0003368517500348389,
|
||||||
|
-0.01115430984646082,
|
||||||
|
0.0, 0.0, 0.0],
|
||||||
|
rotation: [0.9999880790710449, 0.0003024190664291382, -0.004874417092651129,
|
||||||
|
-0.0002965621242765337, 0.9999992251396179, 0.001202247804030776,
|
||||||
|
0.004874777048826218, -0.0012007878394797444, 0.9999874234199524],
|
||||||
|
translation: [-0.023897956848144532,
|
||||||
|
-9.439220279455185e-05,
|
||||||
|
-6.804073229432106e-06]}'
|
||||||
|
ros2 service call /camera/get_user_calib_params orbbec_camera_msgs/srv/GetUserCalibParams '{}'
|
||||||
|
```
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
### 从坐标系A到坐标系B的TF变换:
|
||||||
|
|
||||||
|
在Orbbec相机中,原点(0,0,0)取自camera_link位置
|
||||||
|
|
||||||
|
我们的封装器提供从每个传感器坐标到相机基座(camera_link)之间的静态TF变换
|
||||||
|
|
||||||
|
此外,它还提供从每个传感器ROS坐标到其对应光学坐标的TF变换。
|
||||||
|
|
||||||
|
Gemini335模块的RGB传感器和右红外传感器静态TF变换示例,如rviz2中所示:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 launch orbbec_description view_model.launch.py model:=gemini_335_336.urdf.xacro
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# 可用话题
|
||||||
|
|
||||||
|
话题按数据流和功能组织。默认情况下,所有话题都发布在 `/camera` 命名空间下,可以通过 `camera_name` 启动参数进行更改。
|
||||||
|
|
||||||
|
> **注意:** 特定数据流的话题(例如 `/camera/color/...`)只有在相应的启动参数(例如 `enable_color`)设置为 `true` 时才会发布。
|
||||||
|
|
||||||
|
### 图像流
|
||||||
|
|
||||||
|
这些话题提供每个启用的相机数据流的原始图像数据和相应的校准信息。对于 `color`、`depth`、`ir`、`left_ir` 和 `right_ir` 数据流,模式是一致的。
|
||||||
|
|
||||||
|
* `/camera/color/image_raw`
|
||||||
|
* 彩色流的原始图像数据。
|
||||||
|
* `/camera/color/camera_info`
|
||||||
|
* 彩色流的相机校准数据和元数据。
|
||||||
|
* `/camera/color/metadata`
|
||||||
|
* 来自彩色流固件的底层元数据。
|
||||||
|
|
||||||
|
* `/camera/depth/image_raw`
|
||||||
|
* 深度流的原始图像数据。
|
||||||
|
* `/camera/depth/camera_info`
|
||||||
|
* 深度流的相机校准数据和元数据。
|
||||||
|
* `/camera/depth/metadata`
|
||||||
|
* 来自深度流固件的底层元数据。
|
||||||
|
|
||||||
|
* `/camera/ir/image_raw`
|
||||||
|
* 红外(IR)流的原始图像数据。
|
||||||
|
* `/camera/ir/camera_info`
|
||||||
|
* IR流的相机校准数据和元数据。
|
||||||
|
* `/camera/ir/metadata`
|
||||||
|
* 来自IR流固件的底层元数据。
|
||||||
|
|
||||||
|
### 点云话题
|
||||||
|
|
||||||
|
* `/camera/depth/points`
|
||||||
|
* 从深度流生成的点云数据。
|
||||||
|
* **条件:** 仅在 `enable_point_cloud` 为 `true` 时发布。
|
||||||
|
|
||||||
|
* `/camera/depth_registered/points`
|
||||||
|
* 彩色点云数据,其中深度点配准到彩色图像帧。
|
||||||
|
* **条件:** 仅在 `enable_colored_point_cloud` 为 `true` 时发布。
|
||||||
|
|
||||||
|
### IMU话题
|
||||||
|
|
||||||
|
惯性测量单元(IMU)话题提供加速度计和陀螺仪数据。其行为取决于同步设置。
|
||||||
|
|
||||||
|
* `/camera/accel/sample`
|
||||||
|
* 单独的加速度计数据流。
|
||||||
|
* **条件:** 在 `enable_accel` 为 `true` 且 `enable_sync_output_accel_gyro` 为 `false` 时发布。
|
||||||
|
|
||||||
|
* `/camera/gyro/sample`
|
||||||
|
* 单独的陀螺仪数据流。
|
||||||
|
* **条件:** 在 `enable_gyro` 为 `true` 且 `enable_sync_output_accel_gyro` 为 `false` 时发布。
|
||||||
|
|
||||||
|
* `/camera/gyro_accel/sample`
|
||||||
|
* 包含加速度计和陀螺仪数据的同步数据流(单条消息)。
|
||||||
|
* **条件:** 在 `enable_sync_output_accel_gyro` 为 `true` 时发布。
|
||||||
|
|
||||||
|
### 设备状态与诊断
|
||||||
|
|
||||||
|
* `/camera/device_status`
|
||||||
|
* 报告相机设备的当前状态。
|
||||||
|
|
||||||
|
* `/camera/depth_filter_status`
|
||||||
|
* 报告深度传感器后处理滤波器的状态。
|
||||||
|
|
||||||
|
* `/diagnostics`
|
||||||
|
* 发布相机节点的诊断信息。目前包括设备温度。
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
高级指南
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
本章介绍SDK的高级功能,包括多相机使用和特殊配置模式。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
性能与优化
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
performance/lower_cpu_usage.md
|
||||||
|
performance/efficient_intra_process_communication.md
|
||||||
|
performance/fastdds_tuning.md
|
||||||
|
|
||||||
|
|
||||||
|
多相机
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
multi_camera/multi_camera.md
|
||||||
|
multi_camera/multi_camera_synced.md
|
||||||
|
multi_camera/multi_camera_synced_verification_tool.md
|
||||||
|
multi_camera/gmsl_camera.md
|
||||||
|
|
||||||
|
|
||||||
|
配置与模式
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
configuration/align_depth_color.md
|
||||||
|
configuration/configuration_of_depth_NFOV_and_WFOV_modes.md
|
||||||
|
configuration/depth_work_mode_switch.md
|
||||||
|
configuration/disparity_search_offset.md
|
||||||
|
configuration/interleave_ae_mode.md
|
||||||
|
configuration/predefined_presets.md
|
||||||
|
configuration/net_camera.md
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
## 在 ROS 2 中对齐深度到彩色
|
||||||
|
|
||||||
|
本节说明如何使用 ROS 2 将深度图像与彩色图像对齐以创建叠加图像。这对于需要来自不同传感器模态的同步视觉信息的应用特别有用。
|
||||||
|
|
||||||
|
### 对齐和查看深度和彩色图像的命令
|
||||||
|
|
||||||
|
1. **基本深度到彩色对齐:**
|
||||||
|
|
||||||
|
要简单地将深度图像对齐到彩色图像,请使用以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 launch orbbec_camera gemini_330_series.launch.py depth_registration:=true
|
||||||
|
```
|
||||||
|
|
||||||
|
此命令激活深度配准功能,但不打开查看器。
|
||||||
|
|
||||||
|
2. **查看深度到彩色叠加:**
|
||||||
|
|
||||||
|
如果您希望查看深度到彩色叠加,需要使用以下命令启用查看器:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 launch orbbec_camera gemini_330_series.launch.py depth_registration:=true enable_d2c_viewer:=true
|
||||||
|
```
|
||||||
|
|
||||||
|
这将启动带有深度到彩色配准的相机节点并打开查看器以显示叠加图像。
|
||||||
|
|
||||||
|
### 在 RViz2 中选择话题
|
||||||
|
|
||||||
|
要在 RViz2 中可视化对齐的图像:
|
||||||
|
|
||||||
|
1. 运行上述命令之一后启动 RViz2。
|
||||||
|
2. 选择深度到彩色叠加图像的话题。话题选择示例如下所示:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 深度到彩色叠加示例
|
||||||
|
|
||||||
|
在 RViz2 中选择适当的话题后,您将能够看到深度到彩色叠加图像。它可能看起来像这样:
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# 深度 NFOV 和 WFOV 模式配置
|
||||||
|
|
||||||
|
对于 Femto Mega 和 Femto Bolt 设备,NFOV 和 WFOV 模式通过在启动文件中配置深度和 IR 的分辨率来实现。
|
||||||
|
|
||||||
|
在启动文件中,depth_width、depth_height、ir_width、ir_height 分别表示深度的分辨率和 IR 的分辨率。
|
||||||
|
|
||||||
|
IR 的帧率和分辨率必须与深度保持一致。不同模式与分辨率的对应关系如下:
|
||||||
|
|
||||||
|
- NFOV unbinned:640 x 576
|
||||||
|
- NFOV binned:320 x 288
|
||||||
|
- WFOV unbinned:1024 x 1024
|
||||||
|
- WFOV binned:512 x 512
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# 多相机
|
||||||
|
|
||||||
|
- 要获取相机的 `usb_port`,插入相机并在终端中运行以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 run orbbec_camera list_devices_node
|
||||||
|
```
|
||||||
|
|
||||||
|
- 将 `device_num` 参数设置为您拥有的相机数量。
|
||||||
|
- 转到 `OrbbecSDK_ROS2/launch/multi_xxx.launch.py` 文件并更改 `usb_port`。
|
||||||
|
- 不要忘记将 `include` 标签放在 `group` 标签内。
|
||||||
|
否则,不同相机的参数值可能会被污染。
|
||||||
|
|
||||||
|
```python
|
||||||
|
from launch import LaunchDescription
|
||||||
|
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, GroupAction, ExecuteProcess
|
||||||
|
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||||
|
from launch_ros.actions import Node
|
||||||
|
from ament_index_python.packages import get_package_share_directory
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def generate_launch_description():
|
||||||
|
# Include launch files
|
||||||
|
package_dir = get_package_share_directory('orbbec_camera')
|
||||||
|
launch_file_dir = os.path.join(package_dir, 'launch')
|
||||||
|
launch1_include = IncludeLaunchDescription(
|
||||||
|
PythonLaunchDescriptionSource(
|
||||||
|
os.path.join(launch_file_dir, 'gemini2L.launch.py')
|
||||||
|
),
|
||||||
|
launch_arguments={
|
||||||
|
'camera_name': 'camera_01',
|
||||||
|
'usb_port': '6-2.4.4.2', # replace your usb port here
|
||||||
|
'device_num': '2'
|
||||||
|
}.items()
|
||||||
|
)
|
||||||
|
|
||||||
|
launch2_include = IncludeLaunchDescription(
|
||||||
|
PythonLaunchDescriptionSource(
|
||||||
|
os.path.join(launch_file_dir, 'gemini2L.launch.py')
|
||||||
|
),
|
||||||
|
launch_arguments={
|
||||||
|
'camera_name': 'camera_02',
|
||||||
|
'usb_port': '6-2.4.1', # replace your usb port here
|
||||||
|
'device_num': '2'
|
||||||
|
}.items()
|
||||||
|
)
|
||||||
|
|
||||||
|
# If you need more cameras, just add more launch_include here, and change the usb_port and device_num
|
||||||
|
|
||||||
|
# Launch description
|
||||||
|
ld = LaunchDescription([
|
||||||
|
GroupAction([launch1_include]),
|
||||||
|
GroupAction([launch2_include]),
|
||||||
|
])
|
||||||
|
|
||||||
|
return ld
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
- 要启动相机,运行以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ros2 launch orbbec_camera multi_camera.launch.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 多相机无数据流
|
||||||
|
|
||||||
|
**电源供应不足**:
|
||||||
|
|
||||||
|
- 确保每个相机连接到单独的集线器。
|
||||||
|
- 使用带电源的集线器为每个相机提供足够的电力。
|
||||||
|
|
||||||
|
**高分辨率**:
|
||||||
|
|
||||||
|
- 尝试降低分辨率以解决数据流问题。
|
||||||
|
|
||||||
|
**增加 usbfs_memory_mb 值**:
|
||||||
|
|
||||||
|
- 将 `usbfs_memory_mb` 值增加到 128MB(这是一个参考值,可以根据系统需求进行调整)
|
||||||
|
通过运行以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo 128 | sudo tee /sys/module/usbcore/parameters/usbfs_memory_mb
|
||||||
|
```
|
||||||
|
|
||||||
|
- 要使此更改永久生效,请查看[此链接](https://github.com/OpenKinect/libfreenect2/issues/807)。
|
||||||
|
|
||||||
|
## 多相机图像话题帧率过低
|
||||||
|
|
||||||
|
请参考 [Fast DDS 配置](../performance/fastdds_tuning.md) 文件。
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
性能基准测试
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
本章介绍如何使用性能基准测试工具,并提供不同相机的测试结果。
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
introduction.md
|
||||||
|
benchmark_usage.md
|
||||||
|
benchmark_data.md
|
||||||
|
othertools.md
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# 性能基准测试数据
|
||||||
|
|
||||||
|
本节记录了使用性能基准测试工具测试不同相机的数据。点击链接下载 xlsx 数据。
|
||||||
|
|
||||||
|
## 通用基准测试数据
|
||||||
|
|
||||||
|
使用默认启动文件运行 `common_benchmark_node` 并测试 1 小时的数据。
|
||||||
|
|
||||||
|
- [通用基准测试数据](../../_static/ros2_common_benchmark_data.xlsx)
|
||||||
|
|
||||||
|
## 服务基准测试数据
|
||||||
|
|
||||||
|
使用默认启动文件分别运行 `service_benchmark_node` 和 `service_benchmark_node.py`。每个服务调用 10 次,并记录数据。
|
||||||
|
|
||||||
|
- [服务基准测试数据 C++](../../_static/ros2_service_benchmark_cpp.xlsx)
|
||||||
|
- [服务基准测试数据 Python](../../_static/ros2_service_benchmark_python.xlsx)
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# 性能基准测试使用
|
||||||
|
|
||||||
|
本节介绍如何在 C++ 和 Python 中使用性能基准测试工具,并提供示例 YAML 配置文件。
|
||||||
|
|
||||||
|
## 使用通用基准测试节点
|
||||||
|
|
||||||
|
```
|
||||||
|
ros2 run orbbec_camera common_benchmark_node.py \
|
||||||
|
--run_time 2h \
|
||||||
|
--csv_file /path/to/log.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
* **参数**
|
||||||
|
* **--run_time**:监控持续时间,指定为时间字符串,如 `"10s"`、`"5m"`、`"1h"`、`"2d"`。默认为 10 秒。
|
||||||
|
* **--csv_file**:输出 CSV 文件的路径。默认情况下,它保存在工作空间目录中,名称为 "camera_monitor_log.csv"。
|
||||||
|
|
||||||
|
## 使用服务基准测试节点
|
||||||
|
|
||||||
|
### ROS2 C++
|
||||||
|
|
||||||
|
* **单个服务基准测试**
|
||||||
|
|
||||||
|
```
|
||||||
|
ros2 run orbbec_camera service_benchmark_node \
|
||||||
|
--ros-args \
|
||||||
|
-p service_name:=/camera/get_depth_gain \
|
||||||
|
-p service_type:=orbbec_camera_msgs/srv/GetInt32 \
|
||||||
|
-p count:=10
|
||||||
|
```
|
||||||
|
|
||||||
|
* **多个服务基准测试(YAML 配置)**
|
||||||
|
|
||||||
|
```
|
||||||
|
ros2 run orbbec_camera service_benchmark_node \
|
||||||
|
--ros-args \
|
||||||
|
-p yaml_file:=/path/to/default_service_cpp.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### ROS2 Python
|
||||||
|
|
||||||
|
* **单个服务基准测试**
|
||||||
|
|
||||||
|
```
|
||||||
|
ros2 run orbbec_camera service_benchmark_node.py --service /camera/get_depth_gain --count 10
|
||||||
|
```
|
||||||
|
|
||||||
|
* **多个服务基准测试(YAML 配置)**
|
||||||
|
|
||||||
|
```
|
||||||
|
ros2 run orbbec_camera service_benchmark_node.py --yaml_file /path/to/default_service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### **示例 YAML 配置**
|
||||||
|
|
||||||
|
我们提供了一个示例 YAML 配置,位于 `scripts` 目录中,名为 `service_default.yaml`。
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
default_count: 50
|
||||||
|
|
||||||
|
services:
|
||||||
|
- name: /camera/get_auto_white_balance
|
||||||
|
type: orbbec_camera_msgs/srv/GetInt32
|
||||||
|
- name: /camera/get_color_exposure
|
||||||
|
type: orbbec_camera_msgs/srv/GetInt32
|
||||||
|
- name: /camera/get_color_gain
|
||||||
|
type: orbbec_camera_msgs/srv/GetInt32
|
||||||
|
- name: /camera/get_depth_exposure
|
||||||
|
type: orbbec_camera_msgs/srv/GetInt32
|
||||||
|
- name: /camera/get_depth_gain
|
||||||
|
type: orbbec_camera_msgs/srv/GetInt32
|
||||||
|
- name: /camera/get_device_info
|
||||||
|
type: orbbec_camera_msgs/srv/GetDeviceInfo
|
||||||
|
- name: /camera/send_software_trigger
|
||||||
|
type: std_srvs/srv/SetBool
|
||||||
|
request: {data: false}
|
||||||
|
- name: /camera/set_auto_white_balance
|
||||||
|
type: std_srvs/srv/SetBool
|
||||||
|
request: {data: false}
|
||||||
|
- name: /camera/set_color_ae_roi
|
||||||
|
type: orbbec_camera_msgs/srv/SetArrays
|
||||||
|
request: {data_param: [0,1279,0,719]}
|
||||||
|
- name: /camera/set_color_auto_exposure
|
||||||
|
type: std_srvs/srv/SetBool
|
||||||
|
request: {data: false}
|
||||||
|
- name: /camera/set_color_exposure
|
||||||
|
type: orbbec_camera_msgs/srv/SetInt32
|
||||||
|
request: {data: 30}
|
||||||
|
- name: /camera/set_color_flip
|
||||||
|
type: std_srvs/srv/SetBool
|
||||||
|
request: {data: false}
|
||||||
|
- name: /camera/set_color_gain
|
||||||
|
type: orbbec_camera_msgs/srv/SetInt32
|
||||||
|
request: {data: 20}
|
||||||
|
- name: /camera/set_color_mirror
|
||||||
|
type: std_srvs/srv/SetBool
|
||||||
|
request: {data: false}
|
||||||
|
- name: /camera/set_color_rotation
|
||||||
|
type: orbbec_camera_msgs/srv/SetInt32
|
||||||
|
request: {data: 90}
|
||||||
|
- name: /camera/set_depth_ae_roi
|
||||||
|
type: orbbec_camera_msgs/srv/SetArrays
|
||||||
|
request: {data_param: [0,1279,0,719]}
|
||||||
|
- name: /camera/set_depth_auto_exposure
|
||||||
|
type: std_srvs/srv/SetBool
|
||||||
|
request: {data: false}
|
||||||
|
- name: /camera/set_depth_exposure
|
||||||
|
type: orbbec_camera_msgs/srv/SetInt32
|
||||||
|
request: {data: 3000}
|
||||||
|
- name: /camera/set_depth_flip
|
||||||
|
type: std_srvs/srv/SetBool
|
||||||
|
request: {data: false}
|
||||||
|
- name: /camera/set_depth_gain
|
||||||
|
type: orbbec_camera_msgs/srv/SetInt32
|
||||||
|
request: {data: 200}
|
||||||
|
```
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# 介绍
|
||||||
|
|
||||||
|
本节介绍性能基准测试工具,解释其目的、功能以及它可以帮助您测量的内容。
|
||||||
|
|
||||||
|
## 通用基准测试节点
|
||||||
|
|
||||||
|
`common_benchmark_node.py` 是一个用于监控在 ROS 环境中运行的 Orbbec 相机性能的工具。它实时收集和记录关键相机指标,如帧率、延迟、系统资源使用和丢包率,帮助用户评估相机节点的稳定性和性能(每秒更新一次)。
|
||||||
|
|
||||||
|
**功能**
|
||||||
|
|
||||||
|
- 测量发布的图像帧率和延迟(当前、最小、最大、平均)
|
||||||
|
|
||||||
|
- 监控相机节点的 CPU/ARM 使用率(当前、最小、最大、平均)
|
||||||
|
|
||||||
|
- 跟踪丢帧率(发布者)和丢包率(订阅者)
|
||||||
|
|
||||||
|
- 将实时统计信息(1 Hz)打印到终端并将结果保存到 CSV 文件
|
||||||
|
|
||||||
|
- 支持可配置的运行时长和 CSV 输出路径
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|
在 ROS1 中,可以测量丢帧率和丢包率,而在 ROS2 中,header 缺少 `seq` 字段,因此仅计算发布者端的丢帧率。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 服务基准测试节点
|
||||||
|
|
||||||
|
`service_benchmark_node` 工具用于监控服务调用的性能。它可以测量服务调用的成功率和执行服务所需的时间。
|
||||||
|
|
||||||
|
**功能**
|
||||||
|
|
||||||
|
- 对单个服务调用进行基准测试,测量延迟和成功率
|
||||||
|
|
||||||
|
- 对 YAML 配置文件中定义的多个服务进行基准测试
|
||||||
|
|
||||||
|
- 可选择将基准测试结果保存到 CSV 文件
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
当您需要收集多个服务的数据时,建议使用 CSV 文件进行分析。
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# 其他工具
|
||||||
|
|
||||||
|
## Ob_benchmark 工具
|
||||||
|
|
||||||
|
> 此工具的目标是对各种 OrbbecSDK_ROS2 相机配置的性能进行基准测试。基准测试结果取决于使用的相机和设置。(目前仅适用于 ROS2 Humble)
|
||||||
|
|
||||||
|
您可以在 [example](https://github.com/orbbec/OrbbecSDK_ROS2/tree/v2-main/orbbec_camera/examples) 中找到示例使用代码。
|
||||||
|
|
||||||
|
### 工具配置 ([start_benchmark_params.json](https://github.com/orbbec/OrbbecSDK_ROS2/blob/v2-main/orbbec_camera/config/tools/startbenchmark/start_benchmark_params.json))
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"start_benchmark_params": {
|
||||||
|
"camera_name": [
|
||||||
|
"camera_01",
|
||||||
|
"camera_02",
|
||||||
|
"camera_03",
|
||||||
|
"camera_04"
|
||||||
|
],
|
||||||
|
"process_name": "component_conta",
|
||||||
|
"switch_cycle": 300,
|
||||||
|
"test_cycle": 1,
|
||||||
|
"skip_number": 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `camera_name`:要配置的相机名称。例如:`"camera_01"`、`"camera_02"` 等。
|
||||||
|
- `process_name`:要监控的进程名称。例如,`"component_conta"` 将监控容器进程的数据。
|
||||||
|
- `switch_cycle`:切换配置的周期时间,以秒为单位。例如,设置为 `300` 意味着配置将每 300 秒切换一次。
|
||||||
|
- `test_cycle`:测试周期,以秒为单位。例如,设置为 `1` 意味着工具将每 1 秒收集一次监控进程的数据。
|
||||||
|
- `skip_number`:要跳过的数据点数量。例如,设置为 `30` 意味着将忽略前 30 个数据点。
|
||||||
|
|
||||||
|
### 相机配置(启动文件)
|
||||||
|
|
||||||
|
在 launch 文件夹中,有多个 .launch.py 文件(`ob_benchmark_0.launch.py`、`ob_benchmark_1.launch.py`、...、`ob_benchmark_19.launch.py`)。每个文件对应不同的相机配置。
|
||||||
|
|
||||||
|
### 运行 ob_benchmark 工具
|
||||||
|
|
||||||
|
要运行该工具,请使用以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source install/setup.bash
|
||||||
|
ros2 run orbbec_camera ob_benchmark_node
|
||||||
|
```
|
||||||
|
|
||||||
|
### 输出数据文件
|
||||||
|
|
||||||
|
输出数据文件将存储在 ob_benchmark 文件夹中,文件名如 `0.csv`、`1.csv`、...、19.csv。例如:
|
||||||
|
|
||||||
|
- `0.csv` 包含来自 `ob_benchmark_0.launch.py` 配置的数据。
|
||||||
|
- `1.csv` 包含来自 `ob_benchmark_1.launch.py` 配置的数据。
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# 构建 Debian 软件包
|
||||||
|
|
||||||
|
## 准备环境
|
||||||
|
|
||||||
|
在开始之前,安装所需的工具:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install debhelper fakeroot python3-bloom
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置 ROS 依赖项
|
||||||
|
|
||||||
|
在系统中的 `/etc/ros/rosdep/sources.list.d/00-orbbec.yaml` 添加以下 YAML 文件。确保将 `focal` 替换为您的 Ubuntu 版本的代号,将 `humble` 替换为您的 ROS2 发行版名称:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
orbbec_camera_msgs:
|
||||||
|
ubuntu:
|
||||||
|
focal: [ ros-humble-orbbec-camera-msgs ]
|
||||||
|
```
|
||||||
|
|
||||||
|
接下来,创建一个新文件 `/etc/ros/rosdep/sources.list.d/50-orbbec.list` 并添加此行以指定 YAML 文件的路径:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yaml file:///etc/ros/rosdep/sources.list.d/00-orbbec.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
更新 rosdep 数据库以反映这些更改:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rosdep update
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建软件包
|
||||||
|
|
||||||
|
导航到您的工作空间并构建项目:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ros2_ws/
|
||||||
|
colcon build --event-handlers console_direct+ --cmake-args -DCMAKE_BUILD_TYPE=Release
|
||||||
|
. install/setup.bash
|
||||||
|
cd src/OrbbecSDK_ROS2/
|
||||||
|
bash .make_deb.sh
|
||||||
|
```
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
开发者指南
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
本章为 SDK 的开发人员和维护人员提供文档。
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
building_a_Debian_Package.md
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# 常见问题
|
||||||
|
|
||||||
|
### 意外崩溃
|
||||||
|
|
||||||
|
如果相机节点意外崩溃,它将在当前运行目录中生成崩溃日志:`Log/camera_crash_stack_trace_xx.log`。请将此日志发送给支持团队或提交到GitHub issue以获得进一步帮助。
|
||||||
|
|
||||||
|
### 多相机无数据流
|
||||||
|
|
||||||
|
**电源供应不足**:
|
||||||
|
|
||||||
|
- 确保每个相机连接到单独的集线器。
|
||||||
|
- 使用有源集线器为每个相机提供足够的电力。
|
||||||
|
|
||||||
|
**高分辨率**:
|
||||||
|
|
||||||
|
- 尝试降低分辨率以解决数据流问题。
|
||||||
|
|
||||||
|
**增加usbfs_memory_mb值**:
|
||||||
|
|
||||||
|
- 通过运行以下命令将 `usbfs_memory_mb` 值增加到128MB(这是参考值,可根据系统需求调整):
|
||||||
|
|
||||||
|
```
|
||||||
|
echo 128 | sudo tee /sys/module/usbcore/parameters/usbfs_memory_mb
|
||||||
|
```
|
||||||
|
|
||||||
|
- 要使此更改永久生效,请查看[此链接](https://github.com/OpenKinect/libfreenect2/issues/807)。
|
||||||
|
|
||||||
|
### 其他故障排除
|
||||||
|
|
||||||
|
- 如果遇到其他问题,将 `log_level` 参数设置为 `debug`。这将在运行目录中生成SDK日志文件:`Log/OrbbecSDK.log.txt`。请将此文件提供给支持团队以获得进一步帮助。
|
||||||
|
- 如果需要固件日志,将 `enable_heartbeat` 设置为 `true` 以激活此功能。
|
||||||
|
|
||||||
|
### 为什么有这么多启动文件?
|
||||||
|
|
||||||
|
- 不同的相机具有不同的默认分辨率和图像格式。
|
||||||
|
- 为简化使用,每个相机都有自己的启动文件。
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
常见问题
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
本章收集了与SDK使用相关的常见问题及解答。
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
FAQ.md
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,222 @@
|
|||||||
|
/* 让表格自动拉伸到满宽度 */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 让表格中的每个 <th> 和 <td> 也自动拉伸 */
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
width: 100%;
|
||||||
|
/* 列表宽度占满整个容器 */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 修改 Sphinx Theme 项目标题的字体大小 Book和rtd 均OK */
|
||||||
|
.wy-side-nav-search>a {
|
||||||
|
font-size: 16px;
|
||||||
|
/* 你可以根据需要调整这个值 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 修改项目标题的字体大小 Book和rtd 均OK*/
|
||||||
|
.wy-side-nav-search>div.version {
|
||||||
|
font-size: 16px;
|
||||||
|
/* 你可以根据需要调整这个值 */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sidebar-logo {
|
||||||
|
width: 500px;
|
||||||
|
/* 或者使用百分比 */
|
||||||
|
height: auto;
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sidebar-content {
|
||||||
|
line-height: 1.0;
|
||||||
|
/* 行间距是字体大小的1.5倍 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
padding: 20px;
|
||||||
|
/* 内边距 */
|
||||||
|
margin-bottom: 20px;
|
||||||
|
/* 外边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-text {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
/* 修改侧边栏的背景颜色 */
|
||||||
|
.wy-nav-side {
|
||||||
|
background-color: #cecece !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 针对导航栏链接的选择器 */
|
||||||
|
.wy-nav-side a {
|
||||||
|
color: #000000;
|
||||||
|
/* 修改为您需要的颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 如果需要,您可以添加 hover 和 active 状态的样式 */
|
||||||
|
.wy-nav-side a:hover {
|
||||||
|
color: #fffcfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-nav-side .current>a {
|
||||||
|
color: #108bf0 !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
/* 设置为粗体 */
|
||||||
|
/* 当前活动项的颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 提示:不同版本的 Sphinx 主题生成的 HTML 结构可能有所不同,请根据实际情况调整选择器 */
|
||||||
|
h1.wy-banner-title {
|
||||||
|
color: #0267da !important;
|
||||||
|
/* 将此处的颜色替换为您希望的颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 如果也需要修改小标题 */
|
||||||
|
h2.wy-banner-subtitle {
|
||||||
|
color: #7b7b7b !important;
|
||||||
|
/* 替换为希望的颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search>a {
|
||||||
|
color: #ffffff !important;
|
||||||
|
/* 将 #your-color 替换为你想要颜色的十六进制代码 */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 调整最大宽度 OK */
|
||||||
|
.wy-nav-content {
|
||||||
|
max-width: 960px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 可选:调整侧边栏宽度 */
|
||||||
|
/* .wy-side-scroll {
|
||||||
|
width: 300px;
|
||||||
|
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* ==================== Language Switcher Styles ==================== */
|
||||||
|
|
||||||
|
/* Language switcher container */
|
||||||
|
.language-switcher {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 15px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Language toggle button */
|
||||||
|
.language-toggle {
|
||||||
|
background-color: #2980b9;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-toggle:hover {
|
||||||
|
background-color: #3498db;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-text {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Language dropdown */
|
||||||
|
.language-dropdown {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
right: 0;
|
||||||
|
margin-top: 5px;
|
||||||
|
background-color: white;
|
||||||
|
min-width: 120px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-dropdown.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Language options */
|
||||||
|
.language-option {
|
||||||
|
display: block;
|
||||||
|
padding: 10px 15px;
|
||||||
|
color: #333;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-option:hover {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-option.active {
|
||||||
|
background-color: #2980b9;
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-option.active:hover {
|
||||||
|
background-color: #3498db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Position language switcher in navbar for RTD theme */
|
||||||
|
.wy-nav-top .language-switcher {
|
||||||
|
float: right;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile responsive */
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.language-switcher {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-toggle {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For sidebar placement (alternative position) */
|
||||||
|
.wy-side-nav-search .language-switcher {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user