Z轴可利用代码控制移动
This commit is contained in:
@@ -17,6 +17,7 @@ No test here touches a controller or a DLL.
|
||||
from __future__ import annotations
|
||||
|
||||
import ctypes
|
||||
import logging
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
@@ -25,6 +26,7 @@ from orisys_autocal.motion import (
|
||||
DEFAULT_BAS_TASK,
|
||||
INIT_OK,
|
||||
INIT_RUNNING,
|
||||
BusStatus,
|
||||
ConnectionSpec,
|
||||
DemoTransport,
|
||||
MotionService,
|
||||
@@ -224,6 +226,44 @@ def test_adopted_program_without_a_known_file_says_so():
|
||||
assert "文件名" in result.message or "file name" in result.message
|
||||
|
||||
|
||||
def test_connect_reads_axis_4_and_does_not_write_parameters(caplog):
|
||||
"""Connecting must not replace configuration the vendor software just set."""
|
||||
transport = DemoTransport()
|
||||
writes: list[tuple] = []
|
||||
transport.set_units = lambda axis, value: writes.append(("units", axis, value))
|
||||
transport.set_speed = lambda axis, value: writes.append(("speed", axis, value))
|
||||
transport.set_accel = lambda axis, value: writes.append(("accel", axis, value))
|
||||
transport.bas_download = lambda filename, run_mode=1: writes.append(("bas", filename))
|
||||
service = MotionService(transport)
|
||||
|
||||
with caplog.at_level(logging.INFO):
|
||||
result = service.connect(ConnectionSpec(mode="demo"))
|
||||
|
||||
assert result.ok, result.message
|
||||
assert writes == []
|
||||
readback = [record.message for record in caplog.records if record.message.startswith("connect axis 4")]
|
||||
assert readback, caplog.text
|
||||
assert "mpos=" in readback[-1]
|
||||
assert "not written" in caplog.text
|
||||
|
||||
|
||||
def test_axis_4_jog_reuses_the_shared_motion_call_and_logs_position(caplog):
|
||||
service = MotionService(DemoTransport())
|
||||
assert service.connect(ConnectionSpec(mode="demo")).ok
|
||||
service._bus = BusStatus(bus_type="ecat", init_status=INIT_OK, total_axes=4) # noqa: SLF001
|
||||
|
||||
with caplog.at_level(logging.INFO):
|
||||
result = service.jog(4, True)
|
||||
|
||||
assert result.ok, result.message
|
||||
assert result.code == 0
|
||||
logged = [record.message for record in caplog.records if record.message.startswith("jog axis 4")]
|
||||
assert logged, caplog.text
|
||||
assert "ok=True" in logged[-1]
|
||||
assert "code=0" in logged[-1]
|
||||
assert "mpos=" in logged[-1]
|
||||
|
||||
|
||||
def test_reinit_needs_the_bus_not_to_be_mid_run():
|
||||
service = MotionService(DemoTransport())
|
||||
service.connect(ConnectionSpec(mode="demo"))
|
||||
|
||||
@@ -19,7 +19,7 @@ from __future__ import annotations
|
||||
|
||||
from orisys_app_shared.i18n import t
|
||||
|
||||
from orisys_autocal.motion import BusStatus
|
||||
from orisys_autocal.motion import AxisState, BusStatus, Snapshot
|
||||
from orisys_autocal.motion.pose_move import plan_pose_move
|
||||
|
||||
|
||||
@@ -37,6 +37,44 @@ def _connected(make_window, *, confirm: bool = False):
|
||||
return window
|
||||
|
||||
|
||||
def test_axis_4_controls_stay_available_when_the_bus_count_is_short(make_window):
|
||||
"""A mapped axis 4 uses the same buttons as axes 0-3.
|
||||
|
||||
The bus-count global can still say 4 after the drive is working again.
|
||||
Type 0 stays disabled, so an axis the controller has not mapped is not
|
||||
given a button.
|
||||
"""
|
||||
window = make_window()
|
||||
try:
|
||||
mapped = tuple(AxisState(axis=index, atype=65, read_ok=True) for index in range(5))
|
||||
window.axis_panel.update_snapshot(
|
||||
Snapshot(
|
||||
connected=True,
|
||||
bus=BusStatus(bus_type="ecat", init_status=1, total_axes=4),
|
||||
axes=mapped,
|
||||
)
|
||||
)
|
||||
row = window.axis_panel._rows[4] # noqa: SLF001
|
||||
assert row["enable_button"].isEnabled()
|
||||
assert row["fwd_button"].isEnabled()
|
||||
assert row["rev_button"].isEnabled()
|
||||
assert row["stop_button"].isEnabled()
|
||||
|
||||
unmapped = mapped[:-1] + (AxisState(axis=4, atype=0, read_ok=True),)
|
||||
window.axis_panel.update_snapshot(
|
||||
Snapshot(
|
||||
connected=True,
|
||||
bus=BusStatus(bus_type="ecat", init_status=1, total_axes=4),
|
||||
axes=unmapped,
|
||||
)
|
||||
)
|
||||
row = window.axis_panel._rows[4] # noqa: SLF001
|
||||
assert not row["fwd_button"].isEnabled()
|
||||
assert row["stop_button"].isEnabled() is False
|
||||
finally:
|
||||
window.close()
|
||||
|
||||
|
||||
def test_execute_lives_with_the_point_it_executes(make_window):
|
||||
window = make_window()
|
||||
try:
|
||||
|
||||
@@ -216,6 +216,63 @@ def test_the_guard_names_an_unknown_direction():
|
||||
# ------------------------------------------------------------------------ mover
|
||||
|
||||
|
||||
def test_an_execute_plan_moves_the_four_axes_together_and_leaves_z():
|
||||
"""Calibration execute starts yaw, pitch and X/Y in one command. Z stays put."""
|
||||
service = make_service()
|
||||
called: list[list[tuple[int, float]]] = []
|
||||
|
||||
def record(moves):
|
||||
called.append(list(moves))
|
||||
return MotionResult.success()
|
||||
|
||||
service.move_abs_many = record # type: ignore[method-assign]
|
||||
poller = FakePoller(service)
|
||||
mover = PoseMover(service, poller.submit)
|
||||
plan = plan_pose_move(
|
||||
service,
|
||||
{"x": 2.0, "y": 1.0, "yaw": 10.0, "pitch": -5.0},
|
||||
hold=("z",),
|
||||
together=True,
|
||||
)
|
||||
assert plan.together
|
||||
assert [step.role for step in plan.steps] == ["yaw", "pitch", "x", "y"]
|
||||
assert mover.start(plan).ok
|
||||
assert len(poller.commands) == 1
|
||||
poller.commands[0](service)
|
||||
assert [axis for axis, _value in called[0]] == [3, 2, 0, 1]
|
||||
|
||||
mover.on_snapshot(
|
||||
snapshot_of(service, {0: 1000.0, 1: 0.0, 2: 0.0, 3: 0.0}, idle=False)
|
||||
)
|
||||
assert mover.running
|
||||
assert mover.progress_text().startswith("同时")
|
||||
assert len(poller.commands) == 1, "a later axis was queued instead of moving with the first"
|
||||
|
||||
mover.on_snapshot(
|
||||
snapshot_of(
|
||||
service,
|
||||
{
|
||||
0: 1000.0,
|
||||
1: 500.0,
|
||||
2: -5.0 * 12500.0 / 90.0,
|
||||
3: 10.0 * 29500.0 / 90.0,
|
||||
},
|
||||
)
|
||||
)
|
||||
assert mover.state.finished
|
||||
|
||||
|
||||
def test_return_to_zero_stays_one_axis_at_a_time():
|
||||
service = make_service()
|
||||
poller = FakePoller(service)
|
||||
mover = PoseMover(service, poller.submit)
|
||||
plan = plan_return_to_initial(service)
|
||||
assert not plan.together
|
||||
assert mover.start(plan).ok
|
||||
assert len(poller.commands) == 1
|
||||
assert mover.state.step.role == "z"
|
||||
|
||||
|
||||
def test_the_mover_commands_one_axis_and_waits_for_it_to_arrive():
|
||||
service = make_service()
|
||||
poller = FakePoller(service)
|
||||
|
||||
Reference in New Issue
Block a user