首页 > 应用与设计 > 电器 > Service Robots > 服务型机器人 > TI机器人系统学习套件(TI-RSLK) >

服务型机器人

最新课程

热门课程

TI-RSLK 模块 4 - 讲座视频 - 设计

大家好, 我是 John Valvano。 在本模块中,我们 将讨论软件设计。 我们首先介绍一下 模块化设计这个概念。 模块是什么, 它是系统的一个子集, 它同时包含软件和硬件, 而且具有完整的任务。 所以我们会将它视为 一个完整的任务。 当我们把这些 模块放在一起时, 我们可以从不同的 角度来看待它们。 其中一个角度 叫做调用图。 这意味着,如果 SwitchMain 中的软件 可以调用针对不同 模块的 switch 中的函数, 我们将会绘制这样 一个调用图箭头。 这个箭头表示, 这将是高级别, 这将是低级别。 类似地,如果 SwitchMain 中的软件 可以调用 LaunchPad 中的 软件,我们将会 绘制一个调用图 箭头,来表示 高级别函数与 低级别函数之间的 因果关系-- 层次结构关系。 而且,我们会将 与一个事件相关的 所有任务-- 例如,与开关 相关的所有函数, 以及与 LaunchPad 相关的所有函数-- 封装在独立的模块中。 我们将要 解决的问题 并不复杂, 我们将在一个输入上 配备一个开关。 如果按下开关, 则会将发光二极管 切换到另外一种 状态。 另一种在互连情况下 看待这些模块的方法 称为数据流图。 数据流图 显示了连接情况。 这是一个硬件模块。 这里的所有其他模块 都是软件模块。 关于开关是否 关闭的布尔信息 被编码在 数据流图的箭头中。 所以,数据是向 这个方向流动的。 即使是 SwitchMain 调用 switch, 数据实际上也是 在向另一个方向流动。 而在这里,数据则是 从 main 向 LaunchPad 流动, 因为我想要 开关 LED。 然后,在物理层面上, 我在数据流图中包含了 可以发光的 LED。 而且,通过 这个数据流图, 我们可以定义 模块化意味着什么。 系统的模块化, 如果您愿意, 这也是系统的精华所在-- 是多个模块的函数。 因此,我们希望最大 限度地增加模块数量, 同时尽量减少 它们之间的互连。 特别是,我们可以 查看带宽之类的 东西,它是每秒 跨屏障传输的 字节数。 因此,我们希望最大 限度地增加模块数量, 同时尽量减少 它们之间的互连。 针对互联的一个简单的 定量测量方式是, 测量每秒从一个 模块流到另一个模块的 字节数。 这便是我们将会 在这里采用的理念。 那么,让我们开始吧。 当我们讨论如何制造 一些复杂的东西-- 换句话说, 模块化系统的 整体思路就是 能够提高复杂性。 可让我们做到这一点的 一种方法是使用多个线程。 线程是由正在执行的 软件引起的操作。 所以,引发线程的 是软件的行为。 我们将会得到一个 多线程环境, 其中有一个 主程序。 而且,我们将会 有多个中断。 例如,我可能会有 硬件触发的中断。 当我触摸开关时, 将会触发一个中断。 我们将会在多个 模块中介绍这种中断的 实际工作方式。 但是在这里,我们只需要 了解一点就足够了, 那就是,当您触摸 开关时,系统会 运行与这个触摸操作 相关的软件。 然后,如果我们想要 周期性地执行 某个操作,我们 将需要另外一种中断。 我们将会使用一个频率为, 比如说 100 赫兹的计时器中断。 而且,我们将从这个 层面上执行软件。 我在这里绘制 一个主程序。 然后绘制初始化。 然后,我们在这里绘制一些东西。 然后就有了一个循环。 我们之所以 将其称为线程, 是因为我们可以 将正在执行的软件想象成 一条单一的轨迹。 即使这是一个函数-- 即使这个初始化 是一个函数, 我们仍然可以绘制一条-- 我们可以 一笔画出一条代表 其执行顺序的直线。 这便是我们将其称为线程的原因。 一系列指令, 由这些指令 引起的操作, 这便是线程。 但是中断是特殊的。 中断是硬件 触发的软件 操作。 在这里,我们将 打断这个线程, 从这里开始,因为 我们触摸了开关, 执行该软件,然后 再次打断该线程, 然后重新返回这里。 所以线程是由正在 执行的软件引起的 操作。 在本课程中, 我们将使用一个 单一的前台线程、 一个主程序,以及多个 在特定事件时 执行的中断线程。 这是增加系统 复杂性的一种方法。 您要做的最困难的 事情之一是, 确定从哪里开始。 我要告诉您一个 很不幸的消息。 您可能也在其他地方 听到过这个 说法-- 需要花费 1 万 小时的时间, 才能熟练掌握一个技能。 我并不是 要打击您。 如果您坐在电脑前, 编写尽可能优秀的代码, 在大约一个小时的时间里, 您可能能够 写出 100 行代码。 如果您将这两个 数字相乘, 达到一百万行 代码的分界线后, 您将会成为一名 优秀的软件设计师。 说这些也不是 为了打击您。 我的意思是,行动起来。 说这些是为了鼓励您马上 加入进来并编写许多 许多的代码。 这张幻灯片讨论的是, 在开始写代码之前, 如何完成软件构想。 这涉及到了状态这个概念。 我将状态定义为: 您知道什么? 如果您有一个系统, 您可能知道什么? 或者有时候是, 您认为自己知道什么, 或者您认为什么是真实的, 这便是状态。 例如,我可能在这条 路上有一个机器人。 我的机器人在这里。 我觉得它在沿着这条路 移动的过程中离右侧 墙壁太近了。 离右侧墙壁太近-- 这便是我认为 真实的事情。 您现在要做的是 考虑这个问题, 并写下您的系统 可能处于的 所有状态。 我在一个小圈子里。 我处于停滞状态。 我撞到墙上了。 我走错方向了。 我赢了比赛。 我到达了终点。 所以,我将会考虑 所有的状态。 有些状态是 相互排斥的, 有些则不是。 例如,您可能 会有一个绿色 LED 闪烁的状态。 这个状态可能会与 机器人离墙太近的状态并存。 所以,状态之间 不一定是相互排斥的。 但是,您需要 将它们都写下来, 考虑哪些事情是 您的系统需要知道或 认为是真实的。 这样做后,您可以 问自己以下几个问题。 我们从哪里开始? 初始状态是什么? 或者是下面的这个 也比较简单的问题-- 我需要知道什么? 我要得到什么 信息,才能认为 我离墙壁太近? 在这种情况下,我可以 写下所有的传感器-- 输入传感器。 然后它不单单是 一个数据收集器, 更是一个嵌入式系统。 所以它有输出。 我该怎么做? 我会采取哪些操作? 我想移动。 我想转弯。 我想停下来-- 诸如此类。 我将会使用哪些 操作,为了执行 这些操作,我需要 生成什么输出? 我们将会看到, 我们有两个电机。 我们将必须单独 驱动每个电机。 然后更难的是,如何从一个 状态转变到另一个 状态? 换句话说,如果 我离右侧墙壁太近, 我想要移到中间位置, 我怎样才能从一个不佳的位置 移动到理想位置? 然后,很明显, 我们想知道, 我们如何在完成后获知已经完成? 所以,这种状态 本质上是一种 在实际坐下来 开始写代码前, 构想您的软件和 硬件系统的方法。 另一种思考 问题的方法是 将其分解成模块。 下面我们将介绍这种方法。 用于讨论 将系统分解成 模块化部分的 术语共有三个。 它们具有大致 相同的含义。 逐次求精、 逐步求精 和系统分解-- 在这个背景下, 它们都指的是 相同的事情。 那就是,我们将会 从任务开始。 让我们进行赛跑。 我想要在跑道上 尽可能快地奔跑。 但这太复杂了, 我不知道究竟该怎么办。 因此,求精的整体 思路就是将其分解成 多个片段。 比如,我可能想要移动。 我可能想要进行感测。 我可能想要进行思考。 然后对于上面的 每个任务,我想要 将其分解为更小的部分, 因为这会涉及到 我如何在完成后获知已经完成。 所以,如果我把一个任务 分解成一个子任务, 然后子任务 非常简单, 我知道该如何完成-- 然后我将会完成该子任务。 我将会实施该子任务, 并进行测试和记录。 然后,我可以将其 重新组装回去。 但如果它仍然太复杂, 我将再次进行分解。 所以我们可以讨论诸如停止、 直行和转弯之类的任务。 我可以分解模块。 我可以将其 分解成子模块。 如果它们太复杂, 我将再次进行分解。 例如,对于 线路传感器-- 这是我可能会用到的传感器之一。 如果我不知道 如何实施线路传感器, 我将会将其分解成多个部分, 比如,实施输出, 等待一毫秒, 实施输入, 然后进行思考。 现在我将这个 线路传感器 分解成了多个子模块, 简化到了我能够完成的程度。 然后,我将会 实施这四个步骤, 然后将其重组回去。 需要注意的是, 有时您遇到一个问题-- 这是一个问题-- 我将其分成两部分-- A1 和 A2。 然后我向前走, 哒哒,我走对了。 但是还有一种可能, 在您将 A 分成两部分后, 这部分,A1,可能实际上 比原来的部分更难了。 因此,将一个对象 分成两半,并不代表 它就会变简单。 这整整 1 万小时, 或者说一百万行的代码 真的能让您擅长回答, 如何才能 更有效且更高效的 完成这项工作? 但是现在,我想 让您考虑这个问题, 如果在将问题分解后, 它变得比开始时 更复杂了,我将会 将其重组回去, 并使用另外一些 方式对其进行分解, 我将会持续 尝试不同的分解方法, 直到子部分比初始 任务更简单为止。 然后,我们会将这些子部分 全部都重组回去。 我们知道,不管是 对于数据流图, 还是调用图-- 这是一个数据流图, 我们知道,我们的 工作是将其分解为 不同的部分,从而 得到尽可能多的模块。 但是,我们会有 较小的带宽。 也就是说, 模块之间的 信息传输速率 应尽可能低。 最终,与这个 性质类似的是, 接口将会变得 至关重要。 对于数据流图, 是由这个接口 来传递数据。 对于调用图,模块 A 调用模块 B。 同样,这个接口 将会非常重要。 所以,当我将某个东西 分解成子模块时, 这些模块如何重新 连接对于确保系统的 有效性和高效性 至关重要。 因此,让我们找出一种 定义接口的方法。 如果该接口 非常重要, 我们将会 收集有关该接口的 所有信息, 并将其存储在一处。 这便是我们的 头文件。 同样,系统的 模块化性质-- 该模块的开关-- 将具有两个文件-- 一个是 switch.c, 包含实施信息, 另一个是 switch.h, 包含公有函数的 原型。 也就是说, 该文件包含接口。 它包含一个 可以在该模块中 调用的函数的列表。 这样,我们就可以将 该模块的功能分离出来。 比如,这是一个 简单的模块,您可以 从开关进行输入。 您可以将其打开, 然后您可以输入。 您将把这一点与 它实际的工作方式分离。 它连接到什么端口, 电压是什么, 它是正逻辑 还是负逻辑-- 所有这些低层次细节 都将被分离出来。 这种分离将会 对降低系统的 复杂性大有帮助。 这便是我们 在这里提到的 复杂性抽象。 换句话说,我们将 分离并隐藏 所有的低层次细节, 并暴露给其他模块 一个可用于使用 该模块的简单接口。 同样,包含在 头文件中的是 公有函数的原型 以及关于头文件-- 也就是该模块的功能 和使用方式的注释。 未包含在该模块中的是 该模块的工作方式。 模块内容的细节 不包含在这里。 我们不会将任何 变量放在头文件中。 这种私有概念 全部属于内部运作。 注意这个头文件-- 实际上, 本课程中的 所有头文件-- 都使用了这种奇异的语法, 其中这是参数, 这是返回参数, 这是有关其功能的 简短解释。 这种语法实际上 叫做 doxygen。 doxygen 最厉害的地方 就在于,它会自动 为整个机器人系统 生成用户手册-- 一种软件文档。 您将会看到, 大多数这种文档 都代表了您需要 在本课程中编写的函数。 我们将会为您 提供几个函数, 来支持您开始 编写自己的函数。 所以这个 doxygen 流程 可帮助我们 创建一个美观的 HTML 页面, 用来介绍 软件的所有功能-- 也就是说, 介绍它的功能, 而不介绍它的 实际工作方式。 一个模块具有一个 .c 文件 和一个 .h 文件。 我们说过, .h 文件中包含的是 公有函数的原型。 代码文件中包含的是 实际的实施。 我们将会在下面的 模块中讨论端口的 实际工作方式。 但是在这里,我们只需要 知道 c 文件中包含的是 实际的工作方式, 实际的实施是在 这里。 我们需要变量。 它在 c 文件中。 如果我们有任何 特殊私有函数, 它也会在 c 文件中。 c 文件中的注释会介绍 该函数的工作方式, 它是如何进行测试的, 或者您可以如何更改该函数。 一定要非常谨慎地 对待其他模块的 私有性质。 不要尝试访问 其他模块的 私有信息或 私有函数。 如果您在 Code Composer Studio 中查看该项目, 您将会看到与该项目 关联的所有文件。 但是如果您查看 文件中的内容-- 例如,这里的这个文件, 它是一个高级文件。 这段代码便是在该文件中。 最终,这里的 这些 include 文件 实际上等效于 或者将为您绘制 调用图。 如果这个函数包含 那个函数的头文件, 那么我们便可以 调用它的公有函数。 由于这里的这个 main c 文件包含 LaunchPad.h, 所以它可以调用后者的公有函数。 所以这个 include 文件是这个箭头。 这里的这个 include 文件-- 这是这个箭头。 所以这种将某个事物 分解成模块的做法 对于简化非常 复杂的系统大有帮助。 所以,当我们组建成 我们的机器人时, 您会发现它包含数十个 模块,所有模块均融入到 这个层次结构中。 最后总结一下, 我们定义了模块化, 这是一个增加 模块总数的过程。 但是我们希望最大限度地 减小带宽,互联, 每秒在不同 模块之间 传输的字节数。 我们讨论了头文件。 头文件中包含的是 接口-- 数据的流动方式, 或者调用函数的 方式。 通过这种方式,我们 可以分离其功能-- 高级交互-- 分离其功能和工作方式。 这样,我们将能够打造 一个非常复杂的系统。 所以随着向后面的部分推进, 我们需要考虑该模型。 在本课程开始时, 可能会很简单, 这时您实际上 还不需要使用模块。 但是,当后面变得 越来越复杂, 您将会看到使用 模块化设计的好处。 好的。 在下一个模块中-- 下一个讲座中, 我们将讨论一些 C 语法, 然后,我们将 讨论一些调试方法。 好的。 稍后回来。 401

大家好,

我是 John Valvano。

在本模块中,我们 将讨论软件设计。

我们首先介绍一下 模块化设计这个概念。

模块是什么, 它是系统的一个子集,

它同时包含软件和硬件, 而且具有完整的任务。

所以我们会将它视为 一个完整的任务。

当我们把这些 模块放在一起时,

我们可以从不同的 角度来看待它们。

其中一个角度 叫做调用图。

这意味着,如果 SwitchMain 中的软件

可以调用针对不同 模块的 switch 中的函数,

我们将会绘制这样 一个调用图箭头。

这个箭头表示, 这将是高级别,

这将是低级别。

类似地,如果 SwitchMain 中的软件

可以调用 LaunchPad 中的 软件,我们将会

绘制一个调用图 箭头,来表示

高级别函数与 低级别函数之间的

因果关系-- 层次结构关系。

而且,我们会将 与一个事件相关的

所有任务--

例如,与开关 相关的所有函数,

以及与 LaunchPad 相关的所有函数--

封装在独立的模块中。

我们将要 解决的问题

并不复杂, 我们将在一个输入上

配备一个开关。

如果按下开关,

则会将发光二极管 切换到另外一种

状态。

另一种在互连情况下 看待这些模块的方法

称为数据流图。

数据流图 显示了连接情况。

这是一个硬件模块。

这里的所有其他模块 都是软件模块。

关于开关是否 关闭的布尔信息

被编码在 数据流图的箭头中。

所以,数据是向 这个方向流动的。

即使是 SwitchMain 调用 switch,

数据实际上也是 在向另一个方向流动。

而在这里,数据则是 从 main 向 LaunchPad 流动,

因为我想要 开关 LED。

然后,在物理层面上, 我在数据流图中包含了

可以发光的 LED。

而且,通过 这个数据流图,

我们可以定义 模块化意味着什么。

系统的模块化, 如果您愿意,

这也是系统的精华所在--

是多个模块的函数。

因此,我们希望最大 限度地增加模块数量,

同时尽量减少 它们之间的互连。

特别是,我们可以 查看带宽之类的

东西,它是每秒 跨屏障传输的

字节数。

因此,我们希望最大 限度地增加模块数量,

同时尽量减少 它们之间的互连。

针对互联的一个简单的 定量测量方式是,

测量每秒从一个 模块流到另一个模块的

字节数。

这便是我们将会 在这里采用的理念。

那么,让我们开始吧。

当我们讨论如何制造 一些复杂的东西--

换句话说, 模块化系统的

整体思路就是 能够提高复杂性。

可让我们做到这一点的 一种方法是使用多个线程。

线程是由正在执行的 软件引起的操作。

所以,引发线程的 是软件的行为。

我们将会得到一个 多线程环境,

其中有一个 主程序。

而且,我们将会 有多个中断。

例如,我可能会有 硬件触发的中断。

当我触摸开关时, 将会触发一个中断。

我们将会在多个 模块中介绍这种中断的

实际工作方式。

但是在这里,我们只需要 了解一点就足够了,

那就是,当您触摸 开关时,系统会

运行与这个触摸操作 相关的软件。

然后,如果我们想要 周期性地执行

某个操作,我们 将需要另外一种中断。

我们将会使用一个频率为, 比如说 100 赫兹的计时器中断。

而且,我们将从这个 层面上执行软件。

我在这里绘制 一个主程序。

然后绘制初始化。

然后,我们在这里绘制一些东西。

然后就有了一个循环。

我们之所以 将其称为线程,

是因为我们可以 将正在执行的软件想象成

一条单一的轨迹。

即使这是一个函数--

即使这个初始化 是一个函数,

我们仍然可以绘制一条--

我们可以

一笔画出一条代表 其执行顺序的直线。

这便是我们将其称为线程的原因。

一系列指令, 由这些指令

引起的操作, 这便是线程。

但是中断是特殊的。

中断是硬件 触发的软件

操作。

在这里,我们将 打断这个线程,

从这里开始,因为 我们触摸了开关,

执行该软件,然后 再次打断该线程,

然后重新返回这里。

所以线程是由正在 执行的软件引起的

操作。

在本课程中, 我们将使用一个

单一的前台线程、 一个主程序,以及多个

在特定事件时 执行的中断线程。

这是增加系统 复杂性的一种方法。

您要做的最困难的 事情之一是,

确定从哪里开始。

我要告诉您一个 很不幸的消息。

您可能也在其他地方 听到过这个

说法--

需要花费 1 万 小时的时间,

才能熟练掌握一个技能。

我并不是 要打击您。

如果您坐在电脑前,

编写尽可能优秀的代码, 在大约一个小时的时间里,

您可能能够 写出 100 行代码。

如果您将这两个 数字相乘,

达到一百万行 代码的分界线后,

您将会成为一名 优秀的软件设计师。

说这些也不是 为了打击您。

我的意思是,行动起来。

说这些是为了鼓励您马上 加入进来并编写许多

许多的代码。

这张幻灯片讨论的是, 在开始写代码之前,

如何完成软件构想。

这涉及到了状态这个概念。

我将状态定义为: 您知道什么?

如果您有一个系统, 您可能知道什么?

或者有时候是, 您认为自己知道什么,

或者您认为什么是真实的, 这便是状态。

例如,我可能在这条 路上有一个机器人。

我的机器人在这里。

我觉得它在沿着这条路 移动的过程中离右侧

墙壁太近了。

离右侧墙壁太近--

这便是我认为 真实的事情。

您现在要做的是

考虑这个问题,

并写下您的系统 可能处于的

所有状态。

我在一个小圈子里。

我处于停滞状态。

我撞到墙上了。

我走错方向了。

我赢了比赛。

我到达了终点。

所以,我将会考虑 所有的状态。

有些状态是 相互排斥的,

有些则不是。

例如,您可能 会有一个绿色 LED

闪烁的状态。

这个状态可能会与 机器人离墙太近的状态并存。

所以,状态之间 不一定是相互排斥的。

但是,您需要 将它们都写下来,

考虑哪些事情是 您的系统需要知道或

认为是真实的。

这样做后,您可以 问自己以下几个问题。

我们从哪里开始?

初始状态是什么?

或者是下面的这个 也比较简单的问题--

我需要知道什么?

我要得到什么 信息,才能认为

我离墙壁太近?

在这种情况下,我可以 写下所有的传感器--

输入传感器。

然后它不单单是 一个数据收集器,

更是一个嵌入式系统。

所以它有输出。

我该怎么做?

我会采取哪些操作?

我想移动。

我想转弯。

我想停下来--

诸如此类。

我将会使用哪些 操作,为了执行

这些操作,我需要 生成什么输出?

我们将会看到, 我们有两个电机。

我们将必须单独 驱动每个电机。

然后更难的是,如何从一个 状态转变到另一个

状态?

换句话说,如果 我离右侧墙壁太近,

我想要移到中间位置, 我怎样才能从一个不佳的位置

移动到理想位置?

然后,很明显, 我们想知道,

我们如何在完成后获知已经完成?

所以,这种状态 本质上是一种

在实际坐下来 开始写代码前,

构想您的软件和 硬件系统的方法。

另一种思考 问题的方法是

将其分解成模块。

下面我们将介绍这种方法。

用于讨论 将系统分解成

模块化部分的 术语共有三个。

它们具有大致 相同的含义。

逐次求精、 逐步求精

和系统分解-- 在这个背景下,

它们都指的是 相同的事情。

那就是,我们将会 从任务开始。

让我们进行赛跑。

我想要在跑道上 尽可能快地奔跑。

但这太复杂了, 我不知道究竟该怎么办。

因此,求精的整体 思路就是将其分解成

多个片段。

比如,我可能想要移动。

我可能想要进行感测。

我可能想要进行思考。

然后对于上面的 每个任务,我想要

将其分解为更小的部分, 因为这会涉及到

我如何在完成后获知已经完成。

所以,如果我把一个任务 分解成一个子任务,

然后子任务 非常简单,

我知道该如何完成-- 然后我将会完成该子任务。

我将会实施该子任务, 并进行测试和记录。

然后,我可以将其 重新组装回去。

但如果它仍然太复杂,

我将再次进行分解。

所以我们可以讨论诸如停止、 直行和转弯之类的任务。

我可以分解模块。

我可以将其 分解成子模块。

如果它们太复杂,

我将再次进行分解。

例如,对于 线路传感器--

这是我可能会用到的传感器之一。

如果我不知道 如何实施线路传感器,

我将会将其分解成多个部分, 比如,实施输出,

等待一毫秒,

实施输入, 然后进行思考。

现在我将这个 线路传感器

分解成了多个子模块, 简化到了我能够完成的程度。

然后,我将会 实施这四个步骤,

然后将其重组回去。

需要注意的是, 有时您遇到一个问题--

这是一个问题--

我将其分成两部分--

A1 和 A2。

然后我向前走, 哒哒,我走对了。

但是还有一种可能, 在您将 A 分成两部分后,

这部分,A1,可能实际上 比原来的部分更难了。

因此,将一个对象 分成两半,并不代表

它就会变简单。

这整整 1 万小时, 或者说一百万行的代码

真的能让您擅长回答, 如何才能

更有效且更高效的 完成这项工作?

但是现在,我想 让您考虑这个问题,

如果在将问题分解后, 它变得比开始时

更复杂了,我将会 将其重组回去,

并使用另外一些 方式对其进行分解,

我将会持续 尝试不同的分解方法,

直到子部分比初始 任务更简单为止。

然后,我们会将这些子部分 全部都重组回去。

我们知道,不管是 对于数据流图,

还是调用图-- 这是一个数据流图,

我们知道,我们的 工作是将其分解为

不同的部分,从而 得到尽可能多的模块。

但是,我们会有 较小的带宽。

也就是说, 模块之间的

信息传输速率 应尽可能低。

最终,与这个 性质类似的是,

接口将会变得 至关重要。

对于数据流图, 是由这个接口

来传递数据。

对于调用图,模块 A 调用模块 B。

同样,这个接口 将会非常重要。

所以,当我将某个东西 分解成子模块时,

这些模块如何重新 连接对于确保系统的

有效性和高效性 至关重要。

因此,让我们找出一种 定义接口的方法。

如果该接口

非常重要, 我们将会

收集有关该接口的 所有信息,

并将其存储在一处。

这便是我们的 头文件。

同样,系统的 模块化性质--

该模块的开关-- 将具有两个文件--

一个是 switch.c, 包含实施信息,

另一个是 switch.h, 包含公有函数的

原型。

也就是说, 该文件包含接口。

它包含一个 可以在该模块中

调用的函数的列表。

这样,我们就可以将 该模块的功能分离出来。

比如,这是一个 简单的模块,您可以

从开关进行输入。

您可以将其打开, 然后您可以输入。

您将把这一点与 它实际的工作方式分离。

它连接到什么端口, 电压是什么,

它是正逻辑 还是负逻辑--

所有这些低层次细节 都将被分离出来。

这种分离将会 对降低系统的

复杂性大有帮助。

这便是我们 在这里提到的

复杂性抽象。

换句话说,我们将 分离并隐藏

所有的低层次细节, 并暴露给其他模块

一个可用于使用 该模块的简单接口。

同样,包含在 头文件中的是

公有函数的原型 以及关于头文件--

也就是该模块的功能 和使用方式的注释。

未包含在该模块中的是 该模块的工作方式。

模块内容的细节 不包含在这里。

我们不会将任何 变量放在头文件中。

这种私有概念 全部属于内部运作。

注意这个头文件-- 实际上,

本课程中的 所有头文件--

都使用了这种奇异的语法, 其中这是参数,

这是返回参数,

这是有关其功能的 简短解释。

这种语法实际上 叫做 doxygen。

doxygen 最厉害的地方 就在于,它会自动

为整个机器人系统 生成用户手册--

一种软件文档。

您将会看到, 大多数这种文档

都代表了您需要 在本课程中编写的函数。

我们将会为您 提供几个函数,

来支持您开始 编写自己的函数。

所以这个 doxygen 流程 可帮助我们

创建一个美观的 HTML 页面, 用来介绍

软件的所有功能--

也就是说, 介绍它的功能,

而不介绍它的 实际工作方式。

一个模块具有一个 .c 文件 和一个 .h 文件。

我们说过, .h 文件中包含的是

公有函数的原型。

代码文件中包含的是 实际的实施。

我们将会在下面的 模块中讨论端口的

实际工作方式。

但是在这里,我们只需要 知道 c 文件中包含的是

实际的工作方式, 实际的实施是在

这里。

我们需要变量。

它在 c 文件中。

如果我们有任何 特殊私有函数,

它也会在 c 文件中。

c 文件中的注释会介绍 该函数的工作方式,

它是如何进行测试的, 或者您可以如何更改该函数。

一定要非常谨慎地 对待其他模块的

私有性质。

不要尝试访问 其他模块的

私有信息或 私有函数。

如果您在 Code Composer Studio 中查看该项目,

您将会看到与该项目 关联的所有文件。

但是如果您查看 文件中的内容--

例如,这里的这个文件, 它是一个高级文件。

这段代码便是在该文件中。

最终,这里的 这些 include 文件

实际上等效于 或者将为您绘制

调用图。

如果这个函数包含 那个函数的头文件,

那么我们便可以 调用它的公有函数。

由于这里的这个 main c 文件包含 LaunchPad.h,

所以它可以调用后者的公有函数。

所以这个 include 文件是这个箭头。

这里的这个 include 文件--

这是这个箭头。

所以这种将某个事物 分解成模块的做法

对于简化非常 复杂的系统大有帮助。

所以,当我们组建成 我们的机器人时,

您会发现它包含数十个 模块,所有模块均融入到

这个层次结构中。

最后总结一下, 我们定义了模块化,

这是一个增加

模块总数的过程。

但是我们希望最大限度地 减小带宽,互联,

每秒在不同 模块之间

传输的字节数。

我们讨论了头文件。

头文件中包含的是 接口--

数据的流动方式, 或者调用函数的

方式。

通过这种方式,我们 可以分离其功能--

高级交互--

分离其功能和工作方式。

这样,我们将能够打造 一个非常复杂的系统。

所以随着向后面的部分推进, 我们需要考虑该模型。

在本课程开始时, 可能会很简单,

这时您实际上 还不需要使用模块。

但是,当后面变得 越来越复杂,

您将会看到使用 模块化设计的好处。

好的。

在下一个模块中--

下一个讲座中, 我们将讨论一些 C 语法,

然后,我们将 讨论一些调试方法。

好的。

稍后回来。 401

视频报错
手机看
扫码用手机观看
收藏本课程

相关下载

查看全部

视频简介

TI-RSLK 模块 4 - 讲座视频 - 设计

所属课程:TI机器人系统学习套件(TI-RSLK) 发布时间:2018.08.27 视频集数:69 本节视频时长:19:50
通过调用图、数据流程图、逐步求精、抽象(函数)和模块化设计(页眉文件/代码文件)来学习软件设计。
已有6人参与了讨论去论坛跟帖交流