线条厂各设备控制代码
This commit is contained in:
3
RK1106/.idea/.gitignore
generated
vendored
Normal file
3
RK1106/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
8
RK1106/.idea/Python.iml
generated
Normal file
8
RK1106/.idea/Python.iml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
RK1106/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
RK1106/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
4
RK1106/.idea/misc.xml
generated
Normal file
4
RK1106/.idea/misc.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
RK1106/.idea/modules.xml
generated
Normal file
8
RK1106/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Python.iml" filepath="$PROJECT_DIR$/.idea/Python.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
18
RK1106/ip.sh
Normal file
18
RK1106/ip.sh
Normal file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
# 网络配置脚本:仅设置eth0静态IP(无网关/DNS)
|
||||
case "$1" in
|
||||
start)
|
||||
# 配置eth0静态IP地址和子网掩码(移除多余的反斜杠)
|
||||
ifconfig eth0 192.168.5.100 netmask 255.255.255.0
|
||||
# 可选:添加执行成功提示,方便确认
|
||||
echo "✅ eth0已配置静态IP:192.168.5.100/24"
|
||||
;;
|
||||
stop)
|
||||
;;
|
||||
*)
|
||||
# 补充提示信息,告诉用户正确用法
|
||||
echo "❌ 使用方法:$0 {start|stop}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
5
RK1106/readme.md
Normal file
5
RK1106/readme.md
Normal file
@ -0,0 +1,5 @@
|
||||
# RK1106的IP地址
|
||||
192.168.5.100,自启动设置了IP
|
||||
|
||||
# 测试:
|
||||
先使用stepper_motor_test1进行单独测试,看会不会掉步
|
||||
210
RK1106/stepper_motor.py
Normal file
210
RK1106/stepper_motor.py
Normal file
@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
# @Time : 2026/1/5 15:50
|
||||
# @Author : reenrr
|
||||
# @File : stepper_motor.py
|
||||
# @Desc : 控制步进电机从初始位置移动10cm,移动后回到初始位置
|
||||
'''
|
||||
import time
|
||||
from periphery import GPIO
|
||||
import logging
|
||||
|
||||
# ------------参数配置-------------
|
||||
# 1. 脉冲(PUL)引脚配置 → GPIO32
|
||||
PUL_Pin = 32
|
||||
|
||||
# 2. 方向(DIR)引脚配置 → GPIO33
|
||||
DIR_Pin = 33
|
||||
|
||||
# 3. 驱动器参数(根据拨码调整,默认不变)
|
||||
PULSES_PER_ROUND = 400 # 每圈脉冲数(SW5~SW8拨码,默认400)
|
||||
PULSE_FREQUENCY = 2500 # 脉冲频率(Hz)
|
||||
|
||||
# ------------ 日志+参数配置 ------------
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
log_file_path = os.path.join(script_dir, "stepper_motor.log")
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='[%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
handlers=[
|
||||
logging.StreamHandler(),
|
||||
logging.FileHandler(log_file_path, encoding='utf-8')
|
||||
]
|
||||
)
|
||||
|
||||
class StepperMotor:
|
||||
"""新力川MA860H驱动器步进电机控制类"""
|
||||
# 方向常量定义
|
||||
CLOCKWISE = "clockwise" # 顺时针
|
||||
COUNTER_CLOCKWISE = "counterclockwise" # 逆时针
|
||||
|
||||
def __init__(self,
|
||||
pul_pin: int = PUL_Pin,
|
||||
dir_pin: int = DIR_Pin,
|
||||
pulses_per_round: int = PULSES_PER_ROUND,
|
||||
pulse_frequency: int = PULSE_FREQUENCY,
|
||||
clockwise_level: bool = True,
|
||||
counter_clockwise_level: bool = False):
|
||||
"""
|
||||
初始化步进电机控制器
|
||||
:param pul_pin: 脉冲引脚
|
||||
:param dir_pin: 方向引脚
|
||||
:param pulses_per_round: 每圈脉冲数(SW5~SW8拨码,默认400)
|
||||
:param pulse_frequency: 脉冲频率(Hz,)
|
||||
:param clockwise_level: 顺时针对应的DIR电平
|
||||
:param counter_clockwise_level: 逆时针对应的DIR电平
|
||||
"""
|
||||
# 硬件配置参数
|
||||
self.pul_pin = pul_pin
|
||||
self.dir_pin = dir_pin
|
||||
|
||||
# 驱动器参数
|
||||
self.pulses_per_round = pulses_per_round
|
||||
self.pulse_frequency = pulse_frequency
|
||||
self.clockwise_level = clockwise_level
|
||||
self.counter_clockwise_level = counter_clockwise_level
|
||||
|
||||
# GPIO对象初始化
|
||||
self.pul_gpio = None
|
||||
self.dir_gpio = None
|
||||
|
||||
# 初始化GPIO
|
||||
self._init_gpio()
|
||||
|
||||
def _init_gpio(self):
|
||||
"""初始化PUL和DIR引脚"""
|
||||
try:
|
||||
# 初始化脉冲引脚(输出模式)
|
||||
self.pul_gpio = GPIO(self.pul_pin, "out")
|
||||
# 初始化方向引脚(输出模式)
|
||||
self.dir_gpio = GPIO(self.dir_pin, "out")
|
||||
|
||||
# 初始电平置低(避免电机误动作)
|
||||
self.pul_gpio.write(False)
|
||||
self.dir_gpio.write(False)
|
||||
|
||||
logging.info(f"PUL引脚初始化完成:{self.pul_pin} 引脚")
|
||||
logging.info(f"DIR引脚初始化完成:{self.dir_pin} 引脚")
|
||||
|
||||
except PermissionError:
|
||||
raise RuntimeError("权限不足!请用sudo运行程序(sudo python xxx.py)")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"GPIO初始化失败:{str(e)}") from e
|
||||
|
||||
def _validate_rounds(self, rounds: float) -> bool:
|
||||
"""验证圈数是否合法(内部方法)"""
|
||||
if rounds <= 0:
|
||||
logging.info("圈数必须为正数")
|
||||
return False
|
||||
return True
|
||||
|
||||
def _validate_direction(self, direction: str) -> bool:
|
||||
"""验证方向参数是否合法(内部方法)"""
|
||||
if direction not in [self.CLOCKWISE, self.COUNTER_CLOCKWISE]:
|
||||
logging.info(f"方向参数错误:仅支持 {self.CLOCKWISE}/{self.COUNTER_CLOCKWISE}")
|
||||
return False
|
||||
return True
|
||||
|
||||
def rotate(self, rounds: float, direction: str = CLOCKWISE):
|
||||
"""
|
||||
控制电机旋转(支持正反转)
|
||||
:param rounds: 旋转圈数(可小数,如0.5=半圈)
|
||||
:param direction: 方向(clockwise=顺时针,counterclockwise=逆时针)
|
||||
"""
|
||||
# 参数验证
|
||||
if not self._validate_rounds(rounds) or not self._validate_direction(direction):
|
||||
return
|
||||
|
||||
# 设置旋转方向(DIR电平)
|
||||
if direction == self.CLOCKWISE: # 顺时针
|
||||
self.dir_gpio.write(self.clockwise_level)
|
||||
logging.info(f"\n=== 顺时针旋转 {rounds} 圈 ===")
|
||||
else: # 逆时针
|
||||
self.dir_gpio.write(self.counter_clockwise_level)
|
||||
logging.info(f"\n=== 逆时针旋转 {rounds} 圈 ===")
|
||||
|
||||
# 计算总脉冲数和时序(精准控制,避免丢步)
|
||||
total_pulses = int(rounds * self.pulses_per_round)
|
||||
pulse_period = 1.0 / self.pulse_frequency # 脉冲周期(秒)
|
||||
half_period = pulse_period / 2 # 占空比50%(MA860H最优)
|
||||
|
||||
logging.info(f"总脉冲数:{total_pulses} | 频率:{self.pulse_frequency}Hz | 周期:{pulse_period * 1000:.2f}ms")
|
||||
start_time = time.perf_counter() # 高精度计时(避免丢步)
|
||||
|
||||
# 发送脉冲序列(核心:占空比50%的方波)
|
||||
for _ in range(total_pulses):
|
||||
# 高电平
|
||||
self.pul_gpio.write(True)
|
||||
# 精准延时(比time.sleep稳定,适配高频脉冲)
|
||||
while time.perf_counter() - start_time < half_period:
|
||||
pass
|
||||
# 低电平
|
||||
self.pul_gpio.write(False)
|
||||
# 更新下一个脉冲的起始时间
|
||||
start_time += pulse_period
|
||||
|
||||
logging.info("旋转完成")
|
||||
|
||||
def stop(self):
|
||||
"""紧急停止(置低脉冲引脚)"""
|
||||
if self.pul_gpio:
|
||||
self.pul_gpio.write(False)
|
||||
logging.info("电机已停止")
|
||||
|
||||
def close(self):
|
||||
"""释放GPIO资源"""
|
||||
# 安全释放GPIO资源(关键:避免引脚电平残留)
|
||||
if self.pul_gpio:
|
||||
self.pul_gpio.write(False) # 脉冲引脚置低
|
||||
self.pul_gpio.close()
|
||||
logging.info("\n PUL引脚已关闭(电平置低)")
|
||||
|
||||
if self.dir_gpio:
|
||||
self.dir_gpio.write(False) # 方向引脚置低
|
||||
self.dir_gpio.close()
|
||||
logging.info("DIR引脚已关闭(电平置低)")
|
||||
|
||||
# 重置GPIO对象
|
||||
self.pul_gpio = None
|
||||
self.dir_gpio = None
|
||||
|
||||
def __del__(self):
|
||||
"""析构函数:确保资源释放"""
|
||||
self.close()
|
||||
|
||||
|
||||
#---------控制步进电机外部接口--------------
|
||||
def stepper_motor_control():
|
||||
motor = None
|
||||
try:
|
||||
# 创建电机实例(使用默认配置)
|
||||
motor = StepperMotor()
|
||||
logging.info("\n=== 步进电机控制程序启动 ===")
|
||||
|
||||
# 靠近电机方向 逆时针
|
||||
motor.rotate(rounds=10.0, direction=motor.COUNTER_CLOCKWISE)
|
||||
time.sleep(5) # 暂停5秒
|
||||
# 远离电机方向 顺时针
|
||||
motor.rotate(rounds=10.0, direction=motor.CLOCKWISE)
|
||||
time.sleep(5) # 暂停5秒
|
||||
|
||||
except PermissionError:
|
||||
logging.info("\n 权限不足:请用 sudo 运行!")
|
||||
logging.info("命令:sudo python3 double_direction_motor.py")
|
||||
except ImportError:
|
||||
logging.info("\n 缺少依赖:请安装python-periphery")
|
||||
logging.info("命令:pip install python-periphery")
|
||||
except Exception as e:
|
||||
logging.info(f"\n 程序异常:{str(e)}")
|
||||
finally:
|
||||
if motor:
|
||||
motor.close()
|
||||
logging.info("程序退出完成")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
stepper_motor_control()
|
||||
|
||||
159
RK1106/stepper_motor_test.py
Normal file
159
RK1106/stepper_motor_test.py
Normal file
@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
# @Time : 2026/1/4 15:06
|
||||
# @Author : reenrr
|
||||
# @File : stepper_motor_test.py
|
||||
# @Desc : 线条厂控制步进电机
|
||||
"""
|
||||
import time
|
||||
from periphery import GPIO
|
||||
import sys
|
||||
sys.setswitchinterval(0.000001) # 减小线程切换间隔
|
||||
|
||||
# --------------
|
||||
# 硬件参数配置(必须与你的设备匹配!)
|
||||
# --------------
|
||||
# 1. 脉冲(PUL)引脚配置 → GPIO32
|
||||
PUL_Pin = 32
|
||||
|
||||
# 2. 方向(DIR)引脚配置 → GPIO33
|
||||
DIR_Pin = 33
|
||||
|
||||
# 3. LCDA257C驱动器核心参数(关键!与拨码/软件设置一致)
|
||||
PULSES_PER_ROUND = 400 # 每圈脉冲数(按驱动器细分拨码调整)
|
||||
PULSE_FREQUENCY = 5000 # 初始测试频率(建议从500开始逐步调高)
|
||||
|
||||
# 4. LCDA257C时序参数(遵循手册要求,不可低于最小值)
|
||||
MIN_DIR_DELAY_US = 10 # DIR提前PUL的最小延迟(>8us)
|
||||
PULSE_LOW_MIN_US = 2 # 脉冲低电平最小宽度(≥2us)
|
||||
PULSE_HIGH_MIN_US = 2 # 脉冲高电平最小宽度(≥2us)
|
||||
|
||||
# 5. 方向电平定义(可根据实际测试调整)
|
||||
CLOCKWISE_LEVEL = True # 顺时针→DIR高电平
|
||||
COUNTER_CLOCKWISE_LEVEL = False # 逆时针→DIR低电平
|
||||
|
||||
|
||||
def init_stepper() -> tuple[GPIO, GPIO]:
|
||||
"""初始化PUL和DIR引脚(输出模式,适配LCDA257C)"""
|
||||
try:
|
||||
# 初始化脉冲引脚(输出模式)
|
||||
pul_gpio = GPIO(PUL_Pin, "out")
|
||||
# 初始化方向引脚(输出模式)
|
||||
dir_gpio = GPIO(DIR_Pin, "out")
|
||||
|
||||
# 初始状态:脉冲低电平,方向低电平(驱动器空闲状态)
|
||||
pul_gpio.write(False)
|
||||
dir_gpio.write(False)
|
||||
|
||||
print(f"✅ PUL引脚初始化完成:{PUL_Pin}引脚")
|
||||
print(f"✅ DIR引脚初始化完成:{DIR_Pin}引脚")
|
||||
return pul_gpio, dir_gpio
|
||||
|
||||
except FileNotFoundError:
|
||||
raise RuntimeError(f"GPIO芯片不存在!检查 {PUL_Pin} 是否存在(命令:ls /dev/gpiochip*)")
|
||||
except PermissionError:
|
||||
raise RuntimeError("GPIO权限不足!请用 sudo 运行程序(sudo python test.py)")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"GPIO初始化失败:{str(e)}") from e
|
||||
|
||||
|
||||
def rotate(pul_gpio: GPIO, dir_gpio: GPIO, rounds: float, direction: str = "clockwise",
|
||||
test_freq: int = PULSE_FREQUENCY):
|
||||
"""
|
||||
控制LCDA257C驱动器旋转(优化版脉冲发送,解决频率不生效问题)
|
||||
:param pul_gpio: PUL引脚GPIO对象
|
||||
:param dir_gpio: DIR引脚GPIO对象
|
||||
:param rounds: 旋转圈数(正数,可小数)
|
||||
:param direction: 方向(clockwise/counterclockwise)
|
||||
:param test_freq: 本次旋转使用的脉冲频率(覆盖全局默认值)
|
||||
"""
|
||||
# 1. 参数合法性校验
|
||||
if rounds <= 0:
|
||||
print("❌ 圈数必须为正数!")
|
||||
return
|
||||
if test_freq < 100:
|
||||
print("❌ 频率过低(≥100Hz),请调整test_freq参数!")
|
||||
return
|
||||
|
||||
# 2. 设置旋转方向(严格遵循DIR提前时序)
|
||||
if direction == "clockwise":
|
||||
dir_gpio.write(CLOCKWISE_LEVEL)
|
||||
print(f"\n=== 顺时针旋转 {rounds} 圈(目标频率:{test_freq}Hz)===")
|
||||
elif direction == "counterclockwise":
|
||||
dir_gpio.write(COUNTER_CLOCKWISE_LEVEL)
|
||||
print(f"\n=== 逆时针旋转 {rounds} 圈(目标频率:{test_freq}Hz)===")
|
||||
else:
|
||||
print("❌ 方向参数错误!仅支持 clockwise/counterclockwise")
|
||||
return
|
||||
|
||||
# DIR电平设置后,延迟≥8us(满足LCDA257C时序要求)
|
||||
time.sleep(MIN_DIR_DELAY_US / 1_000_000)
|
||||
|
||||
# 3. 计算脉冲参数(确保高低电平≥最小宽度)
|
||||
total_pulses = int(rounds * PULSES_PER_ROUND)
|
||||
pulse_period = 1.0 / test_freq # 脉冲周期(秒)
|
||||
|
||||
# 确保高低电平宽度不低于驱动器要求(避免脉冲识别失败)
|
||||
high_period = max(pulse_period / 2, PULSE_HIGH_MIN_US / 1_000_000)
|
||||
low_period = max(pulse_period / 2, PULSE_LOW_MIN_US / 1_000_000)
|
||||
|
||||
# 打印参数(便于调试)
|
||||
print(f"总脉冲数:{total_pulses} | 理论高电平:{high_period * 1e6:.1f}us | 理论低电平:{low_period * 1e6:.1f}us")
|
||||
|
||||
# 4. 优化版脉冲发送(解决Python高频延时不准问题)
|
||||
start_total = time.perf_counter() # 高精度计时(统计实际频率)
|
||||
for _ in range(total_pulses):
|
||||
# 高电平(直接sleep,避免while循环的调度延迟)
|
||||
pul_gpio.write(True)
|
||||
time.sleep(high_period)
|
||||
|
||||
# 低电平
|
||||
pul_gpio.write(False)
|
||||
time.sleep(low_period)
|
||||
end_total = time.perf_counter()
|
||||
|
||||
# 5. 计算实际频率(验证是否达到目标)
|
||||
actual_duration = end_total - start_total
|
||||
actual_freq = total_pulses / actual_duration if actual_duration > 0 else 0
|
||||
print(f"✅ 旋转完成 | 实际频率:{actual_freq:.0f}Hz | 耗时:{actual_duration:.2f}秒")
|
||||
|
||||
|
||||
def motor_test_demo():
|
||||
"""电机测试示例(逐步提升频率,验证转速变化)"""
|
||||
pul_gpio = None
|
||||
dir_gpio = None
|
||||
try:
|
||||
# 初始化引脚
|
||||
pul_gpio, dir_gpio = init_stepper()
|
||||
print("\n=== 步进电机频率测试程序启动 ===")
|
||||
|
||||
while True:
|
||||
print(f"\n===== 测试频率:{PULSE_FREQUENCY}Hz =====")
|
||||
|
||||
# 远离电机方向 顺时针
|
||||
rotate(pul_gpio, dir_gpio, rounds=10.0, direction="clockwise")
|
||||
time.sleep(5) #
|
||||
# 靠近电机方向 逆时针
|
||||
rotate(pul_gpio, dir_gpio, rounds=10.0, direction="counterclockwise")
|
||||
time.sleep(5) #
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ 程序异常:{str(e)}")
|
||||
finally:
|
||||
# 安全释放GPIO资源(必须执行,避免引脚电平残留)
|
||||
if pul_gpio:
|
||||
pul_gpio.write(False)
|
||||
pul_gpio.close()
|
||||
print("\n✅ PUL引脚已关闭(低电平)")
|
||||
if dir_gpio:
|
||||
dir_gpio.write(False)
|
||||
dir_gpio.close()
|
||||
print("✅ DIR引脚已关闭(低电平)")
|
||||
print("✅ 程序退出完成")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 运行测试demo(必须sudo执行)
|
||||
motor_test_demo()
|
||||
|
||||
198
RK1106/stepper_motor_test1.py
Normal file
198
RK1106/stepper_motor_test1.py
Normal file
@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
# @Time : 2026/1/4 19:13
|
||||
# @Author : reenrr
|
||||
# @File : stepper_motor_test1.py
|
||||
# @Desc : 线条厂控制步进电机测试 应该不会丢步
|
||||
"""
|
||||
import time
|
||||
from periphery import GPIO # 若未安装:pip install python-periphery
|
||||
|
||||
# ------------参数配置-------------
|
||||
# 1. 脉冲(PUL)引脚配置 → GPIO32
|
||||
PUL_Pin = 32
|
||||
|
||||
# 2. 方向(DIR)引脚配置 → GPIO33
|
||||
DIR_Pin = 33
|
||||
|
||||
# 3. 驱动器参数(根据拨码调整,默认不变)
|
||||
PULSES_PER_ROUND = 400 # 每圈脉冲数(SW5~SW8拨码,默认400)
|
||||
PULSE_FREQUENCY = 2500 # 脉冲频率(Hz,新手建议500~2000,最大200KHz)
|
||||
|
||||
class StepperMotor:
|
||||
"""新力川MA860H驱动器步进电机控制类"""
|
||||
# 方向常量定义
|
||||
CLOCKWISE = "clockwise" # 顺时针
|
||||
COUNTER_CLOCKWISE = "counterclockwise" # 逆时针
|
||||
|
||||
def __init__(self,
|
||||
pul_pin: int = PUL_Pin,
|
||||
dir_pin: int = DIR_Pin,
|
||||
pulses_per_round: int = PULSES_PER_ROUND,
|
||||
pulse_frequency: int = PULSE_FREQUENCY,
|
||||
clockwise_level: bool = True,
|
||||
counter_clockwise_level: bool = False):
|
||||
"""
|
||||
初始化步进电机控制器
|
||||
:param pul_pin: 脉冲引脚
|
||||
:param dir_pin: 方向引脚
|
||||
:param pulses_per_round: 每圈脉冲数(SW5~SW8拨码,默认400)
|
||||
:param pulse_frequency: 脉冲频率(Hz,新手建议500~2000,最大200KHz)
|
||||
:param clockwise_level: 顺时针对应的DIR电平
|
||||
:param counter_clockwise_level: 逆时针对应的DIR电平
|
||||
"""
|
||||
# 硬件配置参数
|
||||
self.pul_pin = pul_pin
|
||||
self.dir_pin = dir_pin
|
||||
|
||||
# 驱动器参数
|
||||
self.pulses_per_round = pulses_per_round
|
||||
self.pulse_frequency = pulse_frequency
|
||||
self.clockwise_level = clockwise_level
|
||||
self.counter_clockwise_level = counter_clockwise_level
|
||||
|
||||
# GPIO对象初始化
|
||||
self.pul_gpio = None
|
||||
self.dir_gpio = None
|
||||
|
||||
# 初始化GPIO
|
||||
self._init_gpio()
|
||||
|
||||
def _init_gpio(self):
|
||||
"""初始化PUL和DIR引脚(内部方法)"""
|
||||
try:
|
||||
# 初始化脉冲引脚(输出模式)
|
||||
self.pul_gpio = GPIO(self.pul_pin, "out")
|
||||
# 初始化方向引脚(输出模式)
|
||||
self.dir_gpio = GPIO(self.dir_pin, "out")
|
||||
|
||||
# 初始电平置低(避免电机误动作)
|
||||
self.pul_gpio.write(False)
|
||||
self.dir_gpio.write(False)
|
||||
|
||||
print(f"✅ PUL引脚初始化完成:{self.pul_pin} 引脚")
|
||||
print(f"✅ DIR引脚初始化完成:{self.dir_pin} 引脚")
|
||||
|
||||
except PermissionError:
|
||||
raise RuntimeError("权限不足!请用sudo运行程序(sudo python xxx.py)")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"GPIO初始化失败:{str(e)}") from e
|
||||
|
||||
def _validate_rounds(self, rounds: float) -> bool:
|
||||
"""验证圈数是否合法(内部方法)"""
|
||||
if rounds <= 0:
|
||||
print("❌ 圈数必须为正数")
|
||||
return False
|
||||
return True
|
||||
|
||||
def _validate_direction(self, direction: str) -> bool:
|
||||
"""验证方向参数是否合法(内部方法)"""
|
||||
if direction not in [self.CLOCKWISE, self.COUNTER_CLOCKWISE]:
|
||||
print(f"❌ 方向参数错误:仅支持 {self.CLOCKWISE}/{self.COUNTER_CLOCKWISE}")
|
||||
return False
|
||||
return True
|
||||
|
||||
def rotate(self, rounds: float, direction: str = CLOCKWISE):
|
||||
"""
|
||||
控制电机旋转(支持正反转)
|
||||
:param rounds: 旋转圈数(可小数,如0.5=半圈)
|
||||
:param direction: 方向(clockwise=顺时针,counterclockwise=逆时针)
|
||||
"""
|
||||
# 参数验证
|
||||
if not self._validate_rounds(rounds) or not self._validate_direction(direction):
|
||||
return
|
||||
|
||||
# 设置旋转方向(DIR电平)
|
||||
if direction == self.CLOCKWISE: # 顺时针
|
||||
self.dir_gpio.write(self.clockwise_level)
|
||||
print(f"\n=== 顺时针旋转 {rounds} 圈 ===")
|
||||
else: # 逆时针
|
||||
self.dir_gpio.write(self.counter_clockwise_level)
|
||||
print(f"\n=== 逆时针旋转 {rounds} 圈 ===")
|
||||
|
||||
# 计算总脉冲数和时序(精准控制,避免丢步)
|
||||
total_pulses = int(rounds * self.pulses_per_round)
|
||||
pulse_period = 1.0 / self.pulse_frequency # 脉冲周期(秒)
|
||||
half_period = pulse_period / 2 # 占空比50%(MA860H最优)
|
||||
|
||||
print(f"总脉冲数:{total_pulses} | 频率:{self.pulse_frequency}Hz | 周期:{pulse_period * 1000:.2f}ms")
|
||||
start_time = time.perf_counter() # 高精度计时(避免丢步)
|
||||
|
||||
# 发送脉冲序列(核心:占空比50%的方波)
|
||||
for _ in range(total_pulses):
|
||||
# 高电平
|
||||
self.pul_gpio.write(True)
|
||||
# 精准延时(比time.sleep稳定,适配高频脉冲)
|
||||
while time.perf_counter() - start_time < half_period:
|
||||
pass
|
||||
# 低电平
|
||||
self.pul_gpio.write(False)
|
||||
# 更新下一个脉冲的起始时间
|
||||
start_time += pulse_period
|
||||
|
||||
print("✅ 旋转完成")
|
||||
|
||||
def stop(self):
|
||||
"""紧急停止(置低脉冲引脚)"""
|
||||
if self.pul_gpio:
|
||||
self.pul_gpio.write(False)
|
||||
print("🛑 电机已停止")
|
||||
|
||||
def close(self):
|
||||
"""释放GPIO资源"""
|
||||
# 安全释放GPIO资源(关键:避免引脚电平残留)
|
||||
if self.pul_gpio:
|
||||
self.pul_gpio.write(False) # 脉冲引脚置低
|
||||
self.pul_gpio.close()
|
||||
print("\n✅ PUL引脚已关闭(电平置低)")
|
||||
|
||||
if self.dir_gpio:
|
||||
self.dir_gpio.write(False) # 方向引脚置低
|
||||
self.dir_gpio.close()
|
||||
print("✅ DIR引脚已关闭(电平置低)")
|
||||
|
||||
# 重置GPIO对象
|
||||
self.pul_gpio = None
|
||||
self.dir_gpio = None
|
||||
|
||||
def __del__(self):
|
||||
"""析构函数:确保资源释放"""
|
||||
self.close()
|
||||
|
||||
|
||||
# 使用示例
|
||||
def motor_demo():
|
||||
"""电机控制示例"""
|
||||
motor = None
|
||||
try:
|
||||
# 创建电机实例(使用默认配置)
|
||||
motor = StepperMotor()
|
||||
print("\n=== 步进电机控制程序启动 ===")
|
||||
|
||||
while True:
|
||||
# 靠近电机方向 逆时针
|
||||
motor.rotate(rounds=10.0, direction=motor.COUNTER_CLOCKWISE)
|
||||
time.sleep(5) # 暂停5秒
|
||||
# 远离电机方向 顺时针
|
||||
motor.rotate(rounds=10.0, direction=motor.CLOCKWISE)
|
||||
time.sleep(5) # 暂停5秒
|
||||
|
||||
|
||||
except PermissionError:
|
||||
print("\n❌ 权限不足:请用 sudo 运行!")
|
||||
print("命令:sudo python3 double_direction_motor.py")
|
||||
except ImportError:
|
||||
print("\n❌ 缺少依赖:请安装python-periphery")
|
||||
print("命令:pip install python-periphery")
|
||||
except Exception as e:
|
||||
print(f"\n❌ 程序异常:{str(e)}")
|
||||
finally:
|
||||
if motor:
|
||||
motor.close()
|
||||
print("✅ 程序退出完成")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
motor_demo()
|
||||
|
||||
292
RK1106/test.py
Normal file
292
RK1106/test.py
Normal file
@ -0,0 +1,292 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
# @Time : 2026/1/5 16:18
|
||||
# @Author : reenrr
|
||||
# @File : test.py
|
||||
# @Desc : 步进电机添加记录脉冲数量(防止断电情况)
|
||||
'''
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
from periphery import GPIO
|
||||
|
||||
# ------------参数配置-------------
|
||||
# 1. 脉冲(PUL)引脚配置 → GPIO32
|
||||
PUL_Pin = 32
|
||||
|
||||
# 2. 方向(DIR)引脚配置 → GPIO33
|
||||
DIR_Pin = 33
|
||||
|
||||
# 3. 驱动器参数(根据拨码调整,默认不变)
|
||||
PULSES_PER_ROUND = 400 # 每圈脉冲数(SW5~SW8拨码,默认400)
|
||||
PULSE_FREQUENCY = 2500 # 脉冲频率(Hz,新手建议500~2000,最大200KHz)
|
||||
|
||||
# 4. 计数持久化配置
|
||||
COUNT_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "motor_pulse_count.json")
|
||||
SAVE_INTERVAL = 10 # 每发送10个脉冲保存一次计数(减少IO开销,可根据需求调整)
|
||||
|
||||
class StepperMotor:
|
||||
"""新力川MA860H驱动器步进电机控制类"""
|
||||
# 方向常量定义
|
||||
CLOCKWISE = "clockwise" # 顺时针
|
||||
COUNTER_CLOCKWISE = "counterclockwise" # 逆时针
|
||||
|
||||
def __init__(self,
|
||||
pul_pin: int = PUL_Pin,
|
||||
dir_pin: int = DIR_Pin,
|
||||
pulses_per_round: int = PULSES_PER_ROUND,
|
||||
pulse_frequency: int = PULSE_FREQUENCY,
|
||||
clockwise_level: bool = True,
|
||||
counter_clockwise_level: bool = False):
|
||||
"""
|
||||
初始化步进电机控制器
|
||||
:param pul_pin: 脉冲引脚
|
||||
:param dir_pin: 方向引脚
|
||||
:param pulses_per_round: 每圈脉冲数(SW5~SW8拨码,默认400)
|
||||
:param pulse_frequency: 脉冲频率(Hz,新手建议500~2000,最大200KHz)
|
||||
:param clockwise_level: 顺时针对应的DIR电平
|
||||
:param counter_clockwise_level: 逆时针对应的DIR电平
|
||||
"""
|
||||
# 硬件配置参数
|
||||
self.pul_pin = pul_pin
|
||||
self.dir_pin = dir_pin
|
||||
|
||||
# 驱动器参数
|
||||
self.pulses_per_round = pulses_per_round
|
||||
self.pulse_frequency = pulse_frequency
|
||||
self.clockwise_level = clockwise_level
|
||||
self.counter_clockwise_level = counter_clockwise_level
|
||||
|
||||
# GPIO对象初始化
|
||||
self.pul_gpio = None
|
||||
self.dir_gpio = None
|
||||
|
||||
# 脉冲计数相关(核心:记录已发送的脉冲数)
|
||||
self.current_pulse_count = 0 # 本次旋转已发送的脉冲数
|
||||
self.total_pulse_history = self._load_pulse_count() # 历史总脉冲数(从文件加载)
|
||||
self.current_rotate_target = 0 # 本次旋转的目标脉冲数
|
||||
|
||||
# 初始化GPIO
|
||||
self._init_gpio()
|
||||
|
||||
def _load_pulse_count(self):
|
||||
"""加载历史脉冲计数(程序启动时执行)"""
|
||||
try:
|
||||
if os.path.exists(COUNT_FILE):
|
||||
with open(COUNT_FILE, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
# 返回历史总脉冲数(默认0)
|
||||
return int(data.get("total_pulses", 0))
|
||||
except Exception as e:
|
||||
print(f"[WARN] 加载历史计数失败:{e},将从0开始计数")
|
||||
return 0
|
||||
|
||||
def _save_pulse_count(self):
|
||||
"""保存当前总脉冲数到文件(持久化)"""
|
||||
try:
|
||||
with open(COUNT_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump({
|
||||
"total_pulses": self.total_pulse_history,
|
||||
"update_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
||||
}, f, ensure_ascii=False, indent=2)
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 保存计数失败:{e}")
|
||||
|
||||
def _init_gpio(self):
|
||||
"""初始化PUL和DIR引脚(内部方法)"""
|
||||
try:
|
||||
# 初始化脉冲引脚(输出模式)
|
||||
self.pul_gpio = GPIO(self.pul_pin, "out")
|
||||
# 初始化方向引脚(输出模式)
|
||||
self.dir_gpio = GPIO(self.dir_pin, "out")
|
||||
|
||||
# 初始电平置低(避免电机误动作)
|
||||
self.pul_gpio.write(False)
|
||||
self.dir_gpio.write(False)
|
||||
|
||||
print(f"[OK] PUL引脚初始化完成:{self.pul_pin} 引脚")
|
||||
print(f"[OK] DIR引脚初始化完成:{self.dir_pin} 引脚")
|
||||
print(
|
||||
f"[INFO] 历史累计脉冲数:{self.total_pulse_history} → 对应圈数:{self.total_pulse_history / self.pulses_per_round:.2f} 圈")
|
||||
|
||||
except PermissionError:
|
||||
raise RuntimeError("权限不足!请用sudo运行程序(sudo python xxx.py)")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"GPIO初始化失败:{str(e)}") from e
|
||||
|
||||
def _validate_rounds(self, rounds: float) -> bool:
|
||||
"""验证圈数是否合法(内部方法)"""
|
||||
if rounds <= 0:
|
||||
print("[ERROR] 圈数必须为正数")
|
||||
return False
|
||||
return True
|
||||
|
||||
def _validate_direction(self, direction: str) -> bool:
|
||||
"""验证方向参数是否合法(内部方法)"""
|
||||
if direction not in [self.CLOCKWISE, self.COUNTER_CLOCKWISE]:
|
||||
print(f"[ERROR] 方向参数错误:仅支持 {self.CLOCKWISE}/{self.COUNTER_CLOCKWISE}")
|
||||
return False
|
||||
return True
|
||||
|
||||
def rotate(self, rounds: float, direction: str = CLOCKWISE):
|
||||
"""
|
||||
控制电机旋转(支持正反转,实时记录脉冲数)
|
||||
:param rounds: 旋转圈数(可小数,如0.5=半圈)
|
||||
:param direction: 方向(clockwise=顺时针,counterclockwise=逆时针)
|
||||
"""
|
||||
# 参数验证
|
||||
if not self._validate_rounds(rounds) or not self._validate_direction(direction):
|
||||
return
|
||||
|
||||
# 重置本次旋转的计数
|
||||
self.current_pulse_count = 0
|
||||
# 计算本次旋转的目标脉冲数
|
||||
self.current_rotate_target = int(rounds * self.pulses_per_round)
|
||||
|
||||
# 设置旋转方向(DIR电平)
|
||||
if direction == self.CLOCKWISE: # 顺时针
|
||||
self.dir_gpio.write(self.clockwise_level)
|
||||
print(f"\n=== 顺时针旋转 {rounds} 圈 ===")
|
||||
else: # 逆时针
|
||||
self.dir_gpio.write(self.counter_clockwise_level)
|
||||
print(f"\n=== 逆时针旋转 {rounds} 圈 ===")
|
||||
|
||||
# 计算总脉冲数和时序(精准控制,避免丢步)
|
||||
total_pulses = self.current_rotate_target
|
||||
pulse_period = 1.0 / self.pulse_frequency # 脉冲周期(秒)
|
||||
half_period = pulse_period / 2 # 占空比50%(MA860H最优)
|
||||
|
||||
print(f"目标脉冲数:{total_pulses} | 频率:{self.pulse_frequency}Hz | 周期:{pulse_period * 1000:.2f}ms")
|
||||
start_time = time.perf_counter() # 高精度计时(避免丢步)
|
||||
|
||||
try:
|
||||
# 发送脉冲序列(核心:占空比50%的方波,实时计数)
|
||||
for _ in range(total_pulses):
|
||||
# 高电平
|
||||
self.pul_gpio.write(True)
|
||||
# 精准延时(比time.sleep稳定,适配高频脉冲)
|
||||
while time.perf_counter() - start_time < half_period:
|
||||
pass
|
||||
# 低电平
|
||||
self.pul_gpio.write(False)
|
||||
# 更新下一个脉冲的起始时间
|
||||
start_time += pulse_period
|
||||
|
||||
# 🌟 核心:累加本次脉冲计数
|
||||
self.current_pulse_count += 1
|
||||
self.total_pulse_history += 1
|
||||
|
||||
# 每发送SAVE_INTERVAL个脉冲,保存一次计数(减少IO开销)
|
||||
if self.current_pulse_count % SAVE_INTERVAL == 0:
|
||||
self._save_pulse_count()
|
||||
|
||||
print(
|
||||
f"[OK] 旋转完成 → 本次发送脉冲:{self.current_pulse_count} | 累计脉冲:{self.total_pulse_history} | 累计圈数:{self.total_pulse_history / self.pulses_per_round:.2f}")
|
||||
|
||||
except Exception as e:
|
||||
# 🌟 关键:异常发生时(如断电前的程序崩溃),立即保存当前计数
|
||||
self._save_pulse_count()
|
||||
# 计算已完成的圈数
|
||||
completed_rounds = self.current_pulse_count / self.pulses_per_round
|
||||
remaining_pulses = self.current_rotate_target - self.current_pulse_count
|
||||
remaining_rounds = remaining_pulses / self.pulses_per_round
|
||||
print(f"\n[ERROR] 旋转过程中异常:{e}")
|
||||
print(f"[INFO] 异常时已发送脉冲:{self.current_pulse_count} → 已完成圈数:{completed_rounds:.2f}")
|
||||
print(f"[INFO] 剩余未发送脉冲:{remaining_pulses} → 剩余圈数:{remaining_rounds:.2f}")
|
||||
print(
|
||||
f"[INFO] 累计总脉冲:{self.total_pulse_history} → 累计总圈数:{self.total_pulse_history / self.pulses_per_round:.2f}")
|
||||
raise # 抛出异常,让上层处理
|
||||
|
||||
def get_current_status(self):
|
||||
"""获取当前电机状态(脉冲数、圈数)"""
|
||||
return {
|
||||
"total_pulses": self.total_pulse_history,
|
||||
"total_rounds": self.total_pulse_history / self.pulses_per_round,
|
||||
"last_rotate_completed_pulses": self.current_pulse_count,
|
||||
"last_rotate_completed_rounds": self.current_pulse_count / self.pulses_per_round,
|
||||
"last_rotate_target_pulses": self.current_rotate_target,
|
||||
"last_rotate_target_rounds": self.current_rotate_target / self.pulses_per_round
|
||||
}
|
||||
|
||||
def reset_count(self):
|
||||
"""重置累计计数(按需使用,如电机归位后)"""
|
||||
self.total_pulse_history = 0
|
||||
self._save_pulse_count()
|
||||
print("[INFO] 累计脉冲计数已重置为0")
|
||||
|
||||
def stop(self):
|
||||
"""紧急停止(置低脉冲引脚)"""
|
||||
if self.pul_gpio:
|
||||
self.pul_gpio.write(False)
|
||||
# 停止时保存当前计数
|
||||
self._save_pulse_count()
|
||||
print("[STOP] 电机已停止,当前计数已保存")
|
||||
|
||||
def close(self):
|
||||
"""释放GPIO资源"""
|
||||
# 安全释放GPIO资源(关键:避免引脚电平残留)
|
||||
if self.pul_gpio:
|
||||
self.pul_gpio.write(False) # 脉冲引脚置低
|
||||
self.pul_gpio.close()
|
||||
print("\n[OK] PUL引脚已关闭(电平置低)")
|
||||
|
||||
if self.dir_gpio:
|
||||
self.dir_gpio.write(False) # 方向引脚置低
|
||||
self.dir_gpio.close()
|
||||
print("[OK] DIR引脚已关闭(电平置低)")
|
||||
|
||||
# 关闭时保存最终计数
|
||||
self._save_pulse_count()
|
||||
print(
|
||||
f"[INFO] 最终累计脉冲:{self.total_pulse_history} → 累计圈数:{self.total_pulse_history / self.pulses_per_round:.2f}")
|
||||
|
||||
# 重置GPIO对象
|
||||
self.pul_gpio = None
|
||||
self.dir_gpio = None
|
||||
|
||||
def __del__(self):
|
||||
"""析构函数:确保资源释放"""
|
||||
self.close()
|
||||
|
||||
# 使用示例
|
||||
def motor_demo():
|
||||
"""电机控制示例"""
|
||||
motor = None
|
||||
try:
|
||||
# 创建电机实例(使用默认配置)
|
||||
motor = StepperMotor()
|
||||
print("\n=== 步进电机控制程序启动 ===")
|
||||
# 打印初始状态
|
||||
init_status = motor.get_current_status()
|
||||
print(f"[INIT] 初始状态 → 累计圈数:{init_status['total_rounds']:.2f} 圈")
|
||||
|
||||
while True:
|
||||
# 靠近电机方向 逆时针
|
||||
motor.rotate(rounds=10.0, direction=motor.COUNTER_CLOCKWISE)
|
||||
time.sleep(5) # 暂停5秒
|
||||
# 远离电机方向 顺时针
|
||||
motor.rotate(rounds=10.0, direction=motor.CLOCKWISE)
|
||||
time.sleep(5) # 暂停5秒
|
||||
|
||||
except PermissionError:
|
||||
print("\n[ERROR] 权限不足:请用 sudo 运行!")
|
||||
print("命令:sudo python3 double_direction_motor.py")
|
||||
except ImportError:
|
||||
print("\n[ERROR] 缺少依赖:请安装python-periphery")
|
||||
print("命令:pip install python-periphery")
|
||||
except KeyboardInterrupt:
|
||||
print("\n[INFO] 用户手动停止程序")
|
||||
except Exception as e:
|
||||
print(f"\n[ERROR] 程序异常:{str(e)}")
|
||||
finally:
|
||||
if motor:
|
||||
# 打印最终状态
|
||||
final_status = motor.get_current_status()
|
||||
print(f"\n[FINAL] 程序退出状态 → 累计脉冲:{final_status['total_pulses']} | 累计圈数:{final_status['total_rounds']:.2f} 圈")
|
||||
motor.close()
|
||||
print("[OK] 程序退出完成")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
motor_demo()
|
||||
Reference in New Issue
Block a user