1. 直线插补基础

任务目标

本案例实现单轴(X轴)的点动控制:按下正向点动按钮,电机以设定速度正向连续运动;按下反向点动按钮,电机反向连续运动;松开按钮立即停止。通过该最小闭环理解运动控制中的速度指令、方向控制与使能/停止三个基本概念,为后续多轴直线插补建立单轴执行基础。

环境与依赖

  • 硬件:任意支持脉冲方向接口的步进/伺服驱动器 + 电机(本案例以逻辑电平模拟验证,不依赖真实硬件)
  • 软件:Python 3.8+,仅使用标准库 threading、time
  • 说明:真实设备接入时,将下方代码中标注的# HARDWARE_IO位置替换为厂商SDK的脉冲输出函数即可,本案例聚焦控制逻辑本身

核心实现

import threading
import time
from enum import Enum

class AxisState(Enum):
    IDLE = 0
    POSITIVE = 1   # 正向点动
    NEGATIVE = -1  # 反向点动

class SingleAxisJog:
    """单轴点动控制器:速度模式,方向由状态决定"""
    def __init__(self, max_speed=1000):  # 单位:脉冲/s
        self.max_speed = max_speed
        self.state = AxisState.IDLE
        self._lock = threading.Lock()
        self._running = False
        self._thread = None

    def _output_pulse(self, direction: int, frequency_hz: float):
        """向驱动器输出脉冲方向信号。
        真实硬件:在此调用SDK的脉冲输出函数,如
        driver.set_pulse(freq=frequency_hz, direction=direction)
        """
        # HARDWARE_IO: 替换为实际脉冲输出调用
        pass

    def _pulse_loop(self):
        """控制周期:按当前状态持续输出脉冲"""
        while self._running:
            with self._lock:
                state = self.state
            if state == AxisState.IDLE:
                self._output_pulse(0, 0)   # 无脉冲
                time.sleep(0.01)
            else:
                direction = 1 if state == AxisState.POSITIVE else -1
                self._output_pulse(direction, self.max_speed)
                time.sleep(0.001)  # 1ms控制周期

    def start(self):
        """启动控制线程"""
        if self._thread and self._thread.is_alive():
            return
        self._running = True
        self._thread = threading.Thread(target=self._pulse_loop, daemon=True)
        self._thread.start()

    def jog_positive(self):
        """正向点动:按下正向按钮时调用"""
        with self._lock:
            self.state = AxisState.POSITIVE

    def jog_negative(self):
        """反向点动:按下反向按钮时调用"""
        with self._lock:
            self.state = AxisState.NEGATIVE

    def stop(self):
        """停止点动:松开按钮时调用"""
        with self._lock:
            self.state = AxisState.IDLE

    def shutdown(self):
        """终止控制线程"""
        self._running = False
        if self._thread:
            self._thread.join(timeout=0.5)
        self._output_pulse(0, 0)

# ---------- 最小验证入口 ----------
if __name__ == "__main__":
    axis = SingleAxisJog(max_speed=500)
    axis.start()

    # 模拟按钮操作序列(无真实硬件时的逻辑验证)
    print("模拟:按下正向点动 0.3s")
    axis.jog_positive()
    time.sleep(0.3)
    assert axis.state == AxisState.POSITIVE, "正向状态错误"

    print("模拟:松开(停止)0.2s")
    axis.stop()
    time.sleep(0.2)
    assert axis.state == AxisState.IDLE, "停止状态错误"

    print("模拟:按下反向点动 0.3s")
    axis.jog_negative()
    time.sleep(0.3)
    assert axis.state == AxisState.NEGATIVE, "反向状态错误"

    axis.stop()
    axis.shutdown()
    print("逻辑验证通过:状态切换与停止行为正确")

运行方式

python single_axis_jog.py

验证方法与判定标准

  • 逻辑验证:运行上述脚本,控制台输出“逻辑验证通过”即表示状态机切换正确(IDLE→正向→IDLE→反向→IDLE)。
  • 硬件验证(如有真实设备):将_output_pulse替换为实际SDK调用后,按下正向按钮,电机应持续正向旋转;松开即停;按下反向按钮,电机反向旋转。若电机方向与预期相反,交换驱动器上的脉冲方向接线即可。
  • 判定标准:按钮按下期间电机保持匀速运动,松开后200ms内完全停止,无自转或抖动。

关键说明

  • 本案例采用速度模式点动:控制线程以固定频率持续输出脉冲,频率对应速度,方向由状态决定。这是工业点动最常用的实现方式。
  • max_speed为最大点动速度(脉冲/s),实际使用时需根据电机额定转速与驱动器细分设置合理值。
  • 控制周期1ms保证松开按钮后能快速响应停止;若使用真实硬件,可根据驱动器最小脉冲宽度调整time.sleep间隔。
  • 本案例未包含加减速规划,点动启停为阶跃速度变化,适用于低速调试;高速场景需引入梯形加减速(后续案例覆盖)。