#!/usr/bin/env python3

################################################################################
# Copyright (c) 2024,D-Robotics.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################

import sys
import signal
import Hobot.GPIO as GPIO
import time

def signal_handler(signal, frame):
    sys.exit(0)

# 支持PWM的管脚: 32 and 33, 在使用PWM时,必须确保该管脚没有被其他功能占用
output_pin = 33

GPIO.setwarnings(False)

def main():
    # Pin Setup:
    # Board pin-numbering scheme
    GPIO.setmode(GPIO.BOARD)
    # 支持的频率范围: 48KHz ~ 192MHz
    p = GPIO.PWM(output_pin, 48000)
    # 初始占空比 25%, 先每0.25秒增加5%占空比,达到100%之后再每0.25秒减少5%占空比
    val = 25
    incr = 5
    p.ChangeDutyCycle(val)
    p.start(val)

    print("PWM running. Press CTRL+C to exit.")
    try:
        while True:
            time.sleep(0.25)
            if val >= 100:
                incr = -incr
            if val <= 0:
                incr = -incr
            val += incr
            p.ChangeDutyCycle(val)
    finally:
        p.stop()
        GPIO.cleanup()

if __name__ == '__main__':
    signal.signal(signal.SIGINT, signal_handler)
    main()

一、整体功能概述

该脚本基于地平线 Hobot.GPIO 库实现硬件 PWM 呼吸灯效果

  1. 使用 BOARD 引脚 33(RDK 仅 32、33 支持硬件 PWM);
  2. PWM 固定频率 48000Hz,初始占空比 25%;
  3. 每 250ms 占空比 ±5%,从 25% 逐步升到 100%,再降到 0%,循环往复;
  4. 支持 Ctrl+C 安全退出,自动停止 PWM 并释放 GPIO 资源;
  5. 硬件 PWM 由 SOC 外设输出,不占用 CPU 循环翻转电平,精度高。

硬件接线:33 引脚串联限流电阻接 LED 正极,LED 负极接 GND,通过 PWM 平均电压实现亮度渐变呼吸效果。

二、逐段代码拆解

1. 头部、通用依赖与信号处理

python

运行

#!/usr/bin/env python3
# Apache2.0开源协议声明
import sys
import signal
import Hobot.GPIO as GPIO
import time

def signal_handler(signal, frame):
    sys.exit(0)
  • #!/usr/bin/env python3:可直接 ./脚本名 运行;
  • signal:捕获 Ctrl+C(SIGINT) 信号,主动退出触发finally资源清理;
  • Hobot.GPIO:地平线专用 GPIO 库,内置硬件 PWM 封装;
  • signal_handler:中断回调,执行系统退出。

2. 硬件引脚定义与警告屏蔽

python

运行

# 支持PWM的管脚: 32 and 33, 在使用PWM时,必须确保该管脚没有被其他功能占用
output_pin = 33
GPIO.setwarnings(False)
  1. RDK 硬件限制:只有 BOARD 32、33 引脚具备硬件 PWM 外设,其余 IO 仅普通数字输入输出;
  2. 使用前必须确认该引脚未被设备树、其他程序复用;
  3. setwarnings(False):屏蔽引脚重复初始化警告日志。

3. 主函数 main ()

3.1 PWM 对象初始化

python

运行

GPIO.setmode(GPIO.BOARD)
# 创建PWM实例:引脚 + 频率48000Hz
p = GPIO.PWM(output_pin, 48000)
val = 25    # 初始占空比 25%
incr = 5    # 每次变化步长 5%
p.ChangeDutyCycle(val)
p.start(val)

关键 API 说明:

  1. GPIO.setmode(GPIO.BOARD):采用开发板物理丝印编号;
  2. GPIO.PWM(pin, freq) 创建 PWM 对象
    • 频率范围文档标注:48KHz ~ 192MHz;示例选用最低 48KHz;
    • 频率越高,人眼频闪感越弱,适合 LED 调光;
  3. p.start(duty_cycle):启动 PWM 输出,参数为初始占空比(0~100);
  4. p.ChangeDutyCycle(val):动态修改占空比,val 取值区间 0 ~ 100
    • 0:完全低电平,LED 熄灭;
    • 100:持续高电平,LED 最亮。
3.2 主循环:亮度渐变逻辑

python

运行

try:
    print("PWM running. Press CTRL+C to exit.")
    while True:
        time.sleep(0.25) # 250ms更新一次亮度
        # 到达上限100%,反向递减
        if val >= 100:
            incr = -incr
        # 到达下限0%,反向递增
        if val <= 0:
            incr = -incr
        val += incr
        p.ChangeDutyCycle(val)

渐变逻辑流程:

  1. 初始 val=25,incr=5 → 每 0.25s +5:25→30→35…→100;
  2. val=100 时 incr 取反 =-5 → 开始递减:100→95→90…→0;
  3. val=0 时 incr 再次取反 = 5,重新递增,无限循环呼吸效果;
  4. time.sleep(0.25) 控制渐变速度,数值越大呼吸越慢。
3.3 finally 资源强制释放(核心规范)

python

运行

finally:
    p.stop()        # 关闭硬件PWM外设输出
    GPIO.cleanup()  # 重置引脚,释放GPIO内核资源

无论正常循环、Ctrl+C 中断、代码异常,finally 一定会执行:

  1. p.stop():停止 PWM 波形输出,引脚变为普通 IO;不调用会持续输出 PWM;
  2. GPIO.cleanup():清空该引脚配置,防止下次运行报引脚占用。

4. 程序入口

python

运行

if __name__ == '__main__':
    signal.signal(signal.SIGINT, signal_handler)
    main()

提前注册 Ctrl+C 中断回调,保证退出流程完整执行资源回收。

三、PWM 核心原理补充

  1. PWM(脉冲宽度调制):固定周期内,高电平时间占比为占空比;
    • 占空比越高,等效平均电压越高,LED 越亮;
  2. 本代码为硬件 PWM:波形由 SOC 硬件外设自动生成,主线程仅周期性修改占空比,CPU 无持续翻转开销;
  3. 频率 48kHz 远高于人眼闪烁感知阈值,肉眼看不到频闪,调光顺滑。

四、完整运行时序

  1. 启动脚本,注册 Ctrl+C 中断;
  2. 初始化 BOARD 模式,创建 48kHz PWM 实例,25% 占空比启动输出;
  3. 进入循环,每 250ms 增减 5% 占空比,自动升降亮度;
  4. 按下 Ctrl+C 触发信号处理函数,执行sys.exit()
  5. 进入 finally,停止 PWM、清理 GPIO,程序安全退出。

五、开发注意事项 & 踩坑点

  1. 引脚限制仅 32、33 支持硬件 PWM,其他引脚调用GPIO.PWM会报错;
  2. 频率范围约束:不可低于 48000Hz;
  3. 占空比范围:0 ≤ val ≤ 100,超出区间无效果;
  4. 权限问题:操作 GPIO 建议加sudo python3 xxx.py
  5. 退出不执行 cleanup/p.stop:会导致引脚持续输出 PWM,占用硬件资源;
  6. 呼吸速度调节:修改sleep(0.25)数值,调大渐变变慢,调小变快;
  7. 步长控制:修改incr=5,数值越大亮度变化跳跃感越强。

六、扩展修改示例

  1. 放慢呼吸速度:time.sleep(0.5)
  2. 亮度每次变化 10%:incr = 10
  3. 更换 PWM 引脚为 33→32:仅修改output_pin = 32即可。
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐