返回教程正文

配套源码

emm.py

app/bricks/zdt_motor/commands/emm.py
zdt_motor Brick:用 Python 控制一台 ZDT 电机app/bricks/zdt_motor/commands/emm.py
Python104 行
"""生成 ZDT Emm 固件使用的速度和位置命令。

当 ``ZDTMotor`` 使用 ``firmware="emm"`` 时,会自动调用本模块。
Emm 固件使用整数 RPM 和 0 至 255 的加速度档位。
"""

from ..config import MotionMode, validate_int, validate_number
from ..errors import ZDTConfigurationError
from ..protocols.zdt import LogicalCommand
from .base import (
    direction_and_magnitude,
    pack_u16,
    pack_u32,
    parse_motion_mode,
    require_whole_number,
)


def build_speed(rpm, *, direction=None, acceleration=10, synchronized=False):
    """
    @description         : 构造Emm固件F6速度模式命令
    @param rpm           : 目标速度,默认设置下为整数RPM,允许用符号表示方向
    @param direction     : cw、ccw或None
    @param acceleration  : Emm加速度档位0至255
    @param synchronized  : True缓存到同步触发,False立即执行
    @return              : LogicalCommand
    """
    resolved_direction, magnitude = direction_and_magnitude(
        "rpm", rpm, direction, 3000
    )
    speed = require_whole_number("rpm", magnitude)
    acceleration_level = validate_int("acceleration", acceleration, 0, 255)
    payload = (
        bytes((resolved_direction,))
        + pack_u16(speed)
        + bytes((acceleration_level, int(bool(synchronized))))
    )
    return LogicalCommand(0xF6, payload, 3, "Emm speed mode")


def degrees_to_pulses(degrees, *, microstep=16, step_angle_degrees=1.8):
    """
    @description         : 按电机步距角和细分把角度转换为Emm脉冲数
    @param degrees       : 非负角度值
    @param microstep     : 细分1至256
    @param step_angle_degrees: 电机步距角0.9或1.8度
    @return              : 四舍五入后的协议脉冲数
    """
    normalized_degrees = validate_number("degrees", degrees, 0, 1e12)
    normalized_microstep = validate_int("microstep", microstep, 1, 256)
    if step_angle_degrees not in (0.9, 1.8):
        raise ZDTConfigurationError("step_angle_degrees must be 0.9 or 1.8")
    pulses = round(
        normalized_degrees * normalized_microstep / step_angle_degrees
    )
    if pulses > 0xFFFFFFFF:
        raise ZDTConfigurationError("degrees exceed Emm uint32 pulse range")
    return pulses


def build_position(
    degrees,
    *,
    rpm,
    direction=None,
    acceleration=10,
    mode=MotionMode.RELATIVE_TO_CURRENT,
    synchronized=False,
    microstep=16,
    step_angle_degrees=1.8,
):
    """
    @description         : 构造Emm固件FD位置模式命令
    @param degrees       : 工程角度,允许用符号表示方向
    @param rpm           : 最大速度,默认设置下为整数RPM
    @param direction     : cw、ccw或None
    @param acceleration  : Emm加速度档位0至255
    @param mode          : 相对当前、相对上一目标或绝对位置
    @param synchronized  : True缓存到同步触发,False立即执行
    @param microstep     : 当前电机细分
    @param step_angle_degrees: 当前电机步距角
    @return              : LogicalCommand
    """
    resolved_direction, magnitude = direction_and_magnitude(
        "degrees", degrees, direction, 1e12
    )
    normalized_rpm = require_whole_number(
        "rpm", validate_number("rpm", rpm, 0, 3000)
    )
    acceleration_level = validate_int("acceleration", acceleration, 0, 255)
    motion_mode = parse_motion_mode(mode)
    pulses = degrees_to_pulses(
        magnitude,
        microstep=microstep,
        step_angle_degrees=step_angle_degrees,
    )
    payload = (
        bytes((resolved_direction,))
        + pack_u16(normalized_rpm)
        + bytes((acceleration_level,))
        + pack_u32(pulses)
        + bytes((motion_mode, int(bool(synchronized))))
    )
    return LogicalCommand(0xFD, payload, 3, "Emm position mode")