基于 BeagleBone® Black 搭建 Web 页面控制 LED 灯并通过 FRP 转发实现远程操控
该项目使用了BeagleBone® Black,实现了Web页面控制LED的设计,它的主要功能为:通过页面控制LED亮灭、闪烁、跑马灯。
标签
Funpack活动
开发板
OceanCurrent
更新2025-01-14
哈尔滨工程大学
328

开源链接:https://github.com/phhandong/bbb_web

Black BeagleBone(BBB) 板卡介绍

BeagleBone® Black 是一款搭载了高达 1GHz 的 ARM Cortext™ A8 内核的开发板,该板卡提供了丰富的外设,包括 RJ45 网口,USB Host 接口,TF 卡接口,JTAG 接口,UART 串口,HDMI D Type 接口,支持 eMMC,充足的 IO 口支持 ADC,I2C,SPI,PWM 和 LCD。值得一提的是,板载 AM3358 处理器不仅有高达 1 GHz 的内核,还集成了 NEON™ SIMD 协处理器,SGX 530 图形引擎,可编程实时单元子系统,2KB 指令缓存,32KB 数据缓存 ,256KB 二级缓存,支持奇偶校验和错误校验码,多种系统的集成赋予了其强劲的图像处理和多任务能力。同时,板上自带的 4 GB eMMC Flash 储存器和 512 MB DDR3 SDRAM 存储器使其在不添加 TF 卡的情况下也足以承担开发任务。

AM3358 拥有两个输入时钟信号 OSC1 和 OCC0,其中 OSC1 为 RTC 提供了 32.768KHz 参考时钟并用于连接 RTC_XTALIN 和 RTC_XTALOUT,OCC0 为所有无 RT 功能的时钟提供 19.2MHz、24MHz、25MHz 或 26MHz 参考时钟,并可用于连接 XTALIN 和 XTALOUT 终端。

通用接口方面,BBB 板卡搭载了 4 组 GPIO 口,每一组 GPIO 模块提供 32 个 IO 管脚,因此通用输入输出管脚总数高达 128 个,相比同行产品,例如 Raspberry Pi、Arduino 有更强的拓展性和更高的性价比。

BBB 不仅具有 POWERVR® SGX 图形加速器子系统,支持 Direct3D Mobile 、 OGL ES 1.1 和 2.0 、 OpenVG 1.0 和 OpenMax,可用于 3D 图像加速以支持应用显示和游戏渲染。板卡还搭载了可编程实时单元(PRU),其包含了两个 32 位 RISC 内核,可实现高达 100 MHz 的 GPIO 输出,更进一步拓展了板卡在专业领域的应用能力。

Getting Started

BBB 板卡提供了开箱即用的体验,板卡出厂内存已经烧录了 Debian Linux 系统,可通过 Mini USB 接口与电脑连接,无需额外提供电源,当板卡成功连接电脑,他将以一个储存设备出现,其中包括了 Readme 自述引导文件,根据自述文件,在 Windows 平台,使用 USB 连接的情况下,可直接在浏览器地址栏输入 192.168.7.2 进入板卡自带的 Cloud9 IDE 界面,对于 Mac OS X, Linux 等其它平台,均有对应的开启方式。

值得注意的是,如果自行烧录了新版系统,需要先在终端通过指令 sudo systemctl enable --now bb-code-server 开启 Web VScode,才能通过对应地址访问并使用 IDE。

在 IDE 界面,BBB 提供了包括 Python,C/C++ 等丰富的运行和 Debug 环境,无需用户自行配置,真正实现了开箱即用。

Web 页面实现

image.png

Python 后端部分

使用 Python 实现了一个基于 Flask 的 Web 应用程序,允许用户通过 Web 界面控制 BeagleBone Black 的四个用户 LED。用户可以通过网页上的按钮来切换 LED 的状态,包括开/关、闪烁(Blink)、循环(Circle)等效果。 Web 应用与硬件的交互通过 GPIO(通用输入输出)接口实现,通过Adafruit_BBIO.GPIO库控制 BeagleBone Black 上的 LED。为了保证响应速度和控制逻辑的实时性,LED 控制部分通过独立的后台线程运行。

依赖库导入

from flask import Flask, render_template, request
import Adafruit_BBIO.GPIO as GPIO
import threading
import os
import time

Flask:用于创建 Web 应用,处理用户请求并提供界面。

Adafruit_BBIO.GPIO:专门为 BeagleBone 系列开发的库,能够控制 GPIO 引脚,从而控制 LED 等硬件设备。

threading:用于创建后台线程,让 LED 控制逻辑能够在后台运行,而不会阻塞 Flask Web 应用的主线程。

os:获取操作系统相关的信息,比如当前的工作目录。

time:提供时间相关的功能,控制 LED 的定时。

Flask 应用与路由定义

app = Flask(__name__)
led_pattern = ""
led_lock = threading.Lock()

Flask 应用Flask(__name__)初始化 Flask 应用。led_pattern是一个全局变量,用于存储当前的 LED 控制模式(如开、关、闪烁、圆形等)。led_lock是一个锁对象,用于在多线程环境下保护led_pattern变量,确保线程安全。

@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
led = request.form.get("led")
set_led_pattern(led)
return render_template("index.html")

Web 路由index()路由处理首页的请求。用户通过浏览器发起的请求会到达这个路由。POST请求会从表单中获取到用户选择的 LED 模式(如开、关、闪烁、圆形等),并更新led_pattern变量。

GPIO 控制函数

def led_on():
for pin in led_pins:
GPIO.output(pin, GPIO.HIGH)

def led_off():
for pin in led_pins:
GPIO.output(pin, GPIO.LOW)

def led_single(index, state):
if state:
GPIO.output(led_pins[index], GPIO.HIGH)
else:
GPIO.output(led_pins[index], GPIO.LOW)

led_on():控制所有 LED 灯亮起,通过将每个 GPIO 引脚设置为HIGH(高电平)来点亮 LED。

led_off():关闭所有 LED 灯,通过将 GPIO 引脚设置为LOW(低电平)来熄灭 LED。

led_single():控制某一个特定 LED 的状态(开或关),通过给定的index(LED 的索引)和state(0 表示关,1 表示开)来操作。

LED 控制循环(后台线程)

def led_control_loop():
current_time = time.time()
led_state = 0
circle_dir = 0
circle_state = 0b0000

while True:
with led_lock:
pattern = led_pattern

if pattern == "on":
led_on()
elif pattern == "off":
led_off()
elif pattern == "blink":
if time.time() - current_time > 0.5:
led_state = 1 - led_state # Toggle state
if led_state:
led_on()
else:
led_off()
current_time = time.time()
elif pattern == "circle":
if time.time() - current_time > 0.1:
if circle_state == 0b1111:
circle_dir = 1
elif circle_state == 0b0000:
circle_dir = 0

if circle_dir == 1:
circle_state -= 0b1
else:
circle_state += 0b1

for i in range(4):
led_single(i, (circle_state >> i) & 0b1)

current_time = time.time()

LED 控制逻辑led_control_loop()是一个循环,持续检查led_pattern变量的状态,并根据不同的模式来控制 LED 的行为。具体模式如下:

  • "on":所有 LED 灯亮起。
  • "off":所有 LED 灯熄灭。
  • "blink":LED 以一定间隔闪烁,控制频率为 0.5 秒。
  • "circle":LED 按顺时针或逆时针依次点亮或熄灭,形成一个循环效果。

启动后台线程

def start_led_thread():
t = threading.Thread(target=led_control_loop, daemon=True)
t.start()

启动后台线程start_led_thread()函数创建并启动一个新的线程,该线程负责执行led_control_loop()函数,从而在后台持续控制 LED 的状态。

Html 前端部分

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Funpack 3-5</title>
<style>
/* 基础布局样式 */
body {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100vh;
margin: 0;
font-family: Arial, sans-serif;
background-color: #f4f4f9;
}

.button-container {
text-align: center;
margin-bottom: 20px;
}

h1, h2 {
margin: 10px 0;
}

/* 按钮通用样式 */
.button {
padding: 10px 20px;
margin: 10px;
font-size: 16px;
cursor: pointer;
border: none;
color: white;
text-decoration: none;
display: inline-block;
transition: transform 0.2s ease;
}

.button:hover {
transform: scale(1.1); /* 鼠标悬停时放大按钮 */
}

/* 按钮特定样式 */
.button-on {
background-color: #4CAF50;
border-radius: 10px;
}

.button-off {
background-color: #f44336;
border-radius: 50%;
width: 60px;
height: 60px;
font-size: 14px;
padding: 0;
}

.button-blink {
background-color: #008CBA;
border-radius: 20px;
padding: 10px 30px;
}

.button-circle {
background-color: #00ECBA;
width: 100px;
height: 40px;
border-radius: 25px;
}

/* 底部文本样式 */
.footer {
position: absolute;
text-align: center;
bottom: 10px;
font-size: 10px;
color: #333;
}

</style>
</head>
<body>
<div class="button-container">
<h1>Funpack</h1>
<h2>Control Panel</h2>

<!-- 按钮链接 -->
<a href="/?led=on"><button class="button button-on">On</button></a>
<a href="/?led=off"><button class="button button-off">Off</button></a>
<a href="/?led=blink"><button class="button button-blink">Blink</button></a>
<a href="/?led=circle"><button class="button button-circle">Circle</button></a>
</div>

<!-- 底部文本 -->
<div class="footer">
<p>Let us have fun together</p>
<p>By OceanCurrent</p>
</div>


</body>
</html>

HTML 结构

<head> 部分包含页面的元数据和样式设置。页面使用 UTF-8 编码,支持响应式布局。

  1. <body> 部分包含了页面的核心内容,包括:一个标题区域,显示"Funpack"和"Control Panel"。一个按钮区域,包含四个按钮,每个按钮链接到不同的 URL 来控制 LED 状态。页面底部展示了简单的版权信息。

样式部分

按钮样式:为不同的按钮定义了独特的样式。

  1. .button-on:绿色矩形按钮,用于开启 LED。
  2. .button-off:红色圆形按钮,用于关闭 LED。
  3. .button-blink:蓝色椭圆形按钮,用于控制 LED 闪烁。
  4. .button-circle:绿色圆形按钮,用于控制 LED 的圆形闪烁效果。
  5. 整体布局:页面采用flexbox布局,确保按钮和文本居中显示,并且页面始终占满整个视口高度。

按钮点击事件:每个按钮都包裹在一个<a>标签中,点击按钮后会触发一个 GET 请求,发送相应的led参数值(例如/?led=on)。按钮的onclick事件触发时,会弹出一个警告框,提示用户按钮已被点击,虽然这里的提示只是为了展示,你可以根据需要将其删除或修改。在实际应用中,按钮点击后会向 Flask 服务器发送请求,Flask 会根据led参数来更新 LED 的控制状态。

FRP 转发

下载 Frp (Linux)

Release v0.60.0 · fatedier/frp

客户端设置

编写配置文件

serverAddr = "your_ip"    #remote ip dress
serverPort = 7000 #communication port

[[proxies]]
name = "funpack"
type = "tcp" #其它页面tcp转发
localIP = "192.168.7.2"
localPort = 88
remotePort = 88

启动服务

./frpc -c ./frpc.toml

设置守护进程,开机自启

vim /etc/systemd/system/frpc.service

自启动任务

[Unit]
Description=frp_service

After=trim_connect.service #在某进程之后启动
After=docker.service
Wants=network-online.target #设置依赖(非强制)

[Service]
Type=simple
ExecStart=//data/frp/frpc -c //data/frp/frpc.toml
Restart=on-failure

[Install]
WantedBy=multi-user.target

自启动失败的解决方案

#E:/etc/systemd/system/rc-local.service:12: Support for option SysVStartPriority= has been removed and it is ignored

#旧版 systemd 支持的选项,用于设置服务的启动优先级。但在较新的 systemd 版本中,该选项已被移除或弃用

#解决方法:
sudo vim /etc/systemd/system/rc-local.service
#将第12
SysVStartPriority=99
#注释
#SysVStartPriority=99
#重载守护进程
sudo systemctl daemon-reload
#验证是否生效
sudo systemd-analyze verify /etc/systemd/system/frpc.service

服务端设置

Frps

vim frps.toml
bindPort = 7000 # 与frpc通信端口
vhostHTTPPort = 88 #http转发端口

Nginx

经过以上操作,使用云服务器端口 your_ip:89 访问,若能访问网页,则已经转发成功。

由于 Frps 转发只是由 Nas 端口转发到了 云服务器 端口上,想要使用域名访问,仍需使用 Nginx 反向代理。

http
{
include mime.types;
#include luawaf.conf;

include proxy.conf;
lua_package_path "/www/server/nginx/lib/lua/?.lua;;";

default_type application/octet-stream;

server_names_hash_bucket_size 512;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;

sendfile on;
tcp_nopush on;

keepalive_timeout 60;

tcp_nodelay on;

fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json image/jpeg image/gif image/png font/ttf font/otf image/svg+xml application/xml+rss text/x-js;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;

server_tokens off;
access_log off;

server {
listen 88;
server_name yourdomain.com;
location / {
# proxy_pass http://127.0.0.1:8080;
# 代理到127.0.0.1:8080可以通过frp.3to.top:8080,但是frp.3to.top还是访问不到,所以改为下面配置
proxy_pass http://yourdomain.com:88;
}
}

至此,已经可以使用域名访问。

同样的,该 FRP 也支持 Windows 系统环境运行。

Reference:

  1. BeagleBone Black CookBook: https://old.beagleboard.org/cookbook
  2. Bilibili, 基于 BeagleBone® Black 的 WEB 控制 LED 实验:https://www.bilibili.com/video/BV1J3tgeWEcn/?spm_id_from=333.337.search-card.all.click&vd_source=2180649056581e91db1398cbc78a4a8f
  3. CSDN, BeagleBone Black 使用(一):狗板简介 https://blog.csdn.net/weixin_43144573/article/details/109640685


附件下载
code.zip
团队介绍
韩栋,智能科学与工程学院2021级本科生
团队成员
OceanCurrent
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号