Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hardware): add acceleration to pick up tip for 96 channel #12944

Merged
merged 28 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
95d068b
add acceleration to tip_action
caila-marashaj Jun 15, 2023
b4d4bee
pick up tip move happens, but rumbly
caila-marashaj Jun 21, 2023
bdea049
linter stuff cleanup
caila-marashaj Jun 21, 2023
782a760
fixed position of acceleration in tipaction msg
caila-marashaj Jun 22, 2023
73d26bf
moving but delayed
caila-marashaj Jun 27, 2023
c3e044a
modify tip action, debugging code still in there
caila-marashaj Jun 28, 2023
a85074e
mostly working but returning position too early
caila-marashaj Jun 29, 2023
1952348
need to update tests
caila-marashaj Jul 6, 2023
fa194a3
updated unit test args for tip_action
caila-marashaj Jul 17, 2023
d2e7927
rebase
caila-marashaj Jul 17, 2023
2b20a20
rough final draft
caila-marashaj Jul 18, 2023
8cf3c15
cleanup
caila-marashaj Jul 18, 2023
7e5b7ef
format
caila-marashaj Jul 18, 2023
8ace0ef
remove redundant data check from gear motors
caila-marashaj Jul 18, 2023
155738b
hardware controller changes
caila-marashaj Jul 19, 2023
0aede03
increase backward distances
caila-marashaj Jul 20, 2023
97e12e9
changed helpers_ot3 function
caila-marashaj Jul 21, 2023
1550c9a
format
caila-marashaj Jul 21, 2023
735ebe7
helpers_ot3 function change
caila-marashaj Jul 21, 2023
af1eefa
got rid of copysign call
caila-marashaj Jul 21, 2023
e2280aa
check if speed exists
caila-marashaj Jul 21, 2023
5be4492
add deafult value to axis convert call
caila-marashaj Jul 24, 2023
93ef4ca
update gear motor position handling after move
caila-marashaj Jul 25, 2023
f1a42d1
test fix
caila-marashaj Jul 25, 2023
2b71f07
moved comments
caila-marashaj Jul 26, 2023
57bb955
remove updategearmotorpositionestimation msg
caila-marashaj Jul 26, 2023
e201a43
removed more unneeded code
caila-marashaj Jul 26, 2023
6eb76e6
address change reqs
caila-marashaj Jul 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
changed helpers_ot3 function
  • Loading branch information
caila-marashaj committed Jul 26, 2023
commit 97e12e90e3001883f9548eb1d56e07742cca4c5f
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ async def tip_action(
self._gear_motor_position = {
NodeId.pipette_left: positions[NodeId.pipette_left][0]
}
print(f"setting gear motor position to {positions[NodeId.pipette_left][0]}")

@requires_update
async def gripper_grip_jaw(
Expand Down
43 changes: 33 additions & 10 deletions api/src/opentrons/hardware_control/ot3api.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,6 @@ async def home_z(
axes = list(Axis.ot3_mount_axes())
await self.home(axes)


async def home_gripper_jaw(self) -> None:
"""
Home the jaw of the gripper.
Expand Down Expand Up @@ -898,7 +897,9 @@ def _effector_pos_from_carriage_pos(
plunger_ax: carriage_position[plunger_ax],
}
if self._gantry_load == GantryLoad.HIGH_THROUGHPUT:
effector_pos[Axis.Q] = self._backend.gear_motor_position
effector_pos[Axis.Q] = axis_convert(self._backend.gear_motor_position, 0.0)[
Axis.P_L
]

return effector_pos

Expand Down Expand Up @@ -1691,18 +1692,29 @@ async def _motor_pick_up_tip(
pipette_axis
]
gear_origin_dict = {Axis.Q: gear_origin_float}
gear_origin_dict = {Axis.Q: gear_origin_float}
clamp_move_target = pipette_spec.pick_up_distance
gear_target_dict = {Axis.Q: clamp_move_target}
clamp_moves = self._build_moves(gear_origin_dict, gear_target_dict)
await self._backend.tip_action(moves=clamp_moves[0], tip_action="clamp")

homing_velocity = self._config.motion_settings.default_max_speed[
homing_velocity = self._config.motion_settings.max_speed_discontinuity[
GantryLoad.HIGH_THROUGHPUT
][OT3AxisKind.Q]
q_axis_distance = axis_convert(self._backend.gear_motor_position, 0.0)[Axis.P_L]

gear_pos_float = gear_start_position = axis_convert(
self._backend.gear_motor_position, 0.0
)[Axis.P_L]
gear_pos_dict = {Axis.Q: gear_pos_float}
fast_home_target = {Axis.Q: self._config.safe_home_distance}

fast_home_moves = self._build_moves(gear_pos_dict, fast_home_target)
# move toward home until a safe distance
await self._backend.tip_action(
moves=fast_home_moves[0], tip_action="clamp"
)
# move the rest of the way home with no acceleration
await self._backend.tip_action(
distance=(pipette_spec.pick_up_distance + pipette_spec.home_buffer),
distance=(self._config.safe_home_distance + pipette_spec.home_buffer),
velocity=homing_velocity,
tip_action="home",
)
Expand Down Expand Up @@ -1786,13 +1798,24 @@ async def drop_tip(

await self._backend.tip_action(moves=drop_moves[0], tip_action="clamp")

homing_velocity = self._config.motion_settings.default_max_speed[
homing_velocity = self._config.motion_settings.max_speed_discontinuity[
GantryLoad.HIGH_THROUGHPUT
][OT3AxisKind.Q]
pipette_axis = Axis.of_main_tool_actuator(mount)
q_axis_distance = axis_convert(self._backend.gear_motor_position, 0.0)[pipette_axis]

gear_pos_float = gear_start_position = axis_convert(
self._backend.gear_motor_position, 0.0
)[Axis.P_L]
gear_pos_dict = {Axis.Q: gear_pos_float}
fast_home_target = {Axis.Q: self._config.safe_home_distance}

fast_home_moves = self._build_moves(gear_pos_dict, fast_home_target)
# move toward home until a safe distance
await self._backend.tip_action(
moves=fast_home_moves[0], tip_action="clamp"
)
# move the rest of the way home with no acceleration
await self._backend.tip_action(
distance=(move.target_position + move.home_buffer),
distance=(self._config.safe_home_distance + move.home_buffer),
velocity=homing_velocity,
tip_action="home",
)
Expand Down
19 changes: 5 additions & 14 deletions hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import asyncio
from dataclasses import dataclass
from datetime import datetime
from math import pi
from math import pi, copysign
from subprocess import run
from time import time
from typing import Callable, Coroutine, Dict, List, Optional, Tuple, Union
Expand Down Expand Up @@ -450,22 +450,13 @@ async def move_tip_motor_relative_ot3(
target_pos = current_pos.copy()
target_pos[Axis.Q] += distance

if distance < 0:
speed *= -1
speed = copysign(speed, distance)

tip_motor_move = api._build_moves(current_pos, target_pos)
await api._backend.tip_action(moves=tip_motor_move[0], tip_action="clamp")
tip_motor_move = api._build_moves(current_pos, target_pos, speed)

if distance < 0:
# change this so that it calls _build_moves, and passes in a speed
action = "home"
else:
action = "clamp"
_move_coro = api._backend.tip_action(
axes=[Axis.Q],
distance=distance,
speed=speed if speed else 5,
tip_action=action,
moves=tip_motor_move[0],
tip_action="clamp",
)
if motor_current is None:
await _move_coro
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ def _listener_filter(arbitration_id: ArbitrationId) -> bool:
data = []

with MultipleMessagesWaitableCallback(
can_messenger,
_listener_filter,
2,
can_messenger,
_listener_filter,
2,
) as reader:
await can_messenger.send(
node_id=NodeId.pipette_left,
Expand Down
31 changes: 23 additions & 8 deletions hardware/opentrons_hardware/hardware_control/move_group_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,7 @@ def _accumulate_move_completions(
] = defaultdict(list)
for arbid, completion in completions:
if isinstance(completion, TipActionResponse):
caila-marashaj marked this conversation as resolved.
Show resolved Hide resolved
continue
position[NodeId(arbid.parts.originating_node_id)].append(
(
(
completion.payload.group_id.value,
completion.payload.seq_id.value,
),
gear_position_response = (
float(completion.payload.current_position_um.value) / 1000.0,
float(completion.payload.encoder_position_um.value) / 1000.0,
bool(
Expand All @@ -193,7 +187,28 @@ def _accumulate_move_completions(
& MotorPositionFlags.encoder_position_ok.value
),
)
)
return {
arbid.parts.originating_node_id: gear_position_response
}
else:
position[NodeId(arbid.parts.originating_node_id)].append(
(
(
completion.payload.group_id.value,
completion.payload.seq_id.value,
),
float(completion.payload.current_position_um.value) / 1000.0,
float(completion.payload.encoder_position_um.value) / 1000.0,
bool(
completion.payload.position_flags.value
& MotorPositionFlags.stepper_position_ok.value
),
bool(
completion.payload.position_flags.value
& MotorPositionFlags.encoder_position_ok.value
),
)
)
# for each node, pull the position from the completion with the largest
# combination of group id and sequence id
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,10 @@ def move_group_single() -> MoveGroups:
]
]


@pytest.fixture
def move_group_tip_action_single() -> MoveGroups:
"""Move group with one move."""
return [
[
{
Expand All @@ -123,7 +125,7 @@ def move_group_tip_action_single() -> MoveGroups:
duration_sec=float64(1),
action=PipetteTipActionType.home,
stop_condition=MoveStopCondition.none,
acceleration_mm_sec_sq=0,
acceleration_mm_sec_sq=float64(0),
)
}
]
Expand All @@ -132,7 +134,7 @@ def move_group_tip_action_single() -> MoveGroups:

@pytest.fixture
def move_group_tip_action_multiple() -> MoveGroups:
"""Move group with one move."""
"""Move group with multiple moves."""
return [
[
{
Expand All @@ -141,16 +143,16 @@ def move_group_tip_action_multiple() -> MoveGroups:
duration_sec=float64(1),
action=PipetteTipActionType.clamp,
stop_condition=MoveStopCondition.none,
acceleration_mm_sec_sq=1,
acceleration_mm_sec_sq=float64(1),
)
},
{
NodeId.pipette_left: MoveGroupTipActionStep(
velocity_mm_sec=float64(3),
velocity_mm_sec=float64(2),
duration_sec=float64(1),
action=PipetteTipActionType.clamp,
stop_condition=MoveStopCondition.none,
acceleration_mm_sec_sq=0,
acceleration_mm_sec_sq=float64(1),
)
},
{
Expand All @@ -159,9 +161,9 @@ def move_group_tip_action_multiple() -> MoveGroups:
duration_sec=float64(1),
action=PipetteTipActionType.clamp,
stop_condition=MoveStopCondition.none,
acceleration_mm_sec_sq=-1,
acceleration_mm_sec_sq=float64(1),
)
}
},
]
]

Expand Down Expand Up @@ -810,10 +812,10 @@ async def test_home_timeout(
[
"move_group_tip_action_single",
"move_group_tip_action_multiple",
]
],
)
async def test_tip_action_move_runner_receives_two_responses(
mock_can_messenger: AsyncMock, move_group_tip_action: MoveGroups, request
mock_can_messenger: AsyncMock, move_group_tip_action: MoveGroups, request: Any
) -> None:
"""The magic call function should receive two responses for a tip action."""
with patch.object(MoveScheduler, "_handle_move_completed") as mock_move_complete:
Expand All @@ -837,10 +839,10 @@ async def test_tip_action_move_runner_receives_two_responses(
[
"move_group_tip_action_single",
"move_group_tip_action_multiple",
]
],
)
async def test_tip_action_move_runner_position_updated(
mock_can_messenger: AsyncMock, move_group_tip_action: MoveGroups, request
mock_can_messenger: AsyncMock, move_group_tip_action: MoveGroups, request: Any
) -> None:
"""Two responses from a tip action move are properly handled."""
move_group_tip_action = request.getfixturevalue(move_group_tip_action)
Expand All @@ -850,18 +852,22 @@ async def test_tip_action_move_runner_position_updated(
mock_can_messenger.send.side_effect = mock_sender.mock_send
completion_message = await subject.run(can_messenger=mock_can_messenger)
assert len(completion_message) == len(move_group_tip_action[0])
# assert completion_message[0][1].payload.current_position_um.value == 2000
for i in range(len(completion_message)):
assert completion_message[i][1].payload.current_position_um.value == 2000


@pytest.mark.parametrize(
"move_group_tip_action",
[
"move_group_tip_action_single",
"move_group_tip_action_multiple",
]
],
)
async def test_tip_action_move_runner_fail_receives_one_response(
mock_can_messenger: AsyncMock, move_group_tip_action: MoveGroups, caplog: Any, request
mock_can_messenger: AsyncMock,
move_group_tip_action: MoveGroups,
caplog: Any,
request: Any,
) -> None:
"""Tip action move should fail if one or less responses received."""
move_group_tip_action = request.getfixturevalue(move_group_tip_action)
Expand Down Expand Up @@ -1117,7 +1123,7 @@ def _build_arb(from_node: NodeId) -> ArbitrationId:
),
),
],
{},
{NodeId.pipette_left: (10, 0, False, False)},
),
(
# empty base case
Expand All @@ -1131,6 +1137,8 @@ def test_accumulate_move_completions(
position_map: NodeMap[Tuple[float, float, bool, bool]],
) -> None:
"""Build correct move results."""
# assert MoveGroupRunner._accumulate_move_completions(completions) == position_map
c = MoveGroupRunner._accumulate_move_completions(completions)
assert MoveGroupRunner._accumulate_move_completions(completions) == position_map


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ def convert_pipette_model(
# to attached pipettes.
# We need to figure out how to default the pipette model as well
# rather than returning a p1000
breakpoint()
if model and not provided_version:
pipette_type, parsed_channels, parsed_version = model.split("_")
channels = channels_from_string(parsed_channels)
Expand Down