1. 通过SSH反向代理实现树莓派外网访问
1.1 原理说明
SSH反向代理通过在树莓派上建立到云服务器的隧道连接,使外网用户可以通过访问云服务器的特定端口连接到内网的树莓派。
1.2 实现步骤
1.2.1 树莓派端配置
ssh -p 22 -qngfNTR [云服务器端口号]:localhost:22 阿里云用户名@114.55.126.125
- 参数说明 :
-p 22
:连接云服务器的SSH端口-q
:安静模式(不显示警告信息)-N
:不执行远程命令-g
:允许远程主机连接到本地转发端口-f
:后台运行-R
:反向代理(云服务器端口:本地主机:本地端口)
1.2.2 阿里云服务器端验证
ss -ntl
检查指定端口是否处于LISTEN状态:
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:你的端口号 0.0.0.0:*
1.2.3 外网访问树莓派
ssh -p [云服务器端口号] 树莓派用户名@114.55.126.125
1.3 自动化脚本
在树莓派上创建autossh.sh
脚本:
#!/bin/bash
REMOTE_PORT=2222 # 云服务器端口
CLOUD_USER="your_username"
CLOUD_IP="114.55.126.125"
autossh -M 0 -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" \
-N -R $REMOTE_PORT:localhost:22 $CLOUD_USER@$CLOUD_IP
设置开机启动:
sudo nano /etc/rc.local
# 在exit 0前添加:
su pi -c '/home/pi/autossh.sh' &
2. PWM呼吸灯控制
2.1 硬件连接
LED颜色 | 树莓派GPIO引脚 (BCM编号) | 物理引脚 |
---|---|---|
黄色 | GPIO17 | 引脚11 |
绿色 | GPIO23 | 引脚16 |
2.2 单灯顺序呼吸代码
import RPi.GPIO as GPIO
import time
# 设置编码方式
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
# 设置引脚
YELLOW_LED = 11 # GPIO17
GREEN_LED = 16 # GPIO23
GPIO.setup(YELLOW_LED, GPIO.OUT)
GPIO.setup(GREEN_LED, GPIO.OUT)
# 创建PWM对象
yellow_pwm = GPIO.PWM(YELLOW_LED, 60) # 60Hz频率
green_pwm = GPIO.PWM(GREEN_LED, 60)
# 启动PWM
yellow_pwm.start(0)
green_pwm.start(0)
try:
for _ in range(3):
# 黄灯呼吸
for dc in range(0, 101, 5):
yellow_pwm.ChangeDutyCycle(dc)
time.sleep(0.1)
for dc in range(100, -1, -5):
yellow_pwm.ChangeDutyCycle(dc)
time.sleep(0.1)
# 绿灯呼吸
for dc in range(0, 101, 5):
green_pwm.ChangeDutyCycle(dc)
time.sleep(0.1)
for dc in range(100, -1, -5):
green_pwm.ChangeDutyCycle(dc)
time.sleep(0.1)
finally:
yellow_pwm.stop()
green_pwm.stop()
GPIO.cleanup()
2.3 双灯同时呼吸(多线程实现)
import RPi.GPIO as GPIO
import time
import threading
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
YELLOW_LED = 11
GREEN_LED = 16
GPIO.setup(YELLOW_LED, GPIO.OUT)
GPIO.setup(GREEN_LED, GPIO.OUT)
yellow_pwm = GPIO.PWM(YELLOW_LED, 60)
green_pwm = GPIO.PWM(GREEN_LED, 60)
yellow_pwm.start(0)
green_pwm.start(0)
def breathe_led(pwm, color_name, delay=0.1):
try:
while True:
for dc in range(0, 101, 5):
pwm.ChangeDutyCycle(dc)
time.sleep(delay)
for dc in range(100, -1, -5):
pwm.ChangeDutyCycle(dc)
time.sleep(delay)
except KeyboardInterrupt:
pass
try:
# 创建线程
yellow_thread = threading.Thread(target=breathe_led,
args=(yellow_pwm, "Yellow"))
green_thread = threading.Thread(target=breathe_led,
args=(green_pwm, "Green"))
# 启动线程
yellow_thread.start()
green_thread.start()
# 等待线程结束
yellow_thread.join()
green_thread.join()
finally:
yellow_pwm.stop()
green_pwm.stop()
GPIO.cleanup()
3. 超声波测距模块
3.1 硬件连接
超声波模块 | 树莓派引脚 (BCM编号) | 物理引脚 |
---|---|---|
VCC | 5V电源 | 引脚2 |
Trig | GPIO23 | 引脚16 |
Echo | GPIO24 | 引脚18 |
GND | GND | 引脚20 |
3.2 测距代码实现
import RPi.GPIO as GPIO
import time
# 设置GPIO模式为BCM
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# 定义GPIO引脚
TRIG = 23
ECHO = 24
# 设置引脚模式
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
def get_distance():
# 确保TRIG引脚为低电平
GPIO.output(TRIG, False)
time.sleep(0.02) # 稳定时间
# 发送10μs的脉冲触发
GPIO.output(TRIG, True)
time.sleep(0.00001) # 10微秒
GPIO.output(TRIG, False)
# 记录回波开始时间
pulse_start = time.time()
timeout = pulse_start + 0.04 # 40ms超时(最大测距约7米)
while GPIO.input(ECHO) == 0 and pulse_start < timeout:
pulse_start = time.time()
# 记录回波结束时间
pulse_end = time.time()
while GPIO.input(ECHO) == 1 and pulse_end < timeout:
pulse_end = time.time()
# 计算时间差
pulse_duration = pulse_end - pulse_start
# 计算距离(声速343m/s = 34300cm/s)
distance = pulse_duration * 17150 # 34300/2(往返距离)
distance = round(distance, 2)
# 有效距离范围(2cm-400cm)
if distance < 2 or distance > 400:
return None
return distance
try:
while True:
dist = get_distance()
if dist is not None:
print(f"测量距离: {dist} cm")
else:
print("超出有效范围")
time.sleep(1)
except KeyboardInterrupt:
print("测量已停止")
GPIO.cleanup()
3.3 提高测量精度技巧
-
多次测量取平均值:
def get_avg_distance(samples=5): distances = [] for i in range(samples): dist = get_distance() if dist is not None: distances.append(dist) time.sleep(0.05) if distances: return sum(distances) / len(distances) return None
-
温度补偿(声速修正):
# 温度传感器获取当前温度(需额外硬件) def get_speed(temp_celsius): return 331.3 * (1 + temp_celsius / 273.15)**0.5 # 在距离计算中使用: speed = get_speed(current_temp) * 100 # 转换为cm/s distance = pulse_duration * speed / 2
4. PWM驱动开发
4.1 开发环境准备
# 安装内核头文件
sudo apt update
sudo apt install raspberrypi-kernel-headers
# 验证内核版本
uname -r
# 示例输出:5.15.32-v7+
# 创建驱动目录
mkdir pwm_driver
cd pwm_driver
4.2 驱动源代码
pwmled.h
#ifndef __PWMLED_H__
#define __PWMLED_H__
#define PWMLED_MAX_BRIGHTNESS 1000
typedef enum {
PWMLED_CMD_SET_BRIGHTNESS = 0x1,
PWMLED_CMD_GET_BRIGHTNESS,
} pwmled_cmd_t;
#endif // __PWMLED_H__
pwmled.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/pwm.h>
#include "pwmled.h"
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("PWM LED Controller Driver");
#define PWMLED_PERIOD 1000000 // 固定周期1ms (1KHz)
static struct {
struct pwm_device* pwm;
unsigned int brightness;
} pwmled;
long pwmled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case PWMLED_CMD_SET_BRIGHTNESS:
// 限制亮度值在0-MAX之间
pwmled.brightness = (arg > PWMLED_MAX_BRIGHTNESS) ?
PWMLED_MAX_BRIGHTNESS : arg;
// 配置PWM:占空比 = 亮度值 * 1000ns
pwm_config(pwmled.pwm, pwmled.brightness * 1000, PWMLED_PERIOD);
// 根据亮度值启用/禁用PWM
if (pwmled.brightness > 0) {
pwm_enable(pwmled.pwm);
} else {
pwm_disable(pwmled.pwm);
}
break;
case PWMLED_CMD_GET_BRIGHTNESS:
return pwmled.brightness;
default:
return -EINVAL;
}
return 0;
}
static const struct file_operations pwmled_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = pwmled_ioctl,
};
static struct miscdevice pwmled_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "pwmled",
.fops = &pwmled_fops,
.mode = 0666,
};
static int __init pwmled_init(void)
{
int ret;
// 申请PWM0通道
pwmled.pwm = pwm_request(0, "pwm0");
if (IS_ERR(pwmled.pwm)) {
printk(KERN_ERR "Failed to request PWM0\n");
return PTR_ERR(pwmled.pwm);
}
// 初始化亮度为0(关闭LED)
pwmled.brightness = 0;
pwm_config(pwmled.pwm, 0, PWMLED_PERIOD);
pwm_disable(pwmled.pwm);
// 注册设备
ret = misc_register(&pwmled_misc);
if (ret) {
printk(KERN_ERR "Failed to register misc device\n");
pwm_free(pwmled.pwm);
return ret;
}
printk(KERN_INFO "PWM LED driver loaded\n");
return 0;
}
static void __exit pwmled_exit(void)
{
misc_deregister(&pwmled_misc);
pwm_disable(pwmled.pwm);
pwm_free(pwmled.pwm);
printk(KERN_INFO "PWM LED driver unloaded\n");
}
module_init(pwmled_init);
module_exit(pwmled_exit);
4.3 Makefile
obj-m := pwmled.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
4.4 编译与安装驱动
# 编译驱动
make
# 加载驱动
sudo insmod pwmled.ko
# 验证设备节点
ls /dev/pwmled
# 设置权限
sudo chmod 666 /dev/pwmled
# 查看内核日志
dmesg | tail
# 预期输出: PWM LED driver loaded
# 测试驱动
sudo apt install python3
python3
>>> import fcntl
>>> fd = open('/dev/pwmled', 'r')
>>> fcntl.ioctl(fd, 0x1, 500) # 设置亮度为50%
>>> fcntl.ioctl(fd, 0x2) # 获取当前亮度
500
# 卸载驱动
sudo rmmod pwmled
4.5 应用层控制示例
import fcntl
import time
# 命令定义(与驱动头文件一致)
SET_BRIGHTNESS = 0x1
GET_BRIGHTNESS = 0x2
def control_led(brightness):
with open('/dev/pwmled', 'r') as f:
# 设置亮度
fcntl.ioctl(f, SET_BRIGHTNESS, brightness)
# 读取当前亮度
current = fcntl.ioctl(f, GET_BRIGHTNESS)
print(f"LED亮度设置为: {current}/1000")
if __name__ == "__main__":
# 呼吸灯效果
try:
while True:
for level in range(0, 1001, 10):
control_led(level)
time.sleep(0.02)
for level in range(1000, -1, -10):
control_led(level)
time.sleep(0.02)
except KeyboardInterrupt:
control_led(0) # 关闭LED
5. 项目集成与优化建议
5.1 系统架构
+-----------------+ +----------------+ +------------------+
| 阿里云服务器 | SSH | 树莓派 | GPIO | 外围设备 |
| (SSH反向代理) |<---->| (运行驱动程序) |---->| - PWM LED呼吸灯 |
| 端口映射:114.55.x.x:2222 | 超声波测距模块 |<---->| - HC-SR04超声波模块|
+-----------------+ +----------------+ +------------------+
5.2 安全增强建议
-
SSH安全加固:
- 使用密钥认证替代密码
- 修改默认SSH端口
- 启用Fail2ban防护
-
驱动权限管理:
-
创建专门的用户组访问设备
-
使用udev规则设置设备权限:
# /etc/udev/rules.d/99-pwmled.rules SUBSYSTEM=="misc", KERNEL=="pwmled", GROUP="ledusers", MODE="0660"
-
5.3 性能优化技巧
-
PWM优化:
- 使用DMA控制PWM减少CPU占用
- 硬件PWM引脚优先(GPIO12/13/18/19)
-
超声波采样优化:
- 中断驱动代替轮询
- 内核模块实现精确计时
-
多进程通信:
# 使用共享内存存储距离数据 from multiprocessing import shared_memory # 创建共享内存 shm = shared_memory.SharedMemory(name='DistanceData', create=True, size=4)
5.4 扩展应用场景
-
智能小车避障系统:
- 超声波实时测距
- PWM控制电机速度
- 距离阈值自动转向
-
智能家居控制面板:
- 远程SSH控制
- PWM调光台灯
- 超声波感应自动开关
-
安防监控系统:
- 超声波入侵检测
- 驱动LED警示灯
- 云平台报警通知
项目总结:本文完整实现了树莓派外网访问、PWM呼吸灯控制、超声波测距及Linux驱动开发全流程,提供了可直接复制到Word的详细技术文档,涵盖了从硬件连接到软件开发的完整解决方案,适用于物联网、嵌入式系统开发教学与实践应用。