2021-09-06

存储和 EEPROM 管理

AP_HAL::Storage 对象,作为 hal.storage 访问
StorageManager 库在 hal.storage 上提供更高级别的抽象层
DataFlash 用于存储到板载记录区域
Posix IO 功能到传统文件系统(例如 microSD 卡上的 VFAT),在支持它的板上
其他需要持久存储的库和函数建立在这些基本系统上。例如,AP_Param 库(处理用户可设置的参数)建立在 StorageManager 之上,而 StorageManager 又建立在 AP_HAL::Storage 之上。AP_Terrain 库(处理地形数据)建立在 Posix IO 函数之上,用于保存地形数据库。

AP_HAL::Storage 库
AP_HAL::Storage 对象在所有平台上都可用。通过此接口在 ArduPilot 支持的板上可用的最小存储大小为 4096 字节。有些板子提供更多空间——例如 PX4v1 有 8k 的 EEPROM,而 Pixhawk 有 16k 的 FRAM。所有这些都隐藏在 AP_HAL::Storage API 之后。

hal.storage API 非常简单。它只有3个功能

init() 启动存储子系统
read_block() 读取一个字节块
write_block() 写入一个字节块
这个非常简单的 API 的原因是鼓励开发人员使用 StorageManager API 而不是 hal.storage。您应该只在启动新板或调试时深入研究 hal.storage。

可用存储的大小 在宏 HAL_STORAGE_SIZE 中的AP_HAL/AP_HAL_Boards.h中设置。这意味着我们尚不支持动态确定此接口可用的存储大小。如果你想要动态大小的存储,你现在需要使用 Posix IO。

我们没有 AP_HAL::Storage API 的示例草图,所以这是您编写一个的机会。如果您已经深入了解 ArduPilot 教程,您应该已经看过足够多的示例草图,知道如何从头开始编写一个草图。所以写一个libraries/AP_HAL/examples/Storage 例子,计算hal.storage 数据全部内容的8 位异或,并打印到控制台。然后将示例作为补丁提交到 ArduPilot github,注意遵循补丁提交指南。

我很想知道在我将这个练习添加到教程之后多久我们会收到提交…

存储管理器库
简单的 hal.storage API 使将 ArduPilot 移植到新板变得非常简单,但不方便实际使用可用存储。为此,我们有 StorageManager。StorageManager 库提供了一个 API,它将存储抽象为具有指定用途的伪连续数据块。因此,我们将可用存储空间划分为提供以下功能的区域:

参数
围栏点
航点
集结点
签名密钥
RC绑定信息
去读一下 libraries/StorageManager/StorageManager.cpp。特别是看看顶部的表格。请注意如何为具有较大存储量的系统定义每种类型的多个区域。这种将多个非连续存储区域组合成单个逻辑存储区域的能力是添加 StorageManager 的主要动机。它使我们能够从在所有板上使用 4k 存储发展到使用每个板上可用的完整存储,而无需要求用户重新加载他们的所有参数或重新加载他们的航点。

这种试图避免让用户重新配置他们的自动驾驶仪板的主题在 ArduPilot 中很常见。我们喜欢用户可以更新到最新固件并且他们之前设置的所有内容仍然有效,同时获得新功能。有时这意味着作为开发人员,我们必须做更多的工作才能实现这一点 - 例如 StorageManager。

StorageManager API 还提供了方便的函数来读取和写入整数等变量。这是像 AP_Mission 这样的库用来保存和恢复航点的 API。

现在去看看 libraries/StorageManager/examples/StorageTest.cpp。这是对 StoageManager 层的压力测试,因此也是对 AP_HAL::Storage 对象的压力测试。它以随机长度的随机偏移量进行随机 IO。这意味着它执行跨越边界的 IO,其中单个参数值在 FRAM 或 EEPROM 中可能不连续。该测试草图旨在对 StorageManager API 进行压力测试,但在将 ArduPilot 移植到新板时也非常有用,因为它非常好地强调了 EEPROM 访问功能。

去尝试在您的板上进行 StorageTest,但请注意,这是一项破坏性测试。它不会破坏您的电路板,但会清除您的所有参数和航点。因此,如果您在您最喜欢的飞机上进行测试,请备份您的配置。

作为练习,向 StorageTest 添加一些分析,以便它以千字节/秒为单位打印总 IO 速率以及读取和写入的 IO 速率。您是否注意到读取率和写入率之间的差异?您是否注意到已在存储中该地址处设置的值的写入速度?看看您是否可以在 StorageManager 中找到解释您的观察结果的代码。然后提交一个补丁,将分析输出添加到 ArduPilot github。

接下来去搜索 ArduPilot 库,找出所有使用 StorageManager 的地方。您正在寻找的是 StorageAccess 句柄,如下所示:

StorageAccess AP_Param::_storage(StorageManager::StorageParam);
它声明了一个名为 AP_Param::_storage 的变量,它提供了对该板上存储的 StorageParam 区域的访问。哪些图书馆使用 StorageAccess?

DataFlash 库
自动驾驶仪需要的另一种存储类型是机载日志。对于由 DataFlash 库提供的 ArduPilot。在很多方面,它都是一个很奇怪的图书馆。首先,这个名字很奇怪,因为它最初是围绕 APM1 的 DataFlash 芯片设计的。它是一个硬件设备驱动程序库,随着时间的推移演变成一个通用的日志系统。图书馆的内部结构以多种方式展示了这段历史(而不是好的方式!)。

如今,DataFlash API 是围绕日志基础架构模型设计的。它允许您为单个日志消息定义自描述数据结构 - 例如“GPS”消息以记录来自 GPS 传感器的数据。它以一种有效的方式将数据记录到持久存储中,并且还为其他库提供 API,当用户在飞行后想要下载他们的日志文件时,可以使用这些 API 来取回数据。

如果您在下载日志时看到了这些天 ArduPilot 使用的“*.bin”文件,那么您已经看到了 ArduPilot 用于存储日志消息的格式。它是“自描述​​的”,意味着地面站可以计算出日志文件中消息的格式,而不必有一些通用的方案。在每个日志文件的前面是一组 FMT 消息,这些消息具有众所周知的格式并描述了后面消息的格式。

去看看 libraries/AP_FlashStorage/examples/FlashTest/FlashTest.cpp。您会在顶部看到一个小表格,它定义了我们将要写入的日志消息,在本例中是一个“TEST”消息,其中包含 4 个无符号 16 位整数和两个有符号 32 位整数(这就是“HHHHii”的意思) . 它还给出了这 6 个变量的名称(巧妙地标记为 V1 到 V4 以及 L1 和 L2)。

在 loop() 函数中,您将看到一个相当奇怪的调用,如下所示:

DataFlash.get_log_boundaries(log_num, start, end);
这是用于 DataFlash 库隐藏电路板实际存储日志文件方式的公共 API。在具有 Posix IO(例如 Pixhawk 或 Linux)的系统上,日志文件作为单独的文件存储在 microSD 卡上的“LOGS”目录中。用户可以通过拔出 microSD 卡并将其放入 PC 来直接复制这些文件。

在像 APM2 这样的板上,事情并不那么简单。APM2 在 DataFlash 芯片上有 4 兆字节的存储空间,可通过 SPI 接口访问。接口本身是面向页面的,因此您需要填充一个 512 字节(或可能是 528 字节!)的页面,然后在填充下一页时告诉芯片将该页面复制到持久存储。在这个 DataFlash 上做随机 IO 是不好的——它是为需要连续写入的代码使用而设计的,这就是日志记录时发生的情况。与自动驾驶仪喜欢记录的数据量相比,4 MB 的大小确实不是很大,因此我们还需要在它填满时处理包装。

所有这些复杂性都隐藏在一个呈现“日志编号”概念的 API 后面,它只是在自动驾驶仪的一次飞行中写入的一堆字节。APM1 和 APM2 上的 DataFlash 实现在每个页面的前面使用很少的标记字节来说明正在写入的日志编号。这些日志编号对应于用户要求检索其日志时下载的日志编号。

Posix IO
ArduPilot 支持的一些自动驾驶板基于具有类似 Posix 的 API 的操作系统。例如,Linux 端口有一个非常好的 Posix 子系统,用于 PX4 的 NuttX 操作系统(例如在 Pixhawk 上)有一个非常合理的 Posix 层。您可以在 ArduPilot 的库中利用这一点,只要您不依赖它来处理必须在所有板上工作的任何事情。

一个很好的例子是 AP_Terrain 库,它保存地形数据。地形数据太大,无法放入EEPROM,而且是随机存取,不适合DataFlash。它对于自动驾驶仪的基本功能也不是必需的,因此它非常适合使用 Posix IO 实现。

我们使用POSIX IO的方式是,先检查,如果董事会通过检查从HAVE_OS_POSIX_IO宏观Posix的IO支持 AP_HAL_Boards.h。然后要知道您应该将数据存储在文件系统的哪个位置,您可以在 AP_HAL_Boards.h 中添加一个数据特定的宏,它给出了应该放置此类数据的目录路径。例如,宏 HAL_BOARD_TERRAIN_DIRECTORY 用于定义地形数据应该去的目录。

一旦你有了这两件事,你应该只使用普通的 Posix IO 函数(即打开、关闭、读取、写入等),尽管有一些警告:

您只能从 IO 计时器或您自己的低优先级线程调用 IO 函数。
切勿从库中可直接访问的 API 调用任何 IO 函数。甚至不是像 stat() 这样简单的。
尽量对慢速存储卡友好,以合理大小的块进行 IO,并尽可能避免查找
这些规则真的很重要。Pixhawk 上 microSD 卡上的简单 IO 可能需要一秒钟。这足以让您宝贵的四轴飞行器倒挂飞行并前往与地面的最后一次会面。Pixhawk microSD 卡上 IO 的平均时间相当短(几毫秒),但偶尔当 microSD 卡决定需要花一些时间重新阅读 SD 卡规格并计算时,您会得到一个缓慢的时间皮。不要仅仅因为在大多数情况下看起来很快就想偷偷地进行一些操作。

一个例外是初始化函数,您肯定知道只能在车辆启动或解除武装时调用。那个时候稍微延迟一下就好了。

现在 去读 一下libraries/AP_Terrain/TerrainIO.cpp,看看它是如何使用Posix IO的。请注意它用于处理所有 IO 的小状态机,这些都是从AP_Terrain::io_timer函数调用的 。看看您是否可以发现任何错误,如果可以,请报告它们!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值