CO-RE-based labware movement discussion (PLR)

Hey all, and maybe @CamilloMoschner and @ben in particular: I’m trying to incorporate some CORE-based plate moves and having some issues with picking up the CORE grippers. The default pickup location for PLR seems to not correspond to where my grippers are held (see photo).

It looks like the robot thinks the grippers are and inch or so towards the back from where they actually are. I know there are different CORE gripper mounts, but I’m not sure which I have, or if/how it’s specified in PLR, or if I can specify manually with x,y coords. Any ideas?

there are multiple co-re configuration types, and right now the firmware command in star.py uses the coordinates of a different gripper block than yours. perhaps you can help by adding your configuration?

@jonlaurent, similarly to what Ben said: Can you please give us some more information regarding your Hamilton machine?

From your image it looks like you have a COREGripTool AtWaste 1000ul?

I believe that PLR currently only has integrated COREGripTool OnWaste 1000ul.

In your image, is this the channel positioning that you have after asking PLR to get the grippers, i.e. the channels are shifted ‘backwards’ in the y-dimension by about 15mm?
Is the distance between the grippers in this position equivalent to the distance of the grippers in their holder?

For 1000ul channel gripper holders I believe there are only 2 options, the AtWaste and the OnWaste options. So we should be able to figure this out and add the one we’re missing to PLR :slight_smile:

Can you please generate a VENUS “method” that uses the grippers, e.g. to pick up a plate and place it down again, and then share the firmware command file with us?

The firmware command file will be in C:\Program Files (x86)\HAMILTON\LogFiles and start with HxUsbComm followed be the date yyyymmdd.

This file contains the information about how far off the robot is when picking up the grippers and should hopefully be enough information to add an OnWaste or AtWaste option to plate movement functions in PLR.

1 Like

Hey guys, thanks for helping out. I’m happy to contribute to additional configurations here, but you may have to bear with me as I learn my way around it all. I’m working on this again now, so I can share some of the info you requested @CamilloMoschner.

I’m actually working with two separate (quite old, mfd '05 and '10) systems, and I noticed as part of this that they each have different gripper mount configurations. The newer one has the OnWaste tool, while the older one (which was originally referenced above) has the AtWaste tool. The default core move commands work fine on the OnWaste configured machine, so we can assume that’s the default in PLR and the AtWaste is the missing config.

I’ve made a simple VENUS method as Camillo requested for the AtWaste configured robot, see below for log file. You’ll see there are several errors there, those are from it attempting to pick up the front gripper but failing several times because of a slight misalignment between the channel and the gripper. I got it to pick up finally by pushing them into alignment manually :upside_down_face:.

The method I made can be seen in the screenshot below as well. If it matters, I set the manual override to 84mm grip width and 90 mm approach width, as it forced me to manually override the labware parameters.

Log:

< 06:47:41.290 8AF#8000#00: C0RQid0101
> 06:47:41.306 8AF#8000#00: C0RQid0101rq0000
< 06:47:41.306 8AF#8000#00: C0QBid0102
> 06:47:41.322 8AF#8000#00: C0QBid0102er00/00qb1
< 06:47:41.322 8AF#8000#00: C0RIid0103
> 06:47:41.337 8AF#8000#00: C0RIid0103er00/00si2018-09-27sn1487
< 06:47:41.337 8AF#8000#00: C0QMid0104
> 06:47:41.384 8AF#8000#00: C0QMid0104er00/00ka000003xt30xa30xw08000xl05xr00xm03500xx11400ys090xu3700xv3700yu0060kl360kc0yx0060ke00000000xn00xo00ym6065kr0km360
< 06:47:41.384 8AF#8000#00: C0RMid0105
> 06:47:41.447 8AF#8000#00: C0RMid0105er00/00kb01kp08 C00000 X00000 P10000 P20000 P30000 P40000 P50000 P60000 P70000 P80000 H00000
< 06:47:41.447 8AF#8000#00: C0RFid0106
> 06:47:41.463 8AF#8000#00: C0RFid0106er00/00rf7.5S 14 2017_09_26 (GRU C0 PLE)
< 06:47:41.463 8AF#8000#00: P1RFid0107
> 06:47:41.478 8AF#8000#00: P1RFid0107rf3.9S f 2016-06-02
< 06:47:41.478 8AF#8000#00: P1RJid0108
> 06:47:41.494 8AF#8000#00: P1RJid0108jd2020-06-10js1
< 06:47:41.494 8AF#8000#00: P2RFid0109
> 06:47:41.509 8AF#8000#00: P2RFid0109rf3.9S f 2016-06-02
< 06:47:41.509 8AF#8000#00: P2RJid0110
> 06:47:41.525 8AF#8000#00: P2RJid0110jd2020-06-10js1
< 06:47:41.525 8AF#8000#00: P3RFid0111
> 06:47:41.541 8AF#8000#00: P3RFid0111rf3.9S f 2016-06-02
< 06:47:41.541 8AF#8000#00: P3RJid0112
> 06:47:41.556 8AF#8000#00: P3RJid0112jd2020-06-10js1
< 06:47:41.556 8AF#8000#00: P4RFid0113
> 06:47:41.556 8AF#8000#00: P4RFid0113rf3.9S f 2016-06-02
< 06:47:41.556 8AF#8000#00: P4RJid0114
> 06:47:41.572 8AF#8000#00: P4RJid0114jd2020-06-10js1
< 06:47:41.572 8AF#8000#00: P5RFid0115
> 06:47:41.587 8AF#8000#00: P5RFid0115rf3.9S f 2016-06-02
< 06:47:41.587 8AF#8000#00: P5RJid0116
> 06:47:41.603 8AF#8000#00: P5RJid0116jd2020-06-10js1
< 06:47:41.603 8AF#8000#00: P6RFid0117
> 06:47:41.619 8AF#8000#00: P6RFid0117rf3.9S f 2016-06-02
< 06:47:41.619 8AF#8000#00: P6RJid0118
> 06:47:41.634 8AF#8000#00: P6RJid0118jd2020-06-10js1
< 06:47:41.634 8AF#8000#00: P7RFid0119
> 06:47:41.650 8AF#8000#00: P7RFid0119rf3.9S f 2016-06-02
< 06:47:41.650 8AF#8000#00: P7RJid0120
> 06:47:41.666 8AF#8000#00: P7RJid0120jd2020-06-10js1
< 06:47:41.666 8AF#8000#00: P8RFid0121
> 06:47:41.666 8AF#8000#00: P8RFid0121rf3.9S f 2016-06-02
< 06:47:41.681 8AF#8000#00: P8RJid0122
> 06:47:41.681 8AF#8000#00: P8RJid0122jd2020-06-10js1
< 06:47:41.681 8AF#8000#00: C0QBid0123
> 06:47:41.712 8AF#8000#00: C0QBid0123er00/00qb1
< 06:47:41.712 8AF#8000#00: X0RFid0124
> 06:47:41.712 8AF#8000#00: X0RFid0124rf1.4S 2012-04-25
< 06:47:41.712 8AF#8000#00: X0RJid0125
> 06:47:41.728 8AF#8000#00: X0RJid0125jd2020-06-10js1
< 06:47:41.728 8AF#8000#00: H0RFid0126
> 06:47:41.728 8AF#8000#00: H0RFid0126rf5.0S 2010-11-03 (H0 XE167)
< 06:47:41.728 8AF#8000#00: H0RJid0127
> 06:47:41.743 8AF#8000#00: H0RJid0127jd2020-06-10js1
< 06:47:41.743 8AF#8000#00: C0RMid0128
> 06:47:41.806 8AF#8000#00: C0RMid0128er00/00kb01kp08 C00000 X00000 P10000 P20000 P30000 P40000 P50000 P60000 P70000 P80000 H00000
< 06:47:41.822 8AF#8000#00: C0QMid0129
> 06:47:41.853 8AF#8000#00: C0QMid0129er00/00ka000003xt30xa30xw08000xl05xr00xm03500xx11400ys090xu3700xv3700yu0060kl360kc0yx0060ke00000000xn00xo00ym6065kr0km360
< 06:47:41.853 8AF#8000#00: H0QGid0130
> 06:47:41.868 8AF#8000#00: H0QGid0130qg2
< 06:47:41.868 8AF#8000#00: C0SRid0131
> 06:47:41.884 8AF#8000#00: C0SRid0131er00/00sr055
< 06:47:41.915 8AF#8000#00: C0RUid0132
> 06:47:41.947 8AF#8000#00: C0RUid0132er00/00ru00950 08000 30000 30000
< 06:47:51.118 8AF#8000#00: C0RVid0133vo00
> 06:47:51.180 8AF#8000#00: C0RVid0133er00/00vd2020-06-09 14:10vs1
< 06:47:51.180 8AF#8000#00: C0RVid0134vo01
> 06:47:51.243 8AF#8000#00: C0RVid0134er00/00vd2020-06-09 14:10vs1
< 06:47:51.243 8AF#8000#00: C0RSid0135
> 06:47:51.259 8AF#8000#00: C0RSid0135er00/00ts2020-06-09 14:21
< 06:47:51.259 8AF#8000#00: C0RIid0136
> 06:47:51.274 8AF#8000#00: C0RIid0136er00/00si2018-09-27sn1487
< 06:47:51.289 8AF#8000#00: C0RMid0137
> 06:47:51.352 8AF#8000#00: C0RMid0137er00/00kb01kp08 C00000 X00000 P10000 P20000 P30000 P40000 P50000 P60000 P70000 P80000 H00000
< 06:47:51.352 8AF#8000#00: P1RVid0138
> 06:47:51.368 8AF#8000#00: P1RVid0138na0000048580nb0000003118nc0000056682nd0000209828
< 06:47:51.368 8AF#8000#00: P2RVid0139
> 06:47:51.384 8AF#8000#00: P2RVid0139na0000028369nb0000003112nc0000037075nd0000084285
< 06:47:51.384 8AF#8000#00: P3RVid0140
> 06:47:51.399 8AF#8000#00: P3RVid0140na0000023841nb0000003105nc0000033656nd0000077230
< 06:47:51.399 8AF#8000#00: P4RVid0141
> 06:47:51.415 8AF#8000#00: P4RVid0141na0000027664nb0000003095nc0000036824nd0000087131
< 06:47:51.430 8AF#8000#00: P5RVid0142
> 06:47:51.430 8AF#8000#00: P5RVid0142na0000027451nb0000003095nc0000037019nd0000088311
< 06:47:51.446 8AF#8000#00: P6RVid0143
> 06:47:51.462 8AF#8000#00: P6RVid0143na0000014435nb0000003095nc0000024876nd0000059883
< 06:47:51.462 8AF#8000#00: P7RVid0144
> 06:47:51.477 8AF#8000#00: P7RVid0144na0000106104nb0000003098nc0000032191nd0000078895
< 06:47:51.477 8AF#8000#00: P8RVid0145
> 06:47:51.493 8AF#8000#00: P8RVid0145na0000117752nb0000003100nc0000041832nd0000180285
< 06:47:51.493 8AF#8000#00: P1VWid0146
> 06:47:51.508 8AF#8000#00: P1VWid0146er30
< 06:47:51.508 8AF#8000#00: P2VWid0147
> 06:47:51.524 8AF#8000#00: P2VWid0147er30
< 06:47:51.524 8AF#8000#00: P3VWid0148
> 06:47:51.524 8AF#8000#00: P3VWid0148er30
< 06:47:51.524 8AF#8000#00: P4VWid0149
> 06:47:51.539 8AF#8000#00: P4VWid0149er30
< 06:47:51.539 8AF#8000#00: P5VWid0150
> 06:47:51.555 8AF#8000#00: P5VWid0150er30
< 06:47:51.555 8AF#8000#00: P6VWid0151
> 06:47:51.571 8AF#8000#00: P6VWid0151er30
< 06:47:51.571 8AF#8000#00: P7VWid0152
> 06:47:51.587 8AF#8000#00: P7VWid0152er30
< 06:47:51.587 8AF#8000#00: P8VWid0153
> 06:47:51.602 8AF#8000#00: P8VWid0153er30
< 06:47:51.633 8AF#8000#00: C0TTid0154tt44tf1tl0570tv01750tg3tu0
> 06:47:51.649 8AF#8000#00: C0TTid0154er00/00
< 06:47:51.664 8AF#8000#00: C0TTid0155tt33tf0tl0319tv00700tg6tu0
> 06:47:51.696 8AF#8000#00: C0TTid0155er00/00
< 06:47:51.696 8AF#8000#00: C0TTid0156tt22tf0tl0424tv00650tg2tu0
> 06:47:51.727 8AF#8000#00: C0TTid0156er00/00
< 06:47:51.743 8AF#8000#00: C0TTid0157tt11tf0tl0490tv00150tg2tu1
> 06:47:51.774 8AF#8000#00: C0TTid0157er00/00
< 06:47:51.774 8AF#8000#00: C0TTid0158tt03tf1tl0219tv00100tg1tu0
> 06:47:51.805 8AF#8000#00: C0TTid0158er00/00
< 06:47:51.821 8AF#8000#00: C0TTid0159tt45tf1tl0870tv03450tg3tu0
> 06:47:51.852 8AF#8000#00: C0TTid0159er00/00
< 06:47:51.883 8AF#8000#00: C0TTid0160tt34tf0tl0235tv00010tg2tu0
> 06:47:51.899 8AF#8000#00: C0TTid0160er00/00
< 06:47:51.914 8AF#8000#00: C0TTid0161tt23tf1tl0424tv00600tg2tu0
> 06:47:51.946 8AF#8000#00: C0TTid0161er00/00
< 06:47:51.961 8AF#8000#00: C0TTid0162tt12tf0tl0490tv03500tg2tu1
> 06:47:51.993 8AF#8000#00: C0TTid0162er00/00
< 06:47:52.008 8AF#8000#00: C0TTid0163tt04tf0tl0871tv12500tg3tu0
> 06:47:52.024 8AF#8000#00: C0TTid0163er00/00
< 06:47:52.039 8AF#8000#00: C0TTid0164tt46tf0tl0290tv17200tg3tu1
> 06:47:52.071 8AF#8000#00: C0TTid0164er00/00
< 06:47:52.086 8AF#8000#00: C0TTid0165tt35tf0tl0570tv03500tg3tu0
> 06:47:52.118 8AF#8000#00: C0TTid0165er00/00
< 06:47:52.133 8AF#8000#00: C0TTid0166tt24tf0tl0820tv01800tg3tu1
> 06:47:52.149 8AF#8000#00: C0TTid0166er00/00
< 06:47:52.164 8AF#8000#00: C0TTid0167tt13tf0tl0820tv12500tg3tu1
> 06:47:52.196 8AF#8000#00: C0TTid0167er00/00
< 06:47:52.211 8AF#8000#00: C0TTid0168tt05tf1tl0871tv10650tg3tu0
> 06:47:52.227 8AF#8000#00: C0TTid0168er00/00
< 06:47:52.258 8AF#8000#00: C0TTid0169tt47tf0tl0465tv00010tg2tu0
> 06:47:52.274 8AF#8000#00: C0TTid0169er00/00
< 06:47:52.289 8AF#8000#00: C0TTid0170tt36tf0tl0870tv03850tg3tu0
> 06:47:52.321 8AF#8000#00: C0TTid0170er00/00
< 06:47:52.336 8AF#8000#00: C0TTid0171tt25tf0tl1080tv54200tg5tu0
> 06:47:52.368 8AF#8000#00: C0TTid0171er00/00
< 06:47:52.383 8AF#8000#00: C0TTid0172tt14tf0tl0220tv00010tg0tu0
> 06:47:52.399 8AF#8000#00: C0TTid0172er00/00
< 06:47:52.414 8AF#8000#00: C0TTid0173tt06tf0tl0519tv00700tg2tu1
> 06:47:52.446 8AF#8000#00: C0TTid0173er00/00
< 06:47:52.461 8AF#8000#00: C0TTid0174tt48tf0tl0829tv08000tg3tu1
> 06:47:52.477 8AF#8000#00: C0TTid0174er00/00
< 06:47:52.492 8AF#8000#00: C0TTid0175tt37tf0tl0319tv00700tg6tu0
> 06:47:52.524 8AF#8000#00: C0TTid0175er00/00
< 06:47:52.539 8AF#8000#00: C0TTid0176tt26tf0tl1080tv00010tg5tu0
> 06:47:52.571 8AF#8000#00: C0TTid0176er00/00
< 06:47:52.586 8AF#8000#00: C0TTid0177tt15tf0tl0256tv00350tg4tu0
> 06:47:52.618 8AF#8000#00: C0TTid0177er00/00
< 06:47:52.618 8AF#8000#00: C0TTid0178tt07tf0tl0519tv03500tg2tu1
> 06:47:52.649 8AF#8000#00: C0TTid0178er00/00
< 06:47:52.664 8AF#8000#00: C0TTid0179tt49tf0tl0820tv03020tg3tu1
> 06:47:52.696 8AF#8000#00: C0TTid0179er00/00
< 06:47:52.711 8AF#8000#00: C0TTid0180tt38tf0tl0490tv00650tg2tu1
> 06:47:52.743 8AF#8000#00: C0TTid0180er00/00
< 06:47:52.758 8AF#8000#00: C0TTid0181tt27tf0tl0190tv00010tg0tu0
> 06:47:52.774 8AF#8000#00: C0TTid0181er00/00
< 06:47:52.789 8AF#8000#00: C0TTid0182tt16tf0tl0251tv00350tg0tu0
> 06:47:52.821 8AF#8000#00: C0TTid0182er00/00
< 06:47:52.836 8AF#8000#00: C0TTid0183tt08tf0tl0871tv12500tg3tu1
> 06:47:52.868 8AF#8000#00: C0TTid0183er00/00
< 06:47:52.883 8AF#8000#00: C0TTid0184tt09tf0tl0731tv12500tg3tu0
> 06:47:52.899 8AF#8000#00: C0TTid0184er00/00
< 06:47:52.930 8AF#8000#00: C0TTid0185tt39tf0tl0820tv01200tg3tu1
> 06:47:52.946 8AF#8000#00: C0TTid0185er00/00
< 06:47:52.961 8AF#8000#00: C0TTid0186tt28tf0tl0626tv04000tg6tu0
> 06:47:52.993 8AF#8000#00: C0TTid0186er00/00
< 06:47:53.008 8AF#8000#00: C0TTid0187tt17tf0tl0251tv00350tg0tu0
> 06:47:53.024 8AF#8000#00: C0TTid0187er00/00
< 06:47:53.039 8AF#8000#00: C0TTid0188tt29tf1tl1080tv43670tg5tu0
> 06:47:53.071 8AF#8000#00: C0TTid0188er00/00
< 06:47:53.086 8AF#8000#00: C0TTid0189tt18tf1tl0210tv12500tg0tu1
> 06:47:53.118 8AF#8000#00: C0TTid0189er00/00
< 06:47:53.133 8AF#8000#00: C0TTid0190tt19tf0tl0534tv00670tg2tu0
> 06:47:53.149 8AF#8000#00: C0TTid0190er00/00
< 06:47:53.164 8AF#8000#00: C0TTid0191tt50tf0tl0820tv08000tg3tu1
> 06:47:53.196 8AF#8000#00: C0TTid0191er00/00
< 06:47:53.211 8AF#8000#00: C0TTid0192tt51tf0tl0111tv00010tg0tu0
> 06:47:53.242 8AF#8000#00: C0TTid0192er00/00
< 06:47:53.242 8AF#8000#00: C0TTid0193tt40tf0tl0820tv02000tg3tu1
> 06:47:53.274 8AF#8000#00: C0TTid0193er00/00
< 06:47:53.289 8AF#8000#00: C0TTid0194tt52tf0tl0430tv00010tg0tu0
> 06:47:53.321 8AF#8000#00: C0TTid0194er00/00
< 06:47:53.336 8AF#8000#00: C0TTid0195tt41tf0tl0820tv03460tg3tu1
> 06:47:53.352 8AF#8000#00: C0TTid0195er00/00
< 06:47:53.367 8AF#8000#00: C0TTid0196tt30tf0tl0519tv04000tg2tu0
> 06:47:53.399 8AF#8000#00: C0TTid0196er00/00
< 06:47:53.414 8AF#8000#00: C0TTid0197tt00tf0tl0519tv04000tg2tu0
> 06:47:53.446 8AF#8000#00: C0TTid0197er00/00
< 06:47:53.461 8AF#8000#00: C0TTid0198tt53tf0tl0485tv35000tg0tu0
> 06:47:53.477 8AF#8000#00: C0TTid0198er00/00
< 06:47:53.492 8AF#8000#00: C0TTid0199tt42tf0tl0490tv03550tg2tu1
> 06:47:53.524 8AF#8000#00: C0TTid0199er00/00
< 06:47:53.539 8AF#8000#00: C0TTid0200tt31tf0tl0422tv00650tg2tu0
> 06:47:53.571 8AF#8000#00: C0TTid0200er00/00
< 06:47:53.586 8AF#8000#00: C0TTid0201tt20tf0tl0343tv00650tg4tu0
> 06:47:53.602 8AF#8000#00: C0TTid0201er00/00
< 06:47:53.617 8AF#8000#00: C0TTid0202tt01tf1tl0519tv03600tg2tu0
> 06:47:53.649 8AF#8000#00: C0TTid0202er00/00
< 06:47:53.664 8AF#8000#00: C0TTid0203tt43tf0tl0820tv11350tg3tu1
> 06:47:53.696 8AF#8000#00: C0TTid0203er00/00
< 06:47:53.711 8AF#8000#00: C0TTid0204tt32tf0tl0219tv00150tg1tu0
> 06:47:53.727 8AF#8000#00: C0TTid0204er00/00
< 06:47:53.758 8AF#8000#00: C0TTid0205tt21tf0tl0442tv00610tg6tu1
> 06:47:53.774 8AF#8000#00: C0TTid0205er00/00
< 06:47:53.789 8AF#8000#00: C0TTid0206tt10tf0tl0519tv04000tg2tu0
> 06:47:53.820 8AF#8000#00: C0TTid0206er00/00
< 06:47:53.820 8AF#8000#00: C0TTid0207tt02tf0tl0219tv00150tg1tu0
> 06:47:53.852 8AF#8000#00: C0TTid0207er00/00
< 06:47:53.852 8AF#8000#00: C0DRid0208
> 06:47:53.867 8AF#8000#00: C0DRid0208er00/00
< 06:47:53.883 8AF#8000#00: C0CUid0209cu0
> 06:47:53.899 8AF#8000#00: C0CUid0209er00/00
< 06:47:53.899 8AF#8000#00: PXAFid0210af0
> 06:47:54.039 8AF#8000#00: PXAFid0210er00
< 06:47:54.039 8AF#8000#00: C0QSid0211
> 06:47:54.086 8AF#8000#00: C0QSid0211er00/00qs0 0 0 0 0 0 0 0
< 06:47:54.086 8AF#8000#00: C0RJid0212
> 06:47:54.133 8AF#8000#00: C0RJid0212er00/00tq1 1 1 1 1 1 1 1
< 06:47:54.133 8AF#8000#00: C0AWid0213
> 06:47:54.477 8AF#8000#00: C0AWid0213er00/00
< 06:47:54.477 8AF#8000#00: C0CBid0214bt7Fmq00
> 06:47:54.508 8AF#8000#00: C0CBid0214er00/00
< 06:47:54.554 8AF#8000#00: C0QWid0215
> 06:47:54.602 8AF#8000#00: C0QWid0215er00/00qw1
< 06:47:54.602 8AF#8000#00: C0RTid0216
> 06:47:54.648 8AF#8000#00: C0RTid0216er00/00rt0 0 0 0 0 0 0 0
< 06:47:54.648 8AF#8000#00: C0QHid0217
> 06:47:54.680 8AF#8000#00: C0QHid0217er00/00qh0
< 06:47:54.711 8AF#8000#00: C0ZTid0218xs07980xd0ya1055yb0795pa07pb08tp2350tz2250th2450tt14
> 06:48:00.397 8AF#8000#00: P8  er00 sm Tip Pick Up Error 75; 1. Try; Tip Target Z Position = 0; Tip Z Position = 967; Tip Presence Sensor = 0
> 06:48:03.819 8AF#8000#00: P8  er00 sm Tip Pick Up Error 75; 2. Try; Tip Target Z Position = 0; Tip Z Position = 977; Tip Presence Sensor = 0
> 06:48:07.553 8AF#8000#00: P8  er00 sm Tip Pick Up Error 75; 3. Try; Tip Target Z Position = 0; Tip Z Position = 703; Tip Presence Sensor = 0
> 06:48:09.382 8AF#8000#00: C0ZTid0218er99/00 P808/75sx000 000 000 000 000 000 000 000sg000 000 000 000 000 000 471 703
< 06:48:09.382 8AF#8000#00: C0RTid0219
> 06:48:09.429 8AF#8000#00: C0RTid0219er00/00rt0 0 0 0 0 0 1 0
< 06:48:27.779 8AF#8000#00: C0ZTid0220xs07980xd0ya1055yb0795pa00pb08tp2350tz2250th2450tt14
> 06:48:32.061 8AF#8000#00: P8  er00 sm Tip Pick Up Error 75; 1. Try; Tip Target Z Position = 0; Tip Z Position = 959; Tip Presence Sensor = 0
> 06:48:35.780 8AF#8000#00: P8  er00 sm Tip Pick Up Error 75; 2. Try; Tip Target Z Position = 0; Tip Z Position = 723; Tip Presence Sensor = 0
> 06:48:39.514 8AF#8000#00: P8  er00 sm Tip Pick Up Error 75; 3. Try; Tip Target Z Position = 0; Tip Z Position = 721; Tip Presence Sensor = 0
> 06:48:41.342 8AF#8000#00: C0ZTid0220er99/00 P808/75sx000 000 000 000 000 000 000 000sg000 000 000 000 000 000 000 721
< 06:48:41.342 8AF#8000#00: C0RTid0221
> 06:48:41.388 8AF#8000#00: C0RTid0221er00/00rt0 0 0 0 0 0 1 0
< 06:48:47.002 8AF#8000#00: C0ZTid0222xs07980xd0ya1055yb0795pa00pb08tp2350tz2250th2450tt14
> 06:48:51.267 8AF#8000#00: P8  er00 sm Tip Pick Up Error 75; 1. Try; Tip Target Z Position = 0; Tip Z Position = 958; Tip Presence Sensor = 0
> 06:48:55.720 8AF#8000#00: C0ZTid0222er00/00sx000 000 000 000 000 000 000 000sg000 000 000 000 000 000 000 507
< 06:48:55.720 8AF#8000#00: C0RTid0223
> 06:48:55.767 8AF#8000#00: C0RTid0223er00/00rt0 0 0 0 0 0 1 1
< 06:48:55.798 8AF#8000#00: C0RTid0224
> 06:48:55.845 8AF#8000#00: C0RTid0224er00/00rt0 0 0 0 0 0 1 1
< 06:48:55.845 8AF#8000#00: C0ZPid0225xs07075xd0yj1145yv2778zj1954zy1287yo0900yg0840yw15th2750te2750
> 06:49:00.189 8AF#8000#00: C0ZPid0225er00/00
< 06:49:00.205 8AF#8000#00: C0ZMid0226xs07075xd0yj1145zj1954th2750zy1287xg4
> 06:49:01.642 8AF#8000#00: C0ZMid0226er00/00
< 06:49:01.657 8AF#8000#00: C0ZRid0227xs07075xd0yj1145zj1954zi010yo0900te2750th2750zy1287xg4
> 06:49:05.439 8AF#8000#00: C0ZRid0227er00/00
< 06:49:05.439 8AF#8000#00: C0ZSid0228xs07980xd0ya1055yb0795pa07pb08tp2150tz2050th2450te2450
> 06:49:10.439 8AF#8000#00: C0ZSid0228er00/00kz000 000 000 000 000 000 345 359vz000 000 000 000 000 000 289 363
< 06:49:10.439 8AF#8000#00: C0RTid0229
> 06:49:10.486 8AF#8000#00: C0RTid0229er00/00rt0 0 0 0 0 0 0 0
< 06:49:10.564 8AF#8000#00: C0AWid0230
> 06:49:10.908 8AF#8000#00: C0AWid0230er00/00
< 06:49:10.923 8AF#8000#00: C0RTid0231
> 06:49:10.970 8AF#8000#00: C0RTid0231er00/00rt0 0 0 0 0 0 0 0
< 06:49:10.970 8AF#8000#00: C0QHid0232
> 06:49:10.986 8AF#8000#00: C0QHid0232er00/00qh0
< 06:49:10.986 8AF#8000#00: C0ZAid0233
> 06:49:11.986 8AF#8000#00: C0ZAid0233er00/00
< 06:49:11.986 8AF#8000#00: C0EVid0234
> 06:49:12.314 8AF#8000#00: C0EVid0234er00/00
< 06:49:12.314 8AF#8000#00: C0JEid0235
> 06:49:14.079 8AF#8000#00: C0JEid0235er00/00
< 06:49:14.079 8AF#8000#00: C0DRid0236
> 06:49:14.095 8AF#8000#00: C0DRid0236er00/00
< 06:49:14.095 8AF#8000#00: C0AZid0237
> 06:49:14.860 8AF#8000#00: C0AZid0237er00/00
< 06:49:14.875 8AF#8000#00: P1RVid0238
> 06:49:14.891 8AF#8000#00: P1RVid0238na0000048580nb0000003118nc0000056682nd0000209828
< 06:49:14.891 8AF#8000#00: P2RVid0239
> 06:49:14.907 8AF#8000#00: P2RVid0239na0000028369nb0000003112nc0000037075nd0000084285
< 06:49:14.907 8AF#8000#00: P3RVid0240
> 06:49:14.923 8AF#8000#00: P3RVid0240na0000023841nb0000003105nc0000033656nd0000077230
< 06:49:14.923 8AF#8000#00: P4RVid0241
> 06:49:14.938 8AF#8000#00: P4RVid0241na0000027664nb0000003095nc0000036824nd0000087131
< 06:49:14.938 8AF#8000#00: P5RVid0242
> 06:49:14.954 8AF#8000#00: P5RVid0242na0000027451nb0000003095nc0000037019nd0000088311
< 06:49:14.954 8AF#8000#00: P6RVid0243
> 06:49:14.969 8AF#8000#00: P6RVid0243na0000014435nb0000003095nc0000024876nd0000059883
< 06:49:14.969 8AF#8000#00: P7RVid0244
> 06:49:14.985 8AF#8000#00: P7RVid0244na0000106105nb0000003099nc0000032191nd0000078895
< 06:49:14.985 8AF#8000#00: P8RVid0245
> 06:49:15.001 8AF#8000#00: P8RVid0245na0000117755nb0000003101nc0000041832nd0000180285
< 06:49:15.001 8AF#8000#00: H0RVid0246
> 06:49:15.016 8AF#8000#00: H0RVid0246na0000004725nb0000004726nc0000008605nd0000009750

3 Likes

Thank you for confirming.

  • AtWaste → old system, not yet working in PLR
  • OnWaste → new system, working in PLR

Can you please confirm:
Even with VENUS you had to manually push the front gripper a bit to make the channel pick it up?

I believe you are referring to the “Grip Move Plate (Single Step)” command here?
“Approach width” being the distance between the two channels when moving down in z to get to the pickup height, next to the plate.
And “grip width” being the distance between the two channels move towards each other when picking up the plate, and moving the plate around.

The gripper pickup is taking place one step before this and should not be affected by these parameters.


Something to try out:

Here is a PLR command I generated for you based on the log file you provided:

Get CoRe gripper tool

await lh.send_command(
    module="C0",
    command="ZT",
    xs="07980", # CoRe gripper tool X position [0.1mm]
    xd="0", # X direction 0 = positive 1 = negative
    ya="1055", # First (lower channel) CoRe gripper tool Y pos. [0.1mm]  <======= THIS IS WHAT YOU WANT TO CHANGE
    yb="0795", # Second (higher channel) CoRe gripper tool Y pos.[0.1mm] <======= THIS IS WHAT YOU WANT TO CHANGE
    pa="07", # channel to use in the back
    pb="08", # channel to use in the front
    tp="2350", # Begin of CoRe gripper tool picking up process (Z- range) [0.1mm]
    tz="2250", # End of CoRe gripper tool picking up process (Z- range) [0.1mm]
    th="2450", # Minimum traverse height at beginning of a command [0.1mm]
    tt="14"
)

…you can see the two command parameters ya and yb I marked. These look to me like the position arguments for the two grippers in the y dimension. We want to identify the correct positions for your system in a safe manner.
Since even your VENUS cannot pick up the grippers and nobody else seems to have a working AtWaste system (in this chat) we need to empirically determine these ya and yb positions.

For testing, I recommend:

  • start a PLR Notebook

Find the correct y-positions for each channel (let’s use P7 & P8 → i.e. channel_idx 6 & 7 in PLR)

  • first, move all channels into a safe back position (PLR commands do not automatically move channels out of the way which means you can tell a channel to go to from y=1800 to y=1500 even if another channel is at y=1600 → smashing the two against one another, so this step tries to prevent this from happening to you by moving channel_0 to y=220, channel_1 to y=210, …):
# Safe positions
y_post_start = 220
for channel_idx in range(0,8):
    print(f"channel {channel_idx} -> {y_post_start}")
    await lh.backend.move_channel_y(y=y_post_start, channel=channel_idx)
    y_post_start -= 10
  • now move channel_7 above the front gripper
    await lh.backend.move_channel_z(z=240, channel=7) # move channel down to make it easier to see whether it is above the gripper but not too far as to not crash the channel into the gripper

    await lh.backend.move_channel_y(y=<empirically_test_y_valye_here>, channel=7)
  • figure out what the correct y-value should be, i.e. where the channel is right above the front gripper → note down value as e.g. correct_AtWaste_front_gripper_y_value.
  • now do the same for the back gripper, using channel=6, to identify correct_AtWaste_back_gripper_y_value.

Only once you have these two values,

  • correct_AtWaste_front_gripper_y_value and
  • correct_AtWaste_back_gripper_y_value,
    …I recommend you test out the above PLR “Get CoRe gripper tool” command.

If the only issue with AtWaste is the y-positions for the gripper pickup, then this should solve it.
If there are also differences in height of the grippers between AtWaste and OnWaste we’ll have to modify a bit more.


Also, once you have the grippers on your channels you need to be able to put them back as well :sweat_smile:

The cheap trick is to restart the system, during initialisation the robot recognises it has “tips” on its channels and will try to throw them into the trash… not ideal because the grippers will crash into the waste wall.

So you need this PLR command to place the grippers back:

await lh.send_command(
    module="C0",
    command="ZS",
    xs="07980", # CoRe gripper tool X direction [0.1mm]
    xd="0", # X direction 0 = positive 1 = negative
    ya="1055", # First (lower channel) CoRe gripper tool Y pos. [0.1mm]  <=======
    yb="0795", # Second (higher channel) CoRe gripper tool Y pos.[0.1mm] <=======
    pa="07",
    pb="08",
    tp="2350", # Begin of CoRe gripper tool picking up process (Z- range) [0.1mm]
    tz="2250", # End of CoRe gripper tool picking up process (Z- range) [0.1mm]
    th="2450", # Minimum traverse height at beginning of a command [0.1mm]
    tt="14", # Tip type (see command "TT” & Tip type default values)

Don’t forget to change ya and yb here too to the corrected values you identify.
If at any point you are unsure just change xs="06500" → this should just drop the grippers 150 mm to the left of the AtWaste in mid air onto the deck.

Disclaimer: I am not a Hamilton employee, all use of PLR is at ones own responsibility and I have not done this before, so please be careful with my troubleshooting suggestions :slight_smile:

1 Like

Small update:

I looked at the log file I shared in this thread on 3rd January, and the functional PLR definition for get_core (STAR.py) with an OnWaste CO-RE gripper parking slot:

As can bee seen in the screenshot, ya and yb and xs (slightly, 0.5mm) are different!!

If the dimensions from your log file were to be correct the direct comparison between AtWaste and OnWaste dimensions would look like this:

→ The new grippers have been moved closer together, and further to the back.

But since you said that you had problems with your VENUS picking up at these locations I marked them with a question mark.

3 Likes

@rickwierenga, this troubleshooting got me to search for a better solution to the pushing plates flush to the carrier problem I mentioned above. After all “quick & dirty” is just supposed to be an interim solution:

So I looked into the log file I submitted here, and after 2 months and 5 days of working with PLR I think I am getting decent at reading Hamilton firmware :sweat_smile:

Converted put-plate & check-plate-is-there (equivalent to pushing plate flush to carrier) to PLR commands (because they are just easier to read):

# "Put plate using CO-RE gripper"
await self.send_command(
    module="C0",
    command="ZR",
    xs="07075", # Plate center in X direction [0.1mm]
    yj="1145", # Plate center in Y direction [0.1mm]
    zj="1952", # Plate deposit height in Z direction [0.1mm] = z position grippers will move to!!!!!
    
    xd="0", # X direction 0 = positive 1 = negative
    xg="4", # X acceleration index <============== NEW ???
    zi="010", # Press on distance [0.1mm] <============== NEW = to overcome springs? (might scratch plate)

    zy="1287", # Z speed [0.1mm/s]ec <============== CHANGED = fast placement to overcome springs
    yo="0920", # Open gripper position [0.1mm] <============== CHANGED
    
    th="2182", # Minimum traverse height at beginning of a command [0.1mm]
    te="2182", # Minimum z-position at end of a command [0.1mm] <============== CHANGED = don't waste time with unnecessary 
                                                            #                    movements when you know the check happens next
)

# "Check plate exists" -> actually a "Get plate using CO-RE gripper" + error handling!
await self.send_command(
    module="C0",
    command="ZP",
    xs="07075", # Plate center in X direction [0.1mm] ->
    yj="1145", # Plate center in Y direction [0.1mm] -> 
    zj="1952", # Plate deposit height in Z direction [0.1mm] -> exact same dimensions! = because the grippers will try to get to
                                                            # the "center" of the plate -> pushing the plate from the top down to
                                                            # its center -> triggers error 62 in the channels used!

    yv = "2778", # Y gripping speed [0.1mm] <============== NEW - not used
    xd="0", # X direction 0 = positive 1 = negative

    zy="0600", # Z speed [0.1mm/s]ec <============== CHANGED = slow crash
    
    yo="0630", # Open gripper position [0.1mm] <============== CHANGED = grippers offset inwards = plate.get_size_y - 2*offset <--- finally enables us to change the offset :)
    yg="0630", # Plate width [0.1mm] <============== NEW = grippers offset inwards = plate.get_size_y - 2*offset <--- finally enables us to change the offset :)
    
    yw="20", # Grip strength 0 = low .. 99 = high <============== NEW - not used
    
    th="2182", # Minimum traverse height at beginning of a command [0.1mm]
    te="2750", # Minimum z-position at end of a command [0.1mm] <============== CHANGED = move grippers to save distance at the end  
    #                                     of the command, will need separate implementation in PLR due to purposeful error triggering
)
# returns
# > 10:30:50.670 8AF#8000#00: C0ZPid0224er99/00 P602/62 P702/62 <===== ERROR 62 = Z-drive movement error, triggered by step monitoring, step loss

→ The checking of whether a plate is present is actually a “get plate” command in disguise, destined to crash the z drive (just like lld_mode(4)) with appropriate handling of the receiving error message :open_mouth:

That is quite an ingenious engineering decision… but it makes me think of the machine more as a bumper car than a delicate fine precision instrument haha

Equipped with this knowledge, I propose we expose this functionality to our current lh.move_plate() method as extra arguments check_plate_exists_at_source=None and check_plate_exists_at_destination=None?

I am frankly a bit surprised the log files don’t have a re-initialize z-drive command after the targeted crash… but I guess the crash is actually not bad enough to need it, maybe because of the reduced z speed?

2 Likes

@CamilloMoschner Thanks a ton for the detailed help! I have some other stuff I need to get to right now, but I will likely work on this over the weekend and report back.

1 Like

Great work on this as always @CamilloMoschner!!

Thanks! This was still buried in my todo list somewhere. What values other than None should check_plate_exists_at_source take? True/False? I think that makes sense, because move_plate also does iswap where this functionality does not exist (?). Do you want to create a PR for this?

LOL! This is a very curious decision indeed.

1 Like

No worries, I remembered you wanted to look into this but jonlaurent’s question got me into troubleshoot mode and I wanted to test how much my Hamilton firmware understanding improved, plus I know you are very busy atm :slight_smile:

Good question. I think the answer is multi-layered, and has to do with whether we just want this command to work as a “push-plate-flush-to-carrier” command or whether we want it to work in the original meaning it was created in, i.e. “check-plate-exists”, and have the “push-plate-flush-to-carrier” as a handy byproduct:

  1. Do we want the robot to stop executing the automated protocol if the check_plate_exists_at_source returns False, i.e. raise an error?
    a. If yes then a tuple like (True, 'cancel_protocol_if_not_found') vs (True, 'ignore_if_not_found') would be useful.
    b. Though, if yes might be simpler to just always raise raise a ValueError(f"Plate not found at location {loc.x, loc.y, loc.z}") and indeed then just requires check_plate_exists_at_source=False as default and can be set to True by users.

To be honest, I propose we approach this implementation through the creation of two new PLR features, an exposure and a new functionality:

  1. New functionality:
    a standalone STAR.check_if_resource_exists_at_known_location(<resource_instance>) method → I believe this has its own merit. For example, it can be used by any protocol, at any time to check that all labware is where it is supposed to be, using only a Resource class instance (or any of its derivatives, including plates, tip_racks, tubes, reservoirs, …).
    → This also has the added benefit of pushing each of these resources into their lowest possible z position, i.e. push them flush to whatever they are standing on.
    → This part is a bit tricky because of the potential size differences between resources but I’ve got a couple of ideas how to make this work.

  2. Exposure of existing functionality:
    add this functionality, nicely wrapped up as the above mentioned check_plate_exists_at_source and check_plate_exists_at_destination arguments to the move_plate method → set their defaults to False, and raise an error (i.e. halting the entire protocol) if the check figures out the plate does not exist. Since we don’t want this to interfere with how the iSWAP moves resources around, I suggest we only execute the checking of labware if use_arm == 'core'.
    (Unfortunately, I don’t have an iSWAP atm… but if I’m not mistaken, doesn’t the iSWAP recognise whether it is picking up a resource of the correct size anyway with some sort of lateral pressure sensors? And this enables the iSWAP to recognise when it loses a plate mid-transport?)
    → This part is pretty easy, the move_plate method already computes all the information we need.

Yes, I am happy to get on this next week. Please let me know what you think about my two suggestion but suggestion no2 I can create quite quickly.

Fun question: What do you think about adding a car bumper sound or the coin sound from Super Mario to this method?
I worked on audio-feedback between users and robots during my PhD, and got a simple function ready that we can add the the move_plate method that is executed when the machine finds a plate/resource in the location it searches.
During my PhD I used it to play a soundtrack to inform users that the machine had finished a task that requires user input next.

This might sound a bit too playful, but I actually found, for my users it was the most memorable idiosyncrasy of my automated workflows :sweat_smile: and it improved the user-robot interaction massively.

(I’d need to check the sound rights for anything we use though… Super Mario soundeffects might be protected, and I am unsure how open-source projects like PLR have to deal with this)

1 Like

I really like the approach you suggested below, which I think corresponds to b. Perhaps it’d be nice to re-use the PLR ResourceNotFoundError that is already used in the PLR resource model instead of a ValueError.

I think it should be doable to get this working on iswap as well. I can add that.

Haha let’s do it. PLR should be the highest fun lab automation framework. As you say, let’s make sure we don’t infringe their copyright though (I don’t know what the rules are exactly either), and be extremely conservative about dependencies / errors.

I have created feature 1 via PR#78: Adding core_check_resource_exists_at_location_center & first PLR audiofeedback.

Discussions on changes are welcome.

I found feature 1 is much harder, and thought I’d start with that. Feature 2 is then pretty straight forward.

1 Like