Add support for Hamilton MLPrep
A (nearly) complete firmware implementation for the Hamilton MLPrep, including the ip layer, harp2 (hamilton robot protocol?) and hoi2. Tested the big five (setup, tip pickup, tip drop, aspirate, dispense) on ours. This is the world's first interface to the Prep that doesn't use the internal computer & touch screen: you can now properly program it.
Plug your computer into the robot's ethernet port (should be a passthrough to the internal board). Assign a static ip to your computer in the 192.168.100.x range, but not 192.168.100.102 since that's the robot's static ip.
TODO:
- [ ] properly define the PrepDeck resource
- [ ] verify it works on other Preps, the harp addressing I haven't figured out 100% yet
- [ ] core grippers
- [ ] error handling
- [ ] manual channel movement works when specifying full xyz coordinates for a channel, but can we do individual dimensions like STAR?
In the branch of this PR, I'm receiving the following error:
from pylabrobot.liquid_handling.backends.hamilton.prep import Prep
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
Cell In[7], line 1
----> 1 from pylabrobot.liquid_handling.backends.hamilton.prep import Prep
File /mnt/c/Users/cmoschner/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/prep.py:10
7 from typing import Any, List, Optional, Tuple, Union
9 from pylabrobot.liquid_handling.backends import LiquidHandlerBackend
---> 10 from pylabrobot.liquid_handling.standard import (
11 Aspiration,
12 AspirationContainer,
13 AspirationPlate,
14 Dispense,
15 DispenseContainer,
16 DispensePlate,
17 Drop,
18 DropTipRack,
19 Pickup,
20 PickupTipRack,
21 ResourceDrop,
22 ResourceMove,
23 ResourcePickup,
24 )
27 class ParameterTypes(Enum):
28 Void = 0
ImportError: cannot import name 'Aspiration' from 'pylabrobot.liquid_handling.standard' (/mnt/c/Users/camillomoschner/pylabrobot/pylabrobot/liquid_handling/standard.py)
@rickwierenga, should this be updated to SingleChannelAspiration (etc.)?
yeah the prep branch was quite old, will fix soon, thanks
I've updated the standard.py command imports to their latest version (though it seems I cannot submit a commit to this PR?), and can then import Prep without a problem.
Next issue:
Sending command: 440006300000020004000400010001000015010002134000000000000103010000021701020000001e001a001701020001002800040000808f4328000400000040401f000000
Received response: 7a0006300000010001000015020004000400010002057600000000000105010000022100020015000f0050003078303030312e3078303045382e3078303230323a307830312c3078303030312c3078304630333b3078303030312e3078303045382e3078303230313a307830312c3078303030322c30783046303300
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[7], line 3
1 lh = LiquidHandler(backend=backend, deck=PrepDeck())
----> 3 await lh.setup()
4 vis = Visualizer(resource=lh)
5 await vis.setup()
File /mnt/c/Users/cmoschner/pylabrobot/pylabrobot/liquid_handling/liquid_handler.py:172, in LiquidHandler.setup(self, **backend_kwargs)
170 self.backend.set_deck(self.deck)
171 self.backend.set_heads(head=self.head, head96=self.head96)
--> 172 await super().setup(**backend_kwargs)
174 self.head = {c: TipTracker(thing=f"Channel {c}") for c in range(self.backend.num_channels)}
175 self.head96 = {c: TipTracker(thing=f"Channel {c}") for c in range(96)}
File /mnt/c/Users/cmoschner/pylabrobot/pylabrobot/machines/machine.py:63, in Machine.setup(self, **backend_kwargs)
62 async def setup(self, **backend_kwargs):
---> 63 await self.backend.setup(**backend_kwargs)
64 self._setup_finished = True
File /mnt/c/Users/cmoschner/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/prep.py:267, in Prep.setup(self)
264 self.socket.connect((self.host, self.port))
265 self.socket.settimeout(30)
--> 267 await self.initialize(
268 tip_drop_params=Prep.InitTipDropParameters(
269 default_values=True,
270 x_position=287.0,
271 rolloff_distance=3,
272 channel_parameters=[],
273 ),
274 smart=False,
275 )
277 await super().setup()
File /mnt/c/Users/cmoschner/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/prep.py:3249, in Prep.initialize(self, tip_drop_params, smart, timeout)
3243 async def initialize(
3244 self,
3245 tip_drop_params: InitTipDropParameters,
3246 smart: bool = False,
3247 timeout: Optional[float] = None,
3248 ) -> None:
-> 3249 return await self.send_command(
3250 command_id=1,
3251 parameters=[
3252 (smart, ParameterTypes.Bool),
3253 (tip_drop_params, ParameterTypes.Structure),
3254 ],
3255 timeout=timeout,
3256 harp_source=self.source_address,
3257 harp_destination=self.destination_address,
3258 )
File /mnt/c/Users/cmoschner/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/prep.py:378, in Prep.send_command(self, command_id, parameters, harp_source, harp_destination, hoi_action, timeout)
375 response = self.socket.recv(1024)
376 print("Received response:", response.hex())
--> 378 self._decode_response(response)
File /mnt/c/Users/cmoschner/pylabrobot/pylabrobot/liquid_handling/backends/hamilton/prep.py:352, in Prep._decode_response(self, response)
350 if len(fragments) > 0 and fragments[0]["format"] == ParameterTypes.HcResult:
351 if fragments[0]["fragment_data"] != 0:
--> 352 raise ValueError(f"Command failed with error code {fragments[0]['fragment_data']}")
354 return
ValueError: Command failed with error code 21
I can see the channels starting to initialise (even the fixed-distance 8-channel head), i.e. move to the front of the arm (performing a flagsearch?), followed by moving into their "default" position. But, immediately after the channels moved into their "default" position this error appears
I've updated the standard.py command imports to their latest version (though it seems I cannot submit a commit to this PR?), and can then import Prep without a problem.
based, can make a branch on your repo and PR into plr:prep?
ValueError: Command failed with error code 21
As far as I understand the prep firmware, this maps to GenericMultipleErrorsReported = 0x0015 (0x15 = 0d21).
Printing the fragments in this string I get:
Fragments: [{'format': <ParameterTypes.HcResult: 33>, 'flags': 0, 'length': 6, 'is_padded': False, 'fragment_data': 21}, {'format': <ParameterTypes.String: 15>, 'flags': 0, 'length': 84, 'is_padded': False, 'fragment_data': '0x0001.0x00E8.0x0202:0x01,0x0001,0x0F03;0x0001.0x00E8.0x0201:0x01,0x0002,0x0F03'}]
... i don't know what '0x0001.0x00E8.0x0202:0x01,0x0001,0x0F03;0x0001.0x00E8.0x0201:0x01,0x0002,0x0F03' means (yet)
fyi, we don't have the 8 channel head
a similar error found in a trace file i got from the prep:
... Type=Error, Src=, Dst=, Message=Source NodeID: 0x0002.0x0009.0x0004 Destination NodeID: 0x0001.0x0001.0x1500 Interface ID: 1 (0x01) Action ID: 1 (0x0001) Harp2 Sequence Number: 57 (0x39) Result: GenericMultipleErrorsReported (0x0015) Approximate Time Sent: 12:01:11.123_942 Timeout: 60000 Additional Information: Exception of type ''Hamilton.Components.TransportLayer.Protocols.HoiException'' was thrown. , Transport=None.";Reno Communication Manager;Communication;Error;Server;0b1976bbe32945f98752c59ffddc503a;;
... Type=ApplicationEntry, Src=, Dst=, Message=Exception type: ComLinkException Message: 0x0001.0x0001.0x2200:0x01,0x0006,0x0F04 (Hamilton.MLPrep.MLPrepSystem.MLPrepRoot.ChannelCoordinator.ChannelXYZCoordinator:IChannelXYZCoordinator,MoveXYZAbsolute,A coordinated movement was stopped early. See following errors for additional details.);0x0001.0x00EC.0x0204:0x01,0x0002,0x0F03 (Hamilton.MLPrep.MLPrepSystem.MLPrepRoot.RearChannel.ZAxis.ZDrive:IZDrive,MoveAbsolute,Motor stall detected.) Source: Hamilton.Components.TransportLayer.ComLink at Hamilton.Components.TransportLayer.ObjectInterfaceCommunication.ComLink.SendAndReceiveEx(HarpAddress srcAddress, HarpAddress dstAddress, Byte interfaceID, Hoi2Action action, UInt16 actionID, Object[]& inParameters, Object[]& outParameters, Int32 timeout) at Hamilton.MLPrep.CMLPrep.Initialize(Boolean smart, InitTipDropParameters tipDropParams, TimeSpan timeout) at Hamilton.XRP2.Instrument.ModuleN.Common.Firmware.MicroLabPrepFirmware.<>c__DisplayClass75_0.<Initialize>b__0() in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.Common\Firmware\MicroLabPrepFirmware.cs:line 782 at Hamilton.XRP2.Instrument.ModuleN.Common.Firmware.ComLinkExceptionScope.Execute(Action action, IDictionary`2 context) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.Common\ComLinkExceptionScope.cs:line 69 at Hamilton.XRP2.Instrument.ModuleN.Common.Firmware.MicroLabPrepFirmware.Initialize(Boolean smart, InitTipDropParameters tipDropParams) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.Common\Firmware\MicroLabPrepFirmware.cs:line 779 at Hamilton.XRP2.Instrument.MicroLabPrep.Firmware.MicroLabPrepFirmwareProxy.<>c__DisplayClass22_0.<Initialize>b__0() in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.Common\Firmware\MicroLabPrepFirmwareProxy.cs:line 73 at Hamilton.XRP2.Instrument.FirmwareProxy.InternalProxy(Action action, Action simulatedAction) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.Common\FirmwareProxy.cs:line 66 at Hamilton.XRP2.Instrument.FirmwareProxy.Proxy(Action action, Action simulatedAction) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.Common\FirmwareProxy.cs:line 86 at Hamilton.XRP2.Instrument.MicroLabPrep.Firmware.MicroLabPrepFirmwareProxy.Initialize(Boolean smart, InitTipDropParameters tipDropParameters) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.Common\Firmware\MicroLabPrepFirmwareProxy.cs:line 75 at Hamilton.XRP2.Instrument.MicroLabPrep.Common.MicroLabPrepFirmwareAdapter.Initialize(Boolean smart) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.PipettingArmControllerEngine.Common\Firmware\MicroLabPrepFirmwareAdapter.cs:line 51 at Hamilton.XRP2.Instrument.MicroLabPrep.Action.Handlers.ExecuteInitializeActionHandler.Execute(IMicroLabPrepPipettingArm controller, Initialize command, CxbeReturn returnObject) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.PipetteArmController\Action\Handlers\ExecuteInitializeActionHandler.cs:line 105 at Hamilton.XRP2.Instrument.Commands.Initialize.InternalExecute(IList`1 parameters, CxbeReturn returnObject) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.PipetteArmController\Commands\Initialize.cs:line 89 at Hamilton.XRP2.Instrument.Commands.MicroLabPrepCommand`1.ExecuteCommand(IList`1 cobjParameter, CxbeReturn objReturn) in C:\Agents\ML Prep Agent 5\_work\506\s\src\ModuleN.PipettingArmControllerEngine.Common\Commands\MicroLabPrepCommand.cs:line 236 at Hamilton.XRP2.Run.CxbeBaseCommand.Execute(IList`1 cobjParameter, CxbeReturn objReturn) at Hamilton.XRP2.Run.CxbeContainerCommand.ExecuteCommand(IList`1 cobjParameter, CxbeReturn objReturn) at Hamilton.XRP2.Run.SchedulerCommand.CxseActivity.ExecuteCommand(IList`1 cobjParameter, CxbeReturn objReturn) at Hamilton.XRP2.Run.CxbeBaseCommand.Execute(IList`1 cobjParameter, CxbeReturn objReturn) at Hamilton.XRP2.Run.CxleRuntimeInternal.Execute(String strEntryPointId, IList`1 cobjParameter) at Hamilton.XRP2.Run.Scheduler.Utils.XslEngineAdapter.Execute(String entryPointId, IList`1 parameter) at Hamilton.XRP2.Run.Scheduler.CsdeActivity.<>c__DisplayClass239_0.<ActivityThreadFunction>b__0() at Hamilton.XRP2.Run.Scheduler.CsdeSchedulerInternal.UnhandledExceptionFrame(Boolean bBeginAbortRun, Action objAction) at Hamilton.XRP2.Run.Scheduler.CsdeActivity.ActivityThreadFunction(Object objState) at Hamilton.XRP2.Run.Scheduler.CsdeThreadPoolThread.ThreadStart() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() ----inner exception details---- Exception type: HoiException Message: Exception of type ''Hamilton.Components.TransportLayer.Protocols.HoiException'' was thrown. Source: Hamilton.Components.TransportLayer.Protocols at Hamilton.Components.TransportLayer.Protocols.HoiProtocol2.SendRecv(HarpAddress srcAddress, HarpAddress dstAddress, HcResult result, HoiPacket2 packet, Boolean response, Int32 timeout) at Hamilton.Components.TransportLayer.ObjectInterfaceCommunication.ComLink.SendAndReceiveEx(HarpAddress srcAddress, HarpAddress dstAddress, Byte interfaceID, Hoi2Action action, UInt16 actionID, Object[]& inParameters, Object[]& outParameters, Int32 timeout), Transport=None.";Reno Communication Manager;Communication;Information;Server;0b1976bbe32945f98752c59ffddc503a;;147
this part stands out:
0x0001.0x00EC.0x0204 : 0x01,0x0002,0x0F03
(Hamilton.MLPrep.MLPrepSystem.MLPrepRoot.RearChannel.ZAxis.ZDrive:
IZDrive, MoveAbsolute, Motor stall detected.)
(spacing added for readability)
0x0F04 is 0d3844, which is in the same range as other Prep.Error objects I found. More importantly, it's the same number as yours: so that would mean 'motor stalled'.
0x0001.0x00E8.0x0202
0x0001.0x00E8.0x0201
the part before the colon could be the address for the two 'heads' (1 & 8 channel). do you have two?
One of the parameters of Prep.initialize (called in setup), is tip_drop_params: InitTipDropParameters, which has channel_parameters: list["Prep.DropTipParameters"] as an attr. It is not set, but could it be that the prep is gonna discard tips and has some default values that don't work with the 8 channel head? Just guessing. Does it physically look like this could be true? I would play around with these values a little bit, since it's impossible for you to get a real log file.
@BioCam did you try to run initialize with smart = True?
@BioCam did you try to run
initializewithsmart = True?
Unfortunately, not difference in the error message with smart = True
I also observed some "Motor stall" errors when I started with the Prep, however I never investigated them as they disapeared later on... @BioCam it would be interesting to get a logfile of a simple method run on the PrepUI and one of a PLR run.
I also observed some "Motor stall" errors when I started with the Prep, however I never investigated them as they disapeared later on... @BioCam it would be interesting to get a logfile of a simple method run on the PrepUI and one of a PLR run.
@jrast, interesting, so it might not just be my machine. I am a bit skeptical of my machine because I bought it second-hand, the seller advertised it as "display broken, otherwise functional" - I figured out the display is absolutely fine, but the onboard Gigabyte PC's ethernet port appears to have connection issues... using PLR on a separate PC makes the machine functional(ish) again :)
But as a consequence I don't have access to the PrepUI (at least until I figure out how to make the VirtualBox running a PrepUI work - will keep this PR updated on progress)