Description
Impact summary: The encoder position (EP) is the only source of ground-truth probe position on a stepper drive. Because EP reads are broken for negative values (see below), there is currently no reliable way to verify or recover the actual physical position of the probe in software. The quantity that is recorded — the immediate position (IP) — is the controller's calculated trajectory, which the Applied Motion manual explicitly states is "not always equal to actual position" (Host Command Reference, p.140). Lost steps, stalls, or slip are silently undetected.
After sending IFD on connect (signed-decimal mode), the drive returns negative positions as e.g. EP=-10000. The recv regexes for EP and SP are missing the -? that the IP regex already has, so fullmatch returns None and .group("return") raises an uncaught AttributeError.
Affected file: bapsf_motion/actors/motor_.py
Command | Current regex | Handles negatives? | Manual range
-- | -- | -- | --
get_position (IP) | IP=(?P-?[0-9]+) | ✅ | signed (p.140)
encoder_position (EP) | EP=(?P[0-9]+) | ❌ | ±2,147,483,647 (p.92)
set_position_SP (SP) | SP=(?P[0-9]+) | ❌ | ±2,147,483,647 (p.252)
Steps to reproduce
- Connect to a drive and issue
IFD (signed-decimal mode — done automatically on connect). - Move the stage to any negative encoder position (e.g. zero the encoder partway through travel, then move toward the origin).
- Read the encoder position via
motor.send_command("encoder_position"). recv.fullmatch("EP=-10000") returns None → None.group("return") raises AttributeError.
The write paths (EP<value>, SP<value>) and Motor.zero() / set_position are unaffected — only the read-back regexes are broken.
Fix
Two one-character changes in motor_.py:
# line ~385 — EP read
recv=re.compile(r"EP=(?P<return>-?[0-9]+)"),
line ~513 — SP read
recv=re.compile(r"SP=(?P<return>-?[0-9]+)"),
This mirrors the existing IP regex, which already handles negatives correctly.
Branch sweep: the broken regex is present on every branch that contains motor_.py (main, export_calc_params, ml_name_allow_commas_and_periods, xyz_calculator, xyz_transform, add_game_controller*, custom-style*). The IP regex has -? on all of them.
Additional context
The Applied Motion Host Command Reference confirms:
- EP (p.92): encoder position, signed range ±2,147,483,647
- SP (p.252): step position, same signed range
- IP (p.140): "calculated trajectory position, which is not always equal to actual position"
This bug surfaces in real use whenever the encoder crosses zero (e.g. after zeroing the counter mid-travel). The failure is silent in some call sites — the AttributeError is caught and the axis is skipped — which masks the problem rather than surfacing it.
Description
After sending
IFDon connect (signed-decimal mode), the drive returns negative positions as e.g.EP=-10000. The recv regexes forEPandSPare missing the-?that theIPregex already has, sofullmatchreturnsNoneand.group("return")raises an uncaughtAttributeError.Affected file:
Command | Current regex | Handles negatives? | Manual range -- | -- | -- | -- get_position (IP) | IP=(?P-?[0-9]+) | ✅ | signed (p.140) encoder_position (EP) | EP=(?P[0-9]+) | ❌ | ±2,147,483,647 (p.92) set_position_SP (SP) | SP=(?P[0-9]+) | ❌ | ±2,147,483,647 (p.252)bapsf_motion/actors/motor_.pySteps to reproduce
IFD(signed-decimal mode — done automatically on connect).motor.send_command("encoder_position").recv.fullmatch("EP=-10000")returnsNone→None.group("return")raisesAttributeError.The write paths (
EP<value>,SP<value>) andMotor.zero()/set_positionare unaffected — only the read-back regexes are broken.Fix
Two one-character changes in
motor_.py:This mirrors the existing
IPregex, which already handles negatives correctly.Branch sweep: the broken regex is present on every branch that contains
motor_.py(main,export_calc_params,ml_name_allow_commas_and_periods,xyz_calculator,xyz_transform,add_game_controller*,custom-style*). The IP regex has-?on all of them.Additional context
The Applied Motion Host Command Reference confirms:
This bug surfaces in real use whenever the encoder crosses zero (e.g. after zeroing the counter mid-travel). The failure is silent in some call sites — the
AttributeErroris caught and the axis is skipped — which masks the problem rather than surfacing it.