245 lines
9.1 KiB
Python
245 lines
9.1 KiB
Python
"""
|
||
============================================================================
|
||
圆柱水槽控制系统 — 精简演示脚本
|
||
============================================================================
|
||
|
||
本脚本演示三个驱动模块的基本用法,适合第一次接触本项目时快速了解全貌。
|
||
|
||
运行方式:
|
||
python3 demo.py
|
||
|
||
注意事项:
|
||
⚠️ 所有涉及真实硬件的操作都会打印 [需要硬件] 标记。
|
||
如果你没有连接实际硬件,可以阅读代码和打印输出来了解流程。
|
||
============================================================================
|
||
"""
|
||
|
||
# ============================================================
|
||
# 第一步:导入依赖
|
||
# ============================================================
|
||
# 导入时间模块,用于延时和计时
|
||
import time
|
||
# 导入数学模块,用于数学计算(如正弦函数)
|
||
import math
|
||
|
||
# 导入三个驱动模块(请确保这些 .py 文件与本脚本在同一目录下)
|
||
# 编码器电机驱动 — 控制圆柱旋转
|
||
from drv_encodermotor import EncoderMotorDriver, SPEED_MODE
|
||
# 步进电机驱动 — 控制圆柱平移
|
||
from drv_stepmotor import StepMotorDriver
|
||
# ADC 驱动 — 采集应变片电压信号
|
||
from drv_adc import ADS124S08
|
||
|
||
|
||
# ============================================================
|
||
# 第二步:EncoderMotor(编码器电机)演示 — 控制圆柱旋转
|
||
# ============================================================
|
||
def demo_encodermotor():
|
||
"""
|
||
演示编码器电机的速度控制流程。
|
||
通过 I2C 总线与 M5Stack 4EncoderMotor 模块通信。
|
||
"""
|
||
print("=" * 60)
|
||
print("【EncoderMotor】编码器电机演示 — 控制圆柱旋转")
|
||
print("=" * 60)
|
||
|
||
# 使用 with 语句创建驱动实例,退出后自动释放 I2C 资源
|
||
# bus=1 表示使用树莓派的 I2C 总线 1(/dev/i2c-1)
|
||
with EncoderMotorDriver(bus=1) as driver:
|
||
|
||
# 1. 设置通道 0 为速度模式(SPEED_MODE)
|
||
# 速度模式下,电机会自动维持设定的目标转速
|
||
print(" [需要硬件] 设置通道 0 为速度模式...")
|
||
driver.set_mode(0, SPEED_MODE)
|
||
|
||
# 2. 配置速度 PID 参数
|
||
# kp(比例)、ki(积分)、kd(微分)配合使速度控制更精确
|
||
print(" [需要硬件] 配置 PID 参数 (kp=1, ki=100, kd=1)...")
|
||
driver.set_speed_pid(0, kp=1, ki=100, kd=1)
|
||
|
||
# 3. 启用软启停功能,让电机加减速更平滑
|
||
print(" [需要硬件] 启用软启停...")
|
||
driver.set_soft_start_and_stop(0, True)
|
||
|
||
# 4. 设置目标线速度(单位:米/秒)
|
||
# 正数 = 正转,负数 = 反转
|
||
print(" [需要硬件] 设定目标速度:0.02 m/s")
|
||
driver.set_linear_speed_m_s(0, 0.02)
|
||
|
||
# 等待 1 秒让电机跑起来
|
||
time.sleep(1)
|
||
|
||
# 5. 读取编码器数值(电机转过的脉冲数)
|
||
print(" [需要硬件] 读取编码器数值...")
|
||
encoder_val = driver.get_encoder_value(0)
|
||
print(f" 编码器数值:{encoder_val}")
|
||
|
||
# 6. 读取电机总电流
|
||
print(" [需要硬件] 读取电机电流...")
|
||
current = driver.get_motor_current()
|
||
print(f" 总电流:{current:.4f} A")
|
||
|
||
# 7. 速度归零,停止电机
|
||
print(" [需要硬件] 停止电机...")
|
||
driver.set_linear_speed_m_s(0, 0.0)
|
||
time.sleep(1)
|
||
|
||
# 退出 with 语句块,I2C 连接自动关闭
|
||
print(" [完成] EncoderMotor 演示结束,资源已释放\n")
|
||
|
||
|
||
# ============================================================
|
||
# 第三步:StepMotor(步进电机)演示 — 控制圆柱平移
|
||
# ============================================================
|
||
def demo_stepmotor():
|
||
"""
|
||
演示步进电机的控制流程。
|
||
通过 I2C + 硬件 PWM 与 M5Stack StepMotor Driver 模块通信。
|
||
三个步进电机共享同一路 PWM 脉冲,但方向可独立控制。
|
||
"""
|
||
print("=" * 60)
|
||
print("【StepMotor】步进电机演示 — 控制圆柱平移")
|
||
print("=" * 60)
|
||
|
||
# 创建驱动实例(这里演示用 try/finally 手动释放资源)
|
||
drv = StepMotorDriver()
|
||
try:
|
||
# 1. 使能电机 — 让电机驱动芯片开始接收脉冲
|
||
print(" [需要硬件] 使能电机...")
|
||
drv.enable_motor()
|
||
|
||
# 2. 复位所有 3 个电机通道(恢复到初始状态)
|
||
print(" [需要硬件] 复位所有电机通道...")
|
||
for i in range(3):
|
||
drv.reset_motor(i, True)
|
||
|
||
# 3. 设置运动方向(True=正向,False=反向)
|
||
print(" [需要硬件] 设置方向为正向...")
|
||
drv.set_dir(True)
|
||
|
||
# 4. S 曲线加速启动(速度 0.02 m/s,用 0.1 秒加速到目标)
|
||
# 加速曲线用了余弦函数,非常平滑
|
||
drv.ramp_time = 0.1 # 为了演示,把加减速时间设短
|
||
print(" [需要硬件] S 曲线加速启动 (0.02 m/s)...")
|
||
drv.start(0.02)
|
||
time.sleep(1)
|
||
|
||
# 5. 在运行中切换速度(0.04 m/s)
|
||
print(" [需要硬件] 切换速度 (0.04 m/s)...")
|
||
drv.change_speed(0.04)
|
||
time.sleep(1)
|
||
|
||
# 6. S 曲线减速停止
|
||
print(" [需要硬件] S 曲线减速停止...")
|
||
drv.stop()
|
||
|
||
print(" [完成] StepMotor 演示结束\n")
|
||
|
||
finally:
|
||
# 释放资源(停止电机、关闭 I2C 和 PWM)
|
||
drv.close()
|
||
|
||
|
||
# ============================================================
|
||
# 第四步:ADC(模数转换器)演示 — 采集电压信号
|
||
# ============================================================
|
||
def demo_adc():
|
||
"""
|
||
演示 ADC 的数据采集流程。
|
||
通过 SPI 总线与 ADS124S08 芯片通信,读取应变片电压信号。
|
||
"""
|
||
print("=" * 60)
|
||
print("【ADC】模数转换器演示 — 采集电压信号")
|
||
print("=" * 60)
|
||
|
||
# 创建 ADC 实例(构造函数会自动完成上电和初始化)
|
||
adc = ADS124S08()
|
||
try:
|
||
# 1. 配置 PGA(可编程增益放大器)
|
||
# pga_en=1 启用放大,gain=5 对应 ×32 倍
|
||
print(" [需要硬件] 配置 PGA (×32 倍)...")
|
||
adc.set_pga(pga_en=1, gain=5)
|
||
|
||
# 2. 配置数据速率和转换模式
|
||
# dr=8 对应 200 SPS(每秒 200 次采样)
|
||
# mode=1 单次转换模式(每次触发转换一次)
|
||
print(" [需要硬件] 配置数据速率 (200 SPS, 单次模式)...")
|
||
adc.set_datarate(dr=8, mode=1)
|
||
|
||
# 3. 读取三个通道(0, 1, 2)的数据
|
||
# 返回 24 位有符号整数的列表
|
||
print(" [需要硬件] 读取通道 0/1/2...")
|
||
channels = [0, 1, 2]
|
||
raw_values = adc.request_channels(channels=channels)
|
||
print(f" 原始采样值:{raw_values}")
|
||
|
||
# 4. 将 ADC 原始值转换为电压
|
||
print(" 转换为电压值:")
|
||
for ch, raw in zip(channels, raw_values):
|
||
voltage = adc.convert_to_voltage(raw)
|
||
print(f" 通道 {ch}:{voltage:.6f} V")
|
||
|
||
print(" [完成] ADC 演示结束\n")
|
||
|
||
finally:
|
||
# 关闭 SPI 总线,释放 GPIO 引脚
|
||
adc.close()
|
||
|
||
|
||
# ============================================================
|
||
# 第五步:信号生成演示(纯数学计算,无需硬件)
|
||
# ============================================================
|
||
def demo_signal_generation():
|
||
"""
|
||
演示如何根据频率分量合成周期运动信号。
|
||
这是控制循环中的核心算法,不需要硬件即可运行。
|
||
"""
|
||
print("=" * 60)
|
||
print("【信号合成】周期运动信号生成演示(纯软件,无需硬件)")
|
||
print("=" * 60)
|
||
|
||
# 定义一组简化的信号特征(包含均值 + 两个正弦波分量)
|
||
signal_feature = {
|
||
"mean": 0.0, # 均值(直流分量)
|
||
"components": [ # 正弦波分量列表
|
||
(0.27, 0.005, -1.5), # (频率Hz, 幅值, 相位rad)
|
||
(0.81, 0.001, 2.8), # (频率Hz, 幅值, 相位rad)
|
||
]
|
||
}
|
||
|
||
# 在 3 秒内每隔 0.5 秒生成一个信号值
|
||
print(" 时间(s) | 信号值(m/s) ")
|
||
print(" -------|-------------")
|
||
t = 0.0
|
||
while t <= 3.0:
|
||
# 合成信号:均值 + 各正弦分量之和
|
||
value = signal_feature["mean"]
|
||
for freq, amp, phase in signal_feature["components"]:
|
||
value += amp * math.cos(2 * math.pi * freq * t + phase)
|
||
print(f" {t:5.1f} | {value:+.6f}")
|
||
t += 0.5
|
||
|
||
print(" [完成] 信号合成演示结束\n")
|
||
|
||
|
||
# ============================================================
|
||
# 主程序入口
|
||
# ============================================================
|
||
if __name__ == "__main__":
|
||
print()
|
||
print("⏺ 圆柱水槽控制系统 — 精简演示")
|
||
print("⏺ 本脚本将逐个演示三个驱动模块和信号生成功能")
|
||
print()
|
||
|
||
# 逐个执行演示(按顺序注释掉可以单独运行某个演示)
|
||
demo_encodermotor()
|
||
demo_stepmotor()
|
||
demo_adc()
|
||
demo_signal_generation()
|
||
|
||
print("=" * 60)
|
||
print("所有演示已完成。")
|
||
print("提示:运行 test.ipynb 可以获得更详细的分步讲解。")
|
||
print("=" * 60)
|
||
print()
|