Files
wire_controlsystem/RK1106/stepper_motor.py

212 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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
import os
# ------------参数配置-------------
# 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()