From dc64b0d7c752f3a46c5d7d1f9d65d0ea4726424d Mon Sep 17 00:00:00 2001 From: Andy Sigler Date: Wed, 23 Jan 2019 12:56:55 -0500 Subject: [PATCH] feat(api): decrease plunger acceleration and add drop tip speed to config (#2904) - decrease plunger acceleration to reduce strain on internal seal - add drop tip speed to pipette configs and respect it during drop tip --- api/src/opentrons/config/pipette_config.py | 2 + api/src/opentrons/config/robot_configs.py | 17 +++++++- .../drivers/smoothie_drivers/driver_3_0.py | 32 ++++++++++++++- .../opentrons/hardware_control/__init__.py | 3 +- api/src/opentrons/legacy_api/api.py | 1 + .../legacy_api/instruments/pipette.py | 8 +++- api/src/opentrons/legacy_api/robot/mover.py | 12 ++++++ api/tests/opentrons/drivers/test_driver.py | 39 +++++++++++++++++++ shared-data/robot-data/pipetteModelSpecs.json | 21 ++++++++++ .../schemas/pipetteModelSpecsSchema.json | 2 + 10 files changed, 131 insertions(+), 6 deletions(-) diff --git a/api/src/opentrons/config/pipette_config.py b/api/src/opentrons/config/pipette_config.py index 08e0922366b..11a183b09ec 100644 --- a/api/src/opentrons/config/pipette_config.py +++ b/api/src/opentrons/config/pipette_config.py @@ -26,6 +26,7 @@ 'model_offset', 'plunger_current', 'drop_tip_current', + 'drop_tip_speed', 'min_volume', 'max_volume', 'ul_per_mm', @@ -99,6 +100,7 @@ def load(pipette_model: str) -> pipette_config: model_offset=cfg.get('modelOffset'), plunger_current=cfg.get('plungerCurrent'), drop_tip_current=cfg.get('dropTipCurrent'), + drop_tip_speed=cfg.get('dropTipSpeed'), min_volume=cfg.get('minVolume'), max_volume=cfg.get('maxVolume'), ul_per_mm=cfg.get('ulPerMm'), diff --git a/api/src/opentrons/config/robot_configs.py b/api/src/opentrons/config/robot_configs.py index 4a354884a9f..66364c2b882 100755 --- a/api/src/opentrons/config/robot_configs.py +++ b/api/src/opentrons/config/robot_configs.py @@ -94,7 +94,22 @@ [0.00, 0.00, 1.00, 0.00], [0.00, 0.00, 0.00, 1.00]] -DEFAULT_ACCELERATION = 'M204 S10000 X3000 Y2000 Z1500 A1500 B2000 C2000' +X_ACCELERATION = 3000 +Y_ACCELERATION = 2000 +Z_ACCELERATION = 1500 +A_ACCELERATION = 1500 +B_ACCELERATION = 200 +C_ACCELERATION = 200 + +DEFAULT_ACCELERATION = { + 'X': X_ACCELERATION, + 'Y': Y_ACCELERATION, + 'Z': Z_ACCELERATION, + 'A': A_ACCELERATION, + 'B': B_ACCELERATION, + 'C': C_ACCELERATION +} + DEFAULT_STEPS_PER_MM = 'M92 X80.00 Y80.00 Z400 A400 B768 C768' # This probe height is ~73 from deck to the top surface of the switch body # per CAD; 74.3mm is the nominal for engagement from the switch drawing. diff --git a/api/src/opentrons/drivers/smoothie_drivers/driver_3_0.py b/api/src/opentrons/drivers/smoothie_drivers/driver_3_0.py index fe265e05c96..5d22a9fd94f 100755 --- a/api/src/opentrons/drivers/smoothie_drivers/driver_3_0.py +++ b/api/src/opentrons/drivers/smoothie_drivers/driver_3_0.py @@ -86,7 +86,8 @@ 'SET_MAX_SPEED': 'M203.1', 'SET_CURRENT': 'M907', 'DISENGAGE_MOTOR': 'M18', - 'HOMING_STATUS': 'G28.6'} + 'HOMING_STATUS': 'G28.6', + 'ACCELERATION': 'M204 S10000'} # Number of digits after the decimal point for coordinates being sent # to Smoothie @@ -301,6 +302,9 @@ def __init__(self, config): self._combined_speed = float(DEFAULT_AXES_SPEED) self._saved_axes_speed = float(self._combined_speed) + self._acceleration = config.acceleration.copy() + self._saved_acceleration = config.acceleration.copy() + # position after homing self._homed_position = HOMED_POSITION.copy() self.homed_flags = {} @@ -599,6 +603,30 @@ def push_axis_max_speed(self): def pop_axis_max_speed(self): self.set_axis_max_speed(self._saved_max_speed_settings) + def set_acceleration(self, settings): + ''' + Sets the acceleration (mm/sec^2) that a given axis will move + + settings + Dict with axes as valies (e.g.: 'X', 'Y', 'Z', 'A', 'B', or 'C') + and floating point number for mm-per-second-squared (mm/sec^2) + ''' + self._acceleration.update(settings) + values = ['{}{}'.format(axis.upper(), value) + for axis, value in sorted(settings.items())] + command = '{} {}'.format( + GCODES['ACCELERATION'], + ' '.join(values) + ) + log.debug("set_acceleration: {}".format(command)) + self._send_command(command) + + def push_acceleration(self): + self._saved_acceleration = self._acceleration.copy() + + def pop_acceleration(self): + self.set_acceleration(self._saved_acceleration) + def set_active_current(self, settings): ''' Sets the amperage of each motor for when it is activated by driver. @@ -956,13 +984,13 @@ def _setup(self): # use gpio to reset into a known state self._smoothie_reset() self._reset_from_error() - self._send_command(self._config.acceleration) self._send_command(self._config.steps_per_mm) self._send_command(GCODES['ABSOLUTE_COORDS']) self._save_current(self.current, axes_active=False) self.update_position(default=self.homed_position) self.pop_axis_max_speed() self.pop_speed() + self.pop_acceleration() def _read_from_pipette(self, gcode, mount) -> Optional[str]: ''' diff --git a/api/src/opentrons/hardware_control/__init__.py b/api/src/opentrons/hardware_control/__init__.py index 64c0234630d..9109fb18bb5 100644 --- a/api/src/opentrons/hardware_control/__init__.py +++ b/api/src/opentrons/hardware_control/__init__.py @@ -938,7 +938,8 @@ async def drop_tip(self, mount, home_after=True): await self._move_plunger(mount, bottom) self._backend.set_active_current(plunger_ax, instr.config.drop_tip_current) - await self._move_plunger(mount, droptip) + await self._move_plunger( + mount, droptip, speed=instr.config.drop_tip_speed) await self._shake_off_tips(mount) instr.set_current_volume(0) instr.remove_tip() diff --git a/api/src/opentrons/legacy_api/api.py b/api/src/opentrons/legacy_api/api.py index f89e89292e9..e8275c2df18 100644 --- a/api/src/opentrons/legacy_api/api.py +++ b/api/src/opentrons/legacy_api/api.py @@ -249,6 +249,7 @@ def _create_pipette_from_config( max_volume=config.max_volume, plunger_current=config.plunger_current, drop_tip_current=config.drop_tip_current, + drop_tip_speed=config.drop_tip_speed, plunger_positions=config.plunger_positions.copy(), ul_per_mm=config.ul_per_mm, pick_up_current=config.pick_up_current, diff --git a/api/src/opentrons/legacy_api/instruments/pipette.py b/api/src/opentrons/legacy_api/instruments/pipette.py index be4079d5d5a..f737f3f3e35 100755 --- a/api/src/opentrons/legacy_api/instruments/pipette.py +++ b/api/src/opentrons/legacy_api/instruments/pipette.py @@ -24,6 +24,7 @@ } DROP_TIP_RELEASE_DISTANCE = 20 +DEFAULT_DROP_TIP_SPEED = 5 DEFAULT_ASPIRATE_SPEED = 5 DEFAULT_DISPENSE_SPEED = 10 @@ -122,6 +123,7 @@ def __init__( dispense_flow_rate=None, plunger_current=0.5, drop_tip_current=0.5, + drop_tip_speed=DEFAULT_DROP_TIP_SPEED, plunger_positions=PLUNGER_POSITIONS, pick_up_current=DEFAULT_PLUNGE_CURRENT, pick_up_distance=DEFAULT_TIP_PRESS_MM, @@ -197,13 +199,12 @@ def __init__( self._pick_up_distance = pick_up_distance self._pick_up_current = pick_up_current - # TODO (andy) these values maybe should persist between sessions, - # by saving within `robot_config` self._plunger_current = plunger_current self._drop_tip_current = drop_tip_current self.speeds = {} self.set_speed(aspirate=aspirate_speed, dispense=dispense_speed) + self._drop_tip_speed = drop_tip_speed self.set_flow_rate( aspirate=aspirate_flow_rate, dispense=dispense_flow_rate) @@ -1046,10 +1047,13 @@ def _drop_tip(location, instrument=self): x=pos_bottom ) self.instrument_actuator.set_active_current(self._drop_tip_current) + self.instrument_actuator.push_speed() + self.instrument_actuator.set_speed(self._drop_tip_speed) self.robot.poses = self.instrument_actuator.move( self.robot.poses, x=pos_drop_tip ) + self.instrument_actuator.pop_speed() self._shake_off_tips(location) if home_after: self._home_after_drop_tip() diff --git a/api/src/opentrons/legacy_api/robot/mover.py b/api/src/opentrons/legacy_api/robot/mover.py index a887b704bee..4385a7acf93 100755 --- a/api/src/opentrons/legacy_api/robot/mover.py +++ b/api/src/opentrons/legacy_api/robot/mover.py @@ -99,6 +99,18 @@ def push_active_current(self): def pop_active_current(self): self._driver.pop_active_current() + def set_acceleration(self, acceleration): + self._driver.set_acceleration({ + axis.upper(): acceleration + for axis in self._axis_mapping.values() + }) + + def push_acceleration(self): + self._driver.push_acceleration() + + def pop_acceleration(self): + self._driver.pop_acceleration() + def probe(self, pose_tree, axis, movement): assert axis in self._axis_mapping, "mapping is not set for " + axis diff --git a/api/tests/opentrons/drivers/test_driver.py b/api/tests/opentrons/drivers/test_driver.py index bb2d6c2e4ea..da1085c99dd 100755 --- a/api/tests/opentrons/drivers/test_driver.py +++ b/api/tests/opentrons/drivers/test_driver.py @@ -313,6 +313,45 @@ def _parse_position_response(arg): fuzzy_assert(result=command_log, expected=expected) +def test_set_acceleration(smoothie, monkeypatch): + from opentrons.drivers import serial_communication + from opentrons.drivers.smoothie_drivers import driver_3_0 + command_log = [] + smoothie._setup() + smoothie.home() + smoothie.simulating = False + + def write_with_log(command, ack, connection, timeout): + command_log.append(command.strip()) + return driver_3_0.SMOOTHIE_ACK + + def _parse_position_response(arg): + return smoothie.position + + monkeypatch.setattr(serial_communication, 'write_and_return', + write_with_log) + monkeypatch.setattr( + driver_3_0, '_parse_position_response', _parse_position_response) + + smoothie.set_acceleration( + {'X': 1, 'Y': 2, 'Z': 3, 'A': 4, 'B': 5, 'C': 6}) + smoothie.push_acceleration() + smoothie.pop_acceleration() + smoothie.set_acceleration( + {'X': 10, 'Y': 20, 'Z': 30, 'A': 40, 'B': 50, 'C': 60}) + smoothie.pop_acceleration() + + expected = [ + ['M204 S10000 A4 B5 C6 X1 Y2 Z3 M400'], + ['M204 S10000 A4 B5 C6 X1 Y2 Z3 M400'], + ['M204 S10000 A40 B50 C60 X10 Y20 Z30 M400'], + ['M204 S10000 A4 B5 C6 X1 Y2 Z3 M400'] + ] + # from pprint import pprint + # pprint(command_log) + fuzzy_assert(result=command_log, expected=expected) + + def test_active_dwelling_current_push_pop(smoothie): assert smoothie._active_current_settings != \ smoothie._dwelling_current_settings diff --git a/shared-data/robot-data/pipetteModelSpecs.json b/shared-data/robot-data/pipetteModelSpecs.json index 70c47d5acb9..a69899ad76e 100644 --- a/shared-data/robot-data/pipetteModelSpecs.json +++ b/shared-data/robot-data/pipetteModelSpecs.json @@ -12,6 +12,7 @@ "modelOffset": [0.0, 0.0, -13], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [1.8263, -0.0958, 1.088], @@ -40,6 +41,7 @@ "modelOffset": [0.0, 0.0, -13], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [1.8263, -0.0958, 1.088], @@ -68,6 +70,7 @@ "modelOffset": [0.0, 0.0, -13], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [1.8263, -0.0958, 1.088], @@ -96,6 +99,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [1.893415617, -1.1069, 3.042593193], @@ -123,6 +127,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [1.893415617, -1.1069, 3.042593193], @@ -150,6 +155,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [1.893415617, -1.1069, 3.042593193], @@ -177,6 +183,7 @@ "modelOffset": [0.0, 0.0, 0.0], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [11.79687499, -0.0098, 3.064988953], @@ -202,6 +209,7 @@ "modelOffset": [0.0, 0.0, 0.0], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [11.79687499, -0.0098, 3.064988953], @@ -227,6 +235,7 @@ "modelOffset": [0.0, 0.0, 0.0], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [11.79687499, -0.0098, 3.064988953], @@ -252,6 +261,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [12.29687531, -0.0049, 3.134703694], @@ -277,6 +287,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [12.29687531, -0.0049, 3.134703694], @@ -302,6 +313,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [12.29687531, -0.0049, 3.134703694], @@ -327,6 +339,7 @@ "modelOffset": [0.0, 0.0, 0.0], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [36.19844973, 0.043, 16.548], @@ -355,6 +368,7 @@ "modelOffset": [0.0, 0.0, 0.0], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [36.19844973, 0.043, 16.548], @@ -383,6 +397,7 @@ "modelOffset": [0.0, 0.0, 0.0], "plungerCurrent": 0.3, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [36.19844973, 0.043, 16.548], @@ -411,6 +426,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [57.25698968, 0.017, 18.132], @@ -436,6 +452,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [57.25698968, 0.017, 18.132], @@ -461,6 +478,7 @@ "modelOffset": [0.0, 31.5, -25.8], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [57.25698968, 0.017, 18.132], @@ -486,6 +504,7 @@ "modelOffset": [0.0, 0.0, 20.0], "plungerCurrent": 0.5, "dropTipCurrent": 0.5, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [148.9157, 0.0213, 56.3986], @@ -515,6 +534,7 @@ "modelOffset": [0.0, 0.0, 20.0], "plungerCurrent": 0.5, "dropTipCurrent": 0.7, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [148.9157, 0.0213, 56.3986], @@ -544,6 +564,7 @@ "modelOffset": [0.0, 0.0, 20.0], "plungerCurrent": 0.5, "dropTipCurrent": 0.7, + "dropTipSpeed": 5, "ulPerMm": { "aspirate": [ [148.9157, 0.0213, 56.3986], diff --git a/shared-data/robot-data/schemas/pipetteModelSpecsSchema.json b/shared-data/robot-data/schemas/pipetteModelSpecsSchema.json index bd7b7ee761a..a21a8993bd9 100644 --- a/shared-data/robot-data/schemas/pipetteModelSpecsSchema.json +++ b/shared-data/robot-data/schemas/pipetteModelSpecsSchema.json @@ -38,6 +38,7 @@ "modelOffset", "plungerCurrent", "dropTipCurrent", + "dropTipSpeed", "ulPerMm", "quirks", "tipLength" @@ -64,6 +65,7 @@ "modelOffset": {"$ref": "#/definitions/xyzArray"}, "plungerCurrent": {"type": "number"}, "dropTipCurrent": {"type": "number"}, + "dropTipSpeed": {"type": "number"}, "ulPerMm": { "type": "object", "required": ["aspirate", "dispense"],