加入Z轴运行控制,加快五轴运行速度
This commit is contained in:
@@ -10,10 +10,10 @@ matters:
|
||||
:class:`~orisys_autocal.motion.poller.MotionPoller` is built, and it is why a stop
|
||||
is possible at all: a mover that sat in a loop inside one command could not be
|
||||
interrupted, because the stop would have to wait for the loop it is meant to abort.
|
||||
* **This module** owns the waiting. An execute plan starts yaw, pitch and table X/Y
|
||||
in one command so they move together; a return plan still retracts one axis at a
|
||||
time. It watches the snapshots the poller already produces and gives up on its
|
||||
own if an axis stops short of its target.
|
||||
* **This module** owns the waiting. Execute and return-to-zero both start yaw, pitch,
|
||||
table X/Y and the press axis in one command so the five axes move together. The
|
||||
mover watches the snapshots the poller already produces and gives up on its own
|
||||
if an axis stops short of its target.
|
||||
|
||||
That shape is the whole reason for the class: ``stop`` is submitted as an ordinary
|
||||
command, so it runs at the next tick and stops the axis that is moving *now*.
|
||||
@@ -51,11 +51,8 @@ STALL_GRACE_S = 2.0
|
||||
#: The order a role move is issued in, for the reason in the module docstring.
|
||||
MOVE_ORDER: tuple[str, ...] = ("yaw", "pitch", "x", "y", "z")
|
||||
|
||||
#: The order "return to the initial state" retracts in: the press axis first, so the
|
||||
#: tool is clear of the sensor before anything rotates, then the stages, then the
|
||||
#: table. Returning in one coordinated swoop would move five axes through poses
|
||||
#: nobody has simulated.
|
||||
RETURN_ORDER: tuple[str, ...] = ("z", "pitch", "yaw", "x", "y")
|
||||
#: Axes a pose execute and a return-to-zero command together, including the press axis.
|
||||
ALIGN_ORDER: tuple[str, ...] = ("yaw", "pitch", "x", "y", "z")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -82,7 +79,6 @@ class MovePlan:
|
||||
#: information the operator needs, not an omission.
|
||||
held: tuple[str, ...] = ()
|
||||
#: When set, every step is commanded in one call and they travel together.
|
||||
#: Return-to-zero leaves this off so the press axis clears before anything turns.
|
||||
together: bool = False
|
||||
|
||||
def describe(self) -> str:
|
||||
@@ -153,11 +149,12 @@ def plan_pose_move(
|
||||
|
||||
|
||||
def plan_return_to_initial(service: MotionService) -> MovePlan:
|
||||
"""Every axis to zero, press axis first, in :data:`RETURN_ORDER`."""
|
||||
"""Yaw, pitch, table X/Y and the press axis back to zero together."""
|
||||
return plan_pose_move(
|
||||
service,
|
||||
{role: 0.0 for role in RETURN_ORDER},
|
||||
order=RETURN_ORDER,
|
||||
{role: 0.0 for role in ALIGN_ORDER},
|
||||
order=ALIGN_ORDER,
|
||||
together=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -242,7 +239,7 @@ class PoseMover(QObject):
|
||||
self.stepStarted.emit(step)
|
||||
|
||||
def _issue_together(self, plan: MovePlan) -> None:
|
||||
"""Command every step in one worker call. Z is absent from the plan."""
|
||||
"""Command every step in one worker call."""
|
||||
moves: list[tuple[int, float]] = []
|
||||
for step in plan.steps:
|
||||
if not step.units == step.units:
|
||||
@@ -317,7 +314,7 @@ class PoseMover(QObject):
|
||||
)
|
||||
|
||||
def _on_snapshot_together(self, snapshot: Snapshot) -> None:
|
||||
"""Finish when every commanded axis has arrived. Z is not in the plan."""
|
||||
"""Finish when every commanded axis has arrived."""
|
||||
plan = self.state.plan
|
||||
if plan is None:
|
||||
return
|
||||
|
||||
@@ -750,13 +750,8 @@ class FingerPanel(QGroupBox):
|
||||
|
||||
The two numbers that matter are the *table's* move and the stage angles: the
|
||||
table translation is what the stages are resolved against, and it is what the
|
||||
preview drew as the cyan path's end.
|
||||
|
||||
z is returned as *held*: executing a simulated pose moves the stages and the
|
||||
table, it does not press. Pressing is P7 and has its own guards — contact
|
||||
detection, press depth, the sensor's second opinion — none of which exist
|
||||
here, so a move that reached the contact height would be a press with none of
|
||||
them.
|
||||
preview drew as the cyan path's end. Z is the contact height, commanded with
|
||||
the other four axes in the same move.
|
||||
"""
|
||||
pose = self._last_pose
|
||||
if pose is None:
|
||||
@@ -767,8 +762,9 @@ class FingerPanel(QGroupBox):
|
||||
"y": float(table_y),
|
||||
"yaw": float(pose.yaw_deg),
|
||||
"pitch": float(pose.pitch_deg),
|
||||
"z": float(pose.contact_z_mm),
|
||||
}
|
||||
return targets, ("z",)
|
||||
return targets, ()
|
||||
|
||||
def _sync_sim_button(self) -> None:
|
||||
self.sim_button.setText(
|
||||
|
||||
@@ -1045,10 +1045,9 @@ class AutoCalMainWindow(QMainWindow):
|
||||
def _on_execute_pose(self) -> None:
|
||||
"""Move the platform to the solved pose of the finger screen's selection.
|
||||
|
||||
Yaw, pitch and table X/Y start together. The press axis is deliberately
|
||||
not commanded, so this is workflow P6's dry run for one point — it cannot
|
||||
reach the sensor. The numbers shown in the confirmation are the ones the
|
||||
preview drew, so the operator checks the simulation against the machine.
|
||||
Yaw, pitch, table X/Y and the press axis start together. The Z target is
|
||||
the solved contact height. The numbers in the confirmation are the ones
|
||||
the preview drew.
|
||||
"""
|
||||
solve = self.finger_panel.solved_pose()
|
||||
if solve is None:
|
||||
@@ -1065,7 +1064,7 @@ class AutoCalMainWindow(QMainWindow):
|
||||
self._start_move(plan, t("move.execute"))
|
||||
|
||||
def _on_return_to_initial(self) -> None:
|
||||
"""Every drive back to zero, press axis first."""
|
||||
"""Yaw, pitch, table X/Y and the press axis back to zero together."""
|
||||
plan = plan_return_to_initial(self.poller.service)
|
||||
self._start_move(plan, t("move.return_initial"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user