1. 开始开发之前,你需要读什么?
后端服务使用 Python3,前端服务是 JavaScript/TypeScript React
1.1 了解 OpenV2X 是什么?它适用于什么场景?
OpenV2X 致力于打造“车路协同”应用在“远边”(边缘云)场景中的开源解决方案(开源协议是 Apache 2.0)。在传统“云-边-端”三层架构中,OpenV2X 只关注“远边侧”部分(5G 基站侧边缘云),致力于提供“路侧设备管理”和“路侧数据采集与分析”能力,以辅助“车载智能”实现自动驾驶。
为什么有了“车载智能驾驶”解决方案还需要“路侧协同”方案?可以简单类比:在黑暗中车也能开,但有了路灯更安全。OpenV2X 在车路协同整体解决方案中,就扮演“路灯”的角色。
参考文档:
- 源代码:Github,同步镜像到 Gitee
- OpenV2X 官网:https://openv2x.org/
1.2 搭建 AIO 的开发基础环境
参考部署文档:Github,或者 Gitee,我们先搭建 AIO 的开发环境,然后去掉多余服务。
上述文档中选用了 CentOS 7.9,但因为:
- CentOS 7.9 会在 2024.06 结束支持
- CentOS 7.9 的基础组件偏旧,操作系统内核 / Docker / Python / Git 等基础组件都需要升级
- OpenV2X 服务可以从 Docker 启动
因此实际上我们可以选用其它操作系统也可以进行开发,本文选用 Ubuntu 22.04 系统。
搭建步骤如下:
1.2.1 准备 AIO 的 Ubuntu 机器
开一台 2Core/4G/40G 的服务器,安装 Ubuntu 22.04 系统
# 软链接,另 python 命令指向 python3
ln -s /usr/bin/python3 /usr/bin/python
# 安装 git review,方便后续提交代码 review
apt-get install git-review -y
查看基础组件版本
root@openv2x-test-master:~# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
...
root@openv2x-test-master:~# uname -a
Linux openv2x-test-master 5.15.0-43-generic #46-Ubuntu SMP Tue Jul 12 10:30:17 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
root@openv2x-test-master:~# python --version
Python 3.10.4
root@openv2x-test-master:~# pip --version
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)
root@openv2x-test-master:~# git version
git version 2.34.1
root@openv2x-test-master:~# git-review --version
git-review version 2.2.0
1.2.2 安装 Docker 和 Docker-Compose
# 安装 docker 和 docker compose
apt install docker.io docker-compose -y
查看版本
root@openv2x-test-master:~# docker --version
Docker version 20.10.12, build 20.10.12-0ubuntu4
root@openv2x-test-master:~# docker-compose --version
docker-compose version 1.29.2, build unknown
1.2.3 安装 OpenV2X
rm -rf openv2x-aio-master.tar.gz && wget https://openv2x.oss-ap-southeast-1.aliyuncs.com/deploy/master/openv2x-aio-master.tar.gz
rm -rf src && tar zxvf openv2x-aio-master.tar.gz
cd src
export OPENV2X_EXTERNAL_IP=100.100.100.100
export OPENV2X_REDIS_ROOT=password
export OPENV2X_MARIADB_ROOT=password
export OPENV2X_MARIADB_DANDELION=password
export OPENV2X_EMQX_ROOT=password
bash ./install.sh
注意,这里 100.100.100.100 是 OpenV2X 对外暴露的 IP 地址,是安装好 OpenV2X 之后,从 Web 页面访问的 URL 地址,不一定是该服务器的内网地址。
安装好之后,根据提示可以访问页面,用提示中的用户名/密码登录,确定登录成功。然后可以根据 OpenV2X 使用手册:Github,或 Gitee,验证功能正常。
1.2.4 删除 OpenV2X 应用服务,只保留基础组件
先看一下 OpenV2X 服务
root@openv2x-test-master:~/src# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ddd3a35a426 openv2x/dandelion:latest "run_service.sh" 37 minutes ago Up 37 minutes dandelion
bdbf23c309cf openv2x/centerview:latest "/docker-entrypoint.…" 37 minutes ago Up 37 minutes centerview
c39809053695 openv2x/edgeview:latest "/docker-entrypoint.…" 37 minutes ago Up 37 minutes edgeview
04e3dfaeb8da openv2x/roadmocker:latest "/docker-entrypoint.…" 37 minutes ago Up 37 minutes 0.0.0.0:6688->80/tcp, :::6688->80/tcp rse-simulator
55d16f1afce4 openv2x/cerebrum:latest "sh /usr/local/bin/s…" 37 minutes ago Up 37 minutes cerebrum
94a3cb4f67a5 emqx/emqx:4.3.0 "/usr/bin/docker-ent…" 37 minutes ago Up 37 minutes 4369-4370/tcp, 5369/tcp, 0.0.0.0:1883->1883/tcp, :::1883->1883/tcp, 0.0.0.0:8081->8081/tcp, :::8081->8081/tcp, 0.0.0.0:8084->8084/tcp, :::8084->8084/tcp, 6369-6370/tcp, 0.0.0.0:8883->8883/tcp, :::8883->8883/tcp, 0.0.0.0:18083->18083/tcp, :::18083->18083/tcp, 11883/tcp, 0.0.0.0:15675->8083/tcp, :::15675->8083/tcp emqx
0237a63b5fcb mariadb:10.5.5 "docker-entrypoint.s…" 37 minutes ago Up 37 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp mariadb
ab2e09e868fc redis:6.2.4-alpine "docker-entrypoint.s…" 37 minutes ago Up 37 minutes 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis
其中基础服务包括:
- emqx:MQTT 服务器
- mariadb:数据库服务器
- redis:缓存服务器
业务服务包括:
- dandelion:RSE 设备管理服务
- cerebrum:RSE 数据处理服务
- rse-simulator:RSE 模拟器
- centerview:中心云控制面板
- edgeview:边缘云控制面板
我们删除业务服务,保留基础服务:
root@openv2x-test-master:~/src# docker-compose -f /tmp/service/docker-compose-service.yaml down
Stopping dandelion ... done
Stopping centerview ... done
Stopping edgeview ... done
Stopping rse-simulator ... done
Stopping cerebrum ... done
Removing dandelion ... done
Removing centerview ... done
Removing edgeview ... done
Removing rse-simulator ... done
Removing cerebrum ... done
Removing network service_default
现在就只有基础服务了
root@openv2x-test-master:~/src# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
94a3cb4f67a5 emqx/emqx:4.3.0 "/usr/bin/docker-ent…" About an hour ago Up About an hour 4369-4370/tcp, 5369/tcp, 0.0.0.0:1883->1883/tcp, :::1883->1883/tcp, 0.0.0.0:8081->8081/tcp, :::8081->8081/tcp, 0.0.0.0:8084->8084/tcp, :::8084->8084/tcp, 6369-6370/tcp, 0.0.0.0:8883->8883/tcp, :::8883->8883/tcp, 0.0.0.0:18083->18083/tcp, :::18083->18083/tcp, 11883/tcp, 0.0.0.0:15675->8083/tcp, :::15675->8083/tcp emqx
0237a63b5fcb mariadb:10.5.5 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp mariadb
ab2e09e868fc redis:6.2.4-alpine "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp redis
2. 开发文档
2.1 Dandelion 路侧设备管理模块
Dandelion 是 OpenV2X 设备管理模块,参考 OpenV2X 架构图:Github 或 Gitlab,在 All-In-One 场景中,Center 和 Edge 节点会部署在一起(Center Dandelion 和 Edge Dandelion 合二为一,即 Dandelion 混合模式)
参考 Dandelion 开发者文档:Github 或 Gitee:
我们尝试搭建 Dandelion 开发环境。
2.1.1 下载、查看和分析源码
在 1.2.4 章节中,我们保留了 MQTT / DB / Redis 三个基础服务,接下来,我们要从 Dandelion 开始启动和调试 OpenV2X 各个组件。
首先是 git clone 源代码(在之前的 Ubuntu 22.04 服务器上):
git clone git@github.com:open-v2x/dandelion.git
然后可以通过文本编辑工具(比如 VIM)查看源码。推荐用 VSCode 的 Remote SSH 插件,可以通过 SSH 直接查看和调试远程服务器上的 Python 代码。
2.1.2 启动服务
因为之前安装过服务,所以配置文件是现成的,在 /etc/dandelion/dandelion.conf,不需要处理。如果希望了解如何修改配置文件,可以参考:Github 或 Gitee
因为之前安装过服务,所以数据库也已经初始化完毕,可以通过 Mariadb 客户端连接到数据库,查看里面的表结构和内容,确认已经初始化完成。如果希望了解如何初始化数据库,可以参考:Github 或 Gitee
pip install tox
tox -e venv
source .tox/venv/bin/activate
uvicorn --reload --reload-dir dandelion --port 28300 --log-level debug dandelion.main:app --host 0.0.0.0
启动后,可以在 http://<external-IP>:28300/docs
看到此服务的 API,可以测试这些 API 是否正常。
也可以用 postman 或者 gabbi,跑全量的 API 测试。gabbi 测试用例(后续会整理到 github 代码仓库里)运行情况如下:
$ ls backend_apitest/*.yaml | xargs gabbi-run 100.100.100.100:28300 --
... ✓ gabbi-runner.area_create_user
... ✓ gabbi-runner.area_user_login
...
... ✓ gabbi-runner.user_login_delete_user
----------------------------------------------------------------------
Ran 4 tests in 1.131s
OK
全量测试通过,确定服务正常。
2.1.3 调试代码
如果要用 VSCode 进行调试,可以停止 uvicorn 进程。
python -m pip install virtualenv
python -m virtualenv .venv
source /root/dandelion/.venv/bin/activate
pip install -r requirements.txt
pip install -r test-requirements.txt
然后从 VSCode 选择 FastAPI 调试,会产生 .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: FastAPI",
"type": "python",
"request": "launch",
"module": "uvicorn",
"args": [
"dandelion.main:app",
"--host",
"0.0.0.0"
],
"jinja": true,
"justMyCode": true
}
]
}
这样 dandelion 会启动在 8000 端口:
(.venv) root@openv2x-test-master:~/dandelion# cd /root/dandelion ; /usr/bin/env /root/dandelion/.venv/bin/python /root/.vscode-server/extensions/ms-python.python-2022.12.1/pythonFiles/lib/python/debugpy/adapter/../../debugpy/launcher 36089 -- -m uvicorn dandelion.main:app --host 0.0.0.0
INFO: Started server process [17430]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
可以下断点,单步调试
2.1.4 提交 Patch
Github 上提交 PR,参考:Github 或 Gitee。
记得始终像 github 提交 PR,不要从向 gitee 提交。github 上的内容会自动更新到 gitee。
2.2 Celebrum 路侧设备信息处理模块
Cerebrum 是 OpenV2X 的“大脑”,负责收集和处理数据。
2.2.1 下载、查看和分析源码
参考 2.1.1 章节,下载 Celerum 代码
git clone git@github.com:open-v2x/cerebrum.git
2.2.2 搭建开发环境
搭建开发环境,我们有如下方法:
- 删除所有 OpenV2X 服务,只保留 3 个基础服务,参考 1.2.4 章节
- 只删除 Cerebrum 服务,保留其它所有服务
这里展示第 2 种方法(只删除 Cerebrum 服务,保留其它所有服务),操作步骤如下:
-
重新部署 OpenV2X,参考 1.2.3 章节
-
停止 Cerebrum 服务
docker stop cerebrum
然后用
docker ps
可以看到 cerebrum 容器确实停止了
2.2.3 启动服务
参考 Cerebrum 文档:Github 或 Gitlab
cd cerebrum
# 创建 python 虚拟环境
python3 -m virtualenv .venv
# 进入 python 虚拟环境
. .venv/bin/activate
# 安装依赖
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements/algo.txt
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r test-requirements.txt
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements/bandit.txt
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements/docstyle.txt
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements/pep8.txt
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements/typecheck.txt
查看 cerebrum 的部署配置,可以看到 cerebrum 靠环境变量完成配置
# cat /tmp/service/docker-compose-service.yaml | grep -i -E '^\s*cerebrum:\s*$' -A 20
cerebrum:
container_name: 'cerebrum'
image: 'openv2x/cerebrum:latest'
restart: 'always'
network_mode: 'host'
environment:
redis_host: '127.0.0.1'
mqtt_host: '127.0.0.1'
mysql_host: '127.0.0.1'
cloud_url: 'http://127.0.0.1:28300/api/v1'
mysql_user: 'root'
mysql_password: password
emqx_password: password
redis_password: password
volumes:
- '/etc/localtime:/etc/localtime'
我们可以将环境变量写进 .bashrc,然后重新进 shell,这样子进程都会继承环境变量。
export redis_host='127.0.0.1'
export mqtt_host='127.0.0.1'
export mysql_host='127.0.0.1'
export cloud_url='http://127.0.0.1:28300/api/v1'
export mysql_user='root'
export mysql_password=password
export emqx_password=password
export redis_password=password
然后运行服务:
python main.py
如果遇到错误 ImportError: libGL.so.1: cannot open shared object file: No such file or directory
:
(.venv) root@openv2x-test-master:~/cerebrum# python main.py
2022-08-30 08:05:43,754 INFO sqlalchemy.engine.Engine SELECT DATABASE()
2022-08-30 08:05:43,754 INFO sqlalchemy.engine.Engine [raw sql] {}
2022-08-30 08:05:43,755 INFO sqlalchemy.engine.Engine SELECT @@sql_mode
2022-08-30 08:05:43,755 INFO sqlalchemy.engine.Engine [raw sql] {}
2022-08-30 08:05:43,755 INFO sqlalchemy.engine.Engine SELECT @@lower_case_table_names
2022-08-30 08:05:43,755 INFO sqlalchemy.engine.Engine [raw sql] {}
2022-08-30 08:05:43,756 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-08-30 08:05:43,758 INFO sqlalchemy.engine.Engine SELECT rsu.rsu_esn AS rsu_rsu_esn, rsu.location AS rsu_location, rsu.bias_x AS rsu_bias_x, rsu.bias_y AS rsu_bias_y, rsu.rotation AS rsu_rotation, rsu.reverse AS rsu_reverse, rsu.scale AS rsu_scale, rsu.lane_info AS rsu_lane_info
FROM rsu
2022-08-30 08:05:43,758 INFO sqlalchemy.engine.Engine [generated in 0.00011s] {}
2022-08-30 08:05:43,759 INFO sqlalchemy.engine.Engine ROLLBACK
Traceback (most recent call last):
File "/root/cerebrum/main.py", line 2, in <module>
from transform_driver.app import App
File "/root/cerebrum/transform_driver/app.py", line 21, in <module>
from pre_process_ai_algo.pre_process import Cfg
File "/root/cerebrum/pre_process_ai_algo/pre_process.py", line 21, in <module>
from pre_process_ai_algo.pipelines.fusion import Fusion
File "/root/cerebrum/pre_process_ai_algo/pipelines/fusion.py", line 17, in <module>
from pre_process_ai_algo.algo_lib import fusion
File "/root/cerebrum/pre_process_ai_algo/algo_lib/fusion/__init__.py", line 20, in <module>
from pre_process_ai_algo.algo_lib.fusion.algorithm import Hungarian
File "/root/cerebrum/pre_process_ai_algo/algo_lib/fusion/algorithm.py", line 22, in <module>
import cv2 # type: ignore
File "/root/cerebrum/.venv/lib/python3.10/site-packages/cv2/__init__.py", line 181, in <module>
bootstrap()
File "/root/cerebrum/.venv/lib/python3.10/site-packages/cv2/__init__.py", line 153, in bootstrap
native_module = importlib.import_module("cv2")
File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
ImportError: libGL.so.1: cannot open shared object file: No such file or directory
可以这样处理:
pip uninstall opencv-python
pip install opencv-python-headless
服务就可以正常启动了:
(.venv) root@openv2x-test-master:~/cerebrum# python main.py
2022-08-30 08:09:13,623 INFO sqlalchemy.engine.Engine SELECT DATABASE()
2022-08-30 08:09:13,623 INFO sqlalchemy.engine.Engine [raw sql] {}
2022-08-30 08:09:13,624 INFO sqlalchemy.engine.Engine SELECT @@sql_mode
2022-08-30 08:09:13,624 INFO sqlalchemy.engine.Engine [raw sql] {}
2022-08-30 08:09:13,624 INFO sqlalchemy.engine.Engine SELECT @@lower_case_table_names
2022-08-30 08:09:13,624 INFO sqlalchemy.engine.Engine [raw sql] {}
2022-08-30 08:09:13,625 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-08-30 08:09:13,627 INFO sqlalchemy.engine.Engine SELECT rsu.rsu_esn AS rsu_rsu_esn, rsu.location AS rsu_location, rsu.bias_x AS rsu_bias_x, rsu.bias_y AS rsu_bias_y, rsu.rotation AS rsu_rotation, rsu.reverse AS rsu_reverse, rsu.scale AS rsu_scale, rsu.lane_info AS rsu_lane_info
FROM rsu
2022-08-30 08:09:13,627 INFO sqlalchemy.engine.Engine [generated in 0.00011s] {}
2022-08-30 08:09:13,628 INFO sqlalchemy.engine.Engine ROLLBACK
2022-08-30 08:09:14 | TRACE | Socket opened
2022-08-30 08:09:14 | TRACE | Watching socket for writability.
2022-08-30 08:09:14,295 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2022-08-30 08:09:14,296 INFO sqlalchemy.engine.Engine SELECT system_config.mqtt_config AS system_config_mqtt_config, system_config.node_id AS system_config_node_id
FROM system_config
LIMIT %(param_1)s
2022-08-30 08:09:14,296 INFO sqlalchemy.engine.Engine [generated in 0.00015s] {'param_1': 1}
2022-08-30 08:09:14,297 INFO sqlalchemy.engine.Engine ROLLBACK
2022-08-30 08:09:14 | TRACE | misc_loop started
2022-08-30 08:09:14 | TRACE | Socket is writable, calling loop_write
2022-08-30 08:09:14 | TRACE | Stop watching socket for writability.
2022-08-30 08:09:14 | TRACE | Socket is readable, calling loop_read
2022-08-30 08:09:14 | TRACE | Watching socket for writability.
2022-08-30 08:09:14 | TRACE | Socket is writable, calling loop_write
2022-08-30 08:09:14 | TRACE | Stop watching socket for writability.
2022-08-30 08:09:14 | TRACE | Socket is readable, calling loop_read
2022-08-30 08:09:14 | TRACE | Socket is readable, calling loop_read
...
可以通过从 RSE 模拟器发送消息来验证服务是否正常,参考 Github 或 Gitee
也可以用脚本做功能和性能测试(脚本后续会上传到 github)
$ sh function_test.sh
====================================== test session starts =======================================
platform darwin -- Python 3.9.7, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /Users/wuwenxiang/local/gitlab/v2x-apitest, configfile: pytest.ini
plugins: anyio-3.6.1, subtests-0.5.0, hypothesis-6.23.2, tavern-1.23.3, html-3.1.1, typeguard-2.13.3, schemathesis-3.10.1, cov-3.0.0, metadata-2.0.2
collected 5 items
function_test/dnp.tavern.yaml . [ 20%]
function_test/rsi.tavern.yaml . [ 40%]
function_test/rsm.tavern.yaml . [ 60%]
function_test/sds.tavern.yaml . [ 80%]
function_test/clc.tavern.yaml . [100%]
------- generated html file: file:///Users/wuwenxiang/local/gitlab/v2x-apitest/report.html -------
======================================= 5 passed in 2.95s ========================================
2.2.4 调试代码
参考 2.1.3 章节,通过 VSCode 进行调试。
2.2.5 提交 Patch
参考 2.1.4 章节
2.3 EdgeView 路侧边缘云控制面板
EdgeView 是 OpenV2X 的“枢纽”,负责管理 RSE 设备,并和 CenterView 以及 Dandelion 进行交互。
2.3.1 下载、查看和分析源码
参考 2.1.1 章节,下载 EdgeView 代码
git clone git@github.com:open-v2x/edgeview.git
然后可以通过文本编辑工具(比如 VIM)查看源码。
2.3.2 搭建开发环境
安装 Node >= 14.17.0
修改config/proxy.ts中的相应配置:
dev: {
'/api': {
target: 'http://47.100.126.13:8080/api',
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
},
2.3.3 启动开发环境
在项目根目录下执行,即 package.json 同级
/* 安装依赖 */
yarn install
/* 启动 */
yarn start
启动成功后打开浏览器访问:http://localhost:8000
,即可查看到 EdgeView 平台页面。默认账户名/密码:admin/dandelion
2.3.4 构建 docker 镜像
docker build -t openv2x/edgeview:latest .
默认的构建脚本采用的是 yarn ,如果想采用 pnpm 发现报错,请按照报错进行添加依赖,因为 pnpm 的依赖是平铺模式,所以需要进行添加,待添加完毕后,可以构建
pnpm install <依赖包名>
2.3.4 提交 Patch
参考 2.1.4 章节
2.4 CenterView 中心云控制面板
CenterView 是 OpenV2X 的云控中心,会显示中心云控下的边缘站点,站点的 RSU,以及大屏展示路口以及路口事件信息。
CenterView 开发者文档参考:Github 或 Gitee:
本地运行 CenterView 开发环境具体步骤如下,环境和版本等要求参考如何开发中的详细说明
2.4.1 下载、查看和分析源码
下载 CenterView 代码
git clone git@github.com:open-v2x/centerview.git
2.4.2 配置后端服务地址
修改config/proxy.ts中的相应配置:
dev: {
'/api': {
target: 'http://47.100.126.13:8080/api',
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
},
2.4.3 启动开发环境
在项目根目录下执行,即 package.json 同级
/* 安装依赖 */
yarn install
/* 启动 */
yarn start
启动成功后打开浏览器访问:http://localhost:8000
,即可查看到 CenterView 平台页面。默认账户名/密码:admin/dandelion
2.4.4 调试代码
通过 VSCode 打开项目进行调试。
2.4.5 提交 Patch
参考 2.1.4 章节
2.5 RoadMocker RSE 模拟器
RoadMocker RSE 是 OpenV2X 基于 MQTT 提供的一款 RSE 模拟器,用于帮助开源用户节约成本并进行开发调试
2.5.1 下载、查看和分析源码
参考 2.1.1 章节,下载 RoadMocker 代码
git clone git@github.com:open-v2x/roadmocker.git
然后可以通过文本编辑工具(比如 VIM)查看源码。
2.5.2 开发调试
具体操作可参看文档:Github 需要注意的是 ClientId 和 EdgeView 的 RSU 序列号,而不是 RSU 设备 ID.
2.5.3 提交 Patch
参考 2.1.4 章节.