在自动驾驶汽车开发中利用机器人数据- Carl Quinn, Zoox
Zoox的工程师们正在建造自动驾驶汽车,以解决全球的移动问题。他们的车辆是机器人,可以捕捉并生成大量数据。他们收集数据、消化数据、对其进行分类,并将其提供给公司的其他部门用于多种用途,例如性能分析、事件分类、机器学习和数据挖掘。在本视频中,Zoox介绍了机器人数据与典型服务器日志数据的不同之处,以及他们如何管理这些数据,将其转变为一个有利于Zoox开发和运营团队的平台。
视频记录
好吧,我要开始了。今天的演讲是关于在自动驾驶汽车开发中利用机器人数据。
我在一家叫Zoox的初创公司工作。我们正在建造自动驾驶汽车,今天我要谈一谈我们如何使用我们在汽车上收集的数据来改进我们的开发过程,并为我们所做的事情提供信息。
所以,自动驾驶汽车是机器人,Zoox正在建造,我不知道你是否知道我们的使命,但是,Zoox,我们的使命是为世界提供机动性,为密集的城市环境,我们的目标是建立一个完整的堆栈,一个完整的解决方案。所以,我们正在建造车辆,我们正在建造人工智能软件,它将驾驶车辆,我们将拥有我们建造的车队,我们将像出租车服务一样运营车队,机器人出租车,所以整个堆栈。
这给了我们一些优势,一些很大的优势,我们认为与其他一些公司相比,这很重要,这些公司实际上只是在现有的汽车上添加了机器人,因为这些汽车是为人类驾驶而设计的,如果你把机器人放在那里,试着驾驶它,有很多事情都不太好。
我们认为,如果你从头开始建造一辆正确的汽车,我们就能做得更好。所以,在我们的开发过程中,我们同时在两个分支上工作,或者开发工作的两个主要方面。
其中之一是,我们正在建造飞行器,我们有一些原型。事实上,今天早上视频里的一些车就是我们在阿拉梅达赛道上行驶的车。它们看起来像沙丘车。这些就是我们实际设计的原型车。但是,我们所做的大部分工作,问题中最难的部分是开发用于实际驾驶的人工智能软件。
这就是我们所说的三级飞行器。所以,我不知道你们是否熟悉交通部的自动驾驶级别,但是一,二,三是人类在驾驶汽车的某个阶段参与的级别。
所以,第三级是一辆基本上是自动驾驶的汽车,但有人在做备份。所以,这就是我们在这里看到的,这也是大多数其他自动驾驶汽车公司在驾驶模型和培训模型中使用的。所以,驾驶座上有一名训练有素的司机和一名软件操作员。在我们的情况下,我们总是有第二个软件操作员在副驾驶座位上做笔记并注意某些事情。
然后,在某个时候,当我们的五级车辆完成了,我们的软件完成了,然后我们将把它们组合在一起,很快就会在公共道路上行驶。
所以,机器人就像青蛙或其他动物一样。如果你这样想,它们有传感器或感官,还有摄像头,激光雷达,雷达,飞行时间,声纳。一些正在制造自动驾驶汽车的自动驾驶汽车公司把一切都押在了摄像头上,理论上,人类可以看到,我们可以驾驶,因此,如果一辆汽车能看到,它就应该能够驾驶。
但是,我们大脑的计算能力与我们在gpu堆栈中拥有的计算能力相比是截然不同的。所以,为了规避这些限制,并引入激光雷达、雷达、飞行时间、声纳和其他近距离传感器的多种模式,我们可以获得大量的交叉参考信息,以及大量关于环境的可靠输入,这是通常只有相机无法获得的。
然后,计算。机器人有计算能力,我们使用CPU和GPU。很多工作,特别是视觉和感知处理可以在GPU上完成。这对于机器学习和这类处理来说效率更高。
然后,每当决定要做什么时,这些信号就会返回来控制马达,执行器,速度控制器,以及各种硬件。
所以,现在每辆车上面都有公交车,对吧?CAN总线,LIN总线,在你的车上有很多不同类型的普通互连它们在传感器和小执行器,控制器之间发送信号,用于汽车的所有不同部分。所以,我们的汽车,我们的交通工具,是类似的。
所以,我们有很多标准的汽车总线我们在低水平上处理物理控制的东西。但是,我们也有一些更高级别的总线,因为你不会在CAN总线上运行激光雷达数据流和摄像机数据流。所以,我们也有,以太网总线和其他类型的路由和交换,更像是一个完整的计算。那车里就装了个小数据中心。
这样就把所有的信息都输入到中央计算机,或者我们称之为PCU,它是汽车的主要大脑。在主大脑中有专门的过程。所以,这是一个有趣的架构。当我加入时,我发现它很吸引人,因为在这台多核、多处理器的机器上,有效地运行着高速消息总线。
但是,消息总线允许不同的进程或组件、软件组件进行发布和订阅。所以,以非常快的速度发布/订阅,消息穿过总线,它们有可以读回消息的目标接收者。
他们各自负责处理图像,检测,分类,实时建立三维模型并在车辆移动时维护这个模型。定位,各种决策,计划机器人的行为。
那么,我们有很多数据,我们应该如何处理它们呢?让我们以某种方式来捕捉它。现在,在传统的服务器环境中,您通常会进行日志收集,因此您会让您的服务器写入,可能只是标准输出,只是转储,您尝试编写筛选脚本或模式匹配,以尝试提取感兴趣的日志并通过日志堆栈路由它们。
也许你的服务器更好了,你的系统更好了,他们正在编写JSON,这真的很好,因为它更容易解析,你知道你有什么,但通常,它有点模糊,你试图从原始文本流中提取精华,逐行。
但是,我们所拥有的有点不同,因为在我们的系统中通过总线的实际上是不同类型的结构化消息。其中大多数是协议缓冲区。我不知道你们是否熟悉谷歌protobufs。
其中一些是来自我们使用的基于ROS的旧开源平台的ROS消息。而且,我们还使用了来自OMG DDS的标准DDS消息。因此,这些不同类型的系统使用不同的信息,这取决于它们来自哪里以及它们被用于什么。
所以,从很多方面来看,这些信息实际上已经很紧凑简洁了,已经自给自足,可解析了,我们可以把它们以某种格式写入光盘,我们已经知道如何处理它们了。我们不需要去分析它们。我们只是在录音。所以,在这一点上,我们的录音更像是飞机上的飞行记录仪。
所以,当我们想要记录时,我们必须控制。我们并不想在汽车行驶时一直记录。所以,我们有,作为软件操作工作流程的一部分,团队要去那里执行一项任务,做一个驱动器,他们将控制设置什么软件组件将启动驱动器,当他们开始记录。
然后,在录音的过程中操作员会做笔记,可能会提示出一些问题,并写一些关于它的文章。因此,所有这些信息都可以打包到消息中,并记录和保存。所以,他们也控制着录音。所以,我们什么时候开始,什么时候结束录音,这很重要。
让我在这里展示一个场景。这就是操作员在驾驶时看到的,没有司机,只有软件操作员,你可以看到他们在打开不同的东西。所以,他们打开激光雷达,关闭激光雷达,规划信息。所以,所有这些都是可视化的,让他们看到车辆,规划者,人工智能组件中的所有组件实际上在做什么和思考什么。
这是信息本身的可视化。操作员可以打开和关闭因为他们不需要总是看到所有的东西。他们通常不需要看到激光雷达,但他们只想看到车辆计划做什么,但我们记录下了一切。所有通过总线的数据都会被记录不管他们对UI做了什么。
这些看起来真的很有趣。我不知道。
你可以看到,这些小旗子上有字母Cs或[听不清00:09:54]one。那么,这些是现场的其他代理我们将它们标记为其他汽车还是行人?而且,它也显示了它们被感知的形态。视觉,激光雷达,雷达。通常我们会用两三个人来接他们。
但是,你可以看到在只有一个模态的情况下,这是一个很好的情况,我们有不止一个模态,我们在寻找东西。如果我们仅仅依靠相机,有很多东西是我们无法捕捉到的,而我们可以用其他方式看到。
那么,我们在收集什么呢?因此,所有的消息都通过总线传输。我们不会收集每一条信息,因为有些信息非常大,但我们捕捉了大部分信息。最主要的是当我们捕捉到有趣的决定和低带宽的感知信息时。所以,定位,3D模型预测规划,所有这些都是非常重要的信息。
它们不是特别大。我们捕捉到了所有这些。传感器输入。我们确实在空间和时间上减少了一些。对于相机数据,我们捕捉的是静止的画面但我们也捕捉视频流。但是,我们将它压缩为H265,因为它太大了,无法记录16个摄像头的原始视频。这只是大量的数据。
但是,执行器控制,其他元数据,比如地图和路线。车去哪了?它用的是什么地图?操作员做了什么?什么模式,他们在哪里?他们的开关是什么?所有这些我们都可以收集。
所以,我们有很多流动的数据。我们正在从巴士上收集。理论上,你可以尝试通过LTE传输到后端。如果我们有这样的带宽,那就太酷了。但实际上,我们不这样做,我们把它写入本地磁盘,然后开车四处收集所有的数据,在运行过程中当任务完成时,我们会把数据带回基站并上传。
那么,我们要怎么做呢?我们应该用什么格式记录呢?在飞行器上,我们写入光盘。我们最初使用,因为我们开始使用一些叫做ROS的开源框架,机器人操作系统。我们使用了一种原生格式,他们称之为包文件,这是一个索引数据库文件,你可以把消息写入其中,这非常方便。很多工具都能很好地使用它,但它倾向于把所有东西都写进一个文件,索引是事后建立的。
所以,当我们在写,写,写的时候,如果我们决定我们想要完成我们的任务和驾驶。在开了这么多车之后,你会得到将近1tb的数据。这些文件太大了,一旦我们试图将它们移植回后端,它们就完全无法使用。
复制和处理这么大的文件确实是个问题。所以,我们改变了我们记录的方式,我们利用了信息的一些基本性质。所有消息都有类型。protobuf有类型,我们知道每个消息的信息类型。它们也会根据主题发表。
因此,像典型的消息总线一样,有一个主题是消息流的标签。这些主题被很好地命名,然后,它们会有时间戳。所以,我们有一个非常精确的时钟。我们可以计时,我们知道消息什么时候被发布,什么时候被写入光盘。我们可以用时间戳来组织它。
所以,我们发明了我们自己的格式,我们称之为CHUM。所以,它代表分块消息。这是个有趣的名字。有些人真的很讨厌它,但它很有趣,而且很流行。所以,这个想法,我把它想象成一个长条录音机,如果你见过那些老式的,在纸上写字的笔。这是一样的。
所以,每个主题都写在自己的文件中,在每分钟结束时,我们关闭文件,刷新它,然后,在下一个目录中启动下一个文件。因此,在叶子上有一个充满文件的目录树,目录都是基于时间的。然后,这些文件是这一分钟窗口的主题。
所以,你有一分钟的时间来写主题,然后,窗口关闭。你写完,然后继续下一篇。所以,一分钟内一个话题的交集会给你一个大块。所以,它工作得很好,因为我们可以连续写入,理论上,你可以在写入新数据的同时写入和上传一小时前的数据。我们在实践中并没有这样做,但在理论上,我们可以这样做,因为这只是一个连续的写作流。
所以,我们确实发明了这个。所以,这是我们自己专有的东西,但我们建立在开源的基础上,低层的库,因为我们不想从头到尾重新发明所有东西。所以,我们把它建立在SSTs之上,SS表,排序字符串表,那是低级存储平台谷歌的level DB数据库建立在它之上。
而且,它工作得非常好,因为sst使用这种数据库作为仅追加模式的写入系统。所以,你要写到底,你要写到底。然后,这些小的不可变的写入序列被封装在内存数据库中,实际上。
同理,我们把记录写成两个字段。以纳秒为单位的时间戳。这张唱片是什么时候写的?然后,消息本身就是剩余的有效负载还有一些元数据来描述,这是什么类型的消息?还有什么额外的小数据需要配合吗?来自总线的消息的元数据可能不在消息中,但它与消息有关。
比如出版时间和写作时间,还有其他一些类似的事情。而且,我们可以在需要的时候添加更多额外的数据,这些数据是实际消息的带外数据。
然后,我们需要把数据放到系统中,放到我们的系统中,数据在车上,我们想把它放到云端。在我们的例子中,云是AWS,而on-prem是我们自己的数据中心,所以这是一种混合,我们只是根据需要数据的系统的性能、成本和延迟来移动东西。
但是最初,S3是一个非常棒的存储系统,我们喜欢它。所以,那是我们的主要寄存地点。所以,我们喜欢做的是把驾驶过程中产生的数据上传,放到云端,进行分类然后提取出一些元数据,包括发生了什么,什么时候,谁在跑,在什么车上?然后,把那个小数据库建立起来,把那个边带连接到CHUM存储器本身。
但是,要获得这么多的数据还存在一些挑战。它通常很尖。我们的团队白天开车到处跑。有些日子真的很忙,我们要经常开车。它们都倾向于在相同的时间回到基站,它们想要掉头再出来,所以,你会看到这些大峰值,每个人都出现了。
我们想要得到数据,然后继续前进。其他日子几乎没有这么忙,这是一年前。我们现在开车的次数比一年前多了很多,但即使在那时也有很大的峰值。所以我们需要把数据从飞行器上拿下来,很快把飞行器拿回来。
所以,我们尝试了一些不同的方法。这些车辆的运行,基本上就像一个小型的计算服务器机架,里面有一堆ssd硬盘,所以它们只是我们可以插入的常规驱动器状态。这是我们的存储空间。它工作得很好。带宽写入到,一个大RAID组的ssd真的很好。这是一个简单的问题。
这也是一件很有趣的事情。也许我们可以插入以太网,上传所有东西,理论上应该可以。但是,在实践中,如果你有一堆车辆在等待,试图通过10g以太网上传1tb的数据,这就开始需要一段时间,因为你永远不会得到100%的效率,而且会有一些上游的东西会减慢一切。
所以,10g以太网最终成为了我们的备份计划。如果驱动器出了问题,或者他们不需要马上使用车辆,我们有时会使用10g。
但是,使用ssd本身是很棒的。我们在基站上设置了一些信息亭,这些信息亭就是非常简单的Linux盒子、驱动器槽、自动安装驱动器、查看上面有什么、上传它们、清理它们。所以,基本上是安全的转移到云端。所以,它只是一台把数据输送到云端的机器。它工作得很好,但有几件事可能会出错。
我想最有可能出现问题的是这些驱动器进出驱动器舱的物理连接。他们真的不是为这个而生的。它们开始磨损,销子弯曲,无法一直固定。所以,人们给他插上电源,然后走开,什么都不会发生。或者,他们会被卸下来。它们可能没有被干净地卸载,它们被拉了下来,然后,它们上的一些引导信息被损坏了,它们看起来没问题,但它们不起作用。
有很多事情在发生。因此,有很多操作符和运行本的东西必须发生在人们知道,“好,我做了这个,我做了这个。”我们如何解决这些问题?另一个也是,网络可能会瘫痪,现在我们被卡住了,或者我们被太多的上传阻塞了,每个人都被阻塞在等待中。
这通常发生在所有知道发生了什么事的人都在度假的时候,而我是负责人,我负责传呼机,然后,“哦。这是怎么呢我必须弄清楚。”
当然,这很好。所以,这种情况偶尔会发生。所以,我们试着寻找其他的解,对吧?如何缓解一直插入这些SATA驱动器的问题?而且,我们目前的解决方案工作得非常好,USB 3.1驱动器。这真的很好,我们可以把所有需要的东西都写在一个硬盘上,而不是八个硬盘。它们很坚固,而且连接器的磨损速度不会像SATA针那样快。
所以,这对我们上传光盘的可靠性来说真的是一个很大的福音,没有太多的人为干预,对吧?事情会顺其自然的。如果需要的话,我们还有网络。
一旦我们上传数据,我们有后端系统会扫描CHUM看看里面有什么,看看元数据,然后,把它分类,分解成运行,我们称之为运行。所以,每一个记录序列,当操作员进入并打开它时,我们正在记录数据,我们称之为一次运行。从头到尾,这就是跑步。它是有目的的。它有一个驱动程序,所有关于它的元数据。
因此,我们将所有这些分类,对于每一个,我们可以提取一堆元数据。所以,我们看所有与。让我试试我的小指针。哦。是的。好的。看看那个。
运行的元数据,它告诉你关于运行的一切,时间和模式,以及车辆,运行的目的,以及它目前在通过工作管道的过程中的位置。我们画一个小图来展示它的位置,以及它发生的位置。离这里有五个街区。那是我们经常开车去的地方。离开百老汇,再往北走。
我们也会扫描…这仍然运行得很好…发生的事件。因此,一些消息将包含发生的事情的元数据信息,或者操作员做了一些笔记,只是随意的笔记,他们注意到一些应该有人看的东西。
或者是一些问题,比如司机不得不脱离控制,因为车辆正在移动,可能离边缘太远了,或者它不知道它是否会对正在发生的事情做出正确的反应。
所以,这些被取出并分类,我们实际上把它们,我们称之为分类事件,它们被放入JIRA,这是对JIRA的滥用。我们对它进行了大量的改进,但它确实工作得很好,因为它最终与开发人员工作流和软件发布工作得很好,我们可以说,“好吧,修复了哪些问题?”并且,他们可以把它们组合在一起并创建元问题,然后代表如何重现错误。
所以,我们有了所有的数据,它们都被编目并准备好了。我们要拿它做什么?所以,我用不同的方式来思考这些数据,我重新思考如何调用它们,但我认为在我的脑海中,最好的一个是,我们用两种方式来处理数据。一种是面向消息的,我们只使用组件写入的数据,这些组件甚至可能是脱机运行的相同组件。
如果我们想要重现一个问题,我们实际上可以运行大部分的部分软件堆栈。也许我们正在运行规划器,我们从实际的驾驶中输入感知信息,规划器认为它在汽车中驾驶,它正在做决定。
因此,我们可以使用它进行回归测试,或者开发人员可以使用它在他们的机器上调试问题。所以,在机器人中实时调试一个问题是很难的。但是,如果你可以完美地重现它,因为你有进入它的确切数据,你可以离线完成,重现它,修复它,写一个回归测试,再也不会破坏它。
然后,我们看数据的另一种方式是分析。我认为用分析的方法来称呼它是一个很好的方法,在数据已经存在但没有真正组织起来回答你的问题的情况下提出问题。我们不会写一张唱片来回答你的问题因为你后来想到了这个问题。
所以,更像传统的数据分析,要求业务信息或其他指标和测量,性能的东西,可能会在以后出现,在那里你聚集了大量的数据。我会更详细地讲一下这些。
对于消息数据,这是我们流量的主要部分。基本上,我们把它保存在数据中心,仍然是相同的CHUM形式。我们可以把它转移到一个不同的存储热访问数据,我们使它在同一位置,更接近于我们的大型计算集群。
所以,我们有,有效地,大型超级计算机集群,很多机架的Linux盒子装满了图形处理器。所以,他们在做各种各样的事情,比如机器学习,运行我们所有正在运行的测试,以及所有其他需要数据的事情。
因此,我们可以通过查看总线上的一些简单元消息来做一些事情,我们可以查看消息之间的时间,我们可以生成报告,以便团队可以查看组件运行的速度有多快?他们是否保持了规定的滴答时间,节奏?他们是否在规定的时间内完成了产出?的性能。什么样的CPU?
所以,一旦你能把它们联系起来,我想这将是下一张幻灯片,更多关于性能的细节。但是,是的,所以你可以通过一些简单的工具直接查看很多信息,我们的核心团队开发了这些工具,可以快速查看在整个车辆中使用的一些原始信息。
但是,我们也可以交叉引用消息中的一些相同的时间信息与CPU的行为,标准的CPU分析和转储,这样我们就可以将CPU使用情况,火焰图与时间和延迟关联起来,以及发生了什么,因为有很多内核在运行,它们都在做不同的事情,它们都在发送消息。调试它真的很棘手,除非你有很好的工具来挖掘和关联。这可能是什么消息被发送的因果关系,什么东西触发了,也许,另一个组件的CPU峰值。
当然,我们使用我们收集的数据。特别是激光雷达的所有数据。可能雷达和视觉也被用来收集大量的记录并建立定位信息。所以,使用GPS和其他系统结合我们在激光雷达上看到的,并在一个很长的过程中平均出来,我们可以创建非常非常精确的数字地图,告诉我们在整个城市区域内,在一厘米或两厘米内,事物彼此完全一致。
而且,回放。所以,我们也可以把我们记录的那些信息回放,并以不同的方式有效地呈现它们。我马上就会播放这个视频,但是你在左边可以看到的是摄像机捕捉到的,然后,有了覆盖层,覆盖层的所有信息,比如盒子在那个空间里的位置,传感器在不同的代理上采集到的模式。这些都被记录下来了。
右边的3D图像的所有信息,所有这些代理,他们是什么类型,他们的计划是什么。这些也被记录下来,然后,覆盖在我们运行的地图上。
所以,这只是我们发布的一个小视频蒙太奇展示了车辆的工作,我们可以根据团队需要构建的内容来布局这些视频代。这是我们做的。主要是为了炫耀。所以,看起来很有趣。你可以看到,粉红色的是行人,蓝色的是车辆,橙色的是自行车或踏板车。
在右边你可以看到计划器。所以,它在顶部显示了指示车辆打算做什么的信号。如果它绕着两辆停着的车,在底部是一样的,但这是俯视图。红色的门说它知道它会停在那里。然后,绿线是来自每个智能体的预测向量,所以我们知道预测,我们认为行人或其他司机会去哪里。好的。
我之前提到的一件事是,当有事情发生时,一般来说,操作员会做笔记,会在信息中记录下。我们将把它带到周围,收集信息,然后,保存在JIRA中。然后,参赛队可以看看JIRA的门票。
QA可能会先看这些,工程师可能会马上看,然后决定什么时候去看。他们需要知道的都在这里了。他们需要所有的元数据,获取CHUM并重现发生的问题,他们可以查看它。
我们可以对它进行分类,我们可以记录它,我们可以回放它,看看在不同的视图中发生了什么,我们可以生成不同的外观。我们有办法设置窗口,在那里我们可以观察发生了什么,并查看消息的度量和时间,以及同时发生的各种诊断信息。
我们可以保存它们,剪掉它们,把它们变成测试,我们可以一遍又一遍地运行,来验证一些东西。我们也可以做那些日志测试,所以只是基于真实数据的测试,部分自动化,手动制作更综合的测试,然后我们可以用同样的方式重现这个问题,但是,添加一些额外的模糊,所以你可以创建……假设,如果行人走得快一点,或慢一点,或向右走得多一点,会发生什么?因此,我们可以展开,乘出,特定测试可以测试的情况。
我想我已经提到过很多了,开发人员调试,让所有数据可用让人们在桌面上调试或者在作业中运行通过在作业队列中写入作业。当然,还有机器学习训练,以及用来识别事物的标签。
然后,最后一点。我只讲一点,就是分析学。在很长一段时间里,我们只是运行脚本,从CHUM中提取数据,然后直接用Python查看。我们可以用这种方式进行分析,它对特别查询非常有效。如果一个工程师想要查看大量的数据,并在很长一段时间内从许多主题中提取一些信息,他们可以使用一些很好的Python分析工具来完成,我们可以直接访问CHUM数据,但我们想要做得更多,更正式一点,让我们利用一些用于数据分析的工具。
因此,我们现在主动地ETL一些我们发现有趣的CHUM数据,并将其放入一个柱状存储中。我们现在用的是红移。可能是将来有用的东西。但是,考虑到我们有这个通用的数据集,它对许多不同的工作非常有用,我们可以将它定期地放入柱状存储中,有规律地摄取,然后,使用它来生成各种不同类型的报告。
这些被故意模糊了一点,但这个想法是,它可以告诉我们我们在旧金山的某条路线上做得有多好。假设我们正在驾驶一条具有挑战性的路线,我们想说,“好吧,这周我们在这条路线上做得怎么样?随着时间的推移,我们是否会变得更好?”或者,在某些情况下,乱穿马路的人或骑自行车的人喜欢跑停车标志。我们在哪里找到它?
我们可以追踪这些信息,从原始数据中收集信息,使其可用,并将其可视化,并在地图中跟踪,创建事物所在的热图。
我们还可以用它来生成我们每年都要做的车管所报告。基本上就是这样。谢谢你!