分分钟搞定 OpenV2X 开发环境 - Columbia 版本

1. 开始开发之前,你需要读什么?

后端服务使用 Python3,前端服务是 JavaScript/TypeScript React

本篇基于《分分钟搞定 OpenV2X 开发环境 - Beihai 版本》修改。

1.1 了解 OpenV2X 是什么?它适用于什么场景?

OpenV2X 致力于打造“车路协同”应用在“远边”(边缘云)或“近边”(路口智能计算盒子)场景中的开源解决方案(开源协议是 Apache 2.0)。在传统“云-边-端”三层架构中,OpenV2X 关注“远边侧”部分(5G 基站侧边缘云)和“近边侧”部分(边缘路口智能计算),致力于提供“路侧设备管理”和“路侧数据采集与智能分析”能力,以满足交管部门“智慧交通”管理需求,和辅助“车载智能”实现自动驾驶。

为什么有了“车载智能驾驶”解决方案还需要“路侧协同”方案?可以简单类比:在黑暗中车也能开,但有了路灯更安全。OpenV2X 在车路协同整体解决方案中,就扮演“路灯”的角色。

参考文档:

  1. 源代码:Github,同步镜像到 Gitee
  2. OpenV2X 官网:https://openv2x.org/

1.2 搭建 AIO 的开发基础环境

参考部署文档:Github,或者 Gitee,我们先搭建 AIO 的开发环境,然后去掉多余服务。

上述文档中选用了 CentOS 7.9,但因为:

  1. CentOS 7.9 会在 2024.06 结束支持
  2. CentOS 7.9 的基础组件偏旧,操作系统内核 / Docker / Python / Git 等基础组件都需要升级
  3. 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_CENTER_IP=100.100.100.100
export OPENV2X_IS_CENTER=true
export OPENV2X_EMQX_ROOT=password
export OPENV2X_REGION=cn
export OPENV2X_ENABLE_DEMO_CAMERA=false
export OPENV2X_REDIS_ROOT=password
export OPENV2X_MARIADB_ROOT=password
export OPENV2X_ENABLE_GPU=false
export OPENV2X_ENDPOINT_HTTP_FLV=http://100.100.100.101:10101/live
export OPENV2X_ENABLE_DEMO_LIDAR=false
export OPENV2X_ENDPOINT_LIDAR=ws://${OPENV2X_EXTERNAL_IP}:8000/ws/127.0.0.1
export OPENV2X_MARIADB_DANDELION=password

bash ./install.sh

注意:

  1. 这里 100.100.100.100 是 OpenV2X 对外暴露的 IP 地址,是安装好 OpenV2X 之后,从 Web 页面访问的 URL 地址,不一定是该服务器的内网地址。
  2. 这里 http://100.100.100.101:10101/live 是 http flv 流的访问地址,不一定是内网地址

安装好之后,根据提示可以访问页面,用提示中的用户名/密码登录,确定登录成功。然后可以根据 OpenV2X 使用手册:Github,或 Gitee,验证功能正常。

1.2.4 删除 OpenV2X 应用服务,只保留基础组件

先看一下 OpenV2X 服务

root@99dev:~/src# docker ps
CONTAINER ID   IMAGE                                                          COMMAND                  CREATED         STATUS         PORTS                                                                                                                                                                                                                                                                                                                       NAMES
2a62b0a85dfd   registry.cn-shanghai.aliyuncs.com/openv2x/lidar:latest         "python3 udp_client.…"   2 minutes ago   Up 2 minutes                                                                                                                                                                                                                                                                                                                               udp_client
54c98806c4e2   registry.cn-shanghai.aliyuncs.com/openv2x/lidar:latest         "python3 udp_server.…"   2 minutes ago   Up 2 minutes                                                                                                                                                                                                                                                                                                                               udp_server
a71c5fd8ba8b   registry.cn-shanghai.aliyuncs.com/openv2x/lidar:latest         "celery worker --app…"   2 minutes ago   Up 2 minutes                                                                                                                                                                                                                                                                                                                               celery_worker
7b1e71e7c594   registry.cn-shanghai.aliyuncs.com/openv2x/roadmocker:latest    "/docker-entrypoint.…"   3 minutes ago   Up 2 minutes   0.0.0.0:6688->80/tcp, :::6688->80/tcp                                                                                                                                                                                                                                                                                       rse-simulator
937f076505a3   registry.cn-shanghai.aliyuncs.com/openv2x/omega:latest         "/docker-entrypoint.…"   3 minutes ago   Up 2 minutes                                                                                                                                                                                                                                                                                                                               omega
75cae64a51bb   registry.cn-shanghai.aliyuncs.com/openv2x/dandelion:latest     "run_service.sh"         3 minutes ago   Up 2 minutes                                                                                                                                                                                                                                                                                                                               dandelion
76f1722c501d   registry.cn-shanghai.aliyuncs.com/openv2x/lidar:latest         "uvicorn main:app --…"   3 minutes ago   Up 2 minutes                                                                                                                                                                                                                                                                                                                               lidar_websocket
16ad5e913289   registry.cn-shanghai.aliyuncs.com/openv2x/cerebrum:latest      "sh /usr/local/bin/s…"   3 minutes ago   Up 2 minutes                                                                                                                                                                                                                                                                                                                               cerebrum
01d497b72ebb   registry.cn-shanghai.aliyuncs.com/openv2x/emqx:4.3.0           "/usr/bin/docker-ent…"   3 minutes ago   Up 3 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
fe308fd009c7   registry.cn-shanghai.aliyuncs.com/openv2x/lal:latest           "/lal/bin/lalserver …"   3 minutes ago   Up 3 minutes   4433/tcp, 5544/tcp, 0.0.0.0:1935->1935/tcp, :::1935->1935/tcp, 8083-8084/tcp, 30000-30100/udp, 0.0.0.0:7001->8080/tcp, :::7001->8080/tcp                                                                                                                                                                                    lalserver
ae8e98c8e4ee   registry.cn-shanghai.aliyuncs.com/openv2x/mariadb:10.5.5       "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp                                                                                                                                                                                                                                                                                   mariadb
1829992c5275   registry.cn-shanghai.aliyuncs.com/openv2x/redis:6.2.4-alpine   "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp                                                                                                                                                                                                                                                                                   redis

其中基础服务包括:

  1. emqx:MQTT 服务器
  2. mariadb:数据库服务器
  3. redis:缓存服务器

业务服务包括:

  1. dandelion:RSE 设备管理服务
  2. cerebrum:RSE 数据处理服务
  3. rse-simulator:RSE 模拟器
  4. omega:控制面板
  5. hippocampus:RSTP 视频感知服务
  6. lidar:激光雷达感知服务

需要开发哪个模块,就 docker stop 对应模块的容器。

2. 开发文档

参考:GithubGitee

2.1 Dandelion 路侧设备管理模块

Dandelion 是 OpenV2X 设备管理模块,参考 OpenV2X 架构图:GithubGitlab,在 All-In-One 场景中,Center 和 Edge 节点会部署在一起(Center Dandelion 和 Edge Dandelion 合二为一,即 Dandelion 混合模式)

参考 Dandelion 开发者文档:GithubGitee

  1. 技术栈
  2. 目录树介绍
  3. 如何开发

我们尝试搭建 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,不需要处理。如果希望了解如何修改配置文件,可以参考:GithubGitee

因为之前安装过服务,所以数据库也已经初始化完毕,可以通过 Mariadb 客户端连接到数据库,查看里面的表结构和内容,确认已经初始化完成。如果希望了解如何初始化数据库,可以参考:GithubGitee

参考 GithubGitee,直接启动服务

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 是否正常。

image

也可以用 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,参考:GithubGitee

记得始终像 github 提交 PR,不要从向 gitee 提交。github 上的内容会自动更新到 gitee。

2.2 Celebrum 路侧设备信息处理模块

Cerebrum 是 OpenV2X 的“大脑”,负责收集和处理数据。

参考:GithubGitee

2.2.1 下载、查看和分析源码

参考 2.1.1 章节,下载 Celerum 代码

git clone git@github.com:open-v2x/cerebrum.git

2.2.2 搭建开发环境

搭建开发环境,我们有如下方法:

  1. 删除所有 OpenV2X 服务,只保留 3 个基础服务,参考 1.2.4 章节
  2. 只删除 Cerebrum 服务,保留其它所有服务

这里展示第 2 种方法(只删除 Cerebrum 服务,保留其它所有服务),操作步骤如下:

  1. 重新部署 OpenV2X,参考 1.2.3 章节

  2. 停止 Cerebrum 服务

    docker stop cerebrum
    

    然后用 docker ps 可以看到 cerebrum 容器确实停止了

2.2.3 启动服务

参考 Cerebrum 文档:GithubGitlab

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 模拟器发送消息来验证服务是否正常,参考 GithubGitee

也可以用脚本做功能和性能测试(脚本后续会上传到 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 RoadMocker RSE 模拟器

RoadMocker RSE 是 OpenV2X 基于 MQTT 提供的一款 RSE 模拟器,用于帮助开源用户节约成本并进行开发调试

参考:GithubGitee

2.3.1 下载、查看和分析源码

参考 2.1.1 章节,下载 RoadMocker 代码

git clone git@github.com:open-v2x/roadmocker.git

然后可以通过文本编辑工具(比如 VIM)查看源码。

2.3.2 开发调试

具体操作可参看文档:Github 需要注意的是 ClientId 和 EdgeView 的 RSU 序列号,而不是 RSU 设备 ID.

2.3.3 提交 Patch

参考 2.1.4 章节.

2.4 Omega 开发

2.5 HippoCampus 开发

2.6 Lidar 开发