Linux树莓派项目实战:外网访问、PWM呼吸灯、超声波测距与驱动开发

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 提高测量精度技巧

  1. 多次测量取平均值:

    复制代码
    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
  2. 温度补偿(声速修正):

    复制代码
    # 温度传感器获取当前温度(需额外硬件)
    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 安全增强建议

  1. ​SSH安全加固​​:

    • 使用密钥认证替代密码
    • 修改默认SSH端口
    • 启用Fail2ban防护
  2. ​驱动权限管理​​:

    • 创建专门的用户组访问设备

    • 使用udev规则设置设备权限:

      复制代码
      # /etc/udev/rules.d/99-pwmled.rules
      SUBSYSTEM=="misc", KERNEL=="pwmled", GROUP="ledusers", MODE="0660"

5.3 性能优化技巧

  1. ​PWM优化​​:

    • 使用DMA控制PWM减少CPU占用
    • 硬件PWM引脚优先(GPIO12/13/18/19)
  2. ​超声波采样优化​​:

    • 中断驱动代替轮询
    • 内核模块实现精确计时
  3. ​多进程通信​​:

    复制代码
    # 使用共享内存存储距离数据
    from multiprocessing import shared_memory
    
    # 创建共享内存
    shm = shared_memory.SharedMemory(name='DistanceData', create=True, size=4)

5.4 扩展应用场景

  1. ​智能小车避障系统​​:

    • 超声波实时测距
    • PWM控制电机速度
    • 距离阈值自动转向
  2. ​智能家居控制面板​​:

    • 远程SSH控制
    • PWM调光台灯
    • 超声波感应自动开关
  3. ​安防监控系统​​:

    • 超声波入侵检测
    • 驱动LED警示灯
    • 云平台报警通知

​项目总结​​:本文完整实现了树莓派外网访问、PWM呼吸灯控制、超声波测距及Linux驱动开发全流程,提供了可直接复制到Word的详细技术文档,涵盖了从硬件连接到软件开发的完整解决方案,适用于物联网、嵌入式系统开发教学与实践应用。

相关推荐
우 유13 分钟前
Linux从入门到入门
linux·运维·服务器
love530love1 小时前
Python 开发环境全栈隔离架构:从 Anaconda 到 PyCharm 的四级防护体系
运维·ide·人工智能·windows·python·架构·pycharm
1688red1 小时前
IPv4编址及IPv4路由基础
运维·网络·华为
Sally璐璐2 小时前
CentOS查日志
linux·运维·centos
fo安方2 小时前
运维的利器–监控–zabbix–第二步:建设–部署zabbix agent5.0--客户端是windows&centos系统--实操记录gys
运维·windows·zabbix
刘俊辉个人博客2 小时前
端口安全配置示例
运维·网络·数据库·计算机网络·安全·网络安全
猪猪b。2 小时前
dhcp 配置IP实战演练!!!!!
运维·服务器·网络
m0_719817112 小时前
Linux运维新人自用笔记(用虚拟机Ubuntu部署lamp环境,搭建WordPress博客)
linux·学习
“αβ”3 小时前
Linux-多线程安全
linux·运维·服务器·ssh·github·线程·进程
我最厉害。,。3 小时前
Webshell篇&魔改哥斯拉&打乱特征指纹&新增后门混淆&过云查杀&过流量识别
linux