本文概述
- 这是怎么回事?
- 所以有什么问题?
- 在敌对环境中实时测量天气
- 跟我的小朋友打招呼!?
- 棒极了!那你是怎么做到的呢?
- “ 我如何创建一个对小偷既不有价值也不有吸引力的气象站?”
- 关于弹跳效果
- 最后
这是怎么回事? 风筝冲浪是世界上最容易上瘾的运动之一。它所需要的只是一个风筝冲浪板, 一团水和一些配件。这是与大自然接触, 解放思想并锻炼身体的好方法。另外, 你真的可以为之疯狂。
所以有什么问题? 哦, 我忘了一个基本要求:风。这就是我们要解决的问题:除非你靠自己喜欢的风筝冲浪点生活, 否则你永远都不知道会不会有风。
我住在阿根廷的科尔多瓦, 距离风筝冲浪湖约130公里(?80英里)。我大约可以开车两个小时。但是我无法应付天气预报不准确的事实。在我居住的地方, 良好的风力条件仅持续几个小时。你要做的最后一件事是清理周一的时间表, 进行风筝冲浪, 并在开车两个小时后发现自己在无风的湖泊上诅咒众神。
我需要实时了解我最喜欢的风筝冲浪场的风况。因此, 我决定建立自己的气象站。
在敌对环境中实时测量天气 目的是将实时天气数据传递到家里的浏览器:
文章图片
在详细介绍之前, 让我们花点时间考虑一下这样的项目中涉及的关键问题和注意事项:
- 如何创建对小偷既不有价值也不有吸引力的气象站?
- 如何使硬件成本和开发时间降至最低?
- 如何实时测量和访问天气数据并以有用的方式显示?
- 必需的测量:阵风和阵风, 风向, 雨, 大气压, 温度, 湿度
- 将电台连接到互联网
- 存储和检索本地天气数据
- 在气象站和服务器之间通信
- 如何减少维护量(几乎)为零?
- 管理软件挂起
- 管理连接中断
- 管理能源供应中断
文章图片
你可能会认为手套在那里使站点显得更友好;但实际上用于测试气压传感器(充气后的手套内部的手套压力会增加)。在右侧, 你可以看到车站的最终位置, 它位于附近的塔楼上。
我还设计和编程了一个有关风筝冲浪的网站, 其中包括该站的实时测量图, 以帮助风筝冲浪社区。最后, 我在Facebook上创建了一个风筝冲浪小组。
文章图片
棒极了!那你是怎么做到的呢? 好吧, 我将依次解决每个问题:
“ 我如何创建一个对小偷既不有价值也不有吸引力的气象站?” 这是一个关键因素, 并且在许多方面推动了其余的设计过程。价格低于2000美元的大多数预制工作站都需要USB连接到计算机。如果一个小偷意识到工作站旁边有台PC, 那将是事情的终结, 因为更换计算机和工作站的成本将超出我的个人预算。因此, 我决定测试几种硬件平台以从头开始以较低的成本实现该工作站。
“ 如何使硬件成本和开发时间降至最低?”
我一个人在负担这个副项目的费用, 并在业余时间做所有工作, 因此, 这当然是一个很大的问题。我从流行的PIC32和一些预组装的微芯片以太网模块开始, 但是成本却没有我所期望的那么低, 并且硬件组装和扩展涉及太多的开销。然后, 我开始研究Arduino:一种使用C语言进行电子原型制作的开源硬件和软件。这正是我想要的, 我可以在DealeXtreme上购买模块。我只花了15美元就花了两天的时间开始玩。
当然, Arduino也有其局限性:我的编译软件只有2KB的RAM和32KB的内存, 这对于多余的字符串或无用的变量并没有太大的余地。
“ 我如何实时测量和访问天气数据并以有用的方式显示它?”
目前, 我的电台可以测量:风速, 阵风, 风向, 温度, 湿度, 雨水和大气压。温度, 湿度和压力由两个库处理, 这使生活变得更加轻松。
测量风速和降雨有点混乱。传感器通过打开和关闭开关(簧片开关)进行操作。因此, 我需要实现硬件中断, 以便在触发输入时立即捕获传感器。也就是说, 我需要调用一些方法:
attachInterrupt(RAINGAUGE_PIN, countRainCycles, FALLING);
一旦开关遇到由闭合或断开电路产生的下降沿, 此中断将中断正常的代码执行并调用countAnemometerCycles或countRainCycles函数。每次开关触发时都会增加一些变量。 (稍后, 请权衡这些变量以考虑单位转换。)
void countRainCycles() {
rainCyclesCounter++;
// This is easy! And it actually works.
}
但是没有那么快!由于任何硬件开关固有的开关弹跳效应, 此过程会产生数百种错误触发。幸运的是, 对于此问题有硬件和软件解决方案。
关于弹跳效果 开关物理断开或闭合其” 触点” 的结果是产生反弹效应, 该” 触点” 与电路的其余部分建立了接触。当触点开始分离(断开开关)或结合(闭合开关)时, 可能会产生一些小的电弧, 以及电路中的机械弹性, 会在几毫秒内触发电路的开和关。拨动电灯开关时, 这种效果并不明显;但是, 当你将中断附加到信号的下降沿时, 这种反弹效果会触发大量中断。这里更多。
文章图片
我在软件中实现了硬件去抖动电路和类似版本。但是, 你究竟如何实现软件去抖动?简单!在第一个预期的触发发生之后, 在开始侦听新的中断之前, “ 等待” 足够的时间使反弹稳定下来。这可以通过几行C语言来完成:
void countRainCycles() {
if (nextTimeRainIterrupt == 0 || nextTimeRainIterrupt <
millis()) {
rainCyclesCounter++;
// The interrupts counter
nextTimeRainIterrupt = millis() + 100;
// Wait 100msecs before next trigger
}
}
millis()函数返回自Arduino打开以来的当前执行时间(以毫秒为单位)。还值得注意的是, 必须将这些变量定义为易失性, 以指示编译器不要优化执行, 从而避免硬件中断期间的值不正确。
不知何故, 我需要工作站存储累积的数据并定期将这些测量结果发送到MySQL数据库。因此, 我添加了带有SD插槽的以太网模块, 以记录值并在用户(服务器)连接到工作站时检索它们。在使用ADSL连接进行的家庭测试中, 效果非常好, 但是当我在3G Internet(使用3G调制解调器)” 现场” 测试时, 我几乎掉了头发, 因为当我尝试取回该设备时, 该站会随机重置自己。测量!经过大量测试之后, 我终于发现, 这些示例在整个Internet上提供, 这些示例描述了向连接的客户端” 提供” 数据的过程, 并没有考虑到连接可能太差以至于在数据包传输过程中可能丢失与客户端的连接, 从而导致输出缓冲区将溢出。但是为什么断开的连接会导致缓冲区溢出?好吧, 假设传输会话开始, 并且站点开始用数据填充输出缓冲区。理想情况下, 客户端消耗此缓冲区的速度比填充缓冲区要快。但是, 当连接3G调制解调器时, 情况并非如此!与客户端的连接太差了, 因此缓冲区填满的速度超过了消耗的速度, 这导致缓冲区溢出和工作站的突然重启。
为了解决这个问题, 我需要向Arduino随附的以太网库中添加一个函数, 如下所示:
int EthernetClient::free() {
if (_sock != MAX_SOCK_NUM)
return W5100.getTXFreeSize(_sock);
return 0;
}
然后, 我能够检查客户端是否在缓冲区中有一些空间, 然后再尝试用更多数据填充它:
while (file.available() >
0) {
if (client.free() >
0) { // This was key to solving the issue
c = file.read();
client.print((char)c);
} else { // No free buffer? Ok, I'll wait a couple of millis...
delay(50);
}
}
file.close();
顺便说一句, 如果你对Arduino编程感兴趣, 这是一个很好的指南。
另一个有趣的任务是LIFO日志的实现。为什么有这个必要?好吧, 通常, 当我将测量结果保存到给定文件时, 方法很简单:打开文件, 将新样本附加到末尾, 然后关闭文件。但是说我想获取按时间顺序排序的最新1000个测量值。这些测量值位于文件的末尾;因此, 我应该打开文件, 将光标移到末尾, 输出最新的测量值, 然后使文件光标返回到先前的测量值, 并通过寻找示例定界符来检测从哪里开始和停止, 从而输出文件。 Arduino没有足够的RAM和处理器功能来快速执行此过程, 因此我需要另一种方法。相反, 我决定将文件以相反的顺序输出到服务器, 然后在服务器端恢复字符串文字:
unsigned long filePosition = file.size();
file.seek(filePosition);
while (filePosition >
= 0) {
if (client.free() >
0){
file.seek(filePosition);
c = file.peek();
if (c != -1) {
client.print((char)c);
}
if (filePosition <
= 0) {
break;
}
filePosition--;
}
}
具有任何PHP开发人员经验, 可以很容易地以正确的顺序获取带有字符的最新示例:
// $output has the reversed string measures, each sample is delimited by ;
$rows = split(";
", trim($output));
array_walk_recursive($rows, 'reverseString');
if (strlen($rows[0]) == 0) {
array_shift($rows);
// Remove the first line if empty
}function reverseString(&
$row, $key) {
$row = trim(strrev($row));
}
// $rows is now the array of the latest samples :)
然后, 在服务器端, 我设置了一个cron进程, 以每两分钟获取一次最新的测量值, 并将数据插入到MySQL引擎中。为了显示数据, 我创建了www.kitesurfcordoba.com.ar, 并使用jQuery自动更新了图表(图表本身是使用强大的开源库pChart v2.0生成的)。
要使一切正常运行, 还有许多其他技巧, 与软件和硬件工程有关, 但是我已经花了很长时间进行讨论, 因此, 让我们来谈谈最大限度地减少维护。
“ 如何将维护量减少到(几乎)零?”
这是一个主要问题, 因为对我来说到达车站肯定不容易-如果我愿意开车两个小时才能解决一个小故障, 那么我就不必首先让她走(我之前没有提到, 但是毕竟我们经过了, 车站实际上是个” 她” , 她的名字叫多萝西(Dorothy)。
那么我们在这里谈论什么样的错误呢?好吧, 例如:软件可能挂起, 网络可能失去连接, 能源供应可能失败(并且确实如此)等。
从本质上讲, 该工作站需要执行尽可能多的自我恢复。这就是为什么我同时使用软性和硬性看门狗的原因。对于不熟悉的人, 看门狗是一种软件或硬件, 它检查系统是否正常运行, 如果不正常, 则尝试使其恢复正常运行。 Arduino具有可以使用的嵌入式看门狗。我将其设置为等待8秒:如果通话时间超过该时间限制, 则软件看门狗将重置板。
wdt_enable(WDTO_8S);
// "wdt" stands for "watchdog timer"
我喜欢这个功能。但是, 有时板会复位而以太网模块不会复位。为什么?嗯, 这是一个价格相对可承受的原型板, 而不是昂贵的防故障设备(你当然不应该用它制造起搏器)。为了克服这个缺点, 我不得不通过将硬件重置输入与板子本身的数字输出交叉接线来入侵Arduino。为了避免复位循环, 还必须添加几行代码:
void setup() {
digitalWrite(RESET_ARDUINO_PIN, HIGH);
// Set it to HIGH immediately on boot
pinMode(RESET_ARDUINO_PIN, OUTPUT);
// We declare it an output ONLY AFTER it's HIGH
digitalWrite(RESET_ARDUINO_PIN, HIGH);
// Default to HIGH, set to LOW to HARD RESET
...
【我如何制作功能齐全的Arduino气象站】之后, 我能够通过简单地调用digitalWrite(RESET_ARDUINO_PIN, LOW)来对Arduino及其顶部的所有模块(包括以太网模块)进行硬件复位, 这使多萝西在几秒钟后恢复了生命。
此外, 电路板在能量损耗后会自动重启。如果Internet连接失败, 我们将利用SD卡的存储功能(数据可以在卡上存储一周以上, 服务器可以提取旧数据以恢复丢失的样本)。结合所有这些功能, 我们可以得到一个高度健壮的气象站, 它可以在为监视而建造的恶劣条件下生存。总共, 这件事花了我大约300美元。
文章图片
最后 自2012年12月以来, 该电台一直在运作。迄今为止, 它并没有失败(或者, 如果确实如此, 则该电台恢复得足够快, 以至于风筝冲浪社区, 我没有注意到)。大约有500名风筝冲浪者在前往现场之前会定期检查气象站。因此, 除了解决一些艰巨的技术挑战的奖励外, 我还有机会为一群人提供更愉快的风筝冲浪体验。
1最初, 我使用的是Arduino Uno。后来, 由于需要增加RAM和闪存, 我切换到了Arduino Mega。
相关:使用ESP32音频采样
推荐阅读
- 使用表情符号管理Sketch文件
- CloudI(将Erlang的容错能力带给多语言开发)
- 原子设计和Sketch–改进工作流程的指南
- Android开发 关于navigation destination xxx is unknown to this NavController 报错的复现分析与解决
- uniapp下uni.request请求的封装
- Android基础教程第4版 PDF下载
- AndroidStudio中使用XML和Java代码混合控制UI界面实现QQ相册照片列表页面
- android-interview
- appiumappium-desktop的使用