Skip to content

Commit 001d2ba

Browse files
committed
Merge branch '8.8.0-into-edge-incremental-mergeback' into edge
2 parents 433ee80 + f6e1228 commit 001d2ba

File tree

88 files changed

+814
-431
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+814
-431
lines changed

api/src/opentrons/hardware_control/backends/ot3controller.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,12 @@ def _build_move_node_axis_runner(
662662
) -> Tuple[Optional[MoveGroupRunner], bool]:
663663
if not target:
664664
return None, False
665-
move_target = MoveTarget.build(position=target, max_speed=speed)
665+
# Create a target that doesn't incorporate the plunger into a joint axis with the gantry
666+
plunger_axes = [Axis.P_L, Axis.P_R]
667+
move_target = self._move_manager.devectorize_axes(
668+
origin, target, speed, plunger_axes
669+
)
670+
666671
try:
667672
_, movelist = self._move_manager.plan_motion(
668673
origin=origin, target_list=[move_target]
@@ -693,6 +698,20 @@ def _build_move_node_axis_runner(
693698
move_group, ordered_nodes, (delay_nodes, delay_time)
694699
)
695700

701+
(
702+
plunger_slowed,
703+
error_str,
704+
) = self._move_manager.ensure_pipette_flow_rate_unchanged(
705+
[node_to_axis(node) for node in ordered_nodes],
706+
origin,
707+
target,
708+
speed,
709+
move_group,
710+
[(ax, axis_to_node(ax)) for ax in plunger_axes],
711+
)
712+
if plunger_slowed:
713+
log.error(error_str)
714+
696715
return (
697716
MoveGroupRunner(
698717
move_groups=[move_group],

api/src/opentrons/protocol_engine/commands/capture_image.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ async def execute(
222222
data=camera_data,
223223
mime_type=MimeType.IMAGE_JPEG,
224224
command_metadata=ImageCaptureCmdFileNameMetadata(
225-
step_number=len(self._state_view.commands.get_all()) + 1,
225+
step_number=len(self._state_view.commands.get_all()),
226226
command_timestamp=datetime.now(),
227227
base_filename=params.fileName,
228228
command_id=this_cmd_id or "",

api/src/opentrons/system/camera.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ def parse_stream_configuration_file_data(data: bytes) -> Dict[str, str] | None:
245245
)
246246
# We don't want to write bad or incomplete data to the file
247247
return None
248+
249+
# Migrate old camera default file data to new uniform default
250+
if contents[StreamConfigurationKeys.SOURCE] == "NONE":
251+
contents[StreamConfigurationKeys.SOURCE] = DEFAULT_SYSTEM_CAMERA
248252
return contents
249253

250254

api/tests/opentrons/hardware_control/backends/test_ot3_controller.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,148 @@ async def test_controller_move(
14831483
assert gear_position == gear_position
14841484

14851485

1486+
@pytest.mark.parametrize(
1487+
argnames=["origin_pos", "target_pos", "expected_pos", "gear_position"],
1488+
argvalues=[
1489+
[
1490+
{
1491+
Axis.X: 0,
1492+
Axis.Y: 0,
1493+
Axis.Z_L: 0,
1494+
Axis.Z_R: 0,
1495+
Axis.P_L: 0,
1496+
Axis.P_R: 0,
1497+
Axis.Z_G: 0,
1498+
Axis.G: 0,
1499+
},
1500+
{
1501+
Axis.X: 10,
1502+
Axis.Y: 10,
1503+
Axis.Z_L: 50,
1504+
Axis.P_L: 70,
1505+
},
1506+
{
1507+
Axis.X: 10,
1508+
Axis.Y: 10,
1509+
Axis.Z_L: 50,
1510+
Axis.Z_R: 0,
1511+
Axis.P_L: 70,
1512+
Axis.P_R: 0,
1513+
Axis.Z_G: 0,
1514+
Axis.G: 0,
1515+
},
1516+
None,
1517+
],
1518+
[
1519+
{
1520+
Axis.X: 0,
1521+
Axis.Y: 0,
1522+
Axis.Z_L: 0,
1523+
Axis.Z_R: 0,
1524+
Axis.P_L: 0,
1525+
Axis.P_R: 0,
1526+
Axis.Z_G: 0,
1527+
Axis.G: 0,
1528+
},
1529+
{
1530+
Axis.X: 20,
1531+
Axis.Y: 20,
1532+
Axis.Z_L: 10,
1533+
Axis.P_L: 48,
1534+
},
1535+
{
1536+
Axis.X: 20,
1537+
Axis.Y: 20,
1538+
Axis.Z_L: 10,
1539+
Axis.Z_R: 0,
1540+
Axis.P_L: 48,
1541+
Axis.P_R: 0,
1542+
Axis.Z_G: 0,
1543+
Axis.G: 0,
1544+
},
1545+
None,
1546+
],
1547+
[
1548+
{
1549+
Axis.X: 0,
1550+
Axis.Y: 0,
1551+
Axis.Z_L: 0,
1552+
Axis.Z_R: 0,
1553+
Axis.P_L: 0,
1554+
Axis.P_R: 0,
1555+
Axis.Z_G: 0,
1556+
Axis.G: 0,
1557+
},
1558+
{
1559+
Axis.P_L: 70,
1560+
},
1561+
{
1562+
Axis.X: 0,
1563+
Axis.Y: 0,
1564+
Axis.Z_L: 0,
1565+
Axis.Z_R: 0,
1566+
Axis.P_L: 70,
1567+
Axis.P_R: 0,
1568+
Axis.Z_G: 0,
1569+
Axis.G: 0,
1570+
},
1571+
None,
1572+
],
1573+
[
1574+
{
1575+
Axis.X: 0,
1576+
Axis.Y: 0,
1577+
Axis.Z_L: 0,
1578+
Axis.Z_R: 0,
1579+
Axis.P_L: 0,
1580+
Axis.P_R: 0,
1581+
Axis.Z_G: 0,
1582+
Axis.G: 0,
1583+
},
1584+
{
1585+
Axis.P_L: 30, # Too short to hit top speed
1586+
},
1587+
{
1588+
Axis.X: 0,
1589+
Axis.Y: 0,
1590+
Axis.Z_L: 0,
1591+
Axis.Z_R: 0,
1592+
Axis.P_L: 30,
1593+
Axis.P_R: 0,
1594+
Axis.Z_G: 0,
1595+
Axis.G: 0,
1596+
},
1597+
None,
1598+
],
1599+
],
1600+
)
1601+
async def test_controller_move_dynamic(
1602+
controller: OT3Controller,
1603+
mock_present_devices: mock.AsyncMock,
1604+
origin_pos: Dict[Axis, float],
1605+
target_pos: Dict[Axis, float],
1606+
expected_pos: Dict[Axis, float],
1607+
gear_position: Optional[float],
1608+
) -> None:
1609+
from copy import deepcopy
1610+
1611+
controller.update_constraints_for_gantry_load(GantryLoad.LOW_THROUGHPUT)
1612+
1613+
run_target_pos = deepcopy(target_pos)
1614+
config = {"run.side_effect": move_group_run_side_effect(controller, run_target_pos)}
1615+
with mock.patch( # type: ignore [call-overload]
1616+
"opentrons.hardware_control.backends.ot3controller.MoveGroupRunner",
1617+
spec=MoveGroupRunner,
1618+
**config
1619+
):
1620+
await controller.move(origin_pos, target_pos, 70)
1621+
position = await controller.update_position()
1622+
gear_position = controller.gear_motor_position
1623+
1624+
assert position == expected_pos
1625+
assert gear_position == gear_position
1626+
1627+
14861628
@pytest.mark.parametrize(
14871629
argnames=["axes", "pipette_has_sensor"],
14881630
argvalues=[[[Axis.P_L, Axis.P_R], True], [[Axis.P_L, Axis.P_R], False]],

app-shell/src/secondary-windows/camera-stream/index.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ interface CameraStreamDetails extends SecondaryWindowDetails {
1414
}
1515

1616
interface OpenCameraStreamParams {
17-
runId: string
1817
windowTitle: string
1918
robotIp: string
2019
robotName: string
@@ -34,19 +33,18 @@ function getWindowIdCameraStream(robotIp: string): string {
3433
return `camera-stream-${robotIp}`
3534
}
3635

37-
const STREAM_URL = (robotName: string, runId: string): string =>
36+
const STREAM_URL = (robotName: string): string =>
3837
`${
3938
SECONDARY_WINDOW_CONFIG.url.protocol
4039
}//${SECONDARY_WINDOW_URL_PATH}#/devices/${encodeURIComponent(
4140
robotName
42-
)}/camera-stream?runId=${encodeURIComponent(runId)}`
41+
)}/camera-stream`
4342

4443
function createCameraStreamUi({
4544
log,
4645
robotName,
4746
windowTitle,
4847
robotIp,
49-
runId,
5048
}: OpenCameraStreamParams): BrowserWindow {
5149
log.debug('Creating camera stream window', {
5250
robotIp,
@@ -63,9 +61,9 @@ function createCameraStreamUi({
6361
}
6462
)
6563

66-
log.info(`Loading camera stream from ${STREAM_URL(robotName, runId)}`)
64+
log.info(`Loading camera stream from ${STREAM_URL(robotName)}`)
6765
// eslint-disable-next-line @typescript-eslint/no-floating-promises
68-
cameraStreamWindow.loadURL(STREAM_URL(robotName, runId), {
66+
cameraStreamWindow.loadURL(STREAM_URL(robotName), {
6967
extraHeaders: 'pragma: no-cache\n',
7068
})
7169

app-shell/src/secondary-windows/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ function detailsByActionType(action: Action): SecondaryWindowDetails | null {
6262
switch (action.type) {
6363
case CAMERA_STREAM_OPEN:
6464
return openCameraStream({
65-
runId: action.payload.runId,
6665
windowTitle: action.payload.windowTitle,
6766
robotIp: action.payload.hostname,
6867
robotName: action.payload.robotName,

app/src/assets/localization/en/anonymous.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"language_preference_description": "The app matches your system language unless you select another language below. You can change the language later in the app settings.",
4848
"learn_uninstalling": "Learn more about uninstalling the app",
4949
"livestream_window_title": "Robot Live Camera",
50+
"live_video_description_odd": "View real-time video of the deck in the App while running a protocol.",
5051
"loosen_screws_and_detach": "Loosen screws and detach gripper",
5152
"modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box.",
5253
"module_calibration_failed": "<block>Module calibration was unsuccessful. Make sure the calibration adapter is fully seated on the module and try again. If you still have trouble, contact support.</block><block>{{error}}</block>",

app/src/assets/localization/en/branded.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"language_preference_description": "The Opentrons App matches your system language unless you select another language below. You can change the language later in the app settings.",
4848
"learn_uninstalling": "Learn more about uninstalling the Opentrons App",
4949
"livestream_window_title": "Opentrons Live Camera",
50+
"live_video_description_odd": "View real-time video of the deck in the Opentrons App while running a protocol.",
5051
"loosen_screws_and_detach": "Loosen screws and detach Flex Gripper",
5152
"modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box. You can also click the link below or scan the QR code to visit the modules section of the Opentrons Help Center.",
5253
"module_calibration_failed": "<block>Module calibration was unsuccessful. Make sure the calibration adapter is fully seated on the module and try again. If you still have trouble, contact Opentrons Support.</block><block>{{error}}</block>",

app/src/assets/localization/en/device_details.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
"reset_estop": "Reset E-stop",
169169
"resume_operation": "Resume operation",
170170
"right": "right",
171-
"robot_control_not_available": "Some robot controls are not available when run is in progress",
171+
"robot_control_not_available": "Some robot controls are not available when run is in progress or robot is busy",
172172
"robot_initializing": "Initializing...",
173173
"run": "Run",
174174
"run_a_protocol": "Run a protocol",

app/src/assets/localization/en/device_settings.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"are_you_sure_you_want_to_disconnect": "Are you sure you want to disconnect from {{ssid}}?",
2020
"attach_a_pipette_before_calibrating": "Attach a pipette in order to perform calibration",
2121
"authentication": "Authentication",
22-
"automatically_capture_image": "Automatically capture an image of the deck if an error occurs.",
22+
"automatically_capture_image": "Automatically capture an image of the deck in the event of an error.",
2323
"boot_scripts": "Boot scripts",
2424
"both": "Both",
2525
"brightness": "Brightness",
@@ -43,7 +43,7 @@
4343
"camera_preferences_description_long": "The deck camera offers live video monitoring during protocol runs and supports image capture.",
4444
"camera_required": "Camera is required",
4545
"camera_status": "Camera Status",
46-
"camera_status_description": "The deck camera provides live video during protocol runs, allows manual or automated image capture of the deck, and records images automatically when errors occur for easier troubleshooting.",
46+
"camera_status_description": "The deck camera offers live video monitoring during protocol runs and supports image capture—either manually, automatically, or in response to runtime errors for easier troubleshooting.",
4747
"cancel_software_update": "Cancel software update",
4848
"change_network": "Change network",
4949
"characters_max": "17 characters max",
@@ -140,7 +140,7 @@
140140
"e_stop_connected": "E-stop successfully connected",
141141
"e_stop_not_connected": "Connect the E-stop to an auxiliary port on the back of the robot.",
142142
"edit_settings": "Edit settings",
143-
"enable_camera_to_run": "Enable the camera to run this protocol",
143+
"enable_camera_to_run": "Enable the camera to start the run",
144144
"enable_status_light": "Enable status light",
145145
"enable_status_light_description": "Turn on or off the strip of color LEDs on the front of the robot.",
146146
"enabled": "Enabled",
@@ -205,7 +205,7 @@
205205
"legacy_settings": "Legacy Settings",
206206
"likely_incorrect_password": "Likely incorrect network password.",
207207
"live_video": "Live Video",
208-
"live_video_description": "View real-time video of the deck during protocol runs.",
208+
"live_video_description": "View real-time video of the deck while a running a protocol",
209209
"live_video_lc": "Live video",
210210
"mac_address": "MAC Address",
211211
"manage_oem_settings": "Manage OEM settings",
@@ -347,7 +347,7 @@
347347
"slider_value": "{{value}}%",
348348
"software_is_up_to_date": "Your software is already up to date!",
349349
"software_update_error": "Software update error",
350-
"some_robot_controls_are_not_available": "Some robot controls are not available when run is in progress",
350+
"some_robot_controls_are_not_available": "Some robot controls are not available when run is in progress or robot is busy",
351351
"ssh_public_keys": "SSH public keys",
352352
"subnet_mask": "Subnet Mask",
353353
"successfully_connected": "Successfully connected!",

0 commit comments

Comments
 (0)