没有静态IP?没问题。一步一步,我们将在树莓派上搭建VPN、网络服务器和HC-SR04超声波距离传感器。
我正在安装大部分软件。
如果觉得本教程中的代码片段难以阅读,请查看本文的 Github 版本(它们的片段格式更好,支持更多语言)。存储库链接在此文本的底部。
如您所见,我们需要使用一些电阻来降低电压,因为高于 3.3V 的电压可能会损坏 RPi,传感器将无法正常工作。
我们的目标是能够从任何地方读取数据,因此我们现在需要设置 VPN。该解决方案更安全,因为我们不会将设备暴露在开放的互联网流量中。
我假设您已经在https://husarnet.com/ 创建了一个帐户。
如果是这样,让我们创建一个网络并添加我们的设备。
1.在 RPi 以及其他设备(例如您的计算机)上安装 Husarnet 客户端,以便您稍后可以显示该网站。要安装客户端,请使用以下命令:
curl https://install.husarnet.com/install.sh | sudo bash
安装过程完成后,建议重启Husarnet:
sudo systemctl restart husarnet
2.登录https://app.husarnet.com/,点击创建网络,成功完成该过程后,在网络面板中点击添加元素。
3.点击后会弹出一个菜单。如您所见,有很多选项可用于将设备添加到网络。其中最普遍的是使用*加入代码*。复制它并继续到 RPi 上的命令行。
sudo husarnet join
设置易于记忆的设备名称是个好主意,因为您以后可以使用它们而不是长而难看的 IPv6 地址。
4. 对要添加到网络的所有其他设备执行相同操作。
成功配置的网络应该与此类似:
您现在可以通过 ping 设备来测试您的网络是否正常工作。
例如,在我的笔记本电脑设备上,我会运行:
ping6 -c 5 rasp
向rasp发送 5 个 ping 。
所有代码都可以在本页底部列出的我的存储库中找到。
在开始编写代码之前,我们需要安装 RPi.GPIO。这非常简单:
pip3 install RPi.GPIO
互联网上有很多可用于 HC-SR04 的代码示例。
在本例中,我们将使用以下 python3 程序:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
TRIG = 23
ECHO =24
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
file = '/var/www/html/data.txt'
try:
while True:
GPIO.output(TRIG,False)
time.sleep(0.1)
GPIO.output(TRIG, True)
time.sleep(0.0001)
GPIO.output(TRIG, False)
while GPIO.input(ECHO) == 0:
pulse_start = time.time()
while GPIO.input(ECHO) == 1:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
dist = pulse_duration * 17150
dist = round(dist, 2)
print("distance:", dist, end='\r', flush=True)
with open(file,'w') as f:
f.write(str(dist))
except KeyboardInterrupt:
print("cleanup")
GPIO.cleanup()
我强烈建议你玩一下 first 的持续时间,time.sleep
这样你的刷新率就不错了,而且你不会遇到很多错误。对我来说,~10Hz 的刷新率非常好。
如您所见,我们只是将计算出的距离保存在 Apache 目录中的 .txt 文件中。这是迄今为止我能想到的访问传感器数据的最简单方法,而无需编写精美的后端服务。
要在 Raspberry Pi 上安装和启用 Apache,请执行以下操作:
sudo apt update
sudo apt install apache2 -y
安装后,您可以重新启动 Apache 以确保服务正常运行:
sudo service apache2 restart
执行类似的命令
curl localhost
应该会得到默认的 Apache index.html 页面。
现在我们有了一个可以从中获取数据的工作界面,我们可以继续将其呈现给用户。为此,我们需要 jQuery 和一些基本的 CSS/JS。
让我们从从文本文件中动态提取数据开始。假设我们将每秒刷新一次数据。
<script>
var hostname = document.location.origin;
var interval = 100; // it's reasonable to set this to the same value as the refresh rate of the sensor
function get_data() {
$.ajax({
url: hostname+"/data.txt",
type: "GET",
dataType : "text",
success: function(data){
d = document.getElementById('sensor-data');
d.innerHTML = data;
bar.set_value(data);
setTimeout(function(){
get_data();
}, interval);
}
});
}
get_data();
script>
我们正在使用 AJAX,它是 jQuery 库的一个组件,用于动态请求和刷新数据,而无需重新加载页面。现在,不要担心从 geElementById 开始的三行,我们稍后会谈到。
我们的函数 get_data 只是向```/data.txt``` 发出请求,这是我们传感器数据的目录。```setTimeout``` 构造设置了一个早先定义的间隔(100ms),之后整个函数逻辑被重复。
现在让我们绘制一个进度条。我们将从定义 3 个 div 开始。
<div class="progress-bar">
<div class="result" id ="sensor-data">div>
<div class = "progress-bar-fill">div>
div>
我们将快速对其进行样式设置,以便将数据很好地呈现给用户(最后将 css 移动到外部文件中)。
<style>
.progress-bar{
width: 100%;
height: 200px;
border: 1px solid black;
position: relative;
}
.progress-bar-fill{
height: 100%;
background: lightblue;
transition: width 0.5s;
}
.result{
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 40px;
font-family: sans-serif;
}
style>
我们现在需要编写一些 Javascript 代码来改变进度条填充 div 的长度。长话短说,我们要更改宽度样式参数(值从 0-100%)。
为此,我们将编写一个名为 ProgressBar 的类(当然是在脚本标签内)。
class ProgressBar{
constructor(element, intial_value){
this.value_elem = element.querySelector('.result');
this.fill_elem = element.querySelector('.progress-bar-fill');
this.set_value(intial_value);
}
set_value(new_value){
this.value_scaled = new_value * 0.25; //100% of the bar is now 400cm, scaled for better visibility
//0.25=100% * 1/400
this.value = new_value;
if (this.value_scaled < 0) {
this.value_scaled = 0;
}
if (this.value_scaled > 100) {
this.value_scaled = 100;
}
this.update();
}
update(){
const percentage = this.value_scaled + '%';
this.fill_elem.style.width = percentage;
this.value_elem.textContent = this.value + 'cm';
}
}
bar = new ProgressBar(document.querySelector('.progress-bar'), 200);
此类的构造函数将样式元素 (*progress-bar-fill* div) 和初始进度条值作为参数。初始值并不重要,因为它会立即被我们的代码更改。
如果您仔细观察,您会注意到我已经初始化了 ProgressBar 类 ( bar ) 的一个实例。这与之前的片段之一(在get_data函数内)中出现的变量相同。
我们的类有两个方法。第一个是 set_value ,它将以厘米为单位的距离缩放为 % (0-100)。我选择将值缩放到 400cm,即 100%,但理论上你可以一直到 4000cm,因为这是 HC-SR04 的最大范围。第二种方法是更新。这设置了我们 div 的实际宽度。
现在让我们通过添加一些动态功能来增强我们的网站 - 浏览器选项卡中的通知和可调整的阈值,它将确定我们是否距离传感器足够远。
首先,我们应该在文档中添加几个 div(就在 *progress-bar* 下方):
<div style="margin-top: 200px; width: 100%; text-align: center">
id="info"> Threshold slider
div> <div class="slidecontainer" style="margin-top: 50px;"> "range" min="1" max="100" value="50" class="slider" id="myRange"> div> <div id="slider-value">div>
我还设置了 div 的样式,以便它们在网站上看起来更好。
为避免代码混乱,我们应该拆分文件。创建一个名为style的目录,并在该目录中创建一个文件 slider.css。这是slider.css的代码:
.slidecontainer {
width: 100%;
}
.slider {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 25px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
}
.slider:hover {
opacity: 1;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 25px;
height: 25px;
background: #4CAF50;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 25px;
height: 25px;
background: #4CAF50;
cursor: pointer;
}
为了使滑块工作,我们需要添加一些用于动态更新的 Javascript。
var slider = document.getElementById("myRange");
var output = document.getElementById("slider-value");
// Display the default slider value
output.innerHTML = "Current threshold value: " + slider.value*4 + "cm";
// Update the current value
slider.oninput = function() {
output.innerHTML = "Current threshold value: " + this.value*4 + "cm";
}
我在bar
(提醒:存储库的源文件中提供完整代码)的初始化下添加了此代码。
好的,还有一件事要做 - 浏览器标签通知。在浏览器的顶部,在我们的网站选项卡中,我们希望有类似的内容:favicon:(distance) Page title 。
要实现动态favicon的效果,我们需要编写一个Javascript函数:
function set_favicon(happy) {
icon = 'img/happy.ico';
if (!happy){
icon = 'img/angry.ico';
}
var link = document.createElement('link');
var old_link = document.getElementById('favicon');
link.id = 'favicon';
link.rel = 'icon';
link.href = icon;
if (old_link){
document.head.removeChild(old_link);
}
document.head.appendChild(link);
}
我们将有两个可能的网站图标 - 愤怒和快乐(由快乐参数确定)。
您可以从我的存储库下载图标。如您所见,我在/var/www/html
img 中创建了一个新目录,用于存储图标。代码非常简单——我们确定要使用哪个图标,我们创建一个链接元素,检查一个是否已经存在并用一个新的替换它。
我们现在需要回到我们的好老朋友那里get_data
做一些调整:
function get_data() {
$.ajax({
url: hostname+"/data.txt",
type: "GET",
dataType : "text",
success: function(data){
d = document.getElementById('sensor-data');
d.innerHTML = data;
bar.set_value(data);
//changes start here
if (slider.value*4 > data){
document.getElementById('info').innerHTML = "Move away";
document.getElementById('bar-fill').style.backgroundColor = "red";
set_favicon(false);
} else{
document.getElementById('info').innerHTML = "OK";
document.getElementById('bar-fill').style.backgroundColor = "#4CAF50";
set_favicon(true);
}
setTimeout(function(){
get_data();
}, interval);
}
});
}
if 语句确定是否超过了阈值,并取决于我们是否被通知(通过一个愤怒的表情符号和一个微妙的后退提示)我们离得太近或被告知我们的距离是合适的。
滑块值乘以 4,因为滑块被设计为具有 0-100 的值(有点像进度条),如前所述,我已确定 400 厘米为最大范围。
最后一点:这是可选的,但看起来很酷——让我们让进度条在超过阈值时改变颜色。这只是两行代码(上面的片段)。
就是这样!
我们现在可以测试我们的网站了。再一次,所有放在一个文件中的 HTML/JS 片段都可以在存储库中使用(get.html
文件,记得将其复制到/var/www/html
目录)。
在您的 RPi 上,运行读取传感器数据的 python 脚本。在脚本所在的目录中运行:
sudo python3 script.py
现在您可以在您的计算机上打开该网站 -
我们去吧!
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !