亚马逊AWS官方博客

自动驾驶数据湖(四):可视化

 1.前言

在亚马逊云科技2020的re:Invent大会上,发布了在云上构建自动驾驶数据湖的参考架构(点击 这里 下载源文件),结合国内的实际业务场景,我们做了一些针对性的细化和调整,修改为如下的参考架构(以MDF4/Rosbag格式数据为参考)。

因为Rosbag数据文件里面包含了例如图片,音视频,雷达,GPS等内容,需要通过解析并识别出来例如带时间戳的图片数据,pcd点云数据等,解析和拆开了对应数据以后就可以进行对应的数据分析,机器学习等环节处理。

因此我们把上图中的自动驾驶数据湖参考架构拆分成一个系列的四篇博客(此处暂时未包括左上角的IoT相关部分),方便用户和读者理解和使用对应的解决方案,这是本系列博客的第四部分:可视化部分(基于上图的1-7-8步骤实现)。

在本篇博客中,更加细化的图像处理流程管道的具体步骤和代码,可以参考如下图所示的参考步骤:

说明:此架构图来自参考文档2里面的步骤架构,我们未做修改。

接下来的博客内容详细代码和步骤参考上图的架构:

a)使用 AWS CDK 将 Webviz 部署为在 AWS Fargate 上运行的容器,对外通过 Application Load Balancer (ALB) 暴露服务。此外,基础设施即代码 (IaC) 可以创建新的 Amazon S3 存储桶或导入现有存储桶。S3 存储桶将更新其跨域资源共享 (CORS) 规则,以允许来自您的 ALB 域的流式处理包文件。

b)存储桶和 ROS Bag 文件不需要公开,因为我们将使用预签名的 Amazon S3 URL 来授权文件的流式传输。

c)最后,AWS CDK 代码部署了一个 AWS Lambda 函数,可以调用该函数来生成格式正确的 Webviz 流 URL,其中包含 HTTP 编码和预签名 URL,用于直接在浏览器中流式传输您的 ROS Bag 文件。

注意:本博客中的可视化部分偏向可视化展现和回放,并没有例如图片抽帧保存,视频截取保存,或者pcd点云数据存储等扩展功能集成。

2.环境准备

我们使用的源代码位于 https://github.com/auto-bwcx-me/ (如果对亚马逊云科技的相关服务特别熟悉,也可以直接使用 官方的GitHub Repo)。

环境说明:

a)我们的操作环境为Cloud9,所有非控制台的操作都基于它完成;

b)因为是博客,为了突出自动驾驶数据湖相关的内容,我们直接给这个Cloud9配置了Administrator的权限,未遵循安全最佳实践里面的最小权限原则,大家在生产环境的时候要注意,尽量遵循最小权限分配的原则,或者操作完毕后删除这个Cloud9实例即可;

c)如果没有特别说明,我们的操作区域为新加坡区域;

d)如果没有特别说明,我们执行脚本的操作目录为代码目录。

注意:如果做过别的实验(如自动驾驶数据湖(一):场景检测),有留存的Cloud9,可以继续使用,各项关于Cloud9的详细配置可以有选择的确认后跳过。

2.1准备Cloud9

因为我们要在Cloud9里面编译代码,所以部署Cloud9实例的时候可以选一个C系列的机型(如c5.2xlarge),这样编译速度会快很多,其他全部默认即可(注意部署到对应的区域,如新加坡区域即可)

创建一个Cloud9环境,取个名字,如“auto4”

确认如下红框选中的配置,其他保持默认即可

约等待1-2分钟即可打开Cloud9控制台,如果出现确实无法访问的情况(不排除是出口网络问题),可以把刚创建的Cloud9删除,重新创建一个。

2.2 安全配置

打开IAM控制台,点击左边的角色(Roles),选择创建新角色:

在添加权限的页面上可以输入“Administrator”进行搜索,然后选中结果里面的“AdministratorAccess”即可(注意:此处配置不符合安全最佳实践,生产环境慎用):

取个名字,例如叫“EC2-for-Cloud9”,然后创建即可。

打开EC2控制台(注意别选错了区域),然后选中对应Cloud9的实例,按下图所示找到修改IAM Role的位置:

选中刚才创建的IAM Role确认即可。

进入到Cloud9的Web控制台,点击右上角的配置按钮:

找到临时Credentials设置,把它关闭(默认是绿色打开的,调整为红色关闭的即可):

至此Cloud9配置完成。

2.3 拉取源代码

进入Cloud9环境,执行如下脚步同步代码:

cd ~/environment

echo "clone code from github"
git clone https://github.com/auto-bwcx-me/aws-autonomous-driving-data-lake-ros-bag-visualization-using-webviz.git 04-viz-using-webviz

cd 04-viz-using-webviz

正常情况如下,如果有异常,请留意URL是否正确

2.4 更新环境变量

在更新Python3.9之前先安装一些系统后续步骤需要用到的依赖包。打开Cloud9环境的命令行执行:

sudo yum -y update
sudo yum -y install jq gettext bash-completion moreutils telnet git

然后更新安装配置,删除临时Crendentials:

echo "delete temp credentials"
rm -vf ${HOME}/.aws/credentials

echo "config cloud9 env"
export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
export AWS_REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/region)
echo "export ACCOUNT_ID=${ACCOUNT_ID}" | tee -a ~/.bash_profile
echo "export AWS_REGION=${AWS_REGION}" | tee -a ~/.bash_profile
aws configure set default.region ${AWS_REGION}
aws sts get-caller-identity

如果返回类似如下内容表示权限配置成功(中间的EC2-for-Cloud9是我们之前配置的IAM角色):

{
    "Account": "123456789012", 
    "UserId": "ARSKWX1234FFAC893KKQK:i-12345678", 
    "Arn": "arn:aws:sts::123456789012:assumed-role/EC2-for-Cloud9/i-12345678"
}


3.测试过程

注意:如果在别的环节调整过Cloud9的默认磁盘大小,可以有选择跳过对应步骤。

默认情况下,部署的Cloud9的磁盘只有10G,我们需要打包好几个Docker镜像,很容易把磁盘撑爆了,所以通过执行这脚本可以把磁盘调整到例如1000G(其实如果只是做这一个实验,100G以上就可以满足,或者曾经调整过磁盘就可以跳过了),确保在代码目录下执行(如果使用的是普通SSD硬盘,记得更换对应脚本文件):

sh resize-ebs-nvme.sh 1000

准备S3存储桶(请确认更新环境变量章节配置成功,不然此步骤会失败):

WEBVIZ_S3=webviz-rosbag-bucket-${ACCOUNT_ID}
aws s3 mb s3://$WEBVIZ_S3
aws s3 ls

检查DynamoDB元数据表是否存在(如果有做过 自动驾驶数据湖(一):场景检测 实验,则跳过此步骤,因为表已经有了)

aws dynamodb create-table \
    --table-name Rosbag-BagFile-Metadata \
    --attribute-definitions AttributeName=bag_file_prefix,AttributeType=S \
    --key-schema AttributeName=bag_file_prefix,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST

3.1配置CDK

配置cdk.json文件

cat > cdk.json <<EOF
{
  "app": "npx ts-node --prefer-ts-exts index.ts",
  "context": {
    "@aws-cdk/core:enableStackNameDuplicates": "true",
    "aws-cdk:enableDiffNoFail": "true",
    "@aws-cdk/core:stackRelativeExports": "true",
    "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true,
    "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true,
    "region": "${AWS_REGION}",
    "bucketName": "${WEBVIZ_S3}",
    "bucketExists": true,
    "generateUrlFunctionName": "generate_ros_streaming_url",
    "putCorsFunctionName": "put_s3_bucket_cors",
    "scenarioDB": {
      "partitionKey": "bag_file",
      "sortKey": "scene_id",
      "region": "${AWS_REGION}",
      "tableName": "Rosbag-Scene-Metadata"
    }
  }
}
EOF

更新npm的相关包

npm install -g npm@latest

npm install

更新CDK的相关包

npm install -g aws-cdk --force

cdk --version

3.2准备代码包

编译Webviz的包

sh build_dependencies.sh

准备Dockerfile

cat > webviz_source/Dockerfile-webviz-nginx <<EOF
FROM node:16.13.2-slim AS builder

# Install some general dependencies for stuff below and for CircleCI;
# https://circleci.com/docs/2.0/custom-images/#required-tools-for-primary-containers
RUN apt-get update && apt-get install -yq gnupg libgconf-2-4 wget git ssh --no-install-recommends

# Copy only the files necessary for installing our package dependencies. This
# way, if the code is updated but the dependencies are the same, we can still
# re-use the cache to avoid re-installing.
WORKDIR /app
COPY lerna.json package.json package-lock.json ./
COPY packages/@cruise-automation/button/package.json \
     packages/@cruise-automation/button/package-lock.json \
     packages/@cruise-automation/button/
COPY packages/@cruise-automation/hooks/package.json \
     packages/@cruise-automation/hooks/package-lock.json \
     packages/@cruise-automation/hooks/
COPY packages/@cruise-automation/tooltip/package.json \
     packages/@cruise-automation/tooltip/package-lock.json \
     packages/@cruise-automation/tooltip/
COPY packages/regl-worldview/package.json \
     packages/regl-worldview/package-lock.json \
     packages/regl-worldview/
COPY packages/webviz-core/package.json \
     packages/webviz-core/package-lock.json \
     packages/webviz-core/

# Copy the rest of the code
COPY . /app

WORKDIR /app

# Install dependencies
RUN npm run bootstrap # install dependencies

# Build static webviz
RUN npm run build-static-webviz # generate static build in __static_webviz__

# Start again with a clean nginx container
FROM nginx:1-alpine

# For backwards compatibility, patch the server config to change the port
RUN sed -i 's/listen  *80;/listen 8080;/g' /etc/nginx/conf.d/default.conf
EXPOSE 8080

# Copy the build products to the web root
COPY --from=builder /app/__static_webviz__ /usr/share/nginx/html
EOF

可以在本地(Cloud9环境)打包测试和验证一下(确保都是OK的再进入下一步):

cd webviz_source
docker build -f Dockerfile-webviz-nginx . -t webviz-nginx
cd ..

因为代码和软件版本匹配的原因,可能会报一些warning提示,在没出错的情况下忽略即可。

3.3部署环境

开始CDK的初始化(一个Region初始化一次即可,不需要重复操作,如下的整个命令是一行,注意复制执行的时候不要折行了):

cdk bootstrap aws://$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document/ |jq -r .accountId)/$(curl -s http://169.254.169.254/latest/meta-data/placement/region)

执行CDK合成

npm run cdk synth

接下来部署测试环境(开始部署后,记得输入“Y”确认)

npm run cdk deploy

4.测试验证

4.1配置模板

部署成功以后,在CloudFormation的控制台找到对应的alb地址(位于Outputs的tab页):

通过浏览器打开它(例如此处的 http://webviz-lb-1056533794.ap-southeast-1.elb.amazonaws.com/)

默认打开是空的,可以定义Webviz的布局,通过导入json文件实现。在项目根目录中包含一个示例配置文件layout.json。 此自定义布局包含特定于我们的 ROS 包格式的主题配置和窗口布局,可以根据您的 ROS 包主题进行修改。

  • 选择配置 → 导入/导出布局
  • 复制并粘贴 layout.json 的内容

类似如下:

配置后如下图所示:

4.2验证测试

参考实验,如自动驾驶数据湖(一):场景检测 里面的测试文件,上传到对应的S3桶,然后配置S3的CORS,打开Lambda函数put_s3_bucket_cors,创建Event并执行:

{
  "ResourceProperties": {
       "bucket_name": "rosbag-scenes-input-<account-id>",
       "allowed_origin": "<alb-domain>" // 例如http://webviz-lb-1056533794.ap-southeast-1.elb.amazonaws.com/
  }
}

使用帮助脚本生成 URL,代码根目录中包含一个 Python 帮助程序脚本,调用 Lambda 函数 generate_ros_streaming_url 来生成链接。要运行帮助程序脚本,请在终端中运行以下命令:

# get s3 bucket name
bag_bucket=$(aws s3 ls |grep rosbag-scenes-input |awk '{print $3}')
echo "S3 bucket is: ${bag_bucket}"

bag_key=2022-03-09-01.bag

python get_url.py \
     --bucket-name ${bag_bucket} \
     --key ${bag_key}

获得URL后,复制出来对应url,然后拼接对应的地址(如拼接到如下url的等号后面)

http://webviz-lb-1056533794.ap-southeast-1.elb.amazonaws.com/?remote-bag-url=

打开加载后就是这样的

也可以通过直接调用 Lambda 函数generate_ros_streaming_url 来生成带签 URL。(此处要注意,seek_to 值通知 Lambda 函数在生成 URL 时添加参数以跳转到指定的 ROS 时间戳,且如果是第一次使用这个S3桶,记得配置CORS)

{
     "key": "<ros_bag_key>",
     "bucket": "<bucket_name>",
     "seek_to": "<ros_timestamp>"
}

4.3场景联动

通过使用 Lambda 函数生成 URL,您可以灵活地将其与其他用户界面或仪表板集成。例如,如果您使用 Amazon QuickSight 可视化检测到的不同场景,您可以定义客户操作以通过 API Gateway 调用 Lambda 函数来获取目标场景的 URL。

同样,自定义 Web 应用程序可用于可视化存储在元数据存储中的场景及其相应的 ROS 包文件。 从您的 Web 服务器调用 Lambda 函数以生成并返回可供 Web 应用程序使用的可视化 URL。

在前面章节 自动驾驶数据湖(一):场景检测 中,场景检测的元数据保持在 Rosbag-Scene-Metadata 中,我们可以基于输出结果,生成URL进一步探索。

打开 DynamoDB 控制台 PartiQL editor 页面,查找 Rosbag-Scene-Metadata 表内容:

SELECT * FROM "Rosbag-Scene-Metadata"

这个表名称在前面的步骤 cdk.json 有定义:

...
    "scenarioDB": {
      "partitionKey": "bag_file",
      "sortKey": "scene_id",
      "region": "${AWS_REGION}",
      "tableName": "Rosbag-Scene-Metadata"
    }
...

任选一条记录,保存 bag_file 和 scene_id 字段,按照以下格式组织:

{
     "record_id": "<scene_description_table_partition_key>",
     "scene_id": "<scene_description_table_sort_key>"
}

打开 Lambda 控制台,定位到 generate_ros_streaming_url 函数,然后准备一个测试事件来获取对应拼接地址,例如:

{
     "record_id": "2022-03-09-01",
     "scene_id": "2022-03-09-01_PersonInLane_1.6058244963E9"
}

或者通过 get_url.py 脚本,也支持额外的场景查找参数。 要查找存储在 Rosbag-Scene-Metadata 表中的场景,请在终端中运行以下命令:

python get_url.py --record <bag_file> --scene <scene_id>

类似如下格式:

python get_url.py --record 2022-03-09-01 --scene 2022-03-09-01_PersonInLane_1.6058245225E9

使用记录和场景参数调用 generate_ros_streaming_url 将从 DynamoDB 中查找场景的 ROS 包文件,预签名 ROS 包文件并返回 URL 以直接在浏览器中流式传输文件。

执行,生成带签URL,然后打开它,这样我们就把第四个可视化场景和第一个场景检测(自动驾驶数据湖(一):场景检测)场景完美的联动集成了起来。

在此我们基于文章最开始的自动驾驶数据湖的主要部分(IoT除外)的博客和内容,代码等全部测试完毕,有实际需求的客户或者读者可以参考我们的样例进行测试,或者基于客户化的代码进行业务代码的替换或优化,也欢迎直接联系亚马逊云科技对应服务于贵公司的商务同事或技术同事。

5.环境清理

虽然绝大部分分配和使用资源型的服务会自动终止资源使用,但是如果客户想手工清除环境的话,可以先清空上述测试过程中创建的S3存储桶里面的数据,然后在代码目录下执行如下脚本即可(大概需要5-10分钟):

cdk destroy --all

参考文档

参考1: 在亚马逊云科技上构建自动驾驶数据湖:

https://aws.amazon.com/cn/blogs/architecture/field-notes-building-an-autonomous-driving-and-adas-data-lake-on-aws/

参考2: 自动驾驶数据湖之可视化:

https://aws.amazon.com/cn/blogs/architecture/field-notes-deploy-and-visualize-ros-bag-data-on-aws-using-rviz-and-webviz-for-autonomous-driving/

参考3: 自动驾驶数据湖(一):场景检测:

https://aws.amazon.com/cn/blogs/china/autonomous-driving-data-lake-scene-detection/

参考4: 自动驾驶数据湖(二):图像处理和模型训练:

https://aws.amazon.com/cn/blogs/china/autonomous-driving-data-lake-image-processing-and-model-training/

参考5: 自动驾驶数据湖(三):图像处理流程管道:

https://aws.amazon.com/cn/blogs/china/autonomous-driving-data-lake-image-extraction-pipeline-using-airflow/

本篇作者

龙斌

亚马逊云科技解决方案架构师,负责协助客户业务系统上云的解决方案架构设计和咨询,现致力于容器和机器学习相关领域的研究。

陈卫琼

亚马逊云科技资深解决方案架构师,负责协助客户业务系统上云的解决方案架构设计和咨询,现致力于大数据和IoT相关领域的研究。

李俊杰

亚马逊云科技解决方案架构师,负责云计算方案的咨询与架构设计,同时致力于容器方面研究和推广。在加入亚马逊云科技之前曾在金融行业IT部门负责传统金融系统的现代化改造,对传统应用的改造,容器化具有丰富经验。

Aubrey Oosthuizen

Aubrey是亚马逊云科技专业服务部的的一名开发运营架构师,他在各个垂直领域工作,结合开发运营和机器学习(MLOP) 来解决客户问题。 他的热情在于自动驾驶和分布式系统。

Tang Junjie

唐俊杰先生是亚马逊云科技专业服务部的首席顾问。作为全球技术主管和自动驾驶数据湖的高级产品经理,他负责亚马逊云科技专业服务部的大数据社区,负责制定数据策略并积累各垂直行业数据分析方面的专业知识。