(敏捷与瀑布)关键算法开发:设计

想象一下瀑布。强大。无可非议。始终朝着即将来临的下降前进。由宇宙中几种基本力之一驱动。



瀑布本身就令人叹为观止,因此工程师对它们有点痴迷也就不足为奇了。推荐使用旧的DOD-STD-2167A标准,而我的遗留工程背景是基于Phase-Gate模型,在我看来,它与瀑布模型非常相似。另一方面,我们这些在大学学习过计算机科学的人可能知道瀑布模型在某种程度上是一种反模式。我们在象牙塔中的朋友告诉我们不,不,敏捷是通往成功的道路,看起来行业已经证明这是事实。



那么,开发人员应该在老化的瀑布模型和新的敏捷方法之间进行选择?在开发算法时,方程式会改变吗?还是一些安全关键软件?



像往常一样,答案介于两者之间。



混合,螺旋和V型



混合开发是中间的答案。如果瀑布模型不允许返回并更改需求,则混合模型可以。如果敏捷在前期设计方面遇到问题,则混合开发为其留有空间。此外,混合开发旨在减少最终产品中的缺陷数量,这是我们在设计安全关键型应用程序算法时可能想要的。



听起来不错,但效果如何?



要回答这个问题,我们都押在混合动力车上的开发工作,而无损检测定位算法。... 本地化是超越自动反应控制的任何自动驾驶堆栈的重要组成部分。如果您不相信我或不熟悉本地化,强烈建议您查看通过此过程开发的一些设计文档



简而言之,什么是混合开发?从业余角度来看,我会说这是一个理想的V形螺旋模型您计划,设计,实施和测试,然后根据在此期间学到的经验教训和新知识,对整个过程进行迭代。



实际使用



更具体地说,我们与Autoware.Auto的NDT工作组一起完成了V模型左级联的第一个下降(即在设计阶段进行了第一次迭代),为伦敦Autoware Hackathon做准备(由Parkopedia运营)。我们在设计阶段的第一步包括以下步骤:



  1. 文献评论
  2. 现有实施概述
  3. 设计高级组件,用例和需求
  4. 故障分析
  5. 指标的定义
  6. API架构和设计


如果您对类似的内容感兴趣,可以查看每个生成的文档,但是在本文的其余部分,我将尝试分解其中的一些文档,并解释在每个阶段中该文档的内容和原因。



文献回顾和现有实施



任何体面的努力的第一步(这就是我对NDT实现进行分类的方式)是看看其他人做了什么。毕竟,人类是社会存在者,我们的所有成就都站在巨人的肩膀上。



除了典故,在考虑“过去的艺术”时,还需要考虑两个重要领域:学术文献和功能实现。



看看贫困学生在饥荒期间正在从事什么工作总是有帮助的。充其量,您会发现有一个可以实现而不是自己实现的完美算法。在最坏的情况下,您将了解决策的空间和变化(这可以帮助信息体系结构),并且还可以了解算法的一些理论基础(以及因此应注意哪些不变式)。



另一方面,看看别人在做什么也很有帮助-毕竟,从开始提示开始做某事总是最容易的。您不仅可以免费借用良好的架构思想,而且还可以发现使算法在实践中可能需要的一些猜测和肮脏技巧(甚至可以将它们完全集成到您的体系结构中)。



我们对NDT文献的回顾,我们已经收集以下信息有用的片段:



  • NDT系列算法具有多种变体:

    -P2D

    -D2D-

    受限

    -语义
  • 有很多肮脏的技巧可以用来使算法更好地执行。
  • 通常将NDT与ICP进行比较
  • NDT更快,更可靠。
  • NDT在指定区域内可靠地运行(成功率很高)


没什么了不起的,但是可以将这些信息保存下来,以备以后在设计和实现中使用。



同样,从对现有实现概述中,我们不仅看到了具体步骤,而且还看到了一些有趣的初始化策略。



用例,需求和机制



任何“设计或计划优先”开发过程的组成部分都是从高层次解决您要解决的问题。从广义上讲,从功能安全的角度(我承认,我与专家相距甚远),“问题的高级观点”大致组织如下:



  1. 您要解决什么
  2. 满足上述用例的解决方案有哪些要求(或限制)?
  3. 哪些机制可以满足上述要求?


上述过程提供了对该问题的有条理的高级概述,并逐渐变得更加详细。



要了解它的外观,可以查看为准备NDT开发而编写的高级本地化项目文档。如果您不想在睡觉前阅读,请继续阅读。



用例



我喜欢用例的三种思维方法(注意,我不是功能安全专家):



  1. 该组件应该做什么?(记住SOTIF!)
  2. 可以将输入内容输入组件的方式有哪些?(输入用例,我喜欢在上游使用它们)
  3. 我可以通过什么方式获得输出?(周末或自上而下的用例)
  4. 额外的问题:此组件可以驻留在整个系统体系结构中?


综合考虑,我们得出以下结论:



  • 大多数算法都可以使用本地化,但最终可以将它们分为在本地和全局均可使用的风味。
  • 本地算法在其转换历史中需要连续性。
  • 几乎任何传感器都可以用作定位数据的来源。
  • 我们需要一种初始化和解决本地化方法的方法。


除了可以想到的各种用例之外,我还喜欢考虑一些非常严格的常见用例。为此,我可以选择(或执行任务)完全无人驾驶的越野旅行,途经多辆载有大篷车的隧道。这种用例有很多烦人之处,例如里程计误差的累积,浮点误差,定位校正和中断。



要求



除了概括您要解决的任何问题外,开发用例的目的还在于定义需求。为了使用例发生(或得到满足),可能有一些必须实现或可能的因素。换句话说,每个用例都有一组特定的要求。



最后,对本地化系统的一般要求并不那么可怕:



  • 提供本地算法的转换
  • 提供全局算法的转换
  • 提供初始化相对定位算法的机制
  • 确保转化不会溢出
  • 确保符合REP105


合格的功能安全专家可能会提出更多要求。这项工作的价值在于以下事实:我们为设计明确提出了某些要求(或限制),这些要求与机制一样,将满足我们对算法操作的要求。



机制



任何分析的最终结果都应该是一组实用的课程或材料。如果作为分析的结果,我们不能使用该结果(甚至是否定的结果!),那么该分析就被浪费了。



就高级工程文档而言,我们正在谈论的是一组机制或封装这些机制的构造,它们可以充分适合我们的用例。



这种特定的高级本地化设计允许构成本地化系统体系结构的一组软件组件,接口和行为。所提出的体系结构的简单框图如下所示。



图片



如果您对有关建筑或设计的更多信息感兴趣,我强烈建议您阅读文件全文



故障分析



由于我们在安全性至关重要的系统上构建组件,因此我们应该尝试避免或至少减轻故障。因此,在我们尝试设计或建造任何东西之前,我们至少应了解事情如何破裂。



在大多数情况下,分析故障时,从多个角度查看组件很有用。为了分析NDT算法的失败,我们以两种不同的方式来考虑:作为一种通用的(相对)定位机制,特别是作为NDT算法的一个实例。



从定位机制的角度来看,主要故障模式表述如下:“如果输入的数据不正确怎么办?”实际上,从单个组件的角度来看,除了对系统的适当性进行基本检查以外,几乎无能为力。在系统级别,您具有其他选项(例如,启用安全功能)。



将NDT视为孤立的算法,通过突出显示适当数量的方面来从算法中进行抽象很有用。注意算法的伪代码版本将很有帮助(这将有助于开发人员更好地了解算法)。在这种情况下,我们将对算法进行详细分析,并研究所有可能破坏算法的情况。



尽管可以通过适当的测试将其修复,但实现错误是完全合理的失败。关于数值算法的一些细微差别开始越来越频繁地出现并且越来越隐蔽。特别是,我们正在谈论寻找逆矩阵,或更广泛地说,是解决线性方程组,这可能会导致数值误差。这是一个非常敏感的故障情况,应予以解决。



我们还确定的另外两个重要失败是,验证某些表达式的大小不受限制(浮点精度控制),并验证输入的大小或大小受到不断监控。我们



总共制定了15条建议... 我建议您熟悉它们。



我还要补充一点,尽管我们没有使用这种方法,但是故障树分析是构造和量化故障分析问题的出色工具。



指标的定义



“衡量的是可以管理的”

-管理人员的流行短语
不幸的是,在专业发展中,当您厌倦了做某事时,仅仅耸耸肩膀并说“完成”是不够的。基本上,任何工作包(同样是无损检测开发项目)都需要接受标准,必须由客户和供应商双方商定(如果您既是客户又是卖方,请跳过此步骤)。存在所有支持这些方面的判例,但是作为工程师,我们可以通过创建度量标准来确定组件的可用性来简化中间商。毕竟,这些数字(大部分)是明确且无可辩驳的。



即使验收标准是不必要的或无关紧要的,也要有一组定义良好的度量标准来表征和改善项目的质量和性能,这仍然很不错。最后,所测量的是可控的。



对于我们的NDT实施,我们将指标分为四大类:



  1. 通用软件质量指标
  2. 通用固件质量指标
  3. 算法的一般指标
  4. 本地化指标


我不会赘述,因为这些指标都是相对标准的。重要的是,已经针对我们的特定问题定义并确定了度量标准,这大约是我们作为开源项目开发人员可以实现的目标。最终,应由部署系统的人员根据项目的具体情况确定接受标准。



我在这里要重复的最后一件事是,虽然度量标准可以很好地测试,但是它们不能代替检查实现理解和使用要求。



架构和API



在认真地定义了我们要解决的问题并加深对解决方案空间的了解之后,我们终于可以深入到与实施接壤的领域。



我最近一直是测试驱动开发的迷。像大多数工程师一样,我喜欢开发过程,而编写测试的想法首先对我来说很麻烦。当我开始专业编程时,我径直走了,并在开发后进行了测试(即使我的大学教授告诉我做相反的事情)。研究表明在实现之前编写测试往往会导致更少的错误,更高的测试覆盖率以及通常更好的代码。也许更重要的是,我相信测试驱动的开发有助于解决算法实现的重大问题。



它是什么样子的?



您可以将问题分解为更有意义的片段,而不是引入称为“ Implement NDT”(包括测试)的单张票据,这会导致数千行代码(无法有效地查看和研究)。



  1. 编写算法的类和公共方法(创建体系结构)
  2. 使用公共API为该算法编写测试(它们应该失败!)。
  3. 实现算法的逻辑


因此,第一步是编写算法的体系结构和API。我将在另一篇文章中介绍其他步骤。



尽管有很多关于如何“架构师”的作品,但在我看来,软件架构设计与黑魔法有关。就我个人而言,我想将软件体系结构视为在概念之间划分界限,并试图描述提出问题的自由度以及如何根据概念解决问题。



那么,无损检测的自由度是多少?



对文献的回顾告诉我们,存在呈现扫描和观察结果的不同方法(例如P2D-NDT和D2D-NDT)。同样,我们的高级工程论文说,我们有几种表示地图的方式(静态和动态),因此这也是一个自由度。最近的文献也表明可以重新考虑优化问题。但是,通过将实际实现与文献进行比较,我们发现即使优化解决方案的细节也可能有所不同。



这样的例子不胜枚举。



根据初步设计结果,我们确定了以下概念:



  • 优化问题
  • 优化方案
  • 扫描检视
  • 地图检视
  • 初始假设生成系统
  • 算法和节点接口


这些项目中有一些细分。



架构的最终期望是它应该是可扩展和可维护的。我们提出的体系结构能否实现这一希望,只有时间会证明一切。



进一步



设计之后,当然是实施的时候了。在Autoware.Auto中实施NDT的正式工作是在Parkopedia组织Autoware黑客马拉松上进行的



应该重申的是,本文只是设计阶段的第一步。已知的没有任何战斗计划可以抵抗敌人,软件设计也可以这样说。瀑布模型的最终失败是在规格和设计完美的前提下进行的。不用说,规范和设计都不是完美的,随着实施和测试的进行,将发现缺陷,并且必须对此处概述的设计和文档进行更改。



没关系。作为工程师,我们不是我们的工作,也不是我们的工作,我们可以做的就是迭代并努力争取完美的系统。在谈到无损检测的发展之后,我认为我们迈出了良好的第一步。



订阅频道:

@TeslaHackers — Tesla-, Tesla

@AutomotiveRu — ,







图片



- automotive . 2500 , 650 .



, , . ( 30, ), -, -, - (DSP-) .



, . , , , . , automotive. , , .


:






All Articles