From bdf5049f960354b7b42cbf1c4ea269c058928908 Mon Sep 17 00:00:00 2001 From: gac-S_Changer Date: Mon, 3 Dec 2018 12:17:40 +0100 Subject: [PATCH] Creation --- config/config.properties | 31 + config/devices - Copy.properties | 67 + config/devices-modbus.properties | 50 + config/devices.properties | 80 + config/jcae.properties | 11 + config/mail.properties | 9 + config/plugins.properties | 21 + config/setup-modbus.properties | 18 + config/setup.properties | 18 + config/tasks.properties | 1 + devices/20161117_163816.png.properties | 20 + devices/BasePlate.properties | 1 + devices/Time.properties | 10 + devices/air_pressure.properties | 5 + devices/cx.properties | 17 + devices/cz.properties | 17 + devices/dewar_level.properties | 6 + devices/dispatcher.properties | 11 + devices/dp1.properties | 11 + devices/fx.properties | 17 + devices/fy.properties | 17 + devices/gripper_cam.properties | 20 + devices/img.properties | 24 + devices/led_ctrl.properties | 8 + devices/led_ctrl_1.properties | 9 + devices/led_ctrl_2.properties | 9 + devices/led_ctrl_3.properties | 9 + devices/led_level.properties | 9 + devices/m1.properties | 13 + devices/m2.properties | 13 + devices/monitoring_cam.properties | 20 + devices/n2_pressure.properties | 5 + devices/p1.properties | 9 + devices/phase_separator.properties | 8 + devices/phase_separator_level.properties | 6 + devices/rim_heater_temp.properties | 6 + devices/robot x.properties | 9 + devices/robot.properties | 8 + devices/robot_j1.properties | 10 + devices/robot_j2.properties | 10 + devices/robot_j3.properties | 10 + devices/robot_j4.properties | 10 + devices/robot_j5.properties | 10 + devices/robot_j6.properties | 10 + devices/robot_modbus.properties | 8 + devices/robot_rx.properties | 10 + devices/robot_ry.properties | 10 + devices/robot_rz.properties | 10 + devices/robot_x.properties | 10 + devices/robot_y.properties | 10 + devices/robot_z.properties | 10 + devices/ry.properties | 17 + devices/smart_magnet.properties | 8 + devices/smc_current.properties | 9 + devices/smc_current_rb.properties | 6 + devices/src1.properties | 24 + devices/src2.properties | 24 + devices/top_cam.properties | 20 + devices/ue.properties | 6 + devices/wago.properties | 8 + plugins/BarcodeReaderPanel.form | 118 ++ plugins/BarcodeReaderPanel.java | 162 ++ plugins/Beeper.java | 72 + plugins/Commands.form | 803 ++++++++ plugins/Commands.java | 914 +++++++++ plugins/Hexiposi.form | 34 + plugins/Hexiposi.java | 78 + plugins/HexiposiPanel.form | 81 + plugins/HexiposiPanel.java | 110 ++ plugins/LN2.form | 34 + plugins/LN2.java | 106 ++ plugins/LaserUE.java | 79 + plugins/LaserUEPanel.form | 59 + plugins/LaserUEPanel.java | 98 + plugins/MXSC-1.10.0.jar | Bin 0 -> 262914 bytes plugins/MXSC-1.10.0.jar.back | Bin 0 -> 206172 bytes plugins/MjpegSource2.java | 149 ++ plugins/PuckDetectionPanel.form | 184 ++ plugins/PuckDetectionPanel.java | 251 +++ plugins/Recovery.form | 140 ++ plugins/Recovery.java | 255 +++ plugins/RobotModbus.java | 21 + plugins/RobotPanel.form | 587 ++++++ plugins/RobotPanel.java | 685 +++++++ plugins/RobotTcp.java | 21 + plugins/SmartMagnetConfig.java | 14 + plugins/SmartMagnetPanel.form | 221 +++ plugins/SmartMagnetPanel.java | 234 +++ plugins/TestZMQ.java | 26 + plugins/WagoPanel.form | 167 ++ plugins/WagoPanel.java | 207 +++ plugins/gui.form | 62 + plugins/gui.java | 96 + script/LN2_Monitoring.scd | 15 + script/LevelMonitoring.scd | 12 + script/calibration/BinarySearchYZ.py | 29 + script/calibration/HillClimbingXZ.py | 45 + script/calibration/ScanRZ.py | 31 + script/calibration/ScanX.py | 81 + script/calibration/ScanY.py | 81 + script/calibration/ScanYZ.py | 93 + script/calibration/ToolCalibration.py | 60 + script/calibration/ToolCalibration2.py | 86 + script/calibration/ToolCalibration3.py | 83 + script/client/PShellClient.py | 369 ++++ script/client/TellClient.py | 184 ++ script/client/sseclient.py | 163 ++ script/client/tell.py | 79 + script/data/get_samples_info.py | 4 + script/data/pucks.py | 22 + script/data/samples.py | 314 ++++ script/data/set_samples_info.py | 4 + script/devices/BarcodeReader.py | 76 + script/devices/Gonio.py | 43 + script/devices/Hexiposi.py | 165 ++ script/devices/LaserDistance.py | 17 + script/devices/LedCtrl.py | 46 + script/devices/OneWire.py | 134 ++ script/devices/RobotModbus.py | 46 + script/devices/RobotMotors.py | 62 + script/devices/RobotSC.py | 318 ++++ script/devices/RobotTCP.py | 863 +++++++++ script/devices/SmartMagnet.py | 122 ++ script/devices/Wago.py | 172 ++ script/hexiposi_positon.scd | 11 + script/imgproc/CameraCalibration.py | 155 ++ script/imgproc/CoverDetection.py | 98 + script/imgproc/CoverDetectionCalibration.py | 40 + script/imgproc/CreateMask.py | 29 + script/imgproc/LedDetectionFilter.py | 102 + script/imgproc/LedDetectionProc.py | 106 ++ script/imgproc/Utils.py | 113 ++ script/local.groovy | 3 + script/local.js | 4 + script/local.py | 338 ++++ script/motion/calibrate_tool.py | 32 + script/motion/dry.py | 48 + script/motion/get_aux.py | 21 + script/motion/get_dewar.py | 30 + script/motion/get_gonio.py | 20 + script/motion/homing_hexiposi.py | 16 + script/motion/mount.py | 119 ++ script/motion/move_aux.py | 18 + script/motion/move_cold.py | 22 + script/motion/move_dewar.py | 18 + script/motion/move_gonio.py | 18 + script/motion/move_heater.py | 18 + script/motion/move_home.py | 18 + script/motion/move_park.py | 18 + script/motion/move_scanner.py | 30 + script/motion/put_aux.py | 21 + script/motion/put_dewar.py | 30 + script/motion/put_gonio.py | 23 + script/motion/recover.py | 154 ++ script/motion/robot_recover.py | 16 + script/motion/scan_pin.py | 94 + script/motion/tools.py | 177 ++ script/motion/trash.py | 36 + script/motion/unmount.py | 69 + script/setup/ExposureScan.py | 33 + script/setup/Layout.py | 292 +++ script/tasks/LedMonitoring.py | 26 + script/test/CameraCalibration.py | 71 + script/test/CoverDetection.py | 116 ++ script/test/PuckDetection.py | 24 + script/test/PuckDetectionTest.py | 11 + script/test/RobotCartesianScan.py | 28 + script/test/SampleDataInput.py | 1861 ++++++++++++++++++ script/test/SampleDataInput_Dominik.py | 1862 +++++++++++++++++++ script/test/SampleDetection.py | 23 + script/test/TestAlign.py | 9 + script/test/TestBugPcAPI | 4 + script/test/TestBugPcAPI.py | 30 + script/test/TestBugPcAPI2.py | 6 + script/test/TestBugPcAPI3.py | 4 + script/test/TestCalib.py | 30 + script/test/TestCameraStability1.py | 11 + script/test/TestCameraStability2.py | 14 + script/test/TestCameraStability3.py | 9 + script/test/TestCmdSynchronization.py | 32 + script/test/TestCoverDetection.py | 19 + script/test/TestEuclidean.py | 23 + script/test/TestLaserScan.py | 12 + script/test/TestLayout.py | 21 + script/test/TestMicrohawk.py | 10 + script/test/TestRecover.py | 15 + script/test/TestRelays.py | 12 + script/test/TestRemoveBackground.py | 31 + script/test/TestRobot.py | 41 + script/test/TestRobot2.py | 72 + script/test/TestRobotCmds.py | 32 + script/test/TestRobotCmds2.py | 25 + script/test/cycle_time | 4 + script/test/imgtest.py | 47 + script/test/ip | 15 + script/test/onewire.py | 122 ++ script/test/test.py | 24 + script/test/test_hexiposi.py | 8 + script/test/test_swingutils.py | 24 + script/tools/CheckPuckDetection.py | 6 + script/tools/Math.py | 68 + script/tools/RestartPuckDetection.py | 8 + script/tools/SshExec.py | 61 + script/tools/StopPuckDetection.py | 8 + 204 files changed, 18029 insertions(+) create mode 100644 config/config.properties create mode 100644 config/devices - Copy.properties create mode 100644 config/devices-modbus.properties create mode 100644 config/devices.properties create mode 100644 config/jcae.properties create mode 100644 config/mail.properties create mode 100644 config/plugins.properties create mode 100644 config/setup-modbus.properties create mode 100644 config/setup.properties create mode 100644 config/tasks.properties create mode 100644 devices/20161117_163816.png.properties create mode 100644 devices/BasePlate.properties create mode 100644 devices/Time.properties create mode 100644 devices/air_pressure.properties create mode 100644 devices/cx.properties create mode 100644 devices/cz.properties create mode 100644 devices/dewar_level.properties create mode 100644 devices/dispatcher.properties create mode 100644 devices/dp1.properties create mode 100644 devices/fx.properties create mode 100644 devices/fy.properties create mode 100644 devices/gripper_cam.properties create mode 100644 devices/img.properties create mode 100644 devices/led_ctrl.properties create mode 100644 devices/led_ctrl_1.properties create mode 100644 devices/led_ctrl_2.properties create mode 100644 devices/led_ctrl_3.properties create mode 100644 devices/led_level.properties create mode 100644 devices/m1.properties create mode 100644 devices/m2.properties create mode 100644 devices/monitoring_cam.properties create mode 100644 devices/n2_pressure.properties create mode 100644 devices/p1.properties create mode 100644 devices/phase_separator.properties create mode 100644 devices/phase_separator_level.properties create mode 100644 devices/rim_heater_temp.properties create mode 100644 devices/robot x.properties create mode 100644 devices/robot.properties create mode 100644 devices/robot_j1.properties create mode 100644 devices/robot_j2.properties create mode 100644 devices/robot_j3.properties create mode 100644 devices/robot_j4.properties create mode 100644 devices/robot_j5.properties create mode 100644 devices/robot_j6.properties create mode 100644 devices/robot_modbus.properties create mode 100644 devices/robot_rx.properties create mode 100644 devices/robot_ry.properties create mode 100644 devices/robot_rz.properties create mode 100644 devices/robot_x.properties create mode 100644 devices/robot_y.properties create mode 100644 devices/robot_z.properties create mode 100644 devices/ry.properties create mode 100644 devices/smart_magnet.properties create mode 100644 devices/smc_current.properties create mode 100644 devices/smc_current_rb.properties create mode 100644 devices/src1.properties create mode 100644 devices/src2.properties create mode 100644 devices/top_cam.properties create mode 100644 devices/ue.properties create mode 100644 devices/wago.properties create mode 100644 plugins/BarcodeReaderPanel.form create mode 100644 plugins/BarcodeReaderPanel.java create mode 100644 plugins/Beeper.java create mode 100644 plugins/Commands.form create mode 100644 plugins/Commands.java create mode 100644 plugins/Hexiposi.form create mode 100644 plugins/Hexiposi.java create mode 100644 plugins/HexiposiPanel.form create mode 100644 plugins/HexiposiPanel.java create mode 100644 plugins/LN2.form create mode 100644 plugins/LN2.java create mode 100644 plugins/LaserUE.java create mode 100644 plugins/LaserUEPanel.form create mode 100644 plugins/LaserUEPanel.java create mode 100644 plugins/MXSC-1.10.0.jar create mode 100644 plugins/MXSC-1.10.0.jar.back create mode 100644 plugins/MjpegSource2.java create mode 100644 plugins/PuckDetectionPanel.form create mode 100644 plugins/PuckDetectionPanel.java create mode 100644 plugins/Recovery.form create mode 100644 plugins/Recovery.java create mode 100644 plugins/RobotModbus.java create mode 100644 plugins/RobotPanel.form create mode 100644 plugins/RobotPanel.java create mode 100644 plugins/RobotTcp.java create mode 100644 plugins/SmartMagnetConfig.java create mode 100644 plugins/SmartMagnetPanel.form create mode 100644 plugins/SmartMagnetPanel.java create mode 100644 plugins/TestZMQ.java create mode 100644 plugins/WagoPanel.form create mode 100644 plugins/WagoPanel.java create mode 100644 plugins/gui.form create mode 100644 plugins/gui.java create mode 100644 script/LN2_Monitoring.scd create mode 100644 script/LevelMonitoring.scd create mode 100644 script/calibration/BinarySearchYZ.py create mode 100644 script/calibration/HillClimbingXZ.py create mode 100644 script/calibration/ScanRZ.py create mode 100644 script/calibration/ScanX.py create mode 100644 script/calibration/ScanY.py create mode 100644 script/calibration/ScanYZ.py create mode 100644 script/calibration/ToolCalibration.py create mode 100644 script/calibration/ToolCalibration2.py create mode 100644 script/calibration/ToolCalibration3.py create mode 100644 script/client/PShellClient.py create mode 100644 script/client/TellClient.py create mode 100644 script/client/sseclient.py create mode 100644 script/client/tell.py create mode 100644 script/data/get_samples_info.py create mode 100644 script/data/pucks.py create mode 100644 script/data/samples.py create mode 100644 script/data/set_samples_info.py create mode 100644 script/devices/BarcodeReader.py create mode 100644 script/devices/Gonio.py create mode 100644 script/devices/Hexiposi.py create mode 100644 script/devices/LaserDistance.py create mode 100644 script/devices/LedCtrl.py create mode 100644 script/devices/OneWire.py create mode 100644 script/devices/RobotModbus.py create mode 100644 script/devices/RobotMotors.py create mode 100644 script/devices/RobotSC.py create mode 100644 script/devices/RobotTCP.py create mode 100644 script/devices/SmartMagnet.py create mode 100644 script/devices/Wago.py create mode 100644 script/hexiposi_positon.scd create mode 100644 script/imgproc/CameraCalibration.py create mode 100644 script/imgproc/CoverDetection.py create mode 100644 script/imgproc/CoverDetectionCalibration.py create mode 100644 script/imgproc/CreateMask.py create mode 100644 script/imgproc/LedDetectionFilter.py create mode 100644 script/imgproc/LedDetectionProc.py create mode 100644 script/imgproc/Utils.py create mode 100644 script/local.groovy create mode 100644 script/local.js create mode 100644 script/local.py create mode 100644 script/motion/calibrate_tool.py create mode 100644 script/motion/dry.py create mode 100644 script/motion/get_aux.py create mode 100644 script/motion/get_dewar.py create mode 100644 script/motion/get_gonio.py create mode 100644 script/motion/homing_hexiposi.py create mode 100644 script/motion/mount.py create mode 100644 script/motion/move_aux.py create mode 100644 script/motion/move_cold.py create mode 100644 script/motion/move_dewar.py create mode 100644 script/motion/move_gonio.py create mode 100644 script/motion/move_heater.py create mode 100644 script/motion/move_home.py create mode 100644 script/motion/move_park.py create mode 100644 script/motion/move_scanner.py create mode 100644 script/motion/put_aux.py create mode 100644 script/motion/put_dewar.py create mode 100644 script/motion/put_gonio.py create mode 100644 script/motion/recover.py create mode 100644 script/motion/robot_recover.py create mode 100644 script/motion/scan_pin.py create mode 100644 script/motion/tools.py create mode 100644 script/motion/trash.py create mode 100644 script/motion/unmount.py create mode 100644 script/setup/ExposureScan.py create mode 100644 script/setup/Layout.py create mode 100644 script/tasks/LedMonitoring.py create mode 100644 script/test/CameraCalibration.py create mode 100644 script/test/CoverDetection.py create mode 100644 script/test/PuckDetection.py create mode 100644 script/test/PuckDetectionTest.py create mode 100644 script/test/RobotCartesianScan.py create mode 100644 script/test/SampleDataInput.py create mode 100644 script/test/SampleDataInput_Dominik.py create mode 100644 script/test/SampleDetection.py create mode 100644 script/test/TestAlign.py create mode 100644 script/test/TestBugPcAPI create mode 100644 script/test/TestBugPcAPI.py create mode 100644 script/test/TestBugPcAPI2.py create mode 100644 script/test/TestBugPcAPI3.py create mode 100644 script/test/TestCalib.py create mode 100644 script/test/TestCameraStability1.py create mode 100644 script/test/TestCameraStability2.py create mode 100644 script/test/TestCameraStability3.py create mode 100644 script/test/TestCmdSynchronization.py create mode 100644 script/test/TestCoverDetection.py create mode 100644 script/test/TestEuclidean.py create mode 100644 script/test/TestLaserScan.py create mode 100644 script/test/TestLayout.py create mode 100644 script/test/TestMicrohawk.py create mode 100644 script/test/TestRecover.py create mode 100644 script/test/TestRelays.py create mode 100644 script/test/TestRemoveBackground.py create mode 100644 script/test/TestRobot.py create mode 100644 script/test/TestRobot2.py create mode 100644 script/test/TestRobotCmds.py create mode 100644 script/test/TestRobotCmds2.py create mode 100644 script/test/cycle_time create mode 100644 script/test/imgtest.py create mode 100644 script/test/ip create mode 100644 script/test/onewire.py create mode 100644 script/test/test.py create mode 100644 script/test/test_hexiposi.py create mode 100644 script/test/test_swingutils.py create mode 100644 script/tools/CheckPuckDetection.py create mode 100644 script/tools/Math.py create mode 100644 script/tools/RestartPuckDetection.py create mode 100644 script/tools/SshExec.py create mode 100644 script/tools/StopPuckDetection.py diff --git a/config/config.properties b/config/config.properties new file mode 100644 index 0000000..3ed16ad --- /dev/null +++ b/config/config.properties @@ -0,0 +1,31 @@ +#Mon Dec 03 12:00:22 CET 2018 +autoSaveScanData=true +commandExecutionEvents=false +createSessionFiles=true +dataLayout=default +dataPath={data}/{year}_{month}/{date}/{date}_{time}_{name} +dataProvider=h5 +dataScanFlushRecords=true +dataScanPreserveTypes=false +dataScanReleaseRecords=false +dataServerPort=-1 +depthDimension=0 +hostName=null +instanceName=X06SA +logDaysToLive=30 +logLevel=Fine +logLevelConsole=Off +logPath={logs}/{date}_{time} +notificationLevel=null +scanStreamerPort=-1 +serverEnabled=true +serverPort=8080 +simulation=true +terminalEnabled=false +terminalPort=3579 +userAuthenticator= +userManagement=false +versionTrackingEnabled=true +versionTrackingLogin={context}/svcusr-hlapp_robot +versionTrackingManual=false +versionTrackingRemote=git@git.psi.ch\:tell/X06SA.git diff --git a/config/devices - Copy.properties b/config/devices - Copy.properties new file mode 100644 index 0000000..cc3672f --- /dev/null +++ b/config/devices - Copy.properties @@ -0,0 +1,67 @@ +img=ch.psi.pshell.prosilica.Prosilica|25001 "PacketSize=1522;PixelFormat=Mono8;BinningX=1;BinningY=1;RegionX=300;RegionY=200;Width=1000;Height=1000"|||false +gripper_cam=ch.psi.pshell.imaging.MjpegSource|http://129.129.110.114/axis-cgi/mjpg/video.cgi||-1000| +microscan=ch.psi.pshell.serial.TcpDevice|129.129.100.200:2001||| +microscan_cmd=ch.psi.pshell.serial.TcpDevice|129.129.100.200:2003||| +ue=LaserUE|COM4|||false +#robot=RobotTcp|127.0.0.1:1000||| +#onewire=ch.psi.pshell.serial.TcpDevice|129.129.126.83:5000||| +puck_detection=ch.psi.mxsc.PuckDetection|tell-raspberrypi:5556||| +#robot_modbus=ch.psi.pshell.modbus.ModbusTCP|129.129.126.100:502||| +#jf1=ch.psi.pshell.modbus.AnalogInput|robot_modbus 0||100| +#jf2=ch.psi.pshell.modbus.AnalogInput|robot_modbus 1||100| +#jf3=ch.psi.pshell.modbus.AnalogInput|robot_modbus 2||100| +#jf4=ch.psi.pshell.modbus.AnalogInput|robot_modbus 3||100| +#jf5=ch.psi.pshell.modbus.AnalogInput|robot_modbus 4||100| +#jf6=ch.psi.pshell.modbus.AnalogInput|robot_modbus 5||100| +#robot_sts=ch.psi.pshell.modbus.AnalogInputArray|robot_modbus 6 6||100| +#robot_cmd=ch.psi.pshell.modbus.AnalogOutput|robot_modbus 12||| +#robot_args=ch.psi.pshell.modbus.AnalogOutputArray|robot_modbus 47 12||| +#robot_req=ch.psi.pshell.modbus.AnalogOutput|robot_modbus 13||| +#robot_ack=ch.psi.pshell.modbus.AnalogInput|robot_modbus 14||| +#robot_ret=ch.psi.pshell.modbus.AnalogInputArray|robot_modbus 15 12||| +#wago_back=ch.psi.pshell.modbus.ModbusTCP|SF-TEST-WAGO1:502||| +wago=ch.psi.pshell.modbus.ModbusTCP|wago-mxsc-1:502||| +led_ok_1=ch.psi.pshell.modbus.DigitalInput|wago 0||1000| +led_ok_2=ch.psi.pshell.modbus.DigitalInput|wago 1||1000| +led_ok_3=ch.psi.pshell.modbus.DigitalInput|wago 2||1000| +feedback_local_safety=ch.psi.pshell.modbus.DigitalInput|wago 3||1000| +feedback_psys_safety=ch.psi.pshell.modbus.DigitalInput|wago 4||1000| +filling_phase_separator=ch.psi.pshell.modbus.DigitalInput|wago 5||1000| +filling_dewar=ch.psi.pshell.modbus.DigitalInput|wago 6||1000| +dewar_level_high_alarm=ch.psi.pshell.modbus.DigitalInput|wago 7||1000| +guiding_tool_park=ch.psi.pshell.modbus.DigitalInput|wago 8||1000| +air_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 9||1000|false +n2_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 10||1000| +he_chamber_valve_1=ch.psi.pshell.modbus.DigitalInput|wago 15||1000| +he_chamber_valve_2=ch.psi.pshell.modbus.DigitalInput|wago 16||1000| +relays=ch.psi.pshell.modbus.DigitalOutputArray|wago 0 16||1000| +release_local_safety=ch.psi.pshell.modbus.DigitalOutput|wago 0||| +release_psys_safety=ch.psi.pshell.modbus.DigitalOutput|wago 1||| +ln2_main_power=ch.psi.pshell.modbus.DigitalOutput|wago 2||| +rim_heater=ch.psi.pshell.modbus.DigitalOutput|wago 3||| +phase_separator_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 4||| +dewar_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 5|||false +valve_he_chamber=ch.psi.pshell.modbus.DigitalOutput|wago 6||| +gripper_dryer=ch.psi.pshell.modbus.DigitalOutput|wago 7||| +valve_1=ch.psi.pshell.modbus.DigitalOutput|wago 8||| +valve_2=ch.psi.pshell.modbus.DigitalOutput|wago 9||| +valve_3=ch.psi.pshell.modbus.DigitalOutput|wago 10||| +valve_4=ch.psi.pshell.modbus.DigitalOutput|wago 11||| +#spare_do_1=ch.psi.pshell.modbus.DigitalOutput|wago 12||| +#spare_do_2=ch.psi.pshell.modbus.DigitalOutput|wago 13||| +#spare_do_3=ch.psi.pshell.modbus.DigitalOutput|wago 14||| +#spare_do_4=ch.psi.pshell.modbus.DigitalOutput|wago 15||| +phase_separator_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 0||10000| +dewar_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 1||10000| +rim_heater_temp=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 2||10000| +air_pressure=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 3||10000| +n2_pressure=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 4||10000| +#spare_ai_1=ch.psi.pshell.modbus.AnalogInput|wago 5||| +#spare_ai_2=ch.psi.pshell.modbus.AnalogInput|wago 6||| +#spare_ai_3=ch.psi.pshell.modbus.AnalogInput|wago 7||| +led_ctrl_1=ch.psi.pshell.modbus.ProcessVariable|wago 0||| +led_ctrl_2=ch.psi.pshell.modbus.ProcessVariable|wago 1||| +led_ctrl_3=ch.psi.pshell.modbus.ProcessVariable|wago 2||| +#spare_ao_3=ch.psi.pshell.modbus.AnalogOutput|wago 3||| +#cam=ch.psi.pshell.epics.AreaDetector|MX-SAMCAM||| +#img_back=ch.psi.pshell.imaging.CameraSource|cam||-100| diff --git a/config/devices-modbus.properties b/config/devices-modbus.properties new file mode 100644 index 0000000..d46c089 --- /dev/null +++ b/config/devices-modbus.properties @@ -0,0 +1,50 @@ +wago=ch.psi.pshell.modbus.ModbusTCP|wago-mxsc-1:502||| +led_ok_1=ch.psi.pshell.modbus.DigitalInput|wago 0||1000| +led_ok_2=ch.psi.pshell.modbus.DigitalInput|wago 1||1000| +led_ok_3=ch.psi.pshell.modbus.DigitalInput|wago 2||1000| +feedback_local_safety=ch.psi.pshell.modbus.DigitalInput|wago 3||1000| +feedback_psys_safety=ch.psi.pshell.modbus.DigitalInput|wago 4||1000| +filling_phase_separator=ch.psi.pshell.modbus.DigitalInput|wago 5||1000| +filling_dewar=ch.psi.pshell.modbus.DigitalInput|wago 6||1000| +dewar_level_high_alarm=ch.psi.pshell.modbus.DigitalInput|wago 7||1000| +guiding_tool_park=ch.psi.pshell.modbus.DigitalInput|wago 8||1000| +air_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 9||1000|false +n2_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 10||1000| +#spare_di_1=ch.psi.pshell.modbus.DigitalInput|wago 11||| +#spare_di_2=ch.psi.pshell.modbus.DigitalInput|wago 12||| +#spare_di_3=ch.psi.pshell.modbus.DigitalInput|wago 13||| +#spare_di_4=ch.psi.pshell.modbus.DigitalInput|wago 14||| +he_chamber_valve_1=ch.psi.pshell.modbus.DigitalInput|wago 15||1000| +he_chamber_valve_2=ch.psi.pshell.modbus.DigitalInput|wago 16||1000| +smc_magnet_status=ch.psi.pshell.modbus.DigitalInput|wago 17||1000| +smc_mounted_1=ch.psi.pshell.modbus.DigitalInput|wago 18||1000| +smc_mounted_2=ch.psi.pshell.modbus.DigitalInput|wago 19||1000| +relays=ch.psi.pshell.modbus.DigitalOutputArray|wago 0 16||1000| +release_local_safety=ch.psi.pshell.modbus.DigitalOutput|wago 0||| +release_psys_safety=ch.psi.pshell.modbus.DigitalOutput|wago 1||| +ln2_main_power=ch.psi.pshell.modbus.DigitalOutput|wago 2||| +rim_heater=ch.psi.pshell.modbus.DigitalOutput|wago 3||| +phase_separator_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 4||| +dewar_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 5|||false +valve_he_chamber=ch.psi.pshell.modbus.DigitalOutput|wago 6||| +gripper_dryer=ch.psi.pshell.modbus.DigitalOutput|wago 7||| +valve_1=ch.psi.pshell.modbus.DigitalOutput|wago 8||| +valve_2=ch.psi.pshell.modbus.DigitalOutput|wago 9||| +valve_3=ch.psi.pshell.modbus.DigitalOutput|wago 10||| +valve_4=ch.psi.pshell.modbus.DigitalOutput|wago 11||| +#spare_do_1=ch.psi.pshell.modbus.DigitalOutput|wago 12||| +smc_sup_det=ch.psi.pshell.modbus.DigitalOutput|wago 13||| +#spare_do_3=ch.psi.pshell.modbus.DigitalOutput|wago 14||| +#spare_do_4=ch.psi.pshell.modbus.DigitalOutput|wago 15||| +phase_separator_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 0||10000| +dewar_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 1||10000| +rim_heater_temp=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 2||10000| +#spare_ai_1=ch.psi.pshell.modbus.AnalogInput|wago 3|||true +smc_current_rb=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 4||1000| +#spare_ai_3=ch.psi.pshell.modbus.AnalogInput|wago 5||| +#spare_ai_4=ch.psi.pshell.modbus.AnalogInput|wago 6||| +#spare_ai_5=ch.psi.pshell.modbus.AnalogInput|wago 7||| +led_ctrl_1=ch.psi.pshell.modbus.ProcessVariable|wago 0||| +led_ctrl_2=ch.psi.pshell.modbus.ProcessVariable|wago 1||| +led_ctrl_3=ch.psi.pshell.modbus.ProcessVariable|wago 2||| +smc_current=ch.psi.pshell.modbus.ProcessVariable|wago 3||| diff --git a/config/devices.properties b/config/devices.properties new file mode 100644 index 0000000..9c89763 --- /dev/null +++ b/config/devices.properties @@ -0,0 +1,80 @@ +#img=ch.psi.pshell.prosilica.Prosilica|25001 "PacketSize=1522;PixelFormat=Mono8;BinningX=1;BinningY=1;RegionX=300;RegionY=200;Width=1000;Height=1000;MulticastEnable=Off"|||false +#gripper_cam=ch.psi.pshell.imaging.MjpegSource|http://axis-accc8e9cc87b.psi.ch/axis-cgi/mjpg/video.cgi?camera=1 reopen||-200| +#monitoring_cam=ch.psi.pshell.imaging.MjpegSource|http://axis-accc8e9cc87b.psi.ch/axis-cgi/mjpg/video.cgi?camera=2 reopen||-200| +#top_cam=ch.psi.pshell.imaging.MjpegSource|http://axis-accc8e9cc87b.psi.ch/axis-cgi/mjpg/video.cgi?camera=3 true||-200| +#cam=ch.psi.pshell.epics.AreaDetector|MX-SAMCAM||| +microscan=ch.psi.pshell.serial.TcpDevice|MicroHAWK38C528:2001||| +microscan_cmd=ch.psi.pshell.serial.TcpDevice|MicroHAWK38C528:2003||| +ue=LaserUE|COM4|||false +puck_detection=ch.psi.mxsc.PuckDetection|tell-raspberrypi:5556||| +#onewire=ch.psi.pshell.serial.TcpDevice|129.129.126.83:5000||| +#robot=RobotTcp|127.0.0.1:1000||| +#$robot_modbus=ch.psi.pshell.modbus.ModbusTCP|129.129.126.100:502||| +#jf1=ch.psi.pshell.modbus.AnalogInput|robot_modbus 0||100| +#jf2=ch.psi.pshell.modbus.AnalogInput|robot_modbus 1||100| +#jf3=ch.psi.pshell.modbus.AnalogInput|robot_modbus 2||100| +#jf4=ch.psi.pshell.modbus.AnalogInput|robot_modbus 3||100| +#jf5=ch.psi.pshell.modbus.AnalogInput|robot_modbus 4||100| +#jf6=ch.psi.pshell.modbus.AnalogInput|robot_modbus 5||100| +#robot_sts=ch.psi.pshell.modbus.AnalogInputArray|robot_modbus 6 6||100| +#robot_cmd=ch.psi.pshell.modbus.AnalogOutput|robot_modbus 12||| +#robot_args=ch.psi.pshell.modbus.AnalogOutputArray|robot_modbus 47 12||| +#robot_req=ch.psi.pshell.modbus.AnalogOutput|robot_modbus 13||| +#robot_ack=ch.psi.pshell.modbus.AnalogInput|robot_modbus 14||| +#robot_ret=ch.psi.pshell.modbus.AnalogInputArray|robot_modbus 15 12||| +wago=ch.psi.pshell.modbus.ModbusTCP|wago-mxsc-1:502||| +led_ok_1=ch.psi.pshell.modbus.DigitalInput|wago 0||1000| +led_ok_2=ch.psi.pshell.modbus.DigitalInput|wago 1||1000| +led_ok_3=ch.psi.pshell.modbus.DigitalInput|wago 2||1000| +feedback_local_safety=ch.psi.pshell.modbus.DigitalInput|wago 3||1000| +feedback_psys_safety=ch.psi.pshell.modbus.DigitalInput|wago 4||1000| +filling_phase_separator=ch.psi.pshell.modbus.DigitalInput|wago 5||1000| +filling_dewar=ch.psi.pshell.modbus.DigitalInput|wago 6||1000| +dewar_level_high_alarm=ch.psi.pshell.modbus.DigitalInput|wago 7||1000| +guiding_tool_park=ch.psi.pshell.modbus.DigitalInput|wago 8||1000| +air_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 9||1000|false +n2_pressure_ok=ch.psi.pshell.modbus.DigitalInput|wago 10||1000| +#spare_di_1=ch.psi.pshell.modbus.DigitalInput|wago 11||| +#spare_di_2=ch.psi.pshell.modbus.DigitalInput|wago 12||| +#spare_di_3=ch.psi.pshell.modbus.DigitalInput|wago 13||| +#spare_di_4=ch.psi.pshell.modbus.DigitalInput|wago 14||| +he_chamber_valve_1=ch.psi.pshell.modbus.DigitalInput|wago 15||1000| +he_chamber_valve_2=ch.psi.pshell.modbus.DigitalInput|wago 16||1000| +smc_magnet_status=ch.psi.pshell.modbus.DigitalInput|wago 17||1000| +smc_mounted_1=ch.psi.pshell.modbus.DigitalInput|wago 18||1000| +smc_mounted_2=ch.psi.pshell.modbus.DigitalInput|wago 19||1000| +relays=ch.psi.pshell.modbus.DigitalOutputArray|wago 0 16||1000| +release_local_safety=ch.psi.pshell.modbus.DigitalOutput|wago 0||| +release_psys_safety=ch.psi.pshell.modbus.DigitalOutput|wago 1||| +ln2_main_power=ch.psi.pshell.modbus.DigitalOutput|wago 2||| +rim_heater=ch.psi.pshell.modbus.DigitalOutput|wago 3||| +phase_separator_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 4||| +dewar_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 5|||false +valve_he_chamber=ch.psi.pshell.modbus.DigitalOutput|wago 6||| +gripper_dryer=ch.psi.pshell.modbus.DigitalOutput|wago 7||| +valve_1=ch.psi.pshell.modbus.DigitalOutput|wago 8||| +valve_2=ch.psi.pshell.modbus.DigitalOutput|wago 9||| +valve_3=ch.psi.pshell.modbus.DigitalOutput|wago 10||| +valve_4=ch.psi.pshell.modbus.DigitalOutput|wago 11||| +#spare_do_1=ch.psi.pshell.modbus.DigitalOutput|wago 12||| +smc_sup_det=ch.psi.pshell.modbus.DigitalOutput|wago 13||| +#spare_do_3=ch.psi.pshell.modbus.DigitalOutput|wago 14||| +#spare_do_4=ch.psi.pshell.modbus.DigitalOutput|wago 15||| +phase_separator_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 0||10000| +dewar_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 1||10000| +rim_heater_temp=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 2||10000| +#spare_ai_1=ch.psi.pshell.modbus.AnalogInput|wago 3|||true +smc_current_rb=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 4||1000| +#spare_ai_3=ch.psi.pshell.modbus.AnalogInput|wago 5||| +#spare_ai_4=ch.psi.pshell.modbus.AnalogInput|wago 6||| +#spare_ai_5=ch.psi.pshell.modbus.AnalogInput|wago 7||| +led_ctrl_1=ch.psi.pshell.modbus.ProcessVariable|wago 0||| +led_ctrl_2=ch.psi.pshell.modbus.ProcessVariable|wago 1||| +led_ctrl_3=ch.psi.pshell.modbus.ProcessVariable|wago 2||| +smc_current=ch.psi.pshell.modbus.ProcessVariable|wago 3||| +#img_back=ch.psi.pshell.imaging.CameraSource|cam||-100| +#fx=ch.psi.pshell.epics.Motor|SAR-EXPMX:MOT_FX|||true +#fy=ch.psi.pshell.epics.Motor|SAR-EXPMX:MOT_FY|||true +#ry=ch.psi.pshell.epics.Motor|SAR-EXPMX:MOT_ROT_Y|||true +#cz=ch.psi.pshell.epics.Motor|SAR-EXPMX:MOT_CZ|||true +#cx=ch.psi.pshell.epics.Motor|SAR-EXPMX:MOT_CX|||true diff --git a/config/jcae.properties b/config/jcae.properties new file mode 100644 index 0000000..2bb0691 --- /dev/null +++ b/config/jcae.properties @@ -0,0 +1,11 @@ +#Tue Sep 06 15:10:24 CEST 2016 +ch.psi.jcae.ContextFactory.addressList= +ch.psi.jcae.ContextFactory.serverPort= +ch.psi.jcae.ContextFactory.maxArrayBytes=20000000 +ch.psi.jcae.ChannelFactory.retries=1 +ch.psi.jcae.ChannelFactory.timeout=500 +ch.psi.jcae.impl.DefaultChannelService.retries=2 +ch.psi.jcae.impl.DefaultChannelService.timeout=1000 +ch.psi.jcae.ContextFactory.autoAddressList=true +ch.psi.jcae.ContextFactory.useShellVariables=false +ch.psi.jcae.ContextFactory.addLocalBroadcastInterfaces=false diff --git a/config/mail.properties b/config/mail.properties new file mode 100644 index 0000000..e04b672 --- /dev/null +++ b/config/mail.properties @@ -0,0 +1,9 @@ +#Mon Oct 23 10:53:54 CEST 2017 +auth=None +from= +host= +port=0 +pwd= +smsSuffix=@sms.switch.ch +to= +usr= diff --git a/config/plugins.properties b/config/plugins.properties new file mode 100644 index 0000000..1568671 --- /dev/null +++ b/config/plugins.properties @@ -0,0 +1,21 @@ +Commands.java=disabled +Recovery.java=disabled +MXSC-1.10.0.jar=enabled +WagoPanel.java=enabled +LaserUEPanel.java=enabled +BarcodeReaderPanel.java=enabled +PuckDetectionPanel.java=enabled +HexiposiPanel.java=enabled +MjpegSource2.java=enabled +LN2.java=disabled +Hexiposi.java=disabled +NewJPanel.java=disabled +RobotPanel.java=enabled +SmartMagnetConfig.java=disabled +SmartMagnetPanel.java=enabled +LaserUE.java=enabled +TestZMQ.java=disabled +RobotModbus.java=disabled +RobotTcp.java=disabled +Beeper.java=disabled +gui.java=disabled diff --git a/config/setup-modbus.properties b/config/setup-modbus.properties new file mode 100644 index 0000000..eb292c1 --- /dev/null +++ b/config/setup-modbus.properties @@ -0,0 +1,18 @@ +#Wed Sep 14 15:16:45 CEST 2016 +configFile={config}/config.properties +configFileDevices={config}/devices-modbus.properties +configFilePlugins={config}/plugins.properties +configFileTasks={config}/tasks.properties +configPath={home}/config +contextPath={outp}/context +dataPath={outp}/data +devicesPath={home}/devices +extensionsPath={home}/extensions +imagesPath={outp}/images +libraryPath={script}; {script}/Lib +logPath={outp}/log +pluginsPath={home}/plugins +scriptPath={home}/script +scriptType=py +sessionsPath={outp}/sessions +wwwPath={home}/www diff --git a/config/setup.properties b/config/setup.properties new file mode 100644 index 0000000..58443d5 --- /dev/null +++ b/config/setup.properties @@ -0,0 +1,18 @@ +#Wed Sep 14 15:16:45 CEST 2016 +configFile={config}/config.properties +configFileDevices={config}/devices.properties +configFilePlugins={config}/plugins.properties +configFileTasks={config}/tasks.properties +configPath={home}/config +contextPath={outp}/context +dataPath={outp}/data +devicesPath={home}/devices +extensionsPath={home}/extensions +imagesPath={outp}/images +libraryPath={script}; {script}/Lib +logPath={outp}/log +pluginsPath={home}/plugins +scriptPath={home}/script +scriptType=py +sessionsPath={outp}/sessions +wwwPath={home}/www diff --git a/config/tasks.properties b/config/tasks.properties new file mode 100644 index 0000000..e291198 --- /dev/null +++ b/config/tasks.properties @@ -0,0 +1 @@ +tasks/LedMonitoring=120 diff --git a/devices/20161117_163816.png.properties b/devices/20161117_163816.png.properties new file mode 100644 index 0000000..be1fd91 --- /dev/null +++ b/devices/20161117_163816.png.properties @@ -0,0 +1,20 @@ +#Mon Oct 23 15:10:20 CEST 2017 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/BasePlate.properties b/devices/BasePlate.properties new file mode 100644 index 0000000..1e25f83 --- /dev/null +++ b/devices/BasePlate.properties @@ -0,0 +1 @@ +#Fri Feb 10 14:35:38 CET 2017 diff --git a/devices/Time.properties b/devices/Time.properties new file mode 100644 index 0000000..33011f0 --- /dev/null +++ b/devices/Time.properties @@ -0,0 +1,10 @@ +#Wed Jun 27 10:48:14 CEST 2018 +maxValue=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +rotation=false +scale=1.0 +sign_bit=0 +unit=null diff --git a/devices/air_pressure.properties b/devices/air_pressure.properties new file mode 100644 index 0000000..e476b09 --- /dev/null +++ b/devices/air_pressure.properties @@ -0,0 +1,5 @@ +#Thu Mar 01 11:13:34 CET 2018 +offset=0.0 +precision=-1 +scale=1.0 +unit=null diff --git a/devices/cx.properties b/devices/cx.properties new file mode 100644 index 0000000..1720045 --- /dev/null +++ b/devices/cx.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:53 CEST 2018 +defaultSpeed=2.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=mm diff --git a/devices/cz.properties b/devices/cz.properties new file mode 100644 index 0000000..b8877dd --- /dev/null +++ b/devices/cz.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:15 CEST 2018 +defaultSpeed=2.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=mm diff --git a/devices/dewar_level.properties b/devices/dewar_level.properties new file mode 100644 index 0000000..38fab62 --- /dev/null +++ b/devices/dewar_level.properties @@ -0,0 +1,6 @@ +#Wed Aug 08 14:23:54 CEST 2018 +offset=-25.81632 +precision=2 +scale=0.003888 +sign_bit=0 +unit=% diff --git a/devices/dispatcher.properties b/devices/dispatcher.properties new file mode 100644 index 0000000..5a3e672 --- /dev/null +++ b/devices/dispatcher.properties @@ -0,0 +1,11 @@ +#Thu May 03 11:54:38 CEST 2018 +disableCompression=false +keepListeningOnStop=false +mappingIncomplete=null +parallelHandlerProcessing=true +sendAwaitFirstMessage=false +sendBuildChannelConfig=null +sendStrategy=null +sendSyncTimeout=0 +socketType=DEFAULT +validationInconsistency=null diff --git a/devices/dp1.properties b/devices/dp1.properties new file mode 100644 index 0000000..c853c11 --- /dev/null +++ b/devices/dp1.properties @@ -0,0 +1,11 @@ +#Fri Jul 08 10:53:26 CEST 2016 +motor1=0.0|4.0|8.0|0.0 +motor2=0.0|5.0|3.0|NaN +motor3=null +motor4=null +motor5=null +motor6=null +motor7=null +motor8=null +positions=Park|Ready|Out|Clear +precision=-1 diff --git a/devices/fx.properties b/devices/fx.properties new file mode 100644 index 0000000..44a1a35 --- /dev/null +++ b/devices/fx.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:14 CEST 2018 +defaultSpeed=2.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=mm diff --git a/devices/fy.properties b/devices/fy.properties new file mode 100644 index 0000000..44a1a35 --- /dev/null +++ b/devices/fy.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:14 CEST 2018 +defaultSpeed=2.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=mm diff --git a/devices/gripper_cam.properties b/devices/gripper_cam.properties new file mode 100644 index 0000000..6fc903f --- /dev/null +++ b/devices/gripper_cam.properties @@ -0,0 +1,20 @@ +#Thu Jun 28 17:46:46 CEST 2018 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/img.properties b/devices/img.properties new file mode 100644 index 0000000..9dffde8 --- /dev/null +++ b/devices/img.properties @@ -0,0 +1,24 @@ +#Wed Sep 12 14:06:31 CEST 2018 +colormap=Grayscale +colormapAutomatic=false +colormapMax=18.133 +colormapMin=6.4 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=899 +roiWidth=893 +roiX=48 +roiY=45 +rotation=230.05382605006437 +rotationCrop=true +scale=1.0 +spatialCalOffsetX=-447.0 +spatialCalOffsetY=-450.0 +spatialCalScaleX=0.5262180258614136 +spatialCalScaleY=0.5227145226413789 +spatialCalUnits=mm +transpose=false diff --git a/devices/led_ctrl.properties b/devices/led_ctrl.properties new file mode 100644 index 0000000..00dcc48 --- /dev/null +++ b/devices/led_ctrl.properties @@ -0,0 +1,8 @@ +#Tue Jun 20 15:07:30 CEST 2017 +maxValue=0.4 +minValue=0.0 +offset=0.0 +precision=2 +resolution=NaN +scale=3.0E-4 +unit=V diff --git a/devices/led_ctrl_1.properties b/devices/led_ctrl_1.properties new file mode 100644 index 0000000..99cebbb --- /dev/null +++ b/devices/led_ctrl_1.properties @@ -0,0 +1,9 @@ +#Mon Dec 03 11:44:53 CET 2018 +maxValue=0.4 +minValue=0.0 +offset=0.0 +precision=2 +resolution=NaN +scale=3.0E-4 +sign_bit=0 +unit=V diff --git a/devices/led_ctrl_2.properties b/devices/led_ctrl_2.properties new file mode 100644 index 0000000..99cebbb --- /dev/null +++ b/devices/led_ctrl_2.properties @@ -0,0 +1,9 @@ +#Mon Dec 03 11:44:53 CET 2018 +maxValue=0.4 +minValue=0.0 +offset=0.0 +precision=2 +resolution=NaN +scale=3.0E-4 +sign_bit=0 +unit=V diff --git a/devices/led_ctrl_3.properties b/devices/led_ctrl_3.properties new file mode 100644 index 0000000..99cebbb --- /dev/null +++ b/devices/led_ctrl_3.properties @@ -0,0 +1,9 @@ +#Mon Dec 03 11:44:53 CET 2018 +maxValue=0.4 +minValue=0.0 +offset=0.0 +precision=2 +resolution=NaN +scale=3.0E-4 +sign_bit=0 +unit=V diff --git a/devices/led_level.properties b/devices/led_level.properties new file mode 100644 index 0000000..52dee03 --- /dev/null +++ b/devices/led_level.properties @@ -0,0 +1,9 @@ +#Tue Jun 19 16:41:24 CEST 2018 +maxValue=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +scale=1.0 +sign_bit=0 +unit=null diff --git a/devices/m1.properties b/devices/m1.properties new file mode 100644 index 0000000..1cf4553 --- /dev/null +++ b/devices/m1.properties @@ -0,0 +1,13 @@ +#Fri Jun 30 09:37:38 CEST 2017 +defaultSpeed=1.0 +estbilizationDelay=0 +maxSpeed=10.0 +maxValue=10.0 +minSpeed=0.1 +minValue=-10.0 +offset=0.0 +precision=2 +resolution=NaN +rotation=false +scale=1.0 +unit=mm diff --git a/devices/m2.properties b/devices/m2.properties new file mode 100644 index 0000000..1cf4553 --- /dev/null +++ b/devices/m2.properties @@ -0,0 +1,13 @@ +#Fri Jun 30 09:37:38 CEST 2017 +defaultSpeed=1.0 +estbilizationDelay=0 +maxSpeed=10.0 +maxValue=10.0 +minSpeed=0.1 +minValue=-10.0 +offset=0.0 +precision=2 +resolution=NaN +rotation=false +scale=1.0 +unit=mm diff --git a/devices/monitoring_cam.properties b/devices/monitoring_cam.properties new file mode 100644 index 0000000..fa56b35 --- /dev/null +++ b/devices/monitoring_cam.properties @@ -0,0 +1,20 @@ +#Thu Aug 09 11:01:09 CEST 2018 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/n2_pressure.properties b/devices/n2_pressure.properties new file mode 100644 index 0000000..e476b09 --- /dev/null +++ b/devices/n2_pressure.properties @@ -0,0 +1,5 @@ +#Thu Mar 01 11:13:34 CET 2018 +offset=0.0 +precision=-1 +scale=1.0 +unit=null diff --git a/devices/p1.properties b/devices/p1.properties new file mode 100644 index 0000000..07d9ba5 --- /dev/null +++ b/devices/p1.properties @@ -0,0 +1,9 @@ +#Fri Jun 30 09:37:38 CEST 2017 +maxValue=1000.0 +minValue=0.0 +offset=0.0 +precision=-1 +resolution=NaN +rotation=false +scale=1.0 +unit=mm diff --git a/devices/phase_separator.properties b/devices/phase_separator.properties new file mode 100644 index 0000000..122f8e9 --- /dev/null +++ b/devices/phase_separator.properties @@ -0,0 +1,8 @@ +#Wed Feb 28 17:35:59 CET 2018 +maxValue=30000.0 +minValue=0.0 +offset=0.0 +precision=-1 +resolution=NaN +scale=0.1 +unit=% diff --git a/devices/phase_separator_level.properties b/devices/phase_separator_level.properties new file mode 100644 index 0000000..92a5279 --- /dev/null +++ b/devices/phase_separator_level.properties @@ -0,0 +1,6 @@ +#Tue Jun 19 16:41:20 CEST 2018 +offset=-25.81632 +precision=2 +scale=0.003888 +sign_bit=0 +unit=% diff --git a/devices/rim_heater_temp.properties b/devices/rim_heater_temp.properties new file mode 100644 index 0000000..e1c3b95 --- /dev/null +++ b/devices/rim_heater_temp.properties @@ -0,0 +1,6 @@ +#Tue Jun 19 16:41:20 CEST 2018 +offset=-25.81632 +precision=2 +scale=0.003888 +sign_bit=0 +unit=C diff --git a/devices/robot x.properties b/devices/robot x.properties new file mode 100644 index 0000000..02ffbf3 --- /dev/null +++ b/devices/robot x.properties @@ -0,0 +1,9 @@ +#Tue Sep 12 15:00:38 CEST 2017 +maxValue=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +rotation=false +scale=1.0 +unit=null diff --git a/devices/robot.properties b/devices/robot.properties new file mode 100644 index 0000000..97f6ad6 --- /dev/null +++ b/devices/robot.properties @@ -0,0 +1,8 @@ +#Thu Jul 21 08:35:47 CEST 2016 +offsetReadAnalogInput=0 +offsetReadAnalogOutput=0 +offsetReadDigitalInput=0 +offsetReadDigitalOutput=0 +offsetWriteAnalogOutput=0 +offsetWriteDigitalOutput=0 +timeout=1000 diff --git a/devices/robot_j1.properties b/devices/robot_j1.properties new file mode 100644 index 0000000..bc3a381 --- /dev/null +++ b/devices/robot_j1.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=180.0 +minValue=-180.0 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j2.properties b/devices/robot_j2.properties new file mode 100644 index 0000000..6a892bc --- /dev/null +++ b/devices/robot_j2.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=127.5 +minValue=-127.5 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j3.properties b/devices/robot_j3.properties new file mode 100644 index 0000000..07bff75 --- /dev/null +++ b/devices/robot_j3.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=152.5 +minValue=-152.5 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j4.properties b/devices/robot_j4.properties new file mode 100644 index 0000000..41d8586 --- /dev/null +++ b/devices/robot_j4.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=270.0 +minValue=-270.0 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j5.properties b/devices/robot_j5.properties new file mode 100644 index 0000000..dab429f --- /dev/null +++ b/devices/robot_j5.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=132.5 +minValue=-122.5 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_j6.properties b/devices/robot_j6.properties new file mode 100644 index 0000000..d688634 --- /dev/null +++ b/devices/robot_j6.properties @@ -0,0 +1,10 @@ +#Fri Aug 24 14:56:42 CEST 2018 +maxValue=400.0 +minValue=-400.0 +offset=0.0 +precision=2 +resolution=0.1 +rotation=false +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_modbus.properties b/devices/robot_modbus.properties new file mode 100644 index 0000000..31a13be --- /dev/null +++ b/devices/robot_modbus.properties @@ -0,0 +1,8 @@ +#Thu Jul 21 12:02:04 CEST 2016 +offsetReadAnalogInput=0 +offsetReadAnalogOutput=0 +offsetReadDigitalInput=0 +offsetReadDigitalOutput=0 +offsetWriteAnalogOutput=0 +offsetWriteDigitalOutput=0 +timeout=1000 diff --git a/devices/robot_rx.properties b/devices/robot_rx.properties new file mode 100644 index 0000000..df63f03 --- /dev/null +++ b/devices/robot_rx.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=180.0 +minValue=-180.0 +offset=0.0 +precision=2 +resolution=0.05 +rotation=true +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_ry.properties b/devices/robot_ry.properties new file mode 100644 index 0000000..a789ebf --- /dev/null +++ b/devices/robot_ry.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=180.0 +minValue=-180.0 +offset=0.0 +precision=-2 +resolution=0.05 +rotation=true +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_rz.properties b/devices/robot_rz.properties new file mode 100644 index 0000000..2b88035 --- /dev/null +++ b/devices/robot_rz.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=360.0 +minValue=-360.0 +offset=0.0 +precision=2 +resolution=0.1 +rotation=true +scale=1.0 +sign_bit=0 +unit=deg diff --git a/devices/robot_x.properties b/devices/robot_x.properties new file mode 100644 index 0000000..5cdadcc --- /dev/null +++ b/devices/robot_x.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=1000.0 +minValue=-1000.0 +offset=0.0 +precision=2 +resolution=0.05 +rotation=false +scale=1.0 +sign_bit=0 +unit=mm diff --git a/devices/robot_y.properties b/devices/robot_y.properties new file mode 100644 index 0000000..eb8022e --- /dev/null +++ b/devices/robot_y.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=1000.0 +minValue=-1000.0 +offset=0.0 +precision=2 +resolution=0.05 +rotation=false +scale=1.0 +sign_bit=0 +unit=null diff --git a/devices/robot_z.properties b/devices/robot_z.properties new file mode 100644 index 0000000..eb8022e --- /dev/null +++ b/devices/robot_z.properties @@ -0,0 +1,10 @@ +#Tue Jun 19 16:41:28 CEST 2018 +maxValue=1000.0 +minValue=-1000.0 +offset=0.0 +precision=2 +resolution=0.05 +rotation=false +scale=1.0 +sign_bit=0 +unit=null diff --git a/devices/ry.properties b/devices/ry.properties new file mode 100644 index 0000000..f43c3d2 --- /dev/null +++ b/devices/ry.properties @@ -0,0 +1,17 @@ +#Fri Aug 10 15:47:14 CEST 2018 +defaultSpeed=50.0 +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=0.0 +minSpeed=NaN +minValue=0.0 +offset=0.0 +precision=3 +resolution=0.001 +rotation=false +scale=1.0 +sign_bit=0 +startRetries=1 +unit=deg diff --git a/devices/smart_magnet.properties b/devices/smart_magnet.properties new file mode 100644 index 0000000..012c86e --- /dev/null +++ b/devices/smart_magnet.properties @@ -0,0 +1,8 @@ +#Thu Oct 25 16:47:21 CEST 2018 +holdingCurrent=30.0 +mountCurrent=10.0 +remanenceCurrent=-10.0 +restingCurrent=10.0 +reverseCurrent=-10.0 +reverseTime=0.4 +unmountCurrent=10.0 diff --git a/devices/smc_current.properties b/devices/smc_current.properties new file mode 100644 index 0000000..aa71f58 --- /dev/null +++ b/devices/smc_current.properties @@ -0,0 +1,9 @@ +#Tue Jun 19 16:41:20 CEST 2018 +maxValue=50.0 +minValue=-50.0 +offset=0.0 +precision=2 +resolution=NaN +scale=0.003 +sign_bit=0 +unit=mA diff --git a/devices/smc_current_rb.properties b/devices/smc_current_rb.properties new file mode 100644 index 0000000..7709ada --- /dev/null +++ b/devices/smc_current_rb.properties @@ -0,0 +1,6 @@ +#Tue Jun 19 16:45:06 CEST 2018 +offset=0.0 +precision=2 +scale=0.003 +sign_bit=15 +unit=mA diff --git a/devices/src1.properties b/devices/src1.properties new file mode 100644 index 0000000..a0b5d6d --- /dev/null +++ b/devices/src1.properties @@ -0,0 +1,24 @@ +#Thu Sep 22 14:45:06 CEST 2016 +colormap=Temperature +colormapAutomatic=true +colormapMax=255.0 +colormapMin=0.0 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/src2.properties b/devices/src2.properties new file mode 100644 index 0000000..2bf8406 --- /dev/null +++ b/devices/src2.properties @@ -0,0 +1,24 @@ +#Thu Sep 22 14:45:06 CEST 2016 +colormap=Grayscale +colormapAutomatic=true +colormapMax=255.0 +colormapMin=0.0 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/top_cam.properties b/devices/top_cam.properties new file mode 100644 index 0000000..827552b --- /dev/null +++ b/devices/top_cam.properties @@ -0,0 +1,20 @@ +#Thu Aug 09 11:46:12 CEST 2018 +flipHorizontally=false +flipVertically=false +grayscale=false +invert=false +rescaleFactor=1.0 +rescaleOffset=0.0 +roiHeight=-1 +roiWidth=-1 +roiX=0 +roiY=0 +rotation=0.0 +rotationCrop=false +scale=1.0 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN +spatialCalUnits=mm +transpose=false diff --git a/devices/ue.properties b/devices/ue.properties new file mode 100644 index 0000000..f241f62 --- /dev/null +++ b/devices/ue.properties @@ -0,0 +1,6 @@ +#Thu Aug 31 16:41:09 CEST 2017 +baudRate=9600 +dataBits=DB_8 +parity=None +port=null +stopBits=SB_1 diff --git a/devices/wago.properties b/devices/wago.properties new file mode 100644 index 0000000..f2650ea --- /dev/null +++ b/devices/wago.properties @@ -0,0 +1,8 @@ +#Wed Feb 28 16:27:51 CET 2018 +offsetReadAnalogInput=0 +offsetReadAnalogOutput=0x200 +offsetReadDigitalInput=0 +offsetReadDigitalOutput=0x200 +offsetWriteAnalogOutput=0 +offsetWriteDigitalOutput=0 +timeout=1000 diff --git a/plugins/BarcodeReaderPanel.form b/plugins/BarcodeReaderPanel.form new file mode 100644 index 0000000..3e615f6 --- /dev/null +++ b/plugins/BarcodeReaderPanel.form @@ -0,0 +1,118 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/BarcodeReaderPanel.java b/plugins/BarcodeReaderPanel.java new file mode 100644 index 0000000..cb269c2 --- /dev/null +++ b/plugins/BarcodeReaderPanel.java @@ -0,0 +1,162 @@ +import ch.psi.pshell.core.Context; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; +import java.util.concurrent.CompletableFuture; + +/** + * + */ +public class BarcodeReaderPanel extends DevicePanel { + + volatile boolean enabled; + public BarcodeReaderPanel() { + initComponents(); + this.startTimer(100); + } + + + CompletableFuture future; + + @Override + public void onTimer(){ + if ((getDevice()!=null) && enabled){ + if ((future==null) || (future.isDone())){ + future = Context.getInstance().evalLineBackgroundAsync("barcode_reader.get()"); + } + } + } + + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (BarcodeReaderPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + if (ret == null){ + SwingUtils.showMessage(this, "Return", "No code detected", 20000); + } else { + SwingUtils.showMessage(this, "Return", "Detected code: " +ret, 20000); + } + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel3 = new javax.swing.JPanel(); + buttonEnable = new javax.swing.JButton(); + buttonDisable = new javax.swing.JButton(); + buttonRead = new javax.swing.JButton(); + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + deviceValuePanel1 = new ch.psi.pshell.swing.DeviceValuePanel(); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Commands")); + + buttonEnable.setText("Enable"); + buttonEnable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonEnableActionPerformed(evt); + } + }); + + buttonDisable.setText("Disable"); + buttonDisable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonDisableActionPerformed(evt); + } + }); + + buttonRead.setText("Read"); + buttonRead.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReadActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonEnable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonDisable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonRead) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonDisable, buttonEnable, buttonRead}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonEnable) + .addComponent(buttonDisable) + .addComponent(buttonRead)) + .addContainerGap()) + ); + + deviceStatePanel1.setDeviceName("barcode_reader"); + + deviceValuePanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Value")); + deviceValuePanel1.setDeviceName("barcode_reader"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) + ); + }// //GEN-END:initComponents + + private void buttonEnableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEnableActionPerformed + execute("barcode_reader.enable()", false); + enabled = true; + }//GEN-LAST:event_buttonEnableActionPerformed + + private void buttonDisableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDisableActionPerformed + enabled = false; + execute("barcode_reader.disable()", false); + }//GEN-LAST:event_buttonDisableActionPerformed + + private void buttonReadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReadActionPerformed + enabled = false; + execute("barcode_reader.read(5.0) ", true); + }//GEN-LAST:event_buttonReadActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonDisable; + private javax.swing.JButton buttonEnable; + private javax.swing.JButton buttonRead; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private ch.psi.pshell.swing.DeviceValuePanel deviceValuePanel1; + private javax.swing.JPanel jPanel3; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/Beeper.java b/plugins/Beeper.java new file mode 100644 index 0000000..c1fea67 --- /dev/null +++ b/plugins/Beeper.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.*; +import com.sun.jna.Function; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.win32.StdCallLibrary; +import com.sun.jna.win32.W32APIFunctionMapper; +import com.sun.jna.win32.W32APITypeMapper; +import java.util.HashMap; +import java.util.Map; + +/** + */ +public class Beeper extends DeviceBase { + + public Beeper(String name) { + super(name); + } + + // JNA Mapping + static Map UNICODE_OPTIONS = new HashMap() { + + { + put("type-mapper", W32APITypeMapper.UNICODE); + put("function-mapper", W32APIFunctionMapper.UNICODE); + } + }; + + interface Kernel32 extends StdCallLibrary { + + public static final String LIBRARY_NAME = "kernel32"; + Kernel32 INSTANCE = (Kernel32) Native.loadLibrary(LIBRARY_NAME, Kernel32.class, UNICODE_OPTIONS); + Kernel32 SYNC_INSTANCE = (Kernel32) Native.synchronizedLibrary(INSTANCE); + + boolean Beep(int FREQUENCY, int DURATION); + + void Sleep(int DURATION); + + int CreateEventW(Pointer securityAttributes, boolean manualReset, boolean initialState, String name); + + int CreateThread(/*Pointer*/int lpThreadAttributes, IntByReference dwStackSize, Function lpStartAddress, Structure lpParameter, int dwCreationFlags, IntByReference lpThreadId); + public static final int STILL_ACTIVE = 259; + + int GetExitCodeThread(int hThread, IntByReference lpExitCode); + + int GetLastError(); + + boolean CloseHandle(int handle); + + } + private final int mEventHandle = Kernel32.INSTANCE.CreateEventW(Pointer.NULL, true, false, null); + + + //Public interface + public int getLastError(){ + return Kernel32.SYNC_INSTANCE.GetLastError(); + } + + public void sleep(int duration){ + Kernel32.SYNC_INSTANCE.Sleep(duration); + } + + public void beep(int frequency, int duration){ + Kernel32.SYNC_INSTANCE.Beep(frequency, duration); + } + +} diff --git a/plugins/Commands.form b/plugins/Commands.form new file mode 100644 index 0000000..70c71b4 --- /dev/null +++ b/plugins/Commands.form @@ -0,0 +1,803 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/Commands.java b/plugins/Commands.java new file mode 100644 index 0000000..f861b06 --- /dev/null +++ b/plugins/Commands.java @@ -0,0 +1,914 @@ +/* + * Copyright (c) 2014-2017 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.device.DeviceAdapter; +import ch.psi.pshell.device.GenericDevice; +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import java.awt.Component; +import javax.swing.JComponent; +import javax.swing.JSpinner; +import javax.swing.JTextField; + +/** + * + */ +public class Commands extends Panel { + + public Commands() { + initComponents(); + ((JSpinner.DefaultEditor)spinnerSegment.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); + ((JSpinner.DefaultEditor)spinnerPuck.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); + ((JSpinner.DefaultEditor)spinnerSample.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + GenericDevice basePlate = getDevice("BasePlate"); + if (basePlate != null){ + basePlate.addListener(new DeviceAdapter() { + @Override + public void onValueChanged(Device device, Object value, Object former) { + if (value!=null){ + String segment = ((Object[])value)[0].toString(); + spinnerSegment.setValue(segment); + Integer puck = (Integer) ((Object[])value)[1]; + spinnerPuck.setValue(Integer.valueOf(puck)); + Integer sample = (Integer) ((Object[])value)[2]; + if (sample!=null){ + spinnerSample.setValue(Integer.valueOf(sample)); + } + } + } + }); + } + } + + @Override + public void onStateChange(State state, State former) { + boolean enabled = (state == State.Ready); + for (Component c: SwingUtils.getComponentsByType(this, JComponent.class)){ + c.setEnabled(enabled); + } + spinnerSegment.setEnabled(enabled && !checkAuxiliary.isSelected()); + spinnerPuck.setEnabled(enabled && !checkAuxiliary.isSelected()); + buttonScanPuck.setEnabled(enabled && !checkAuxiliary.isSelected()); + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + //Callback to perform update - in event thread + @Override + protected void doUpdate() { + } + + @Override + public boolean isActive() { + return true; + } + + + void execute(String statement){ + execute(statement, false); + } + + void execute(String statement, boolean background){ + execute(statement, background, false); + } + + void execute(String statement, boolean background, boolean showReturn){ + try { + evalAsync(statement, background).handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + SwingUtils.showMessage(getTopLevel(), "Return", String.valueOf(ret)); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + void execute(String script, Object args){ + try { + runAsync(script, args).handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jTabbedPane1 = new javax.swing.JTabbedPane(); + tabCommands = new javax.swing.JPanel(); + pnDry = new javax.swing.JPanel(); + jLabel6 = new javax.swing.JLabel(); + spinnerDryTime = new ch.psi.utils.swing.HorizontalSpinner(); + buttonDry = new javax.swing.JButton(); + spinnerDrySpeed = new ch.psi.utils.swing.HorizontalSpinner(); + jLabel7 = new javax.swing.JLabel(); + ckeckParkOnDry = new javax.swing.JCheckBox(); + pnTransfer = new javax.swing.JPanel(); + buttonMount = new javax.swing.JButton(); + jPanel5 = new javax.swing.JPanel(); + jLabel4 = new javax.swing.JLabel(); + checkForce = new javax.swing.JCheckBox(); + spinnerSample = new ch.psi.utils.swing.HorizontalSpinner(); + spinnerPuck = new ch.psi.utils.swing.HorizontalSpinner(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + spinnerSegment = new ch.psi.utils.swing.HorizontalSpinner(); + jLabel3 = new javax.swing.JLabel(); + jLabel5 = new javax.swing.JLabel(); + checkDatamatrix = new javax.swing.JCheckBox(); + buttonUnmount = new javax.swing.JButton(); + buttonScanPin = new javax.swing.JButton(); + buttonScanPuck = new javax.swing.JButton(); + checkAuxiliary = new javax.swing.JCheckBox(); + jPanel1 = new javax.swing.JPanel(); + buttonGripperScan = new javax.swing.JButton(); + buttonTrash = new javax.swing.JButton(); + tabAdvanced = new javax.swing.JPanel(); + pnLowLevel = new javax.swing.JPanel(); + buttonMovePark = new javax.swing.JButton(); + buttonMoveCold = new javax.swing.JButton(); + buttonMoveGonio = new javax.swing.JButton(); + buttonMoveHeater = new javax.swing.JButton(); + buttonGetGonio = new javax.swing.JButton(); + buttonPutGonio = new javax.swing.JButton(); + buttonMoveDewar = new javax.swing.JButton(); + buttonMoveHome = new javax.swing.JButton(); + buttonMoveScanner = new javax.swing.JButton(); + buttonGetDewar = new javax.swing.JButton(); + buttonPutDewar = new javax.swing.JButton(); + buttonMoveAux = new javax.swing.JButton(); + buttonGetAux = new javax.swing.JButton(); + buttonPutAux = new javax.swing.JButton(); + pnDatabase = new javax.swing.JPanel(); + buttonClearSampleDb = new javax.swing.JButton(); + buttonResetPuckIds = new javax.swing.JButton(); + pnMotion = new javax.swing.JPanel(); + buttonRecover = new javax.swing.JButton(); + buttonEnableAll = new javax.swing.JButton(); + + pnDry.setBorder(javax.swing.BorderFactory.createTitledBorder("Drying")); + + jLabel6.setText("Heat time(s):"); + + spinnerDryTime.setModel(new javax.swing.SpinnerNumberModel(30.0d, 1.0d, 30.0d, 1.0d)); + + buttonDry.setText("Dry"); + buttonDry.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonDryActionPerformed(evt); + } + }); + + spinnerDrySpeed.setModel(new javax.swing.SpinnerNumberModel(0.5d, 0.1d, 10.0d, 1.0d)); + + jLabel7.setText("Speed(%):"); + + ckeckParkOnDry.setText("Park on finish"); + + javax.swing.GroupLayout pnDryLayout = new javax.swing.GroupLayout(pnDry); + pnDry.setLayout(pnDryLayout); + pnDryLayout.setHorizontalGroup( + pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDryLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonDry, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ckeckParkOnDry)) + .addGap(18, 25, Short.MAX_VALUE) + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jLabel6) + .addComponent(jLabel7)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(spinnerDrySpeed, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spinnerDryTime, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + pnDryLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonDry, spinnerDrySpeed, spinnerDryTime}); + + pnDryLayout.setVerticalGroup( + pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDryLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDryLayout.createSequentialGroup() + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonDry) + .addComponent(spinnerDryTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnDryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(spinnerDrySpeed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel7) + .addComponent(ckeckParkOnDry))) + .addComponent(jLabel6)) + .addContainerGap()) + ); + + pnTransfer.setBorder(javax.swing.BorderFactory.createTitledBorder("Sample Transfer")); + + buttonMount.setText("Mount"); + buttonMount.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMountActionPerformed(evt); + } + }); + + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel4.setText("Force:"); + + checkForce.setSelected(true); + checkForce.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + + spinnerSample.setModel(new javax.swing.SpinnerNumberModel(1, 1, 16, 1)); + + spinnerPuck.setModel(new javax.swing.SpinnerNumberModel(1, 1, 5, 1)); + + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel1.setText("Segment:"); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel2.setText("Puck:"); + + spinnerSegment.setModel(new javax.swing.SpinnerListModel(new String[] {"A", "B", "C", "D", "E", "F"})); + + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel3.setText("Sample:"); + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel5.setText("Read DM:"); + + checkDatamatrix.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + + javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5); + jPanel5.setLayout(jPanel5Layout); + jPanel5Layout.setHorizontalGroup( + jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel5Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel3) + .addComponent(jLabel2) + .addComponent(jLabel1) + .addComponent(jLabel4) + .addComponent(jLabel5)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(spinnerPuck, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(checkForce) + .addComponent(checkDatamatrix) + .addComponent(spinnerSample, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spinnerSegment, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 0, 0)) + ); + + jPanel5Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jLabel1, jLabel2, jLabel3, jLabel4, jLabel5}); + + jPanel5Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {spinnerPuck, spinnerSample, spinnerSegment}); + + jPanel5Layout.setVerticalGroup( + jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel5Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel1) + .addComponent(spinnerSegment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel2) + .addComponent(spinnerPuck, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel3) + .addComponent(spinnerSample, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel4) + .addComponent(checkForce)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel5) + .addComponent(checkDatamatrix))) + ); + + buttonUnmount.setText("Unmount"); + buttonUnmount.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonUnmountActionPerformed(evt); + } + }); + + buttonScanPin.setText("Scan Pin"); + buttonScanPin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonScanPinActionPerformed(evt); + } + }); + + buttonScanPuck.setText("Scan Puck"); + buttonScanPuck.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonScanPuckActionPerformed(evt); + } + }); + + checkAuxiliary.setText("Auxiliary"); + checkAuxiliary.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + checkAuxiliaryActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnTransferLayout = new javax.swing.GroupLayout(pnTransfer); + pnTransfer.setLayout(pnTransferLayout); + pnTransferLayout.setHorizontalGroup( + pnTransferLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnTransferLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnTransferLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonMount, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonUnmount, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonScanPin, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonScanPuck, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(checkAuxiliary)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pnTransferLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonMount, buttonScanPin, buttonUnmount}); + + pnTransferLayout.setVerticalGroup( + pnTransferLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnTransferLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnTransferLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(pnTransferLayout.createSequentialGroup() + .addComponent(buttonMount) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonUnmount) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonScanPin) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonScanPuck) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(checkAuxiliary))) + .addContainerGap()) + ); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Gripper")); + + buttonGripperScan.setText("Scan"); + buttonGripperScan.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonGripperScanActionPerformed(evt); + } + }); + + buttonTrash.setText("Trash"); + buttonTrash.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonTrashActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonGripperScan, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonTrash, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonGripperScan) + .addComponent(buttonTrash)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + javax.swing.GroupLayout tabCommandsLayout = new javax.swing.GroupLayout(tabCommands); + tabCommands.setLayout(tabCommandsLayout); + tabCommandsLayout.setHorizontalGroup( + tabCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabCommandsLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(tabCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pnDry, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnTransfer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + ); + tabCommandsLayout.setVerticalGroup( + tabCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabCommandsLayout.createSequentialGroup() + .addContainerGap() + .addComponent(pnDry, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(pnTransfer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + jTabbedPane1.addTab("Commands", tabCommands); + + pnLowLevel.setBorder(javax.swing.BorderFactory.createTitledBorder("Low-level Motion Commands")); + + buttonMovePark.setText("Move Park"); + buttonMovePark.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveParkActionPerformed(evt); + } + }); + + buttonMoveCold.setText("Move Cold"); + buttonMoveCold.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveColdActionPerformed(evt); + } + }); + + buttonMoveGonio.setText("Move Gonio"); + buttonMoveGonio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveGonioActionPerformed(evt); + } + }); + + buttonMoveHeater.setText("Move Heater"); + buttonMoveHeater.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveHeaterActionPerformed(evt); + } + }); + + buttonGetGonio.setText("Get Gonio"); + buttonGetGonio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonGetGonioActionPerformed(evt); + } + }); + + buttonPutGonio.setText("Put Gonio"); + buttonPutGonio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPutGonioActionPerformed(evt); + } + }); + + buttonMoveDewar.setText("Move Dewar"); + buttonMoveDewar.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveDewarActionPerformed(evt); + } + }); + + buttonMoveHome.setText("Move Home"); + buttonMoveHome.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveHomeActionPerformed(evt); + } + }); + + buttonMoveScanner.setText("Move Scanner"); + buttonMoveScanner.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveScannerActionPerformed(evt); + } + }); + + buttonGetDewar.setText("Get Dewar"); + buttonGetDewar.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonGetDewarActionPerformed(evt); + } + }); + + buttonPutDewar.setText("Put Dewar"); + buttonPutDewar.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPutDewarActionPerformed(evt); + } + }); + + buttonMoveAux.setText("Move Aux"); + buttonMoveAux.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonMoveAuxActionPerformed(evt); + } + }); + + buttonGetAux.setText("Get Aux"); + buttonGetAux.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonGetAuxActionPerformed(evt); + } + }); + + buttonPutAux.setText("Put Aux"); + buttonPutAux.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPutAuxActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnLowLevelLayout = new javax.swing.GroupLayout(pnLowLevel); + pnLowLevel.setLayout(pnLowLevelLayout); + pnLowLevelLayout.setHorizontalGroup( + pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnLowLevelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonMovePark, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveAux) + .addComponent(buttonMoveCold, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveHeater) + .addComponent(buttonGetGonio) + .addComponent(buttonGetDewar, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonGetAux, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 64, Short.MAX_VALUE) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonPutDewar, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonPutGonio, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveGonio, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveHome, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveDewar, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonMoveScanner) + .addComponent(buttonPutAux, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + pnLowLevelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonGetAux, buttonGetDewar, buttonGetGonio, buttonMoveAux, buttonMoveCold, buttonMoveDewar, buttonMoveGonio, buttonMoveHeater, buttonMoveHome, buttonMovePark, buttonMoveScanner, buttonPutAux, buttonPutDewar, buttonPutGonio}); + + pnLowLevelLayout.setVerticalGroup( + pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnLowLevelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonGetDewar) + .addComponent(buttonPutDewar)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonGetAux) + .addComponent(buttonPutAux)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonGetGonio) + .addComponent(buttonPutGonio)) + .addGap(18, 18, 18) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonMoveGonio) + .addComponent(buttonMoveAux)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonMovePark) + .addComponent(buttonMoveHome)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonMoveDewar) + .addComponent(buttonMoveCold)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnLowLevelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonMoveHeater) + .addComponent(buttonMoveScanner)) + .addContainerGap()) + ); + + pnDatabase.setBorder(javax.swing.BorderFactory.createTitledBorder("Database")); + + buttonClearSampleDb.setText("Clear Sample Db"); + buttonClearSampleDb.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonClearSampleDbActionPerformed(evt); + } + }); + + buttonResetPuckIds.setText("Reset Puck IDs"); + buttonResetPuckIds.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonResetPuckIdsActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnDatabaseLayout = new javax.swing.GroupLayout(pnDatabase); + pnDatabase.setLayout(pnDatabaseLayout); + pnDatabaseLayout.setHorizontalGroup( + pnDatabaseLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDatabaseLayout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonClearSampleDb) + .addGap(18, 18, Short.MAX_VALUE) + .addComponent(buttonResetPuckIds) + .addContainerGap()) + ); + + pnDatabaseLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonClearSampleDb, buttonResetPuckIds}); + + pnDatabaseLayout.setVerticalGroup( + pnDatabaseLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnDatabaseLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnDatabaseLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonClearSampleDb) + .addComponent(buttonResetPuckIds)) + .addContainerGap()) + ); + + pnMotion.setBorder(javax.swing.BorderFactory.createTitledBorder("Motion")); + + buttonRecover.setText("Dewar Recovery"); + buttonRecover.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonRecoverActionPerformed(evt); + } + }); + + buttonEnableAll.setText("Enable Motion"); + buttonEnableAll.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonEnableAllActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnMotionLayout = new javax.swing.GroupLayout(pnMotion); + pnMotion.setLayout(pnMotionLayout); + pnMotionLayout.setHorizontalGroup( + pnMotionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnMotionLayout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonRecover) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonEnableAll) + .addContainerGap()) + ); + + pnMotionLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonEnableAll, buttonRecover}); + + pnMotionLayout.setVerticalGroup( + pnMotionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnMotionLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnMotionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonRecover) + .addComponent(buttonEnableAll)) + .addContainerGap()) + ); + + javax.swing.GroupLayout tabAdvancedLayout = new javax.swing.GroupLayout(tabAdvanced); + tabAdvanced.setLayout(tabAdvancedLayout); + tabAdvancedLayout.setHorizontalGroup( + tabAdvancedLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabAdvancedLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(tabAdvancedLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pnMotion, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnDatabase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnLowLevel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, 0)) + ); + tabAdvancedLayout.setVerticalGroup( + tabAdvancedLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tabAdvancedLayout.createSequentialGroup() + .addContainerGap() + .addComponent(pnLowLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(pnDatabase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(pnMotion, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + jTabbedPane1.addTab("Advanced", tabAdvanced); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jTabbedPane1, javax.swing.GroupLayout.Alignment.TRAILING) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + ); + }// //GEN-END:initComponents + + private void buttonEnableAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEnableAllActionPerformed + execute("enable_motion()", true); + }//GEN-LAST:event_buttonEnableAllActionPerformed + + private void buttonMountActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMountActionPerformed + String segment = checkAuxiliary.isSelected() ? "X" : (String) spinnerSegment.getValue(); + int puck = checkAuxiliary.isSelected() ? 1 :(Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + String readDatamatrix = checkDatamatrix.isSelected() ? "True" : "False"; + execute("mount('" + segment + "'," + puck + "," + sample + ", force=" + force + ", read_dm=" + readDatamatrix + ")"); + + }//GEN-LAST:event_buttonMountActionPerformed + + private void buttonMoveAuxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveAuxActionPerformed + execute("move_aux()"); + }//GEN-LAST:event_buttonMoveAuxActionPerformed + + private void buttonUnmountActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonUnmountActionPerformed + String segment = checkAuxiliary.isSelected() ? "X" : (String) spinnerSegment.getValue(); + int puck = checkAuxiliary.isSelected() ? 1 :(Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("unmount('" + segment + "'," + puck + "," + sample + ", force=" + force + ")"); + }//GEN-LAST:event_buttonUnmountActionPerformed + + private void buttonGetDewarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGetDewarActionPerformed + String segment = (String) spinnerSegment.getValue(); + int puck = (Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("get_dewar('" + segment + "'," + puck + "," + sample + ", force=" + force + ")"); + }//GEN-LAST:event_buttonGetDewarActionPerformed + + private void buttonPutDewarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPutDewarActionPerformed + String segment = (String) spinnerSegment.getValue(); + int puck = (Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("put_dewar('" + segment + "'," + puck + "," + sample + ", force=" + force + ")"); + }//GEN-LAST:event_buttonPutDewarActionPerformed + + private void buttonGetGonioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGetGonioActionPerformed + String force = checkForce.isSelected() ? "True" : "False"; + execute("get_gonio(force=" + force + ")"); + }//GEN-LAST:event_buttonGetGonioActionPerformed + + private void buttonPutGonioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPutGonioActionPerformed + String force = checkForce.isSelected() ? "True" : "False"; + execute("put_gonio(force=" + force + ")"); + }//GEN-LAST:event_buttonPutGonioActionPerformed + + private void buttonMoveParkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveParkActionPerformed + execute("move_park()"); + }//GEN-LAST:event_buttonMoveParkActionPerformed + + private void buttonMoveHomeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveHomeActionPerformed + execute("move_home()"); + }//GEN-LAST:event_buttonMoveHomeActionPerformed + + private void buttonMoveGonioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveGonioActionPerformed + execute("move_gonio()"); + }//GEN-LAST:event_buttonMoveGonioActionPerformed + + private void buttonMoveDewarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveDewarActionPerformed + execute("move_dewar()"); + }//GEN-LAST:event_buttonMoveDewarActionPerformed + + private void buttonMoveScannerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveScannerActionPerformed + execute("move_scanner()"); + }//GEN-LAST:event_buttonMoveScannerActionPerformed + + private void buttonMoveHeaterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveHeaterActionPerformed + execute("move_heater()"); + }//GEN-LAST:event_buttonMoveHeaterActionPerformed + + private void buttonDryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDryActionPerformed + double dryTime = (Double) spinnerDryTime.getValue(); + double streamTime = (Double) spinnerDrySpeed.getValue(); + boolean park = ckeckParkOnDry.isSelected(); + + execute("dry(" + dryTime + ", " + streamTime + (park ? ", wait_cold=-1": "") + ")"); + }//GEN-LAST:event_buttonDryActionPerformed + + private void buttonRecoverActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRecoverActionPerformed + execute("robot_recover()"); + }//GEN-LAST:event_buttonRecoverActionPerformed + + private void buttonMoveColdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveColdActionPerformed + execute("move_cold()"); + }//GEN-LAST:event_buttonMoveColdActionPerformed + + private void buttonClearSampleDbActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonClearSampleDbActionPerformed + execute("clear_samples_info()", true); + }//GEN-LAST:event_buttonClearSampleDbActionPerformed + + private void buttonResetPuckIdsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonResetPuckIdsActionPerformed + execute("reset_puck_datamatrix()", true); + }//GEN-LAST:event_buttonResetPuckIdsActionPerformed + + private void buttonScanPinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonScanPinActionPerformed + String segment = checkAuxiliary.isSelected() ? "X" : (String) spinnerSegment.getValue(); + int puck = checkAuxiliary.isSelected() ? 1 :(Integer) spinnerPuck.getValue(); + int sample = (Integer) spinnerSample.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("scan_pin('" + segment + "'," + puck + "," + sample + ", force=" + force + ")", false, true); + }//GEN-LAST:event_buttonScanPinActionPerformed + + private void buttonScanPuckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonScanPuckActionPerformed + String segment = checkAuxiliary.isSelected() ? "X" : (String) spinnerSegment.getValue(); + int puck = checkAuxiliary.isSelected() ? 1 :(Integer) spinnerPuck.getValue(); + String force = checkForce.isSelected() ? "True" : "False"; + execute("scan_puck('" + segment + "'," + puck + ", force=" + force + ")", false, true); + }//GEN-LAST:event_buttonScanPuckActionPerformed + + private void buttonGetAuxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGetAuxActionPerformed + int sample = (Integer) spinnerSample.getValue(); + execute("get_aux('" + sample + ")"); + }//GEN-LAST:event_buttonGetAuxActionPerformed + + private void buttonPutAuxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPutAuxActionPerformed + int sample = (Integer) spinnerSample.getValue(); + execute("put_aux('" + sample + ")"); + }//GEN-LAST:event_buttonPutAuxActionPerformed + + private void checkAuxiliaryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkAuxiliaryActionPerformed + onStateChange(getState(), null); + }//GEN-LAST:event_checkAuxiliaryActionPerformed + + private void buttonGripperScanActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGripperScanActionPerformed + execute("scan_gripper()"); + }//GEN-LAST:event_buttonGripperScanActionPerformed + + private void buttonTrashActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonTrashActionPerformed + execute("trash()"); + }//GEN-LAST:event_buttonTrashActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonClearSampleDb; + private javax.swing.JButton buttonDry; + private javax.swing.JButton buttonEnableAll; + private javax.swing.JButton buttonGetAux; + private javax.swing.JButton buttonGetDewar; + private javax.swing.JButton buttonGetGonio; + private javax.swing.JButton buttonGripperScan; + private javax.swing.JButton buttonMount; + private javax.swing.JButton buttonMoveAux; + private javax.swing.JButton buttonMoveCold; + private javax.swing.JButton buttonMoveDewar; + private javax.swing.JButton buttonMoveGonio; + private javax.swing.JButton buttonMoveHeater; + private javax.swing.JButton buttonMoveHome; + private javax.swing.JButton buttonMovePark; + private javax.swing.JButton buttonMoveScanner; + private javax.swing.JButton buttonPutAux; + private javax.swing.JButton buttonPutDewar; + private javax.swing.JButton buttonPutGonio; + private javax.swing.JButton buttonRecover; + private javax.swing.JButton buttonResetPuckIds; + private javax.swing.JButton buttonScanPin; + private javax.swing.JButton buttonScanPuck; + private javax.swing.JButton buttonTrash; + private javax.swing.JButton buttonUnmount; + private javax.swing.JCheckBox checkAuxiliary; + private javax.swing.JCheckBox checkDatamatrix; + private javax.swing.JCheckBox checkForce; + private javax.swing.JCheckBox ckeckParkOnDry; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JLabel jLabel7; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel5; + private javax.swing.JTabbedPane jTabbedPane1; + private javax.swing.JPanel pnDatabase; + private javax.swing.JPanel pnDry; + private javax.swing.JPanel pnLowLevel; + private javax.swing.JPanel pnMotion; + private javax.swing.JPanel pnTransfer; + private javax.swing.JSpinner spinnerDrySpeed; + private javax.swing.JSpinner spinnerDryTime; + private javax.swing.JSpinner spinnerPuck; + private javax.swing.JSpinner spinnerSample; + private javax.swing.JSpinner spinnerSegment; + private javax.swing.JPanel tabAdvanced; + private javax.swing.JPanel tabCommands; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/Hexiposi.form b/plugins/Hexiposi.form new file mode 100644 index 0000000..4687d34 --- /dev/null +++ b/plugins/Hexiposi.form @@ -0,0 +1,34 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/Hexiposi.java b/plugins/Hexiposi.java new file mode 100644 index 0000000..2c55c2c --- /dev/null +++ b/plugins/Hexiposi.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014-2018 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.core.Context; +import ch.psi.pshell.ui.StripChart; +import ch.psi.pshell.ui.App; +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import java.io.File; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class Hexiposi extends Panel { + final StripChart stripChart; + public Hexiposi() { + initComponents(); + stripChart = new StripChart(this.getTopLevel(), false, App.getStripChartFolderArg()); + panel.add(stripChart.getPlotPanel()); + + try { + stripChart.open(new File(Context.getInstance().getSetup().expandPath("{home}/stripchart/hexiposi_positon.scd"))); + stripChart.start(); + } catch (Exception ex) { + showException(ex); + Logger.getLogger(Hexiposi.class.getName()).log(Level.WARNING, null, ex); + } + + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + + } + + @Override + public void onStateChange(State state, State former) { + + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + + //Callback to perform update - in event thread + @Override + protected void doUpdate() { + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + panel = new javax.swing.JPanel(); + + panel.setLayout(new java.awt.BorderLayout()); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel panel; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/HexiposiPanel.form b/plugins/HexiposiPanel.form new file mode 100644 index 0000000..65d0c18 --- /dev/null +++ b/plugins/HexiposiPanel.form @@ -0,0 +1,81 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/HexiposiPanel.java b/plugins/HexiposiPanel.java new file mode 100644 index 0000000..b29a526 --- /dev/null +++ b/plugins/HexiposiPanel.java @@ -0,0 +1,110 @@ + + +import ch.psi.pshell.core.Context; +import ch.psi.pshell.device.Device; +import ch.psi.pshell.swing.DevicePanel; + +/** + * + */ +public class HexiposiPanel extends DevicePanel { + + /** + * Creates new form HexiposiPositionPanel + */ + public HexiposiPanel() { + initComponents(); + } + + @Override + public void setDevice(Device device){ + super.setDevice(device); + discretePositionerPanel.setDevice(device); + } + + @Override + public void setEnabled(boolean enabled){ + super.setEnabled(enabled); + discretePositionerPanel.setEnabled(enabled); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + discretePositionerPanel = new ch.psi.pshell.swing.DiscretePositionerPanel(); + jPanel1 = new javax.swing.JPanel(); + buttonHoming = new javax.swing.JButton(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Initialize")); + + buttonHoming.setText("Homing"); + buttonHoming.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonHomingActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonHoming) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(buttonHoming) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(discretePositionerPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(discretePositionerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// //GEN-END:initComponents + + private void buttonHomingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonHomingActionPerformed + try { + //Context.getInstance().evalLineAsync("hexiposi.move_home()").handle((ret, ex) -> { + Context.getInstance().evalLineAsync("homing_hexiposi()").handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + + }//GEN-LAST:event_buttonHomingActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonHoming; + private ch.psi.pshell.swing.DiscretePositionerPanel discretePositionerPanel; + private javax.swing.JPanel jPanel1; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/LN2.form b/plugins/LN2.form new file mode 100644 index 0000000..4687d34 --- /dev/null +++ b/plugins/LN2.form @@ -0,0 +1,34 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/LN2.java b/plugins/LN2.java new file mode 100644 index 0000000..2300e49 --- /dev/null +++ b/plugins/LN2.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014-2018 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.core.Context; +import ch.psi.pshell.plot.TimePlotBase; +import ch.psi.pshell.ui.StripChart; +import ch.psi.pshell.ui.App; +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import java.awt.Dimension; +import java.io.File; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class LN2 extends Panel { + final StripChart stripChart; + TimePlotBase plot; + public LN2() { + initComponents(); + stripChart = new StripChart(this.getTopLevel(), false, App.getStripChartFolderArg()); + panel.add(stripChart.getPlotPanel()); + + try { + stripChart.open(new File(Context.getInstance().getSetup().expandPath("{home}/stripchart/LN2_Monitoring.scd"))); + stripChart.start(); + } catch (Exception ex) { + showException(ex); + Logger.getLogger(LN2.class.getName()).log(Level.WARNING, null, ex); + } + + plot = (TimePlotBase) SwingUtils.getComponentsByType(stripChart.getPlotPanel(),TimePlotBase.class)[0]; + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + } + + + @Override + public void onStop() { + //saveImage(); + super.onStop(); + } + + @Override + public void onStateChange(State state, State former) { + if ( (state == State.Closing) || + ((state == State.Initializing) && (former != State.Invalid)) + ){ + saveImage(); + } + + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + public void saveImage(){ + getLogger().severe("Saving image"); + try { + String fileName = new File(getContext().getSetup().expandPath("{images}/ln2/{date}_{time}.png")).getCanonicalPath(); + getLogger().severe("File: " + fileName); + plot.saveSnapshot(fileName, "png", new Dimension(1200,800)); + } catch (Exception ex) { + getLogger().log(Level.SEVERE, null, ex); + } + getLogger().severe("Done"); + } + + //Callback to perform update - in event thread + @Override + protected void doUpdate() { + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + panel = new javax.swing.JPanel(); + + panel.setLayout(new java.awt.BorderLayout()); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel panel; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/LaserUE.java b/plugins/LaserUE.java new file mode 100644 index 0000000..37dd6ee --- /dev/null +++ b/plugins/LaserUE.java @@ -0,0 +1,79 @@ + +import ch.psi.pshell.device.Readable; +import ch.psi.pshell.serial.SerialPortDevice; +import ch.psi.pshell.serial.SerialPortDeviceConfig; +import static ch.psi.utils.BitMask.*; +import ch.psi.utils.State; +import java.io.IOException; + +/* + * + */ + +/** + * + */ +public class LaserUE extends SerialPortDevice{ + final Readable readable; + static final double RANGE_MIN = 1.0; + static final double RANGE_MAX = 30.0; + public LaserUE(String name, String port) { + super(name, port, 921600, SerialPortDeviceConfig.DataBits.DB_8, SerialPortDeviceConfig.StopBits.SB_1, SerialPortDeviceConfig.Parity.None); + this.setMode(Mode.FullDuplex); + readable = new Readable() { + @Override + public Object read() throws IOException, InterruptedException { + return take(); + } + @Override + public String getName(){ + return LaserUE.this.getName()+"_readout"; + } + }; + } + + @Override + protected void doInitialize() throws IOException, InterruptedException{ + super.doInitialize(); + //TODO: Start DAQ in ILD1320: http://www.micro-epsilon.com/download/manuals/man--optoNCDT-1320--en.pdf + setState(State.Ready); + write("OUTPUT RS422\n\r"); + } + + public Readable getReadable(){ + return readable; + } + + int value = 0; + int count = 0; + + @Override + protected void onByte(int rx) { + int index = ((rx&BIT7) > 0) ? 2 : (((rx&BIT6) > 0) ? 1 : 0); + if (count==index){ + if (index ==0){ + value = rx & 0x3F; + count = 1; + } else if (index ==1){ + value = ((rx& 0x3F)<<6) + value; + count = 2; + } else if (index ==2){ + value = ((rx& 0x0F)<<12) + value; + double val = ((double)value)/1000; + if ((valRANGE_MAX)){ + val = Double.NaN; + } + setCache(val); + count = 0; + } else { + count = 0; + } + } + else{ + count = 0; + } + } + + + +} diff --git a/plugins/LaserUEPanel.form b/plugins/LaserUEPanel.form new file mode 100644 index 0000000..c9c5f8d --- /dev/null +++ b/plugins/LaserUEPanel.form @@ -0,0 +1,59 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/LaserUEPanel.java b/plugins/LaserUEPanel.java new file mode 100644 index 0000000..017fb77 --- /dev/null +++ b/plugins/LaserUEPanel.java @@ -0,0 +1,98 @@ +import ch.psi.pshell.core.Context; +import ch.psi.pshell.device.Device; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; + +/** + * + */ +public class LaserUEPanel extends DevicePanel { + + public LaserUEPanel() { + initComponents(); + } + + @Override + public void setDevice(Device device){ + super.setDevice(device); + if (device!=null){ + historyChart.addDevice("Laser Distance", device); + } else { + for (Device d: historyChart.getDevices()){ + historyChart.removeDevice(device); + } + } + } + + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (LaserUEPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + if (ret == null){ + SwingUtils.showMessage(this, "Return", "No code detected", 20000); + } else { + SwingUtils.showMessage(this, "Return", "Detected code: " +ret, 20000); + } + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + deviceStatePanel2 = new ch.psi.pshell.swing.DeviceStatePanel(); + try { + historyChart = new ch.psi.pshell.swing.HistoryChart(); + } catch (java.lang.ClassNotFoundException e1) { + e1.printStackTrace(); + } catch (java.lang.InstantiationException e2) { + e2.printStackTrace(); + } catch (java.lang.IllegalAccessException e3) { + e3.printStackTrace(); + } + deviceValuePanel1 = new ch.psi.pshell.swing.DeviceValuePanel(); + + deviceStatePanel2.setDeviceName("ue"); + + deviceValuePanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Value")); + deviceValuePanel1.setDeviceName("ue"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(historyChart, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(deviceStatePanel2, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(historyChart, javax.swing.GroupLayout.DEFAULT_SIZE, 307, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(deviceStatePanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + ); + }// //GEN-END:initComponents + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel2; + private ch.psi.pshell.swing.DeviceValuePanel deviceValuePanel1; + private ch.psi.pshell.swing.HistoryChart historyChart; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/MXSC-1.10.0.jar b/plugins/MXSC-1.10.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..5e3025c8f71cc6fa79fd781f23d1a337641a49c0 GIT binary patch literal 262914 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

}L!?^%<*AriDDLlCLM&UtoVT&MmVj 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

e?2@B|ao9e^JiL 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

{7}`a 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

N)#BeVq5FgF6+w2Yjk z=_B+{ry33M1Hm!2GOHNOt6AZP$E(xCZmjt0ON9*Ao1Nm080hPW#tIH&X zmI{(ai@i99xW)0V@xNnHi|F&_r0@@xGc|W!B*K38Zz`dD%Hqk%Juut32Ma}xi~&H6cBcD+~2 z|3_~2>85l#@9*&T-^{u{L+^jXR^BD^^Ik2N%{xxwuetG)>)y0y+NXjf94;9BS%9H>?Z`eN?4caE@G+wH$ zH6_~L7IMFlX97~uVCo$^L`!WzD#|dizxGGuU6N0P@iGpGyv5G{jJ!wmIj`FMri3lt z)EF!xnK{CwBI@>?s=?alZKU_vB%+jIu(XoBPrgJ!_gi;+4`!_&uqRMw3W;7Mv~RJS z(ohm+BKE65pal6~u?WfINEBIa+l`_oiNT#yPa`y`q=^$%fTysS;!YTB3PM{zU>ect zCk!p?az{ML_y5^wh;EfOIcDCY2W$4sr-(C69?4p?zCaW^T2wm$V&~?O9Y!?BRV&JB z2{vgg#ck*~p8gJ;LSPl1yKd>tUUnLY=@)Wc&UC^_nA%1ohj3S^2<`-RvI-=GoahTZ1L=krvX##Wza~K z%4Ru5Ma;d8luy`k+;;c~44Zp8*PlZ%vyV+iG8jDql#UhPaQYT8!QXYTQ(o+xUJaF93{6aFOnr%n&^iK|e(NZhbJFk4rfiXmfjp z^F2n0A3R{0$vV25CUjND%Z9Gf9zo6fkG=~1=GUuXe6G{5sXhj=aI%0|4zuXb1SiPp z0|MEAp-X%X_Md`kgUI;n-$M7F#@zoz7t}}LFLd?h2Wv{R5@jm^zH1~P3H2j-f!npF z`58n@I6iTf!E9!F^haHV>vvtnpa?sOZHOUd$Qg?n_G>wni*1TQ!}D9m+-sOTqM(ECd+(eGCD+=$ z#gtRqI8>y4iPOz!`*N+c32P*@a;0v{bN-&o`)cj%iyWHRjN$?c#^NTj}-1 z!RBJH%D4)!4;C|!ybc606#+e@>M~fYO|?AyGfH3ZBFeE;=F(jl!aN`-0nN(jW`9vE zBd>FkU4DT2(~T1uVc4WgDVUD#LHY4B;I~>PveWvrjig-yv3`8Tf-4^Ep%r5bkW`bI zt|LDS0gVQgz$)C|jRq9_@6d6_9Z`VWhe{zqI(rM8?yy62??CEJmN9%ZVVl}qwRO~X z@T#7I2k299^*WVz;`p5x5pqHVVG(74`yHkr0g`H%A-01 z7qH#;zb{Ss_gdkfrfZHSl()*l0{>B0M(60bG^9ZiE{gzUd@u=3BmrS?yfJVBkfA{E z=zapMjOp$K2}xl%4PCj$pbxqr%02RDa2FJ}Dz90srP{m}J?-l17Cn9|{?`cJqb_b~ zrljhdti}zekH>YV>8{Jor=b%wxlaO&z7>7ESICH!YUbnRZ+#aCB!fWjh(TK zcQLSezVjK`T;;<(tmyZ^4XWxDUgQO-$~8|8$WUAF7N zk(Yubrk&sStT8qxL}ns`#z<+_kS+<9Bt@nQy}FX;s5xo0X5AKiUjn^Yt{^Q*c;F3| z_O&h&6@nTbbur(v{{Xs1!2mak8nsHbH>4sEy*$71t6Z-t6-&KEGc@+Hb3ve$in-~$ zDAm()lUlC})ziwp3gJkpC)gJ%YeVHAXxs@GR5qu1PcUrN<-Srf)Ru

TPh;mPU&r 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 JfX)u|{{UXDX|n(T literal 0 HcmV?d00001 diff --git a/plugins/MXSC-1.10.0.jar.back b/plugins/MXSC-1.10.0.jar.back new file mode 100644 index 0000000000000000000000000000000000000000..3f40c4579894b7453611415fe4f76a1d38fca26f GIT binary patch literal 206172 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�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%0D#35#b#>oHb)ee%OJB}%|EcjysK*Z3|m@5ry?Cw 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

8mir;TeKaFeAbxMl;395aP9 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 { + try { + while (true) { + try { + doUpdate(); + Thread.sleep(1); + } catch (IOException ex) { + getLogger().log(Level.FINE, null, ex); + } + } + } catch (InterruptedException ex) { + return; + } + }); + monitoredThread.setDaemon(true); + monitoredThread.start(); + } else if (!value && (monitoredThread != null)) { + monitoredThread.interrupt(); + monitoredThread = null; + } + } + + final byte[] START_OF_FRAME = {(byte) 0xFF, (byte) 0xD8}; + final byte[] END_OF_FRAME = {(byte) 0xFF, (byte) 0xD9}; + final int MAX_FRAME_SIZE = 512 * 1024; + + @Override + protected void doUpdate() throws IOException, InterruptedException { + byte[] data = null; + if (stream != null) { + if (flushOnUpdate) { + flush(); + } + try { + data = readData(); + } catch (EOFException ex) { + //Try to reopen stream + doInitialize(); + data = readData(); + } + } + if (data == null) { + pushImage(null); + } else { + BufferedImage img = Utils.newImage(data); + pushImage(img); + } + } + byte[] readData() throws IOException { + if (stream != null) { + stream.mark(MAX_FRAME_SIZE); + int startOfFrame = waitBytes(START_OF_FRAME) - START_OF_FRAME.length; + if (startOfFrame >= 0) { + int endOfFrame = waitBytes(END_OF_FRAME); + if (endOfFrame >= 0) { + stream.reset(); + stream.skip(startOfFrame); + int length = endOfFrame ;//- END_OF_FRAME.length ; + byte[] data = new byte[length]; + stream.read(data, 0, length); + return data; + } + } + } + return null; + } + + int waitBytes(byte[] data) throws IOException { + int index = 0; + int dataPos = 0; + while (true) { + int ret = stream.read(); + if (ret < 0) { + throw new EOFException(); + } + byte value = (byte) ret; + if (value == data[dataPos]) { + dataPos++; + if (dataPos == data.length) { + return (index + 1); + } + } else { + dataPos = 0; + } + index++; + if (index >= MAX_FRAME_SIZE) { + return -1; + } + } + } + + public void flush() throws IOException { + //stream.skip(stream.available()); + //TODO: Skipping won't make the current image to be displayed + stream.close(); + stream = new URL(url).openStream(); + if (!stream.markSupported()) { + stream = new BufferedInputStream(stream); + } + } + +} diff --git a/plugins/PuckDetectionPanel.form b/plugins/PuckDetectionPanel.form new file mode 100644 index 0000000..9d644a4 --- /dev/null +++ b/plugins/PuckDetectionPanel.form @@ -0,0 +1,184 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + </TableColumnModel> + </Property> + <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> + <TableHeader reorderingAllowed="true" resizingAllowed="true"/> + </Property> + </Properties> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="deviceStatePanel1"> + <Properties> + <Property name="deviceName" type="java.lang.String" value="puck_detection"/> + </Properties> + </Component> + </SubComponents> +</Form> diff --git a/plugins/PuckDetectionPanel.java b/plugins/PuckDetectionPanel.java new file mode 100644 index 0000000..e36c4db --- /dev/null +++ b/plugins/PuckDetectionPanel.java @@ -0,0 +1,251 @@ +import ch.psi.mxsc.Puck; +import ch.psi.mxsc.PuckDetection; +import ch.psi.mxsc.PuckState; +import ch.psi.mxsc.PuckState.SwitchState; +import ch.psi.pshell.core.Context; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; + +/** + * + */ +public class PuckDetectionPanel extends DevicePanel { + + public PuckDetectionPanel() { + initComponents(); + int row = 0; + for (String segment : new String[]{"A", "B", "C", "D", "E", "F"}){ + for (int puck=1; puck<=5; puck++){ + table.getModel().setValueAt(segment+puck, row++, 0); + } + } + } + + @Override + public PuckDetection getDevice(){ + return (PuckDetection) super.getDevice(); + } + + + @Override + protected void onDeviceCacheChanged(Object value, Object former, long timestamp, boolean arg3) { + for (int row=0; row< 30; row++){ + String name = table.getModel().getValueAt(row, 0).toString(); + //int id = row+1; + try { + Puck puck = getDevice().getPuck(name); + int id = puck.getIndex() + 1; + PuckState state = getDevice().getPuckState(id); + table.getModel().setValueAt(state.online, row, 1); + table.getModel().setValueAt((SwitchState.Off == state.mecSwitch) ? "" : String.valueOf(state.mecSwitch), row, 2); + table.getModel().setValueAt((SwitchState.Off == state.indSwitch) ? "" : String.valueOf(state.indSwitch), row, 3); + table.getModel().setValueAt(puck.getDetection() == null ? "" : puck.getDetection(), row, 4); + table.getModel().setValueAt(puck.getPuckType() == null ? "" : puck.getPuckType(), row, 5); + } catch (Exception ex) { + ex.printStackTrace(); + table.getModel().setValueAt(false, row, 1); + table.getModel().setValueAt(false, row, 2); + table.getModel().setValueAt(false, row, 3); + table.getModel().setValueAt("", row, 4); + table.getModel().setValueAt("", row, 5); + } + } + } + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + SwingUtils.showMessage(this, "Return", String.valueOf(ret)); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jPanel3 = new javax.swing.JPanel(); + buttonPuckDetCheck = new javax.swing.JButton(); + buttonPuckDetStop = new javax.swing.JButton(); + buttonPuckDetStart = new javax.swing.JButton(); + jPanel1 = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + table = new javax.swing.JTable(); + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Raspberry Pi ")); + + buttonPuckDetCheck.setText("Ckeck"); + buttonPuckDetCheck.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetCheckActionPerformed(evt); + } + }); + + buttonPuckDetStop.setText("Stop"); + buttonPuckDetStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetStopActionPerformed(evt); + } + }); + + buttonPuckDetStart.setText("Start"); + buttonPuckDetStart.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetStartActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonPuckDetCheck) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 107, Short.MAX_VALUE) + .addComponent(buttonPuckDetStop) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 108, Short.MAX_VALUE) + .addComponent(buttonPuckDetStart) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonPuckDetCheck, buttonPuckDetStart, buttonPuckDetStop}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonPuckDetCheck) + .addComponent(buttonPuckDetStop) + .addComponent(buttonPuckDetStart)) + .addContainerGap()) + ); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Detection")); + + table.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null} + }, + new String [] { + "Puck", "Online", "Mechanical", "Inductive", "Detection", "Image" + } + ) { + Class[] types = new Class [] { + java.lang.String.class, java.lang.Boolean.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class + }; + boolean[] canEdit = new boolean [] { + false, false, false, false, false, false + }; + + public Class getColumnClass(int columnIndex) { + return types [columnIndex]; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return canEdit [columnIndex]; + } + }); + jScrollPane1.setViewportView(table); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE) + .addContainerGap()) + ); + + deviceStatePanel1.setDeviceName("puck_detection"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonPuckDetCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetCheckActionPerformed + execute("check_puck_detection()", true); + }//GEN-LAST:event_buttonPuckDetCheckActionPerformed + + private void buttonPuckDetStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetStopActionPerformed + execute("stop_puck_detection()", false); + }//GEN-LAST:event_buttonPuckDetStopActionPerformed + + private void buttonPuckDetStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetStartActionPerformed + execute("start_puck_detection()", false); + }//GEN-LAST:event_buttonPuckDetStartActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonPuckDetCheck; + private javax.swing.JButton buttonPuckDetStart; + private javax.swing.JButton buttonPuckDetStop; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel3; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JTable table; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/Recovery.form b/plugins/Recovery.form new file mode 100644 index 0000000..e892c04 --- /dev/null +++ b/plugins/Recovery.form @@ -0,0 +1,140 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="ledKnownPosition" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="jLabel6" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> + <Component id="textPosition" max="32767" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="ledValidSegment" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="jLabel7" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="16" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="0" pref="0" max="32767" attributes="0"/> + <Component id="jLabel8" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="textDistance" min="-2" pref="86" max="-2" attributes="0"/> + </Group> + <Component id="textSegment" max="32767" attributes="0"/> + </Group> + </Group> + </Group> + <EmptySpace min="-2" pref="8" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace pref="136" max="32767" attributes="0"/> + <Group type="103" groupAlignment="1" attributes="0"> + <Component id="buttonAbort" linkSize="1" min="-2" pref="73" max="-2" attributes="0"/> + <Component id="buttonRecover" linkSize="1" alignment="1" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace pref="144" max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="ledKnownPosition" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="textPosition" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="ledValidSegment" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="jLabel7" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="textSegment" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="jLabel8" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="textDistance" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace pref="81" max="32767" attributes="0"/> + <Component id="buttonRecover" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="buttonAbort" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledKnownPosition"> + </Component> + <Component class="javax.swing.JLabel" name="jLabel6"> + <Properties> + <Property name="text" type="java.lang.String" value="Known position"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledValidSegment"> + </Component> + <Component class="javax.swing.JLabel" name="jLabel7"> + <Properties> + <Property name="text" type="java.lang.String" value="Valid segment"/> + </Properties> + </Component> + <Component class="javax.swing.JButton" name="buttonRecover"> + <Properties> + <Property name="text" type="java.lang.String" value="Recover"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonRecoverActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonAbort"> + <Properties> + <Property name="text" type="java.lang.String" value="Abort"/> + <Property name="enabled" type="boolean" value="false"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonAbortActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JTextField" name="textPosition"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textSegment"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textDistance"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + <Property name="horizontalAlignment" type="int" value="11"/> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel8"> + <Properties> + <Property name="text" type="java.lang.String" value="Distance:"/> + </Properties> + </Component> + </SubComponents> +</Form> diff --git a/plugins/Recovery.java b/plugins/Recovery.java new file mode 100644 index 0000000..7b6381b --- /dev/null +++ b/plugins/Recovery.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2014-2017 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import java.awt.Color; +import java.util.List; +import javax.swing.SwingUtilities; + +/** + * + */ +public class Recovery extends Panel { + + public Recovery() { + initComponents(); + startTimer(5000, 200); + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + + } + + @Override + public void onStateChange(State state, State former) { + if (state==State.Ready){ + SwingUtilities.invokeLater(()->{onTimer();}); + } + textSegment.setEnabled(state == State.Ready); + textDistance.setEnabled(state == State.Ready); + textPosition.setEnabled(state == State.Ready); + updateButton(); + } + + void updateButton(){ + buttonRecover.setEnabled((getContext().getState() == State.Ready) && + (!textSegment.getText().trim().isEmpty()) && + (textPosition.getText().trim().isEmpty()) ); + + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + + + @Override + protected void onTimer() { + Device robot = getContext().getDevicePool().getByName("robot", Device.class); + if ((robot==null) || (!robot.getState().isNormal())){ + ledValidSegment.setColor(Color.BLACK); + textSegment.setText(""); + ledKnownPosition.setColor(Color.BLACK); + textPosition.setText(""); + } else { + if (getState()==State.Ready){ + String point = null; + try{ + point = (String) eval("robot.get_current_point()", true); + ledKnownPosition.setColor((point == null) ? Color.RED : Color.GREEN); + textPosition.setText((point == null) ? "": point); + } catch (Exception ex) { + System.out.println(ex); + ledKnownPosition.setColor(Color.BLACK); + textPosition.setText(""); + } + try{ + List segment = (List) eval("get_current_segment()", true); + ledValidSegment.setColor((segment == null) ? Color.RED : Color.GREEN); + textSegment.setText((segment == null) ? "": segment.get(0) + "->" + segment.get(1) + " [" + segment.get(2) + "mm]"); + if ((segment == null)||(point!=null)){ + textDistance.setText(""); + } else { + try{ + Object distance = eval("get_current_distance()", true); + textDistance.setText((distance == null) ? "" : String.format("%1.2f",((Number)distance).doubleValue())); + } catch (Exception ex) { + textDistance.setText(""); + } + } + } catch (Exception ex) { + System.out.println(ex); + ledValidSegment.setColor(Color.BLACK); + textSegment.setText(""); + textDistance.setText(""); + } + } + } + updateButton(); + } + + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + ledKnownPosition = new ch.psi.pshell.swing.Led(); + jLabel6 = new javax.swing.JLabel(); + ledValidSegment = new ch.psi.pshell.swing.Led(); + jLabel7 = new javax.swing.JLabel(); + buttonRecover = new javax.swing.JButton(); + buttonAbort = new javax.swing.JButton(); + textPosition = new javax.swing.JTextField(); + textSegment = new javax.swing.JTextField(); + textDistance = new javax.swing.JTextField(); + jLabel8 = new javax.swing.JLabel(); + + jLabel6.setText("Known position"); + + jLabel7.setText("Valid segment"); + + buttonRecover.setText("Recover"); + buttonRecover.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonRecoverActionPerformed(evt); + } + }); + + buttonAbort.setText("Abort"); + buttonAbort.setEnabled(false); + buttonAbort.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonAbortActionPerformed(evt); + } + }); + + textPosition.setEditable(false); + + textSegment.setEditable(false); + + textDistance.setEditable(false); + textDistance.setHorizontalAlignment(javax.swing.JTextField.TRAILING); + + jLabel8.setText("Distance:"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(ledKnownPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel6) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(textPosition)) + .addGroup(layout.createSequentialGroup() + .addComponent(ledValidSegment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel7) + .addGap(16, 16, 16) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(jLabel8) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(textDistance, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(textSegment)))) + .addGap(8, 8, 8)) + .addGroup(layout.createSequentialGroup() + .addContainerGap(136, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(buttonAbort, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonRecover)) + .addContainerGap(144, Short.MAX_VALUE)) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonAbort, buttonRecover}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(ledKnownPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6) + .addComponent(textPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(ledValidSegment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel7) + .addComponent(textSegment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel8) + .addComponent(textDistance, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 81, Short.MAX_VALUE) + .addComponent(buttonRecover) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonAbort) + .addContainerGap()) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonRecoverActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRecoverActionPerformed + try{ + buttonAbort.setEnabled(true); + evalAsync("recover()", false).handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } else { + SwingUtils.showMessage(getTopLevel(), "Return", String.valueOf(ret)); + } + buttonAbort.setEnabled(false); + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + }//GEN-LAST:event_buttonRecoverActionPerformed + + private void buttonAbortActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonAbortActionPerformed + try { + abort(); + try{ + eval("robot.disable()", true); + } catch (Exception ex){ + this.showException(ex); + } + try{ + eval("stop_task()", true); + } catch (Exception ex){ + this.showException(ex); + } + try{ + eval("robot.reset_motion()", true); + } catch (Exception ex){ + this.showException(ex); + } + } catch (InterruptedException ex) { + showException(ex); + } + }//GEN-LAST:event_buttonAbortActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonAbort; + private javax.swing.JButton buttonRecover; + private javax.swing.JLabel jLabel6; + private javax.swing.JLabel jLabel7; + private javax.swing.JLabel jLabel8; + private ch.psi.pshell.swing.Led ledKnownPosition; + private ch.psi.pshell.swing.Led ledValidSegment; + private javax.swing.JTextField textDistance; + private javax.swing.JTextField textPosition; + private javax.swing.JTextField textSegment; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/RobotModbus.java b/plugins/RobotModbus.java new file mode 100644 index 0000000..ca2e149 --- /dev/null +++ b/plugins/RobotModbus.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.*; +import ch.psi.pshell.modbus.*; + +/** + */ +public class RobotModbus extends ModbusTCP { + + public RobotModbus(String name, String server) { + super(name, server); + } + + public Object run() throws Exception{ + Thread.sleep(1000); + return ("Done run"); + } + +} diff --git a/plugins/RobotPanel.form b/plugins/RobotPanel.form new file mode 100644 index 0000000..bf9c0d6 --- /dev/null +++ b/plugins/RobotPanel.form @@ -0,0 +1,587 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jPanel1" max="32767" attributes="0"/> + <Component id="jPanel2" alignment="0" max="32767" attributes="0"/> + <Component id="jPanel3" alignment="0" max="32767" attributes="0"/> + <Component id="panelState" alignment="0" max="32767" attributes="0"/> + <Component id="jPanel4" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jPanel1" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel4" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel2" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel3" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelState" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Container class="javax.swing.JPanel" name="jPanel1"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Power"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jLabel1" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledPowered" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelPowerCtr" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel1" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledPowered" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelPowerCtr" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledPowered"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel1"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Powered:"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelPowerCtr"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="buttonEnable" min="-2" max="-2" attributes="0"/> + <EmptySpace pref="18" max="32767" attributes="0"/> + <Component id="buttonDisable" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Group type="103" alignment="2" groupAlignment="1" max="-2" attributes="0"> + <Component id="buttonDisable" alignment="1" max="32767" attributes="0"/> + <Component id="buttonEnable" alignment="1" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonDisable"> + <Properties> + <Property name="text" type="java.lang.String" value="Disable"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonDisableActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonEnable"> + <Properties> + <Property name="text" type="java.lang.String" value="Enable"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonEnableActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="jPanel2"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Motion"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <Component id="jLabel7" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledMoving" min="-2" max="-2" attributes="0"/> + </Group> + <Component id="jLabel2" alignment="0" min="-2" pref="52" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="14" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" max="-2" attributes="0"> + <Component id="panelMotionCtr" max="32767" attributes="0"/> + <Component id="spinnerSpeed" max="32767" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel7" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledMoving" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelMotionCtr" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="spinnerSpeed" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JLabel" name="jLabel2"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Speed:"/> + </Properties> + </Component> + <Component class="javax.swing.JSpinner" name="spinnerSpeed"> + <Properties> + <Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor"> + <SpinnerModel initial="10" maximum="100" numberType="java.lang.Integer" stepSize="1" type="number"/> + </Property> + </Properties> + <Events> + <EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spinnerSpeedStateChanged"/> + </Events> + <AuxValues> + <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new ch.psi.utils.swing.HorizontalSpinner()"/> + </AuxValues> + </Component> + <Component class="javax.swing.JLabel" name="jLabel7"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Moving:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledMoving"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelMotionCtr"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="0" max="-2" attributes="0"/> + <Component id="butonStop" pref="45" max="32767" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="buttonPause" pref="46" max="32767" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="buttonResume" pref="47" max="32767" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="0" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="butonStop" alignment="2" max="32767" attributes="0"/> + <Component id="buttonPause" alignment="2" max="32767" attributes="0"/> + <Component id="buttonResume" alignment="2" max="32767" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="butonStop"> + <Properties> + <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> + <Connection code="new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Stop.png"))" type="code"/> + </Property> + <Property name="text" type="java.lang.String" value=" "/> + <Property name="horizontalTextPosition" type="int" value="0"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="butonStopActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonResume"> + <Properties> + <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> + <Connection code="new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Play.png"))" type="code"/> + </Property> + <Property name="text" type="java.lang.String" value=" "/> + <Property name="horizontalTextPosition" type="int" value="0"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonResumeActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonPause"> + <Properties> + <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> + <Connection code="new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Pause.png"))" type="code"/> + </Property> + <Property name="text" type="java.lang.String" value=" "/> + <Property name="horizontalTextPosition" type="int" value="0"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonPauseActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="jPanel3"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Status"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel8" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledTask" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="103" alignment="0" groupAlignment="1" attributes="0"> + <Group type="102" attributes="0"> + <Component id="jLabel4" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledEmpty" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="1" attributes="0"> + <Component id="jLabel3" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledSettled" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + <Group type="102" attributes="0"> + <Component id="jLabel9" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledPosition" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="textTask" max="32767" attributes="0"/> + <Component id="textPosition" max="32767" attributes="0"/> + </Group> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel6" linkSize="2" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledMode" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="textMode" max="32767" attributes="0"/> + </Group> + </Group> + <EmptySpace min="-2" max="-2" attributes="0"/> + <Component id="buttonAbort" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="1" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel3" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledSettled" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel4" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledEmpty" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="textMode" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledMode" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="jLabel6" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="buttonAbort" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="jLabel8" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledTask" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="textTask" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel9" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledPosition" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="textPosition" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JLabel" name="jLabel3"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Settled:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledSettled"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel4"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Empty:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledEmpty"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textTask"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + <Property name="horizontalAlignment" type="int" value="0"/> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel6"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Mode:"/> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textMode"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + <Property name="horizontalAlignment" type="int" value="0"/> + </Properties> + </Component> + <Component class="javax.swing.JButton" name="buttonAbort"> + <Properties> + <Property name="text" type="java.lang.String" value="Abort"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonAbortActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JLabel" name="jLabel8"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Task:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledTask"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledMode"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="textPosition"> + <Properties> + <Property name="editable" type="boolean" value="false"/> + <Property name="horizontalAlignment" type="int" value="0"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledPosition"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel9"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Position:"/> + </Properties> + </Component> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="panelState"> + </Component> + <Container class="javax.swing.JPanel" name="jPanel4"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Tool"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jLabel5" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledOpen" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelPowerCtr1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel5" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledOpen" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelPowerCtr1" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledOpen"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel5"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Open:"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelPowerCtr1"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="buttonOpen" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace pref="18" max="32767" attributes="0"/> + <Component id="buttonClose" linkSize="3" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Group type="103" alignment="2" groupAlignment="1" max="-2" attributes="0"> + <Component id="buttonClose" alignment="1" max="32767" attributes="0"/> + <Component id="buttonOpen" alignment="1" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonClose"> + <Properties> + <Property name="text" type="java.lang.String" value=" Close "/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonCloseActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonOpen"> + <Properties> + <Property name="text" type="java.lang.String" value=" Open "/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonOpenActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + </SubComponents> +</Form> diff --git a/plugins/RobotPanel.java b/plugins/RobotPanel.java new file mode 100644 index 0000000..e841f57 --- /dev/null +++ b/plugins/RobotPanel.java @@ -0,0 +1,685 @@ + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.ui.App; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.pshell.core.Context; +import ch.psi.utils.State; +import java.awt.Color; +import java.util.Map; +import javax.swing.JSpinner; +import javax.swing.JTextField; + +/** + * + */ +public class RobotPanel extends DevicePanel { + + /** + * Creates new form RobotPanel + */ + public RobotPanel() { + initComponents(); + ((JSpinner.DefaultEditor)spinnerSpeed.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); + } + + @Override + public void setDevice(Device device) { + super.setDevice(device); + if (device == null) { + + } + panelState.setDevice(device); + } + + @Override + protected void onDeviceStateChanged(State state, State former) { + boolean enabled = state.isNormal(); + spinnerSpeed.setEnabled(enabled); + buttonAbort.setEnabled(enabled); + if (!enabled){ + buttonEnable.setEnabled(enabled); + buttonDisable.setEnabled(enabled); + butonStop.setEnabled(enabled); + buttonPause.setEnabled(enabled); + buttonResume.setEnabled(enabled); + } + } + + boolean updating; + @Override + protected void onDeviceCacheChanged(Object value, Object former, long timestamp, boolean valueChange) { + updating = true; + try{ + Boolean powered = null; + Boolean empty = null; + Boolean settled = null; + Boolean moving = null; + Boolean open = null; + Integer speed = null; + String task = null; + String mode = null; + String position = null; + + if ((value != null) && (value instanceof Map)) { + Map status = (Map) value; + try { + powered = (Boolean) status.get("powered"); + } catch (Exception ex) { + } + try { + empty = (Boolean) status.get("empty"); + } catch (Exception ex) { + } + try { + settled = (Boolean) status.get("settled"); + } catch (Exception ex) { + } + try { + open = (Boolean) status.get("open"); + } catch (Exception ex) { + } + try { + speed = (Integer) status.get("speed"); + } catch (Exception ex) { + } + try { + position = (String) status.get("pos"); + if (position==null){ + position = ""; + } + } catch (Exception ex) { + } + try { + task = ((status.containsKey("task")) && (status.get("task") == null)) ? "" : ((String) status.get("task")).trim(); + } catch (Exception ex) { + System.out.println(ex); + ex.printStackTrace(); + } + try { + mode = ((String) status.get("mode")).trim(); + //mode = (String) Context.getInstance().evalLineBackground(getDevice().getName() + ".working_mode"); + } catch (Exception ex) { + } + try { + //if (status.get("status").equals("hold")){ + // moving = false; + //} else if (status.get("status").equals("move")){ + // moving = true; + //} + moving = Boolean.FALSE.equals(settled) || Boolean.FALSE.equals(empty); + } catch (Exception ex) { + } + } + + boolean remote = mode.equals("remote"); + boolean enabled = Boolean.TRUE.equals(powered); + buttonEnable.setEnabled((powered != null) && (powered == false)); + buttonDisable.setEnabled(enabled); + + butonStop.setEnabled(remote && Boolean.TRUE.equals(moving)); + buttonPause.setEnabled(remote && enabled && Boolean.TRUE.equals(moving) && Boolean.FALSE.equals(settled)); + buttonResume.setEnabled(remote && enabled && Boolean.TRUE.equals(moving) && Boolean.TRUE.equals(settled)); + + + ledPowered.setColor((powered == null) ? Color.GRAY : (powered ? Color.YELLOW : Color.DARK_GRAY)); + ledEmpty.setColor((empty == null) ? Color.GRAY : (empty ? Color.GREEN : Color.YELLOW)); + ledSettled.setColor((settled == null) ? Color.GRAY : (settled ? Color.GREEN : Color.YELLOW)); + ledOpen.setColor((open == null) ? Color.GRAY : (open ? Color.GREEN : Color.DARK_GRAY)); + ledMoving.setColor((moving == null) ? Color.GRAY : (moving ? Color.YELLOW : Color.DARK_GRAY)); + textTask.setText((task == null) ? "" : task); + ledTask.setColor((task == null) ? Color.GRAY : (task.isEmpty() ? Color.DARK_GRAY : Color.YELLOW)); + textPosition.setText((position == null) ? "" : position); + ledPosition.setColor((position == null) ? Color.GRAY : (position.isEmpty() ? Color.DARK_GRAY : Color.GREEN)); + //buttonAbort.setEnabled(!textTask.getText().isEmpty()); + spinnerSpeed.setEnabled(speed != null); + if (speed == null) { + spinnerSpeed.setValue(0); + } else { + spinnerSpeed.setValue(speed); + } + ledMode.setColor((mode == null) ? Color.BLACK : (remote ? Color.GREEN : Color.YELLOW)); + textMode.setText((mode == null) ? "" : mode); + + } finally{ + updating = false; + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + ledPowered = new ch.psi.pshell.swing.Led(); + jLabel1 = new javax.swing.JLabel(); + panelPowerCtr = new javax.swing.JPanel(); + buttonDisable = new javax.swing.JButton(); + buttonEnable = new javax.swing.JButton(); + jPanel2 = new javax.swing.JPanel(); + jLabel2 = new javax.swing.JLabel(); + spinnerSpeed = new ch.psi.utils.swing.HorizontalSpinner(); + jLabel7 = new javax.swing.JLabel(); + ledMoving = new ch.psi.pshell.swing.Led(); + panelMotionCtr = new javax.swing.JPanel(); + butonStop = new javax.swing.JButton(); + buttonResume = new javax.swing.JButton(); + buttonPause = new javax.swing.JButton(); + jPanel3 = new javax.swing.JPanel(); + jLabel3 = new javax.swing.JLabel(); + ledSettled = new ch.psi.pshell.swing.Led(); + jLabel4 = new javax.swing.JLabel(); + ledEmpty = new ch.psi.pshell.swing.Led(); + textTask = new javax.swing.JTextField(); + jLabel6 = new javax.swing.JLabel(); + textMode = new javax.swing.JTextField(); + buttonAbort = new javax.swing.JButton(); + jLabel8 = new javax.swing.JLabel(); + ledTask = new ch.psi.pshell.swing.Led(); + ledMode = new ch.psi.pshell.swing.Led(); + textPosition = new javax.swing.JTextField(); + ledPosition = new ch.psi.pshell.swing.Led(); + jLabel9 = new javax.swing.JLabel(); + panelState = new ch.psi.pshell.swing.DeviceStatePanel(); + jPanel4 = new javax.swing.JPanel(); + ledOpen = new ch.psi.pshell.swing.Led(); + jLabel5 = new javax.swing.JLabel(); + panelPowerCtr1 = new javax.swing.JPanel(); + buttonClose = new javax.swing.JButton(); + buttonOpen = new javax.swing.JButton(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Power")); + + ledPowered.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel1.setText("Powered:"); + + buttonDisable.setText("Disable"); + buttonDisable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonDisableActionPerformed(evt); + } + }); + + buttonEnable.setText("Enable"); + buttonEnable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonEnableActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelPowerCtrLayout = new javax.swing.GroupLayout(panelPowerCtr); + panelPowerCtr.setLayout(panelPowerCtrLayout); + panelPowerCtrLayout.setHorizontalGroup( + panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtrLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(buttonEnable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 18, Short.MAX_VALUE) + .addComponent(buttonDisable)) + ); + panelPowerCtrLayout.setVerticalGroup( + panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtrLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(buttonDisable, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonEnable)) + .addGap(0, 0, 0)) + ); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledPowered, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelPowerCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel1) + .addComponent(ledPowered, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelPowerCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + + jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Motion")); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel2.setText("Speed:"); + + spinnerSpeed.setModel(new javax.swing.SpinnerNumberModel(10, null, 100, 1)); + spinnerSpeed.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerSpeedStateChanged(evt); + } + }); + + jLabel7.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel7.setText("Moving:"); + + ledMoving.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + butonStop.setIcon(new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Stop.png"))); + butonStop.setText(" "); + butonStop.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + butonStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + butonStopActionPerformed(evt); + } + }); + + buttonResume.setIcon(new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Play.png"))); + buttonResume.setText(" "); + buttonResume.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + buttonResume.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonResumeActionPerformed(evt); + } + }); + + buttonPause.setIcon(new javax.swing.ImageIcon(App.class.getResource("/ch/psi/pshell/ui/Pause.png"))); + buttonPause.setText(" "); + buttonPause.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + buttonPause.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPauseActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelMotionCtrLayout = new javax.swing.GroupLayout(panelMotionCtr); + panelMotionCtr.setLayout(panelMotionCtrLayout); + panelMotionCtrLayout.setHorizontalGroup( + panelMotionCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelMotionCtrLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(butonStop, javax.swing.GroupLayout.DEFAULT_SIZE, 45, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonPause, javax.swing.GroupLayout.DEFAULT_SIZE, 46, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonResume, javax.swing.GroupLayout.DEFAULT_SIZE, 47, Short.MAX_VALUE) + .addGap(0, 0, 0)) + ); + panelMotionCtrLayout.setVerticalGroup( + panelMotionCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelMotionCtrLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelMotionCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(butonStop, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonPause, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonResume, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, 0)) + ); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel7, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledMoving, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(14, 14, 14) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(panelMotionCtr, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spinnerSpeed)) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel7) + .addComponent(ledMoving, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelMotionCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel2) + .addComponent(spinnerSpeed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Status")); + + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel3.setText("Settled:"); + + ledSettled.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel4.setText("Empty:"); + + ledEmpty.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + textTask.setEditable(false); + textTask.setHorizontalAlignment(javax.swing.JTextField.CENTER); + + jLabel6.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel6.setText("Mode:"); + + textMode.setEditable(false); + textMode.setHorizontalAlignment(javax.swing.JTextField.CENTER); + + buttonAbort.setText("Abort"); + buttonAbort.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonAbortActionPerformed(evt); + } + }); + + jLabel8.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel8.setText("Task:"); + + ledTask.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + ledMode.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + textPosition.setEditable(false); + textPosition.setHorizontalAlignment(javax.swing.JTextField.CENTER); + + ledPosition.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel9.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel9.setText("Position:"); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel8, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledTask, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledEmpty, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledSettled, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel9, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(textTask) + .addComponent(textPosition))) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(textMode))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonAbort) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jLabel3, jLabel4, jLabel6, jLabel8, jLabel9}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel3) + .addComponent(ledSettled, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel4) + .addComponent(ledEmpty, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(textMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ledMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6)) + .addGap(2, 2, 2) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(buttonAbort) + .addComponent(jLabel8) + .addComponent(ledTask, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(textTask, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel9) + .addComponent(ledPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(textPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + + jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder("Tool")); + + ledOpen.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel5.setText("Open:"); + + buttonClose.setText(" Close "); + buttonClose.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCloseActionPerformed(evt); + } + }); + + buttonOpen.setText(" Open "); + buttonOpen.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonOpenActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelPowerCtr1Layout = new javax.swing.GroupLayout(panelPowerCtr1); + panelPowerCtr1.setLayout(panelPowerCtr1Layout); + panelPowerCtr1Layout.setHorizontalGroup( + panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtr1Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(buttonOpen) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 18, Short.MAX_VALUE) + .addComponent(buttonClose)) + ); + + panelPowerCtr1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonClose, buttonOpen}); + + panelPowerCtr1Layout.setVerticalGroup( + panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtr1Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(buttonClose, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonOpen)) + .addGap(0, 0, 0)) + ); + + javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledOpen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelPowerCtr1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel5) + .addComponent(ledOpen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelPowerCtr1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelState, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonEnableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEnableActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".enable()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonEnableActionPerformed + + private void buttonDisableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDisableActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".disable()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonDisableActionPerformed + + private void spinnerSpeedStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerSpeedStateChanged + try{ + if (!updating){ + Context.getInstance().evalLineBackground(getDevice().getName() + ".set_monitor_speed(" + spinnerSpeed.getValue() + ")"); + } + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_spinnerSpeedStateChanged + + private void butonStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_butonStopActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".reset_motion()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_butonStopActionPerformed + + private void buttonPauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPauseActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".stop()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonPauseActionPerformed + + private void buttonResumeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonResumeActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".resume()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonResumeActionPerformed + + private void buttonAbortActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonAbortActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".stop_task()"); + //Context.getInstance().evalLineBackground(getDevice().getName() + ".task_kill('" + textTask.getText() + "')"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonAbortActionPerformed + + private void buttonCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCloseActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".close_tool()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonCloseActionPerformed + + private void buttonOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonOpenActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".open_tool()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonOpenActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton butonStop; + private javax.swing.JButton buttonAbort; + private javax.swing.JButton buttonClose; + private javax.swing.JButton buttonDisable; + private javax.swing.JButton buttonEnable; + private javax.swing.JButton buttonOpen; + private javax.swing.JButton buttonPause; + private javax.swing.JButton buttonResume; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JLabel jLabel7; + private javax.swing.JLabel jLabel8; + private javax.swing.JLabel jLabel9; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private ch.psi.pshell.swing.Led ledEmpty; + private ch.psi.pshell.swing.Led ledMode; + private ch.psi.pshell.swing.Led ledMoving; + private ch.psi.pshell.swing.Led ledOpen; + private ch.psi.pshell.swing.Led ledPosition; + private ch.psi.pshell.swing.Led ledPowered; + private ch.psi.pshell.swing.Led ledSettled; + private ch.psi.pshell.swing.Led ledTask; + private javax.swing.JPanel panelMotionCtr; + private javax.swing.JPanel panelPowerCtr; + private javax.swing.JPanel panelPowerCtr1; + private ch.psi.pshell.swing.DeviceStatePanel panelState; + private javax.swing.JSpinner spinnerSpeed; + private javax.swing.JTextField textMode; + private javax.swing.JTextField textPosition; + private javax.swing.JTextField textTask; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/RobotTcp.java b/plugins/RobotTcp.java new file mode 100644 index 0000000..d3f4c33 --- /dev/null +++ b/plugins/RobotTcp.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.device.*; +import ch.psi.pshell.serial.*; + +/** + */ +public class RobotTcp extends TcpDevice { + + public RobotTcp(String name, String server) { + super(name, server); + } + + public Object run() throws Exception{ + Thread.sleep(1000); + return ("Done"); + } + +} diff --git a/plugins/SmartMagnetConfig.java b/plugins/SmartMagnetConfig.java new file mode 100644 index 0000000..2c6213c --- /dev/null +++ b/plugins/SmartMagnetConfig.java @@ -0,0 +1,14 @@ + +import ch.psi.pshell.device.DeviceConfig; + +/** + * + */ +public class SmartMagnetConfig extends DeviceConfig{ + public double holdingCurrent; + public double restingCurrent; + public double mountCurrent; + public double unmountCurrent; + public double remanenceCurrent; + +} diff --git a/plugins/SmartMagnetPanel.form b/plugins/SmartMagnetPanel.form new file mode 100644 index 0000000..f9de056 --- /dev/null +++ b/plugins/SmartMagnetPanel.form @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jPanel1" max="32767" attributes="0"/> + <Component id="panelState" alignment="0" max="32767" attributes="0"/> + <Group type="103" groupAlignment="0" max="-2" attributes="0"> + <Component id="panelCurrent" max="32767" attributes="0"/> + <Component id="jPanel2" max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jPanel1" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelCurrent" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel2" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelState" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Container class="javax.swing.JPanel" name="jPanel1"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Status"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel1" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledStatus" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelPowerCtr" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel5" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledMounted" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel10" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelCurrentRb" min="-2" pref="173" max="-2" attributes="0"/> + </Group> + </Group> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel1" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledStatus" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelPowerCtr" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel5" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledMounted" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jLabel10" min="-2" max="-2" attributes="0"/> + <Component id="panelCurrentRb" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledStatus"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel1"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Status:"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelPowerCtr"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <EmptySpace min="0" pref="150" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <EmptySpace min="0" pref="23" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + </Layout> + </Container> + <Component class="javax.swing.JLabel" name="jLabel5"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Mounted:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledMounted"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel10"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Current:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.DeviceValuePanel" name="panelCurrentRb"> + <Properties> + <Property name="deviceName" type="java.lang.String" value="smc_current_rb"/> + </Properties> + </Component> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="panelState"> + </Component> + <Component class="ch.psi.pshell.swing.ProcessVariablePanel" name="panelCurrent"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Current"/> + </Border> + </Property> + <Property name="deviceName" type="java.lang.String" value="smc_current"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="jPanel2"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Gonio"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jLabel2" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledMountPosition" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="1" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel2" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledMountPosition" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JLabel" name="jLabel2"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Mount Position:"/> + </Properties> + </Component> + <Component class="ch.psi.pshell.swing.Led" name="ledMountPosition"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + </SubComponents> + </Container> + </SubComponents> +</Form> diff --git a/plugins/SmartMagnetPanel.java b/plugins/SmartMagnetPanel.java new file mode 100644 index 0000000..185028d --- /dev/null +++ b/plugins/SmartMagnetPanel.java @@ -0,0 +1,234 @@ + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.ui.App; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.pshell.core.Context; +import ch.psi.utils.State; +import java.awt.Color; +import java.lang.reflect.Method; +import java.util.Map; + +/** + * + */ +public class SmartMagnetPanel extends DevicePanel { + + /** + * Creates new form RobotPanel + */ + public SmartMagnetPanel() { + initComponents(); + } + + @Override + public void setDevice(Device device) { + super.setDevice(device); + if (device == null) { + + } + panelState.setDevice(device); + this.startTimer(1000, 100); + } + + @Override + protected void onTimer(){ + Color color = Color.RED; + try{ + if (Context.getInstance().evalLineBackground("in_mount_position").equals(Boolean.TRUE)){ + color = Color.GREEN; + } + } catch (Exception ex){ + } + ledMountPosition.setColor(color); + } + + @Override + protected void onDeviceStateChanged(State state, State former) { + switch(state){ + case Ready: + ledStatus.setColor(Color.GREEN); + ledMounted.setColor(Color.BLACK); + break; + case Busy: + ledStatus.setColor(Color.GREEN); + ledMounted.setColor(Color.GREEN); + break; + case Fault: + ledStatus.setColor(Color.RED); + ledMounted.setColor(Color.RED); + break; + default: + ledStatus.setColor(Color.BLACK); + ledMounted.setColor(Color.BLACK); + break; + } + } + + @Override + protected void onDeviceCacheChanged(Object value, Object former, long timestamp, boolean valueChange) { + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + ledStatus = new ch.psi.pshell.swing.Led(); + jLabel1 = new javax.swing.JLabel(); + panelPowerCtr = new javax.swing.JPanel(); + jLabel5 = new javax.swing.JLabel(); + ledMounted = new ch.psi.pshell.swing.Led(); + jLabel10 = new javax.swing.JLabel(); + panelCurrentRb = new ch.psi.pshell.swing.DeviceValuePanel(); + panelState = new ch.psi.pshell.swing.DeviceStatePanel(); + panelCurrent = new ch.psi.pshell.swing.ProcessVariablePanel(); + jPanel2 = new javax.swing.JPanel(); + jLabel2 = new javax.swing.JLabel(); + ledMountPosition = new ch.psi.pshell.swing.Led(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Status")); + + ledStatus.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel1.setText("Status:"); + + javax.swing.GroupLayout panelPowerCtrLayout = new javax.swing.GroupLayout(panelPowerCtr); + panelPowerCtr.setLayout(panelPowerCtrLayout); + panelPowerCtrLayout.setHorizontalGroup( + panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 150, Short.MAX_VALUE) + ); + panelPowerCtrLayout.setVerticalGroup( + panelPowerCtrLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 23, Short.MAX_VALUE) + ); + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel5.setText("Mounted:"); + + ledMounted.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel10.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel10.setText("Current:"); + + panelCurrentRb.setDeviceName("smc_current_rb"); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledStatus, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelPowerCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledMounted, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel10, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelCurrentRb, javax.swing.GroupLayout.PREFERRED_SIZE, 173, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel1) + .addComponent(ledStatus, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelPowerCtr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel5) + .addComponent(ledMounted, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel10) + .addComponent(panelCurrentRb, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + panelCurrent.setBorder(javax.swing.BorderFactory.createTitledBorder("Current")); + panelCurrent.setDeviceName("smc_current"); + + jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Gonio")); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel2.setText("Mount Position:"); + + ledMountPosition.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledMountPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel2) + .addComponent(ledMountPosition, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelState, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(panelCurrent, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelCurrent, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// </editor-fold>//GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel10; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel5; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private ch.psi.pshell.swing.Led ledMountPosition; + private ch.psi.pshell.swing.Led ledMounted; + private ch.psi.pshell.swing.Led ledStatus; + private ch.psi.pshell.swing.ProcessVariablePanel panelCurrent; + private ch.psi.pshell.swing.DeviceValuePanel panelCurrentRb; + private javax.swing.JPanel panelPowerCtr; + private ch.psi.pshell.swing.DeviceStatePanel panelState; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/TestZMQ.java b/plugins/TestZMQ.java new file mode 100644 index 0000000..cec2c40 --- /dev/null +++ b/plugins/TestZMQ.java @@ -0,0 +1,26 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/** + * + * @author gac-S_Changer + */ +public class TestZMQ { + public static void main(String[] args) { + String server = "raspberrypi:5556"; + org.zeromq.ZMQ.Context context = org.zeromq.ZMQ.context(1); + org.zeromq.ZMQ.Socket subscriber = context.socket(org.zeromq.ZMQ.SUB); + subscriber.connect("tcp://" + server); + subscriber.subscribe("Status".getBytes()); + while (!Thread.currentThread().isInterrupted()) { + String type = subscriber.recvStr(); + String contents = subscriber.recvStr(); + System.out.println(type + " : " + contents); + } + subscriber.close(); + context.term(); + } +} diff --git a/plugins/WagoPanel.form b/plugins/WagoPanel.form new file mode 100644 index 0000000..9864ffa --- /dev/null +++ b/plugins/WagoPanel.form @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="deviceStatePanel1" max="32767" attributes="0"/> + <Component id="panelSafety" max="32767" attributes="0"/> + <Component id="panelRobot1" max="32767" attributes="0"/> + <Component id="panelDewar" alignment="0" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="panelSafety" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelDewar" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelRobot1" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="deviceStatePanel1" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="deviceStatePanel1"> + <Properties> + <Property name="deviceName" type="java.lang.String" value="wago"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelSafety"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Safety"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="buttonReleasePsys" linkSize="2" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="buttonReleaseLocal" linkSize="2" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="buttonReleaseLocal" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="buttonReleasePsys" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonReleasePsys"> + <Properties> + <Property name="text" type="java.lang.String" value="Release PSYS"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonReleasePsysActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonReleaseLocal"> + <Properties> + <Property name="text" type="java.lang.String" value="Release Local"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonReleaseLocalActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="panelRobot1"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Dryer"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="buttonHeater" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="buttonStream" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="buttonHeater" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="buttonStream" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JToggleButton" name="buttonHeater"> + <Properties> + <Property name="text" type="java.lang.String" value="Heater"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonHeaterActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JToggleButton" name="buttonStream"> + <Properties> + <Property name="text" type="java.lang.String" value="Air Stream"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonStreamActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.ProcessVariablePanel" name="panelDewar"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder justification="1" title="Dewar Light"/> + </Border> + </Property> + <Property name="deviceName" type="java.lang.String" value="led_level"/> + <Property name="showAdvanced" type="boolean" value="false"/> + <Property name="showButtons" type="boolean" value="false"/> + <Property name="showLimitButtons" type="boolean" value="false"/> + <Property name="showSlider" type="boolean" value="true"/> + <Property name="showStop" type="boolean" value="false"/> + </Properties> + </Component> + </SubComponents> +</Form> diff --git a/plugins/WagoPanel.java b/plugins/WagoPanel.java new file mode 100644 index 0000000..cacadcd --- /dev/null +++ b/plugins/WagoPanel.java @@ -0,0 +1,207 @@ +import ch.psi.mxsc.Controller; +import ch.psi.pshell.core.Context; +import ch.psi.pshell.swing.DevicePanel; +import java.util.concurrent.CompletableFuture; +import javax.swing.border.TitledBorder; + +/** + * + */ +public class WagoPanel extends DevicePanel { + + public WagoPanel() { + initComponents(); + this.startTimer(10000); + } + + + CompletableFuture future; + + @Override + public void onTimer(){ + if ((getDevice()!=null)){ + updateTitle(); + } + } + + void updateTitle(){ + Boolean roomTemp = (Controller.getInstance().isLedRoomTemp()); + if (roomTemp==null){ + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light"); + } else if (roomTemp==true){ + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light (room temperature)"); + } else { + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light (LN2)"); + } + } + + + void execute(String statement){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (WagoPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + panelSafety = new javax.swing.JPanel(); + buttonReleasePsys = new javax.swing.JButton(); + buttonReleaseLocal = new javax.swing.JButton(); + panelRobot1 = new javax.swing.JPanel(); + buttonHeater = new javax.swing.JToggleButton(); + buttonStream = new javax.swing.JToggleButton(); + panelDewar = new ch.psi.pshell.swing.ProcessVariablePanel(); + + deviceStatePanel1.setDeviceName("wago"); + + panelSafety.setBorder(javax.swing.BorderFactory.createTitledBorder("Safety")); + + buttonReleasePsys.setText("Release PSYS"); + buttonReleasePsys.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReleasePsysActionPerformed(evt); + } + }); + + buttonReleaseLocal.setText("Release Local"); + buttonReleaseLocal.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReleaseLocalActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelSafetyLayout = new javax.swing.GroupLayout(panelSafety); + panelSafety.setLayout(panelSafetyLayout); + panelSafetyLayout.setHorizontalGroup( + panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSafetyLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonReleasePsys) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonReleaseLocal) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + panelSafetyLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonReleaseLocal, buttonReleasePsys}); + + panelSafetyLayout.setVerticalGroup( + panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSafetyLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonReleaseLocal) + .addComponent(buttonReleasePsys)) + .addContainerGap()) + ); + + panelRobot1.setBorder(javax.swing.BorderFactory.createTitledBorder("Dryer")); + + buttonHeater.setText("Heater"); + buttonHeater.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonHeaterActionPerformed(evt); + } + }); + + buttonStream.setText("Air Stream"); + buttonStream.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonStreamActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelRobot1Layout = new javax.swing.GroupLayout(panelRobot1); + panelRobot1.setLayout(panelRobot1Layout); + panelRobot1Layout.setHorizontalGroup( + panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelRobot1Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonHeater) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonStream) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + panelRobot1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonHeater, buttonStream}); + + panelRobot1Layout.setVerticalGroup( + panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelRobot1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonHeater) + .addComponent(buttonStream)) + .addContainerGap()) + ); + + panelDewar.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Dewar Light", javax.swing.border.TitledBorder.LEFT, javax.swing.border.TitledBorder.DEFAULT_POSITION)); + panelDewar.setDeviceName("led_level"); + panelDewar.setShowAdvanced(false); + panelDewar.setShowButtons(false); + panelDewar.setShowLimitButtons(false); + panelDewar.setShowSlider(true); + panelDewar.setShowStop(false); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelSafety, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelRobot1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelDewar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(panelSafety, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelDewar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelRobot1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonReleasePsysActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReleasePsysActionPerformed + execute("release_psys()"); + }//GEN-LAST:event_buttonReleasePsysActionPerformed + + private void buttonReleaseLocalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReleaseLocalActionPerformed + execute("release_local()"); + }//GEN-LAST:event_buttonReleaseLocalActionPerformed + + private void buttonHeaterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonHeaterActionPerformed + execute("set_heater(" + (buttonHeater.isSelected() ? "True": "False") + ")"); + }//GEN-LAST:event_buttonHeaterActionPerformed + + private void buttonStreamActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStreamActionPerformed + execute("set_air_stream(" + (buttonStream.isSelected()? "True": "False")+ ")"); + }//GEN-LAST:event_buttonStreamActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JToggleButton buttonHeater; + private javax.swing.JButton buttonReleaseLocal; + private javax.swing.JButton buttonReleasePsys; + private javax.swing.JToggleButton buttonStream; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private ch.psi.pshell.swing.ProcessVariablePanel panelDewar; + private javax.swing.JPanel panelRobot1; + private javax.swing.JPanel panelSafety; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/gui.form b/plugins/gui.form new file mode 100644 index 0000000..5775937 --- /dev/null +++ b/plugins/gui.form @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="renderer1" min="-2" pref="154" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="82" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="51" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jButton1" min="-2" max="-2" attributes="0"/> + <Component id="linePlotJFree1" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace pref="250" max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="24" max="-2" attributes="0"/> + <Component id="jButton1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="renderer1" min="-2" pref="102" max="-2" attributes="0"/> + <EmptySpace pref="20" max="32767" attributes="0"/> + <Component id="linePlotJFree1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="jButton1"> + <Properties> + <Property name="text" type="java.lang.String" value="Abort"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/> + </Events> + </Component> + <Component class="ch.psi.pshell.imaging.Renderer" name="renderer1"> + </Component> + <Component class="ch.psi.pshell.plot.LinePlotJFree" name="linePlotJFree1"> + </Component> + </SubComponents> +</Form> diff --git a/plugins/gui.java b/plugins/gui.java new file mode 100644 index 0000000..abeb59b --- /dev/null +++ b/plugins/gui.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ + +import ch.psi.pshell.ui.Panel; +import ch.psi.utils.State; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class gui extends Panel { + + public gui() { + initComponents(); + } + + //Overridable callbacks + @Override + public void onInitialize(int runCount) { + + } + + @Override + public void onStateChange(State state, State former) { + + } + + @Override + public void onExecutedFile(String fileName, Object result) { + } + + + //Callback to perform update - in event thread + @Override + protected void doUpdate() { + } + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jButton1 = new javax.swing.JButton(); + renderer1 = new ch.psi.pshell.imaging.Renderer(); + linePlotJFree1 = new ch.psi.pshell.plot.LinePlotJFree(); + + jButton1.setText("Abort"); + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(renderer1, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(82, 82, 82)) + .addGroup(layout.createSequentialGroup() + .addGap(51, 51, 51) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jButton1) + .addComponent(linePlotJFree1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(250, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(24, 24, 24) + .addComponent(jButton1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(renderer1, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 20, Short.MAX_VALUE) + .addComponent(linePlotJFree1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + }// </editor-fold>//GEN-END:initComponents + + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + try { + abort(); + } catch (InterruptedException ex) { + Logger.getLogger(gui.class.getName()).log(Level.SEVERE, null, ex); + } + }//GEN-LAST:event_jButton1ActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton jButton1; + private ch.psi.pshell.plot.LinePlotJFree linePlotJFree1; + private ch.psi.pshell.imaging.Renderer renderer1; + // End of variables declaration//GEN-END:variables +} diff --git a/script/LN2_Monitoring.scd b/script/LN2_Monitoring.scd new file mode 100644 index 0000000..d2ab014 --- /dev/null +++ b/script/LN2_Monitoring.scd @@ -0,0 +1,15 @@ +[ + [ [ true, "phase_separator_level", "Device", 1, 1, "102,204,255" ], + [ true, "filling_phase_separator", "Device", 1, 1, "51,255,255" ], + [ true, "filling_dewar", "Device", 1, 1, "0,0,102" ], + [ true, "dewar_level", "Device", 1, 1, "0,51,153" ], + [ true, "rim_heater_temp", "Device", 1, 1, "255,0,51" ] ], + [ [ "1", 0.0, 100.0, null, null, 1000000.0, false, null ], + [ "2", null, null, null, null, null, null, null ], + [ "3", null, null, null, null, null, null, null ], + [ "4", null, null, null, null, null, null, null ], + [ "5", null, null, null, null, null, null, null ] ], + [ [ ] ], + [ [ "", 20000, 100 ], + [ "", "" ] ] +] \ No newline at end of file diff --git a/script/LevelMonitoring.scd b/script/LevelMonitoring.scd new file mode 100644 index 0000000..ae328cc --- /dev/null +++ b/script/LevelMonitoring.scd @@ -0,0 +1,12 @@ +[ + [ [ true, "phase_separator_level", "Device", 1, 1, "255,0,0" ], + [ true, "dewar_level", "Device", 1, 1, "0,0,255" ] ], + [ [ "1", 0.0, 100.0, null, null, 100000.0, false, null ], + [ "2", null, null, null, null, null, null, null ], + [ "3", null, null, null, null, null, null, null ], + [ "4", null, null, null, null, null, null, null ], + [ "5", null, null, null, null, null, null, null ] ], + [ [ ] ], + [ [ "", 20000, 100 ], + [ "", "" ] ] +] \ No newline at end of file diff --git a/script/calibration/BinarySearchYZ.py b/script/calibration/BinarySearchYZ.py new file mode 100644 index 0000000..42db379 --- /dev/null +++ b/script/calibration/BinarySearchYZ.py @@ -0,0 +1,29 @@ +import plotutils +import math + + +#STRATEGY = "Normal" +#STRATEGY = "Boundary" +#STRATEGY = "FullNeighborhood" +RANGE = [-5.0, 5.0] +STEP_SIZE = 0.1 +LATENCY = 0.05 + + +robot.enable() +move_to_laser() + + +robot.set_motors_enabled(True) +current_y = robot_y.getPosition() +current_z = robot_z.getPosition() + + +r = bsearch([robot_y, robot_z], laser_distance,[RANGE[0], RANGE[0]], [RANGE[1], RANGE[1]], [STEP_SIZE,STEP_SIZE], relative = True, maximum=True, strategy = STRATEGY, latency = LATENCY, title = "Binary Search YZ") + + +print r.print() +opt_y, opt_z= r.getOptimalPosition() +offset_y, offset_z = opt_y - current_y, opt_z - current_z + +print "offset_y: ", offset_y, " offset_z: ", offset_z \ No newline at end of file diff --git a/script/calibration/HillClimbingXZ.py b/script/calibration/HillClimbingXZ.py new file mode 100644 index 0000000..2fcab26 --- /dev/null +++ b/script/calibration/HillClimbingXZ.py @@ -0,0 +1,45 @@ +import plotutils +import math + + +#STRATEGY = "Normal" +STRATEGY = "Boundary" +#STRATEGY = "FullNeighborhood" +RANGE = [-5.0, 5.0] +INITIAL_STEP = 1.0 +STEP_SIZE = 0.05 +LATENCY = 0.05 +NOISE_FILTER = 1 + + +robot.enable() +move_to_laser() + + +robot.set_motors_enabled(True) + +current_x = robot_x.getPosition() +current_z = robot_z.getPosition() + + + + +class Distance(Readable): + def read(self): + ret = ue.readable.read() + ret = 0.0 if math.isnan(ret) else ret + return ret + +laser_distance=Distance() +start = time.time() +r = hsearch([robot_x, robot_z],laser_distance, [RANGE[0], RANGE[0]], [RANGE[1], RANGE[1]], [INITIAL_STEP,INITIAL_STEP], [STEP_SIZE,STEP_SIZE], NOISE_FILTER, relative = True, maximum=True, latency = LATENCY, title = "Hill Climbing XZ") + + + +print r.print() +opt_x, opt_z= r.getOptimalPosition() +offset_x, offset_z = opt_x - current_x, opt_z - current_z + +print "offset_x: ", offset_x, " offset_z: ", offset_z + + diff --git a/script/calibration/ScanRZ.py b/script/calibration/ScanRZ.py new file mode 100644 index 0000000..55d3bba --- /dev/null +++ b/script/calibration/ScanRZ.py @@ -0,0 +1,31 @@ +#Imports +import plotutils +from mathutils import fit_gaussian, Gaussian + +#Parameters +RANGE = [-120.0,120.0] +STEP = 5.0 +LATENCY = 0.005 +RELATIVE = False + +#Enabling and checking +#enable_motion() +#system_check() +robot.enable() + + +#Body +robot.set_tool(TOOL_DEFAULT) +move_to_laser() +#robot.set_joint_motors_enabled(True) +robot.set_motors_enabled(True) +robot_rz.move(0.0) +robot.set_motors_enabled(True) +ret = lscan(robot_rz, ue.readable, RANGE[0], RANGE[1], STEP, latency = LATENCY, relative = RELATIVE, range = "auto", title = "Scan2") + + +#Cleanup + + + + diff --git a/script/calibration/ScanX.py b/script/calibration/ScanX.py new file mode 100644 index 0000000..e72350d --- /dev/null +++ b/script/calibration/ScanX.py @@ -0,0 +1,81 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + + +d = robot.get_distance_to_pnt("pLaser") +if d<0: + raise Exception ("Error calculating distance to laser: " + str(d)) + +if d>20: + raise Exception ("Should be near the laser position to perform the scan") + +RANGE = [-2.0, 2.0] #[-1.5, 1.5] +STEP = 0.02 +Z_OFFSET = 0 #-1.0 +LATENCY = 0.025 +BORDER_SIZE = 0.15 + +robot.enable() +robot.set_motors_enabled(True) +current_positon = robot_x.getPosition() +robot_z.moveRel(Z_OFFSET) + +robot.setPolling(25) +try: + ret = lscan(robot_x, ue.readable, RANGE[0], RANGE[1], STEP, latency = LATENCY, relative = True) +finally: + robot.setPolling(DEFAULT_ROBOT_POLLING) + +d = ret.getReadable(0) + +first_index = -1 +last_index = -1 +for i in range(len(d)): + if not math.isnan(d[i]): + if first_index<0: + first_index = i + last_index = i + +if first_index == -1 or last_index < first_index: + raise Exception("Invalid range") + + +remove = int(max(BORDER_SIZE, STEP) / STEP) + +_range = [first_index+remove, last_index-remove] +if _range[1] <= _range[0]: + raise Exception("Invalid range: " + str(_range)) + + +center_index = int((_range[0] + _range[1])/2) +center_positon = ret.getPositions(0)[center_index] + + + + +y = ret.getReadable(0)[_range[0] : _range[1]] +x = ret.getPositions(0)[_range[0]: _range[1]] +#x = enforce_monotonic(x) +#(normalization, mean_val, sigma) = fit_gaussian([-v for v in y], x) + + +closest_x = x[y.indexOf(min(y))] +closest_y = y[y.indexOf(min(y))] + + + +if closest_x is None or closest_x <= ret.getPositions(0)[first_index] or closest_x >= ret.getPositions(0)[last_index]: + raise Exception("Invalid Fit") + + + +center_offset = center_positon-closest_y +#center_offset = current_positon-closest_y + + + +p=get_plots()[0] +p.addMarker(closest_y, p.AxisId.X, str(closest_y), Color.GREEN) + +robot.set_motors_enabled(True) +robot_x.move(closest_x) diff --git a/script/calibration/ScanY.py b/script/calibration/ScanY.py new file mode 100644 index 0000000..17252f1 --- /dev/null +++ b/script/calibration/ScanY.py @@ -0,0 +1,81 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + + +d = robot.get_distance_to_pnt("pLaser") +if d<0: + raise Exception ("Error calculating distance to laser: " + str(d)) + +if d>20: + raise Exception ("Should be near the laser position to perform the scan") + +RANGE = [-2.0, 2.0] #[-1.5, 1.5] +STEP = 0.02 +Z_OFFSET = 0 #-1.0 +LATENCY = 0.025 +BORDER_SIZE = 0.15 + +robot.enable() +robot.set_motors_enabled(True) +current_positon = robot_y.getPosition() +robot_z.moveRel(Z_OFFSET) + +robot.setPolling(25) +try: + ret = lscan(robot_y, ue.readable, RANGE[0], RANGE[1], STEP, latency = LATENCY, relative = True) +finally: + robot.setPolling(DEFAULT_ROBOT_POLLING) + +d = ret.getReadable(0) + +first_index = -1 +last_index = -1 +for i in range(len(d)): + if not math.isnan(d[i]): + if first_index<0: + first_index = i + last_index = i + +if first_index == -1 or last_index < first_index: + raise Exception("Invalid range") + + +remove = int(max(BORDER_SIZE, STEP) / STEP) + +_range = [first_index+remove, last_index-remove] +if _range[1] <= _range[0]: + raise Exception("Invalid range: " + str(_range)) + + +center_index = int((_range[0] + _range[1])/2) +center_positon = ret.getPositions(0)[center_index] + + + + +y = ret.getReadable(0)[_range[0] : _range[1]] +x = ret.getPositions(0)[_range[0]: _range[1]] +#x = enforce_monotonic(x) +#(normalization, mean_val, sigma) = fit_gaussian([-v for v in y], x) + + +closest_y = x[y.indexOf(min(y))] +closest_x = y[y.indexOf(min(y))] + + + +if closest_y is None or closest_y <= ret.getPositions(0)[first_index] or closest_y >= ret.getPositions(0)[last_index]: + raise Exception("Invalid Fit") + + + +center_offset = center_positon-closest_y +#center_offset = current_positon-closest_y + + + +p=get_plots()[0] +p.addMarker(closest_y, p.AxisId.X, str(closest_y), Color.GREEN) + +robot.set_motors_enabled(True) +robot_y.move(closest_y) diff --git a/script/calibration/ScanYZ.py b/script/calibration/ScanYZ.py new file mode 100644 index 0000000..bee63e6 --- /dev/null +++ b/script/calibration/ScanYZ.py @@ -0,0 +1,93 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + +SINGLE_PASS = False +if SINGLE_PASS: + STEP_SIZE = 0.2 +else: + STEP_SIZE = 1.0 +STEP_Z_FINAL = 0.1 + +RANGE = [-5.0, 5.0] +LATENCY = 0.05 + +Z_FINAL_OFFSET = 0.0 + + +SINGLE_PASS = True +STEP_SIZE = 0.1 + + +robot.enable() +move_to_laser() + +step_y = STEP_SIZE +step_z = STEP_SIZE +range_y = [RANGE[0], RANGE[1]] +range_z = [RANGE[0], RANGE[1]] + +robot.set_motors_enabled(True) +current_y = robot_y.getPosition() +current_z = robot_z.getPosition() + +print "Current pos y,z" , current_y, ",", current_z +ret = ascan([robot_y, robot_z], ue.readable, [range_y[0], range_z[0]], [range_y[1], range_z[1]], [step_y,step_z], latency = LATENCY, relative = True , zigzag=False, title = "Scan XY") +data = ret.getData(0)[0] +#plot(Convert.transpose(data), title="Data") + +integ = [] +for x in data: integ.append(sum( [ (0.0 if (math.isnan(y)) else y) for y in x])) + +xdata= frange(range_y[0], range_y[1], step_y , False, True) +p = plot(integ, title = "Fit", xdata=xdata)[0] + + +max_x_index = integ.index(max(integ)) +max_x = xdata[max_x_index] +try: + (normalization, mean_val, sigma) = fit_gaussian(integ, xdata) +except: + raise Exception("Invalid Fit") +gaussian = Gaussian(normalization, mean_val, sigma) +xdata= frange(range_y[0], range_y[1], step_y/100.0 , False, True) +plot_function(p, gaussian, "Fit", xdata, show_points = False, show_lines = True, color = Color.BLUE) + +#So +if abs(mean_val - max_x) > 1.0: + raise Exception("Invalid Y detection") +y_offset = mean_val +center_y = current_y + y_offset + +print "Y offset = ", y_offset + +robot_y.move(center_y) +if SINGLE_PASS: + z_scan_data = data[max_x_index] +else: + step_z = STEP_Z_FINAL + ret2 = lscan(robot_z, ue.readable, range_z[0], range_z[1], step_z, latency = LATENCY, relative = True , zigzag=False) + z_scan_data = ret2.getData(0)[0] + +max_z_index= z_scan_data.index(max(z_scan_data)) +last_z_index = 0 +for i in range(len(z_scan_data)): + if not math.isnan(z_scan_data[i]): + last_z_index = i +#Shape is cone: z is inceraseing. For proper detection last Z must be furthest +if abs(max_z_index - last_z_index) * step_z > 1.0: + raise Exception("Invalid Z detection") + +if SINGLE_PASS: + max_z = ret.getPositions(1)[len(data[0]) * max_x_index + last_z_index] +else: + max_z = ret2.getPositions(0)[last_z_index] + +z_offset = max_z - current_z + Z_FINAL_OFFSET + +robot_z.move(max_z + Z_FINAL_OFFSET) + +print "Z offset = ", z_offset + + +#Updating tool: +#update_tool(None, x_offset=x_offset, z_offset=z_offset) diff --git a/script/calibration/ToolCalibration.py b/script/calibration/ToolCalibration.py new file mode 100644 index 0000000..602403b --- /dev/null +++ b/script/calibration/ToolCalibration.py @@ -0,0 +1,60 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + + +robot.assert_tool(TOOL_CALIBRATION) +robot.set_motors_enabled(True) +robot.set_joint_motors_enabled(True) + + +initial_pos = robot.get_cartesian_pos() + +robot.enable() +move_to_laser() + +robot.align() + + +run("calibration/ScanYZ") + +robot.set_motors_enabled(True) + + +first_y = robot_y.take() +first_z = robot_z.take() +first_y = ue.take() +first_j6 = robot_j6.take() +if first_y is None: + raise Exception("Invalid YZ scan values in first scan") + + +robot.set_joint_motors_enabled(True) +if first_j6>0: + robot_j6.moveRel(-180.0, -1) +else: + robot_j6.moveRel(180.0, -1) + + +robot.set_motors_enabled(True) +run("calibration/ScanYZ") + +robot.set_motors_enabled(True) + +second_y = robot_y.take() +second_z = robot_z.take() +second_y = ue.take() +second_j6 = robot_j6.take() +if second_y is None: + raise Exception("Invalid XZ scan values in first scan") + + +#Updates the tool +xoff = (first_x - second_x)/2 +yoff = (first_y - second_y)/2 +t=robot.get_tool_trsf(TOOL_DEFAULT) +t[0]=xoff +t[1]=-yoff +robot.set_tool_trsf(t, TOOL_DEFAULT) + + + diff --git a/script/calibration/ToolCalibration2.py b/script/calibration/ToolCalibration2.py new file mode 100644 index 0000000..e9b71ae --- /dev/null +++ b/script/calibration/ToolCalibration2.py @@ -0,0 +1,86 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + + +#robot.assert_tool(TOOL_CALIBRATION) +#cal_tool = TOOL_DEFAULT +cal_tool = TOOL_CALIBRATION + +robot.set_tool(cal_tool) +robot.enable() +move_to_laser() + + +robot.set_motors_enabled(True) +robot.set_joint_motors_enabled(True) +initial_pos = robot.get_cartesian_pos() + +robot.enable() +move_to_laser() + +#robot.align() + + +run("calibration/ScanY") + +pos1 = robot.get_cartesian_pos() +x1, y1 = closest_x, closest_y + +print "Closest 1: ", [x1, y1] +print "Position 1: ", pos1 + + +pj6 = robot_j6.position +if pj6>0: + robot_j6.move(pj6 - 180.0) +else: + robot_j6.move(pj6 + 180.0) + + +run("calibration/ScanY") + + +x2, y2 = closest_x, closest_y + +print "Closest 2: ", [x2, y2] + + + +off_x = x1 - x2 + +#robot.set_motors_enabled(True) +#robot_x.moveRel(off_x, -1) + +#For composing cannot use tcp_p, need another auxiliary point. tcp_t is also destroyed. +robot.set_pnt(robot.get_cartesian_pos(), "pTemp") +robot.set_trsf([off_x, 0,0,0,0,0]) +c=robot.compose("pTemp", FRAME_TABLE, "tcp_t" ) +robot.set_pnt(c, "pTemp") +robot.movel("pTemp", cal_tool, DESC_SCAN, sync=True) + + +pos2 = robot.get_cartesian_pos() +print pos2 + +print "Position 2: ", pos2 + + + +#Updates the tool +xoff = (pos2[0]-pos1[0])/2 +yoff = (pos2[1]-pos1[1])/2 + +#print "Offset: ", [xoff, yoff] + +t=robot.get_tool_trsf(TOOL_DEFAULT) +t[0]=xoff +t[1]=-yoff +print "Offset: ", [t[0], t[1]] +robot.set_tool_trsf(t, TOOL_DEFAULT) + +robot.set_tool(TOOL_DEFAULT) +d = robot.get_distance_to_pnt("pLaser") +if d<POSITION_TOLERANCE: + print "Moving calibrated tool to laser" +else: + print "Cannot move calibrated tool to laser: toog big offset" diff --git a/script/calibration/ToolCalibration3.py b/script/calibration/ToolCalibration3.py new file mode 100644 index 0000000..969707d --- /dev/null +++ b/script/calibration/ToolCalibration3.py @@ -0,0 +1,83 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + +cal_tool = TOOL_CALIBRATION + +robot.set_tool(cal_tool) + +robot.enable() +move_to_laser() + + +robot.set_motors_enabled(True) +robot.set_joint_motors_enabled(True) +initial_pos = robot.get_cartesian_pos() + +#robot.align() +try: + robot.set_frame(FRAME_TABLE) + run("calibration/ScanX") +finally: + robot.set_default_frame() + +pos1 = robot.get_cartesian_pos() +x1, l1 = closest_x, closest_y + +print "Scan 1 result: ", [x1, l1] +print "Position 1: ", pos1 + + +pj6 = robot_j6.position +if pj6>0: + robot_j6.move(pj6 - 180.0) +else: + robot_j6.move(pj6 + 180.0) + + +try: + robot.set_frame(FRAME_TABLE) + run("calibration/ScanX") +finally: + robot.set_default_frame() + +pos2 =robot.get_cartesian_pos() +x2, l2 = closest_x, closest_y + +print "Scan 2 result: ", [x2, l2] +print "Position 2: ", pos1 + +off_l = l2 - l1 +print "Offset l: ", off_l + +#For composing cannot use tcp_p, need another auxiliary point. tcp_t is also destroyed. +robot.set_pnt(robot.get_cartesian_pos(), "pTemp") +robot.set_trsf([0, -off_l, 0, 0, 0, 0]) +c=robot.compose("pTemp", FRAME_TABLE, "tcp_t" ) +robot.set_pnt(c, "pTemp") +robot.movel("pTemp", cal_tool, DESC_SCAN, sync=True) + + +pos3 = robot.get_cartesian_pos() +print "Position 3: ", pos3 + + +#Updates the tool +t=robot.get_tool_trsf(TOOL_DEFAULT) +print "Former tool: " + str(t) + +xoff = (pos3[0]-pos1[0])/2 +yoff = (pos3[1]-pos1[1])/2 +xrot = math.degrees(math.atan(yoff/t[2])) +yrot = math.degrees(math.atan(xoff/t[2])) +t[0]=xoff +t[1]=-yoff +print "Calibrated tool: " + str(t) +robot.set_tool_trsf(t, TOOL_DEFAULT) + +robot.set_tool(TOOL_DEFAULT) +d = robot.get_distance_to_pnt("pLaser") +if d<POSITION_TOLERANCE: + print "Moving calibrated tool to laser" + #move_to_laser() +else: + print "Cannot move calibrated tool to laser: too big offset" diff --git a/script/client/PShellClient.py b/script/client/PShellClient.py new file mode 100644 index 0000000..a40b1df --- /dev/null +++ b/script/client/PShellClient.py @@ -0,0 +1,369 @@ +import threading +import time +import sys +import requests +import json + +try: + from urllib import quote # Python 2 +except ImportError: + from urllib.parse import quote # Python 3 + +try: + from sseclient import SSEClient +except: + SSEClient = None + + +class PShellClient: + def __init__(self, url): + self.url = url + self.sse_event_loop_thread = None + self.subscribed_events = None + self.event_callback = None + + def _get_response(self, response, is_json=True): + if response.status_code != 200: + raise Exception(response.text) + return json.loads(response.text) if is_json else response.text + + def _get_binary_response(self, response): + if response.status_code != 200: + raise Exception(response.text) + return response.raw.read() + + def get_version(self): + """Return application version. + + Args: + + Returns: + String with application version. + + """ + return self._get_response(requests.get(url=self.url+"/version"), False) + + def get_config(self): + """Return application configuration. + + Args: + + Returns: + Dictionary. + """ + return self._get_response(requests.get(url=self.url+"/config")) + + def get_state(self): + """Return application state. + + Args: + + Returns: + String: Invalid, Initializing,Ready, Paused, Busy, Disabled, Closing, Fault, Offline + """ + return self._get_response(requests.get(url=self.url+"/state")) + + def get_logs(self): + """Return application logs. + + Args: + + Returns: + List of logs. + Format of each log: [date, time, origin, level, description] + + """ + return self._get_response(requests.get(url=self.url+"/logs")) + + def get_history(self, index): + """Access console command history. + + Args: + index(int): Index of history entry (0 is the most recent) + + Returns: + History entry + + """ + return self._get_response(requests.get(url=self.url+"/history/"+str(index)), False) + + def get_script(self, path): + """Return script. + + Args: + path(str): Script path (absolute or relative to script folder) + + Returns: + String with file contents. + + """ + return self._get_response(requests.get(url=self.url+"/script/"+str(path)), False) + + def get_devices(self): + """Return global devices. + + Args: + + Returns: + List of devices. + Format of each device record: [name, type, state, value, age] + + """ + return self._get_response(requests.get(url=self.url+"/devices")) + + def abort(self, command_id=None): + """Abort execution of command + + Args: + command_id(optional, int): id of the command to be aborted. + if None (default), aborts the foreground execution. + + Returns: + + """ + if command_id is None: + requests.get(url=self.url+"/abort") + else: + return requests.get(url=self.url+"/abort/"+str(command_id)) + + def reinit(self): + """Reinitialize the software. + + Args: + + Returns: + + """ + requests.get(url=self.url+"/reinit") + + def stop(self): + """Stop all devices implementing the 'Stoppable' interface. + + Args: + + Returns: + + """ + requests.get(url=self.url+"/stop") + + def update(self): + """Update all global devices. + + Args: + + Returns: + + """ + requests.get(url=self.url+"/update") + + def eval(self,statement): + """Evaluates a statement in the interpreter. + If the statement finishes by '&', it is executed in background. + Otherwise statement is executed in foreground (exclusive). + + Args: + statement(str): input statement + + Returns: + String containing the console return. + If an exception is produces in the interpretor, it is re-thrown here. + """ + statement = quote(statement) + return self._get_response(requests.get(url=self.url+"/eval/"+statement), False) + + def run(self,script, pars=None, background=False): + """Executes script in the interpreter. + + Args: + script(str): name of the script (absolute or relative to the script base folder). Extension may be omitted. + pars(optional, list or dict): if a list is given, it sets sys.argv for the script. + If a dict is given, it sets global variable for the script. + background(optional, bool): if True script is executed in background. + + Returns: + Return value of the script. + If an exception is produces in the interpretor, it is re-thrown here. + """ + return self._get_response(requests.put(url=self.url+"/run", json={"script":script, "pars":pars, "background":background, "async":False })) + + def start_eval(self,statement): + """Starts evaluation of a statement in the interpreter. + If the statement finishes by '&', it is executed in background. + Otherwise statement is executed in foreground (exclusive). + + Args: + statement(str): input statement + + Returns: + Command id (int), which is used to retrieve command execution status/result (get_result). + """ + statement = quote(statement) + return int(self._get_response(requests.get(url=self.url+"/evalAsync/"+statement), False)) + + def start_run(self,script, pars=None, background=False): + """Starts execution of a script in the interpreter. + + Args: + script(str): name of the script (absolute or relative to the script base folder). Extension may be omitted. + pars(optional, list or dict): if a list is given, it sets sys.argv for the script. + If a dict is given, it sets global variable for the script. + background(optional, bool): if True script is executed in background. + + Returns: + Command id (int), which is used to retrieve command execution status/result (get_result). + """ + return int(self._get_response(requests.put(url=self.url+"/run", json={"script":script, "pars":pars, "background":background, "async":True }))) + + def get_result(self, command_id=-1): + """Gets status/result of a command executed asynchronously (start_eval and start_run). + + Args: + command_id(optional, int): command id. If equals to -1 (default) return status/result of the foreground task. + + Returns: + Dictionary with the fields: 'id' (int): command id + 'status' (str): unlaunched, invalid, removed, running, aborted, failed or completed. + 'exception' (str): if status equals 'failed', holds exception string. + 'return' (obj): if status equals 'completed', holds return value of script (start_run) + or console return (start_eval) + """ + return self._get_response(requests.get(url=self.url+"/result/"+str(command_id))) + + def help(self, input = "<builtins>"): + """Returns help or auto-completion strings. + + Args: + input(optional, str): - ":" for control commands + - "<builtins>" for builtin functions + - "devices" for device names + - builtin function name for function help + - else contains entry for auto-completion + + Returns: + List + + """ + return self._get_response(requests.get(url=self.url+"/autocompletion/" + input)) + + def get_contents(self, path=None): + """Returns contents of data path. + + Args: + path(optional, str): Path to data relative to data home path. + - Folder + - File + - File (data root) | internal path + - internal path (on currently open data root) + + Returns: + List of contents + + """ + return self._get_response(requests.get(url=self.url+ "/contents" + ("" if path is None else ( "/"+path))), False) + + def get_data(self, path, type="txt"): + """Returns data on a given path. + + Args: + path(str): Path to data relative to data home path. + - File (data root) | internal path + - internal path (on currently open data root) + type(optional, str): txt, "json", "bin", "bs" + + Returns: + Data accordind to selected format/. + + """ + if type == "json": + return self._get_response(requests.get(url=self.url+ "/data-json/"+path), True) + elif type == "bin": + return self._get_binary_response(requests.get(url=self.url+"/data-bin/"+path, stream=True)) + elif type == "bs": + from collections import OrderedDict + bs = self._get_binary_response(requests.get(url=self.url+"/data-bs/"+path, stream=True)) + index=0 + msg = [] + for i in range(4): + size =int.from_bytes(bs[index:index+4], byteorder='big', signed=False) + index=index+4 + msg.append(bs[index:index+size]) + index=index+size + [main_header, data_header, data, timestamp] = msg + main_header = json.loads(main_header, object_pairs_hook=OrderedDict) + data_header = json.loads(data_header, object_pairs_hook=OrderedDict) + channel = data_header["channels"][0] + channel["encoding"] = "<" if channel.get("encoding", "little") else ">" + from bsread.data.helpers import get_channel_reader + channel_value_reader = get_channel_reader(channel) + return channel_value_reader(data) + + return self._get_response(requests.get(url=self.url+ "/data" + ("" if path is None else ( "/"+path))), False) + + def print_logs(self): + for l in self.get_logs(): + print ("%s %s %-20s %-8s %s" % tuple(l)) + + def print_devices(self): + for l in self.get_devices(): + print ("%-16s %-32s %-10s %-32s %s" % tuple(l)) + + def print_help(self, input = "<builtins>"): + for l in self.help(input): + print (l) + + #Events + def _sse_event_loop_task(self): + try: + while True: + try: + messages = SSEClient(self.url+"/events") + for msg in messages: + if (self.subscribed_events is None) or (msg.event in self.subscribed_events): + try: + value = json.loads(msg.data) + except: + value = str(msg.data) + self.event_callback(msg.event, value) + except IOError as e: + #print(e) + pass + except: + print("Error:", sys.exc_info()[1]) + #raise + finally: + print ("Exit SSE loop task") + self.sse_event_loop_thread = None + + + def start_sse_event_loop_task(self, subscribed_events = None, event_callback = None): + """ + Initializes server event loop task. + Args: + subscribed_events: list of event names to substribe to. If None subscribes to all. + event_callback: callback function. If None, self.on_event is called instead. + + Usage example: + def on_event(name, value): + if name == "state": + print ("State changed: ", value) + elif name == "record": + print ("Received scan record: ", value) + + pc.start_sse_event_loop_task(["state", "record"], on_event) + + """ + self.event_callback = event_callback if event_callback is not None else self.on_event + self.subscribed_events = subscribed_events + if SSEClient is not None: + if self.sse_event_loop_thread is None: + self.sse_event_loop_thread = threading.Thread(target=self._sse_event_loop_task, \ + args = (), \ + kwargs={}, \ + daemon=True) + self.sse_event_loop_thread.start() + else: + raise Exception ("sseclient library is not instlled: server events are not available") + + def on_event(self, name, value): + pass + \ No newline at end of file diff --git a/script/client/TellClient.py b/script/client/TellClient.py new file mode 100644 index 0000000..256dbdd --- /dev/null +++ b/script/client/TellClient.py @@ -0,0 +1,184 @@ +from PShellClient import PShellClient +import json +import time +import sys + + + +class TellClient(PShellClient): + def __init__(self, url): + PShellClient.__init__(self, url) + self.start_sse_event_loop_task(["state", "shell"]) + self.state = self.get_state() + self.debug=False + + def on_event(self, name, value): + if name == "state": + self.state = value + print ("State: ", value) + elif name == "shell": + if self.debug: + print ("> ", value) + + def get_state(self): + self.state = PShellClient.get_state(self) + return self.state + + def wait_ready(self): + count = 0 + #Monitors event but polls every second just n case an event is missed + while (True): + if self.state != "Busy": + break + time.sleep(0.01) + count = count + 1 + if count>=100: + count=0 + self.get_state() + if self.state != "Ready": + raise Exception("Invalid state: " + str(self.state)) + + def set_in_mount_position(self, value): + self.eval("in_mount_position = " + str(value) +"&") + + def is_in_mount_position(self): + return self.eval("in_mount_position&").lower()=="true" + + def get_samples_info(self): + return json.loads(self.eval("get_samples_info()&")) + + def set_samples_info(self, info): + #c.run("data/set_samples_info", pars= [info,], background=True) + self.eval("set_samples_info(" + json.dumps(info) + ")&") + + def start_cmd(self, cmd, *argv): + cmd = cmd + "(" + for a in argv: + cmd = cmd + (("'" + a + "'") if type(a) is str else str(a) ) + ", " + cmd = cmd + ")" + ret = self.start_eval(cmd) + self.get_state() + return ret + + def wait_cmd(self, cmd): + self.wait_ready() + result = self.get_result(cmd) + #print (result) + if result["exception"] is not None: + raise Exception(result["exception"] ) + return result["return"] + + def mount(self, segment, puck, sample, force=False, read_dm=False, auto_unmount=False): + #return self.run("motion/mount", pars= [segment,puck, sample, force, read_dm], background=True) + return self.start_cmd("mount", segment, puck, sample, force, read_dm, auto_unmount) + + def unmount(self, segment = None, puck = None, sample = None, force=False): + return self.start_cmd("unmount", segment, puck, sample, force) + + def scan_pin(self, segment, puck, sample, force=False): + return self.start_cmd("scan_pin", segment, puck, sample, force) + + def scan_puck(self, segment, puck, force=False): + return self.start_cmd("scan_puck", segment, puck, force) + + def dry(self, heat_time=30.0, speed=0.5, wait_cold = 30.0): + return self.start_cmd("dry", heat_time, speed, wait_cold) + + def move_cold(self): + return self.start_cmd("move_cold") + + def trash(self): + return self.start_cmd("trash") + + def abort_cmd(self): + self.abort() + self.eval("robot.stop_task()&") + + def set_gonio_mount_position(homing = False): + if homing: + self.eval("home_fast_table()") + self.eval("set_mount_position()") + + def get_mounted_sample(self): + ret = self.eval("get_setting('mounted_sample_position')&").strip() + return None if len(ret)==0 else ret + + def get_system_check(self): + try: + ret = self.eval("system_check()&") + except Exception as ex: + return ex + return "Ok" + + def get_robot_state(self): + return self.eval("robot.state&") + + + def get_robot_status(self): + status = self.eval("robot.take()&") + return status + + def get_detected_pucks(self): + return self.eval("get_detected_pucks()&") + + def set_pin_offset(self, value): + self.eval("set_pin_offset(" + str(value)+ ")&") + + def get_pin_offset(self): + return self.eval("get_pin_offset()&") + + def print_info(self): + print ("State: " + str(self.get_state())) + print ("Mounted sample: " + str(self.get_mounted_sample())) + print ("System check: " + str(self.get_system_check())) + print ("Robot state: " + str(self.get_robot_state())) + print ("Robot status: " + str(self.get_robot_status())) + print ("Detected pucks: " + str(self.get_detected_pucks())) + print ("Pin offset: " + str(self.get_pin_offset())) + print ("Mount position: " + str(self.is_in_mount_position())) + print ("") + +if __name__ == "__main__": + tell = TellClient("http://Alexandres-MBP.psi.ch:8080") + tell.print_info() + + info = [ + { + "userName": "User", + "dewarName": "Dewar", + "puckName": "Puck", + "puckBarcode": "XXX0001", + "puckType": "Minispine", + "puckAddress": "", + "sampleName": "Sample", + "sampleBarcode": "YYY0001", + "samplePosition": "1", + "sampleStatus": "Present", + "sampleMountCount": "0" , + }, + ] + print (tell.get_samples_info()) + tell.set_samples_info(info) + print (tell.get_samples_info()) + + tell.abort_cmd() + + cmd = tell.move_cold() + print (tell.wait_cmd(cmd)) + + cmd = tell.trash() + print (tell.wait_cmd(cmd)) + + cmd = tell.scan_pin("A", 1, 1) + print (tell.wait_cmd(cmd)) + + cmd = tell.scan_puck("A", 1, 1) + print (tell.wait_cmd(cmd)) + + cmd = tell.mount("A", 1, 1) + print (tell.wait_cmd(cmd)) + + print ("Mounted sample: " + str(tell.get_mounted_sample())) + cmd = tell.unmount() + print (tell.wait_cmd(cmd)) + print ("Mounted sample: " + str(tell.get_mounted_sample())) diff --git a/script/client/sseclient.py b/script/client/sseclient.py new file mode 100644 index 0000000..3c42858 --- /dev/null +++ b/script/client/sseclient.py @@ -0,0 +1,163 @@ +import codecs +import re +import time +import warnings + +import six + +import requests + + +# Technically, we should support streams that mix line endings. This regex, +# however, assumes that a system will provide consistent line endings. +end_of_field = re.compile(r'\r\n\r\n|\r\r|\n\n') + +class SSEClient(object): + def __init__(self, url, last_id=None, retry=3000, session=None, chunk_size=1024, **kwargs): + self.url = url + self.last_id = last_id + self.retry = retry + self.chunk_size = chunk_size + + # Optional support for passing in a requests.Session() + self.session = session + + # Any extra kwargs will be fed into the requests.get call later. + self.requests_kwargs = kwargs + + # The SSE spec requires making requests with Cache-Control: nocache + if 'headers' not in self.requests_kwargs: + self.requests_kwargs['headers'] = {} + self.requests_kwargs['headers']['Cache-Control'] = 'no-cache' + + # The 'Accept' header is not required, but explicit > implicit + self.requests_kwargs['headers']['Accept'] = 'text/event-stream' + + # Keep data here as it streams in + self.buf = u'' + + self._connect() + + def _connect(self): + if self.last_id: + self.requests_kwargs['headers']['Last-Event-ID'] = self.last_id + + # Use session if set. Otherwise fall back to requests module. + requester = self.session or requests + self.resp = requester.get(self.url, stream=True, **self.requests_kwargs) + self.resp_iterator = self.resp.iter_content(chunk_size=self.chunk_size) + + # TODO: Ensure we're handling redirects. Might also stick the 'origin' + # attribute on Events like the Javascript spec requires. + self.resp.raise_for_status() + + def _event_complete(self): + return re.search(end_of_field, self.buf) is not None + + def __iter__(self): + return self + + def __next__(self): + decoder = codecs.getincrementaldecoder( + self.resp.encoding)(errors='replace') + while not self._event_complete(): + try: + next_chunk = next(self.resp_iterator) + if not next_chunk: + raise EOFError() + self.buf += decoder.decode(next_chunk) + + except (StopIteration, requests.RequestException, EOFError) as e: + time.sleep(self.retry / 1000.0) + self._connect() + + # The SSE spec only supports resuming from a whole message, so + # if we have half a message we should throw it out. + head, sep, tail = self.buf.rpartition('\n') + self.buf = head + sep + continue + + # Split the complete event (up to the end_of_field) into event_string, + # and retain anything after the current complete event in self.buf + # for next time. + (event_string, self.buf) = re.split(end_of_field, self.buf, maxsplit=1) + msg = Event.parse(event_string) + + # If the server requests a specific retry delay, we need to honor it. + if msg.retry: + self.retry = msg.retry + + # last_id should only be set if included in the message. It's not + # forgotten if a message omits it. + if msg.id: + self.last_id = msg.id + + return msg + + if six.PY2: + next = __next__ + + +class Event(object): + + sse_line_pattern = re.compile('(?P<name>[^:]*):?( ?(?P<value>.*))?') + + def __init__(self, data='', event='message', id=None, retry=None): + self.data = data + self.event = event + self.id = id + self.retry = retry + + def dump(self): + lines = [] + if self.id: + lines.append('id: %s' % self.id) + + # Only include an event line if it's not the default already. + if self.event != 'message': + lines.append('event: %s' % self.event) + + if self.retry: + lines.append('retry: %s' % self.retry) + + lines.extend('data: %s' % d for d in self.data.split('\n')) + return '\n'.join(lines) + '\n\n' + + @classmethod + def parse(cls, raw): + """ + Given a possibly-multiline string representing an SSE message, parse it + and return a Event object. + """ + msg = cls() + for line in raw.splitlines(): + m = cls.sse_line_pattern.match(line) + if m is None: + # Malformed line. Discard but warn. + warnings.warn('Invalid SSE line: "%s"' % line, SyntaxWarning) + continue + + name = m.group('name') + if name == '': + # line began with a ":", so is a comment. Ignore + continue + value = m.group('value') + + if name == 'data': + # If we already have some data, then join to it with a newline. + # Else this is it. + if msg.data: + msg.data = '%s\n%s' % (msg.data, value) + else: + msg.data = value + elif name == 'event': + msg.event = value + elif name == 'id': + msg.id = value + elif name == 'retry': + msg.retry = int(value) + + return msg + + def __str__(self): + return self.data diff --git a/script/client/tell.py b/script/client/tell.py new file mode 100644 index 0000000..56c70b4 --- /dev/null +++ b/script/client/tell.py @@ -0,0 +1,79 @@ +import sys +import os +import code +import readline +import rlcompleter +import atexit + +from TellClient import TellClient + +tell = TellClient("http://PC12288:8080") + +def info(): + tell.print_info() + +def help(): + print ("Commands: \n\thelp()\n\tinfo()\n\tmount(segment, puck, sample)\n\tunmount() \n\tdry() " \ + "\n\tscan(segment, puck, sample=None) \n\tmove_cold() \n\ttrash() \n\tabort() " \ + "\n\tset_pin_offset(value)") + +def assert_transfer_allowed(): + if not tell.is_in_mount_position(): + raise Exception("Gonio is not in mount position") + +def mount(segment, puck, sample): + assert_transfer_allowed() + cmd = tell.mount(segment, puck, sample, True, True, True) + print (tell.wait_cmd(cmd)) + +def unmount(): + assert_transfer_allowed() + cmd=tell.unmount(force=True) + print (tell.wait_cmd(cmd)) + +def move_cold(): + cmd=tell.move_cold() + print (tell.wait_cmd(cmd)) + +def trash(): + cmd=tell.trash() + print (tell.wait_cmd(cmd)) + +def dry(): + cmd=tell.dry() + print (tell.wait_cmd(cmd)) + +def scan(segment, puck, sample=None): + if sample is None: + cmd=tell.scan_puck(segment, puck, True) + else: + cmd=tell.scan_pin(segment, puck, sample, True) + print (tell.wait_cmd(cmd)) + +def abort(): + tell.abort_cmd() + +def set_pin_offset(value): + tell.set_pin_offset(value) + +info() +help() + +#for line in sys.stdin: +# tell.print_info() +#print ("", end='\r> ') + +historyPath = os.path.expanduser("./.history") +def save_history(historyPath=historyPath): + readline.write_history_file(historyPath) +if os.path.exists(historyPath): + readline.read_history_file(historyPath) +atexit.register(save_history) + +#vars = globals(); vars.update(locals()) +vars =locals() +readline.set_completer(rlcompleter.Completer(vars).complete) +readline.parse_and_bind("tab: complete") + +code.interact(banner = "", local=vars) + diff --git a/script/data/get_samples_info.py b/script/data/get_samples_info.py new file mode 100644 index 0000000..00a5bc3 --- /dev/null +++ b/script/data/get_samples_info.py @@ -0,0 +1,4 @@ + + + +set_return(get_samples_info(as_json=False)) \ No newline at end of file diff --git a/script/data/pucks.py b/script/data/pucks.py new file mode 100644 index 0000000..bdb925b --- /dev/null +++ b/script/data/pucks.py @@ -0,0 +1,22 @@ +def get_puck_names(): + return [str(a)+str(b) for a in BLOCKS for b in range(1,6)] + + +def get_puck_info(): + ret = [] + #for puck in get_puck_names(): + for puck in BasePlate.pucks: + ret.append({"address" : str(puck.name), "status": str(puck.status), "barcode" : str(puck.id)}) + return ret + + +def get_puck_obj(address): + return BasePlate.getChild(address) + + +def get_puck_obj_by_id(puck_id): + for puck in BasePlate.pucks: + if puck.id == puck_id: + return puck + return None + \ No newline at end of file diff --git a/script/data/samples.py b/script/data/samples.py new file mode 100644 index 0000000..f6ba272 --- /dev/null +++ b/script/data/samples.py @@ -0,0 +1,314 @@ +import json +import org.python.core.PyDictionary as PyDictionary + +SAMPLE_INFO_KEYS = ["userName", "dewarName", "puckName", "puckBarcode", "puckType", "puckAddress", + "sampleName", "samplePosition", "sampleBarcode", "sampleStatus", "sampleMountCount"] +samples_info = [] + + +def set_samples_info(info): + global samples_info + if (is_string(info)): + info = json.loads(info) + if not is_list(info): + raise Exception("Sample info must be a list (given object type is " + str(type(info)) + ")") + #Sanitize list + remove = [] + for sample in info: + try: + if set(sample.keys()) != set(SAMPLE_INFO_KEYS): + raise Exception() + except: + remove.append(sample) + for el in remove: + info.remove(el) + print "Invalid samples info element: " + str(el) + samples_info = info + save_samples_info() + #Trust beamline on assignments, so update puck info + update_puck_table() + + +def clear_samples_info(): + set_samples_info([]) + +def save_samples_info(): + data = get_samples_info(True) + output_file = open( get_context().setup.expandPath("{context}/samples_info.json") , "w") + output_file.write(data) + output_file.close() + +def restore_samples_info(): + try: + inputfile = open(get_context().setup.expandPath("{context}/samples_info.json"), "r") + info = inputfile.read() + except: + print >> sys.stderr, "Error reading sample info file: " + str(sys.exc_info()[1]) + info = [] + set_samples_info(info) + +def get_samples_info(as_json=True): + global samples_info + return json.dumps(to_list(samples_info)) if as_json else samples_info + +def has_puck_datamatrix(datamatrix): + if samples_info is not None: + for si in samples_info: + if si["puckBarcode"] == datamatrix: + return True + return False + +def add_puck_datamatrix(barcode, address = "", dewar = "Unknown", user = "Unknown", puck = "Unknown", type = "unipuck", sample_prefix = "Sample"): + if has_puck_datamatrix(barcode): + raise Exception("Datamatrix already defined: " + str(barcode)) + for s in range(1,17): + info = \ + { "userName": user, \ + "dewarName": dewar, \ + "puckName": puck, \ + "puckBarcode": address if barcode is None else barcode, \ + "puckType": type, \ + "puckAddress": address,\ + "sampleName": sample_prefix + " " + str(s), \ + "samplePosition": str(s),\ + "sampleStatus": "Unknown", \ + "sampleMountCount": "0", + } + samples_info.append(info) + save_samples_info() + +def remove_puck_datamatrix(barcode): + remove = [] + for si in samples_info: + if si["puckBarcode"] == barcode: + remove.append(si) + for el in remove: samples_info.remove(el) + save_samples_info() + +def set_puck_datamatrix(puck, datamatrix): + if puck is None: + puck = "" + if datamatrix is None: + datamatrix = "" + if samples_info is not None: + for si in samples_info: + if si["puckBarcode"] == datamatrix: + si["puckAddress"] = puck + elif si["puckAddress"] == puck: + si["puckAddress"] = "" + save_samples_info() + +def reset_puck_datamatrix(puck = None): + if samples_info is not None: + for si in samples_info: + if (si["puckAddress"] == puck) or (puck is None): + si["puckAddress"] = "" + save_samples_info() + for p in BasePlate.getChildren(): + if (p.name == puck) or (puck is None): + p.id = None + +def get_puck_datamatrix(): + ret = {} + for si in samples_info: + if si["puckBarcode"] is not None and si["puckBarcode"]!="": + ret[si["puckBarcode"]] = si["puckAddress"] + return ret + +def get_puck_address(barcode): + try: + return get_puck_datamatrix()[barcode] + except: + return None + + +def update_puck_table(): + dms = get_puck_datamatrix() + for barcode in dms.keys(): + address = dms[barcode] + puck = get_puck_obj(address) + if puck is not None: + puck.id = barcode + + +#Sample mount/unmount + +def update_samples_info_sample_mount(puck_address, sample_position, sample_detected, sample_id): + try: + if (samples_info is not None) and (puck_address is not None): + for si in samples_info: + if str(si["puckAddress"]) == str(puck_address) and str(si["samplePosition"]) == str(sample_position): + if sample_detected: + if si["sampleStatus"] != "Mounted": + si["sampleStatus"] = "Mounted" + try: + mount_count = int(si["sampleMountCount"]) + except: + mount_count = 0 + si["sampleMountCount"] = mount_count + 1 + else: + si["sampleStatus"] = "Unknown" + + if sample_id is not None: + si["sampleBarcode"] = sample_id + + save_samples_info() + return + except: + pass + +def update_samples_info_sample_unmount(puck_address, sample_position): + try: + if (samples_info is not None) and (puck_address is not None): + for si in samples_info: + if str(si["puckAddress"]) == str(puck_address) and str(si["samplePosition"]) == str(sample_position): + si["sampleStatus"] = "HasBeenMounted" + save_samples_info() + return + except: + pass + +def update_samples_info_sample_scan(puck_address, sample_position, sample_detected, sample_id): + try: + if (samples_info is not None) and (puck_address is not None): + for si in samples_info: + if str(si["puckAddress"]) == str(puck_address) and str(si["samplePosition"]) == str(sample_position): + if sample_detected: + if si["sampleStatus"] == "Unknown": + si["sampleStatus"] = "Present" + else: + if si["sampleStatus"] == "Present": + si["sampleStatus"] = "Unknown" + if sample_id is not None: + si["sampleBarcode"] = sample_id + save_samples_info() + return + except: + pass + + + +test_sample_data = [ \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0001", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "MySample 5", \ + "sampleBarcode": "", \ + "samplePosition": 5,\ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": "Alexandre", \ + "dewarName": "TEST", \ + "puckName": "My puck", \ + "puckBarcode": "AAA0002", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "MySample 5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + ] + \ No newline at end of file diff --git a/script/data/set_samples_info.py b/script/data/set_samples_info.py new file mode 100644 index 0000000..bc7e803 --- /dev/null +++ b/script/data/set_samples_info.py @@ -0,0 +1,4 @@ + + + +set_samples_info(args[0]) \ No newline at end of file diff --git a/script/devices/BarcodeReader.py b/script/devices/BarcodeReader.py new file mode 100644 index 0000000..70c5160 --- /dev/null +++ b/script/devices/BarcodeReader.py @@ -0,0 +1,76 @@ + + +class BarcodeReader(DeviceBase): + + def doInitialize(self): + self.disable() + self.readout = None + self.processing = False + self.task_callable=None + + def enable(self): + microscan_cmd.write("<H>") + self.setState(State.Ready) + + def disable(self): + microscan_cmd.write("<I>") + self.setState(State.Disabled) + + def get(self,timeout=1.0): + self.state.assertReady() + try: + self.setState(State.Busy) + microscan.flush() + ret = microscan.waitString(int(timeout * 1000)) + if ret is not None: + ret = ret.strip() + self.setCache(ret, None) + return ret + except: + self.setCache(None, None) + return None + finally: + if self.state == State.Busy: + self.setState(State.Ready) + + def doUpdate(self): + self.get() + + + def read(self,timeout=1.0): + if self.processing: + raise Exception("Ongoing read operation") + self.processing = True + try: + initial = self.state + if initial == State.Disabled: + self.enable() + try: + return self.get(timeout) + finally: + if initial == State.Disabled: + self.disable() + finally: + self.processing = False + + def _read_task(self, timeout): + global readout + self.readout = self.read(timeout) + return self.readout + + def start_read(self, timeout=1.0): + self.readout = None + self.task_callable = fork((self._read_task, (timeout,))) + + def get_readout(self): + return self.readout + + def wait_readout(self): + if self.task_callable is not None: + join(self.task_callable) + self.task_callable = None + return self.readout + + +add_device(BarcodeReader("barcode_reader"), force = True) + \ No newline at end of file diff --git a/script/devices/Gonio.py b/script/devices/Gonio.py new file mode 100644 index 0000000..0f264f5 --- /dev/null +++ b/script/devices/Gonio.py @@ -0,0 +1,43 @@ + + +def home_fast_table(): + caput ("SAR-EXPMX1:ASYN.AOUT", "enable plc 1") + +def get_fx_pos(): + return caget("SAR-EXPMX:MOT_FX.RBV", 'f') + +def set_fx_pos(pos): + return caput("SAR-EXPMX:MOT_FX.VAL", float(pos)) + + +def get_fy_pos(): + return caget("SAR-EXPMX:MOT_FY.RBV", 'f') + +def set_fy_pos(pos): + return caput("SAR-EXPMX:MOT_FY.VAL", float(pos)) + +def get_ry_pos(): + return caget("SAR-EXPMX:MOT_ROT_Y.RBV", 'f') + +def set_ry_pos(pos): + return caput("SAR-EXPMX:MOT_ROT_Y.VAL", float(pos)) + +def get_cz_pos(): + return caget("SAR-EXPMX:MOT_CZ.RBV", 'f') + +def set_cz_pos(pos): + return caput("SAR-EXPMX:MOT_CZ.VAL", float(pos)) + +def get_cx_pos(): + return caget("SAR-EXPMX:MOT_CX.RBV", 'f') + +def set_cx_pos(pos): + return caput("SAR-EXPMX:MOT_CX.VAL", float(pos)) + + +def set_mount_position(): + set_fx_pos(0.0) + set_fy_pos(0.0) + set_ry_pos(0.0) + set_cz_pos(0.0) + set_cx_pos(0.0) \ No newline at end of file diff --git a/script/devices/Hexiposi.py b/script/devices/Hexiposi.py new file mode 100644 index 0000000..52c86c4 --- /dev/null +++ b/script/devices/Hexiposi.py @@ -0,0 +1,165 @@ +import ch.psi.pshell.device.DiscretePositionerBase as DiscretePositionerBase +import requests +import json + +class Hexiposi(DiscretePositionerBase): + def __init__(self, name, url): + DiscretePositionerBase.__init__(self, name, ["A","B","C","D","E","F"]) + self.PORT_SET=8002 + self.PORT_GET=8002 + if not url.startswith("http://"): + url = "http://" + url + if not url.endswith(":"): + url = url + ":" + self.url_set = url + str (self.PORT_SET)+ "/hexiposi/" + self.url_get = url + str (self.PORT_GET)+ "/hexiposi/" + self.moved = True + self.homing_state = State.Disabled + self.rback = self.UNKNOWN_POSITION + self.timeout = 3.0 + self.offline = False + + def doInitialize(self): + super(Hexiposi, self).doInitialize() + self.val = self.doReadReadback() + + def get_response(self, response): + if (response.status_code!=200): + raise Exception (response.text) + return json.loads(response.text) + + def get_status(self): + try: + self.status = self.get_response(requests.get(url=self.url_get+"get", timeout=self.timeout)) + self.estop = self.status["estop"] + self.homed = self.status["homed"] + self.error = self.status["errorCode"] + self.remote = self.status["mode"] == "remote" + self.moving = self.status["errorCode"] + self.pos = self.status["position"] + self.moving = self.status["moving"] + self.offset = self.status["offset"] + self.dpos = self.status["discretePosition"] + if (self.homed==False): rback = self.UNKNOWN_POSITION + elif self.dpos == 1: rback = "A" + elif self.dpos == 2: rback = "B" + elif self.dpos == 4: rback = "C" + elif self.dpos == 8: rback = "D" + elif self.dpos == 16: rback = "E" + elif self.dpos == 32: rback = "F" + else: rback = self.UNKNOWN_POSITION + if (rback == self.UNKNOWN_POSITION) or (rback != self.rback): + self.moved = True + self.rback = rback + self.offline = False + return self.status + except: + self.offline = True + self.updateState() + raise + + def set_deadband(self, value = 0.1): #degrees + ret = self.get_response(requests.get(url=self.url_set+"setDeadband?deadband=" + str(value), timeout=self.timeout)) + if ret["deadbandOutput"] == value: + return value + raise Excepiton("Error setting deadband: " + str(ret)) + + def move_pos(self, pos): + return self.get_response(requests.get(url=self.url_set+"set?pos=" + str(pos), timeout=self.timeout)) + + def move_home(self): + ret = self.get_response(requests.get(url=self.url_set+"set?home=1", timeout=self.timeout)) + try: + self.waitState(self.homing_state,1200) + except: + pass + return ret + + def stop_move(self): + return self.get_response(requests.get(url=self.url_set+"set?stop=1", timeout=self.timeout)) + + def set_offset(self, offset): + return self.get_response(requests.get(url=self.url_set+"setOffset?offset="+str(offset), timeout=self.timeout)) + + def doUpdate(self): + self.get_status() + super(Hexiposi, self).doUpdate() + + + def doStop(self): + self.stop_move() + + def doRead(self): + return str(self.val) + + def doReadReadback(self): + self.get_status() + return self.rback + + def doWrite(self, val): + val = ord(val) - ord('A') +1 + if val<1 or val>6: + raise Exception("Invalid value: " + str(val)) + moving = val != self.val + self.val = val + self.move_pos(self.val) + #Workaround as state does not changes immediatelly + if moving: + #try: + # self.waitState(State.Busy,1200) + #except: + # print sys.exc_info()[1] + start = time.time() + while self.state != State.Busy: + if time.time() - start > 1.5: + print "Timeout waiting Hexiposi busy" + break + self.update() + + def is_in_position(self, pos): + return take() == pos + + + def assert_in_position(self, pos): + if not is_in_position(pos): + raise Exception ("Hexiposi is not in position") + + def assert_homed(self): + if self.homed == False: + raise Exception ("Hexiposi is not homed") + + + #def isReady(self): + # self.get_status() + # return self.moving == False + + def updateState(self): + if self.offline: + self.setState(State.Offline) + elif self.homed == False: + self.setState(self.homing_state) + elif self.moving: + self.setState(State.Busy) + else: + self.setState(State.Ready) + + + +#http://myriotell:8003/hexiposi/get +dev = Hexiposi("hexiposi", "myriotell") + +add_device(dev, True) +hexiposi.polling=1000 +#print dev.url +#print dev.get_status() + +class hexiposi_position(ReadonlyRegisterBase): + def doRead(self): + try: + return float(hexiposi.pos) + except: + return float("nan") + +add_device(hexiposi_position(), True) +hexiposi_position.polling = 1000 +hexiposi.set_deadband(0.5) diff --git a/script/devices/LaserDistance.py b/script/devices/LaserDistance.py new file mode 100644 index 0000000..97efea4 --- /dev/null +++ b/script/devices/LaserDistance.py @@ -0,0 +1,17 @@ +class LaserDistance(ReadonlyRegisterBase): + def __init__(self): + ReadonlyRegisterBase.__init__(self, "laser_distance") + def doRead(self): + ret = ue.readable.read() + ret = 0.0 if math.isnan(ret) else ret + return ret + +class ListenerAI (DeviceListener): + def onValueChanged(self, device, value, former): + laser_distance.setCache( 0.0 if math.isnan(value) else value, None) + +listenerAI = ListenerAI() +ue.addListener(listenerAI) + +laser_distance=LaserDistance() +add_device(laser_distance, True) diff --git a/script/devices/LedCtrl.py b/script/devices/LedCtrl.py new file mode 100644 index 0000000..da4e51d --- /dev/null +++ b/script/devices/LedCtrl.py @@ -0,0 +1,46 @@ +import ch.psi.pshell.device.DiscretePositionerBase as DiscretePositionerBase + + +class LedPositioner(DiscretePositionerBase): + def __init__(self): + DiscretePositionerBase.__init__(self, "led_ctrl", ["On", "Off"]) + self.setState(State.Ready) + self.val = self.doReadReadback() + + def doRead(self): + return self.val + + def doReadReadback(self): + return "On" if get_led_state() else "Off" + + def doWrite(self, val): + self.val = val + if self.val == "On": + set_led_state(True) + else: + set_led_state(False) + + +add_device(LedPositioner(), True) +led_ctrl.polling = 1000 + + + + +import ch.psi.pshell.device.ProcessVariableConfig as ProcessVariableConfig +class LedLevel(ProcessVariableBase): + def __init__(self, name): + ProcessVariableBase.__init__(self, name, ProcessVariableConfig()) + + def doRead(self): + return get_led_level() + + def doWrite(self, val): + return set_led_level(val) + +led_level = LedLevel("led_level") +led_level.config.minValue = 0.0 +led_level.config.maxValue = 100.0 +led_level.config.unit = "%" +add_device(led_level, True) +led_level.polling = 1000 \ No newline at end of file diff --git a/script/devices/OneWire.py b/script/devices/OneWire.py new file mode 100644 index 0000000..20e590f --- /dev/null +++ b/script/devices/OneWire.py @@ -0,0 +1,134 @@ +import traceback +from datetime import datetime + +class Detector(ReadonlyRegisterBase): + def __init__(self, name): + ReadonlyRegisterBase.__init__(self, name) + self.reset() + + def set_inputs(self, inputs): + self.inputs = inputs + if self.take() != inputs.values(): + self.setCache(inputs.values(), None) + if self.getParent()!=None: + self.getParent().updateCache() + if (len(self.take()) == 0): + self.setState(State.Offline) + else: + self.setState(State.Ready) + + def set_input(self, index, val): + self.inputs[index] = val + self.set_inputs(self.inputs) + + def reset(self): + self.id = None + self.sn = None + self.status = None + self.type = None + self.set_inputs({}) + +class Esera(TcpDevice): + def __init__(self, name, server, timeout = 1000, retries = 1): + TcpDevice.__init__(self, name, server) + self.setMode(self.Mode.FullDuplex) + self.detectors = [] + for i in range(30): + self.detectors.append(Detector("Detector " + str(i+1))) + self.setChildren(self.detectors) + self.completed_initializatiod = False + self.debug = False + + def start(self): + self.getLogger().info("Starting controller") + self.write("set,sys,run,1\n") + + def stop(self): + self.getLogger().info("Stopping controller") + self.write("set,sys,run,0\n") + + def list(self): + self.write("get,owb,listall1\n") + + def req_data(self): + self.write("get,sys,data\n") + + def doInitialize(self): + super(Esera, self).doInitialize() + self.init_timestamp = time.time() + try: + self.setState(State.Ready) #So can communicate + for det in self.detectors: + det.reset() + self.list() + time.sleep(1.0) + self.check_started() + self.req_data() + except: + print >> sys.stderr, traceback.format_exc() + self.getLogger().warning(traceback.format_exc()) + raise + + def doUpdate(self): + self.check_started() + self.req_data() + + def updateCache(self): + #print "Update" + cache = [] + for det in self.detectors: + cache.append(det.take()) + self.setCache(cache, None) + + + def check_started(self): + if not self.completed_initializatiod: + init = True + for det in self.detectors: + if det.id == None: + init = False + break + if init: + self.completed_initializatiod = True + print("Completed initialization") + self.getLogger().info("Completed initialization") + self.start() + + def onString(self, msg): + if self.debug: + print datetime.now() , " - " , msg + tokens = msg.split("|") + if len(tokens)>1: + try: + if msg[:3] == "LST": + #LST|1_OWD1|3AF361270000009E|S_0|DS2413| + if tokens[1] > 1: + index = int(tokens[1].split("_")[1][3:]) - 1 + if index < len(self.detectors): + det = self.detectors[index] + det.id = tokens[1] + det.sn= tokens[2] if len(tokens)>2 else None + det.status = int(tokens[3][2:]) if len(tokens)>3 else None + det.type = tokens[4] if len(tokens)>4 else None + if det.status!= 0: + det.set_inputs({}) + else: + for det in self.detectors: + if det.id is not None and msg.startswith(det.id): + det_id = int(tokens[0][len(det.id)+1:]) + det.set_input(det_id, int(tokens[1])) + except: + print >> sys.stderr, traceback.format_exc() + self.getLogger().log(traceback.format_exc()) + + + + + + + +add_device(Esera("onewire", "129.129.126.83:5000"), force = True) +onewire.setPolling(500) +add_device(onewire.detectors[0], force = True) +add_device(onewire.detectors[1], force = True) +add_device(onewire.detectors[2], force = True) diff --git a/script/devices/RobotModbus.py b/script/devices/RobotModbus.py new file mode 100644 index 0000000..cd8abaf --- /dev/null +++ b/script/devices/RobotModbus.py @@ -0,0 +1,46 @@ +class RobotModbus(DeviceBase): + def __init__(self, name): + DeviceBase.__init__(self, name) + robot_req.write(0) + + def execute(self, command, *argv): + if robot_req.read() != 0: + raise Exception("Ongoing command") + if robot_ack.read() != 0: + raise Exception("Robot is not ready") + robot_cmd.write(command) + args = [0] * robot_args.size + index = 0 + for arg in argv: + args[index] = arg + index = index + 1 + if index == robot_args.size: + raise Exception("Invalid number of arguments") + robot_args.write(to_array(args, 'i')) + try: + self.request() + err = robot_ack.take() + if err == 1: + ret = robot_ret.read() + return ret + if err == 2: + raise Exception("Invalid command: " + str(command)) + raise Exception("Unknown error: " + str(err)) + finally: + self.cancel_request() + + def request(self): + robot_req.write(1) + while robot_ack.read() == 0: + time.sleep(0.001) + + def cancel_request(self): + robot_req.write(0) + while robot_ack.read() != 0: + time.sleep(0.001) + + def mount(self, puck, sample): + return self.execute('1', '1', puck, sample) + +add_device(RobotModbus("robot_mb"), force = True) + diff --git a/script/devices/RobotMotors.py b/script/devices/RobotMotors.py new file mode 100644 index 0000000..07ba862 --- /dev/null +++ b/script/devices/RobotMotors.py @@ -0,0 +1,62 @@ + +import ch.psi.pshell.device.PositionerConfig as PositionerConfig + + + +ROBOT_MOTORS = ["x" , "y", "z", "rx", "ry", "rz"] + + +class RobotCartesianMotor (PositionerBase): + def __init__(self, robot, index): + PositionerBase.__init__(self, robot.name + "_" + ROBOT_MOTORS[index], PositionerConfig()) + self.index = index + self.robot = robot + + #ATTENTION: Always initialize cartesian motors before scanning (or call robot.set_motors_enabled(True)) + def doInitialize(self): + self.setCache(self.doRead(), None) + + def doRead(self): + return float("nan") if self.robot.cartesian_destination is None else float(self.robot.cartesian_destination[self.index]) + + def doWrite(self, value): + if self.robot.cartesian_destination is not None: + #print "Move " + ROBOT_MOTORS[self.index] + " to " + str(value) + self.robot.cartesian_destination[self.index] = float(value) + self.robot.set_pnt(robot.cartesian_destination , "tcp_p") + self.robot.movel("tcp_p", self.robot.tool , DESC_SCAN) + + def doReadReadback(self): + return float("nan") if self.robot.cartesian_pos is None else float(self.robot.cartesian_pos[self.index]) + + + + +ROBOT_JOINT_MOTORS = ["j1" , "j2", "j3", "j4", "j5", "j6"] + + +class RobotJointMotor (PositionerBase): + def __init__(self, robot, index): + PositionerBase.__init__(self, robot.name + "_" + ROBOT_JOINT_MOTORS[index], PositionerConfig()) + self.index = index + self.robot = robot + + def doInitialize(self): + self.setpoint = self.doReadReadback() + self.setCache(self.doRead(), None) + + def doRead(self): + return self.setpoint + + def doWrite(self, value): + #print "Move " + ROBOT_JOINT_MOTORS[self.index] + " to " + str(value) + self.setpoint = value + joint = self.robot.herej() + joint[self.index] = value + self.robot.set_jnt(joint, name="tcp_j") + self.robot.movej("tcp_j", self.robot.tool , DESC_SCAN) + + def doReadReadback(self): + return self.robot.herej()[self.index] if self.robot.joint_pos is None else float(self.robot.joint_pos[self.index]) + + \ No newline at end of file diff --git a/script/devices/RobotSC.py b/script/devices/RobotSC.py new file mode 100644 index 0000000..f878be7 --- /dev/null +++ b/script/devices/RobotSC.py @@ -0,0 +1,318 @@ +TOOL_CALIBRATION = "tCalib" +TOOL_SUNA= "tSuna" +TOOL_DEFAULT= TOOL_SUNA + +FRAME_TABLE = "fTable" + +DESC_FAST = "mFast" +DESC_SLOW = "mSlow" +DESC_SCAN = "mScan" +DESC_DEFAULT = DESC_FAST + +AUX_SEGMENT = "X" + + +DEFAULT_ROBOT_POLLING = 500 +TASK_WAIT_ROBOT_POLLING = 50 + + +run("devices/RobotTCP") + + +simulation = False + +joint_forces = False + +class RobotSC(RobotTCP): + def __init__(self, name, server, timeout = 1000, retries = 1): + RobotTCP.__init__(self, name, server, timeout, retries) + self.set_tasks(["getDewar", "putDewar", "putGonio", "getGonio", "recover", "moveDewar", "moveCold", "movePark", "moveGonio","moveHeater", "moveScanner","moveHome", "moveAux"]) + self.set_known_points(["pPark", "pGonio", "pDewar", "pGonioG", "pScan", "pHeater", "pHeat", "pHeatB", "pScanStop","pHelium", "pHome", "pCold", "pAux"]) + self.setPolling(DEFAULT_ROBOT_POLLING) + #self.setSimulated() + + def move_dewar(self): + self.start_task('moveDewar') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_dewar() + + def move_cold(self): + self.start_task('moveCold') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_cold() + + def move_home(self): + self.start_task('moveHome') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_home() + + def get_dewar(self, segment, puck, sample): + segment = self.toSegmentNumber(segment) + self.start_task('getDewar',segment, puck, sample, is_room_temp()) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_dewar() + + def put_dewar(self, segment, puck, sample): + segment = self.toSegmentNumber(segment) + self.assert_dewar() + self.start_task('putDewar',segment, puck, sample, is_room_temp()) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + #self.assert_dewar() + self.assert_cold() + + def put_gonio(self): + pin_offset = get_pin_offset() + pin_angle_offset = get_pin_angle_offset() + self.start_task('putGonio', pin_offset) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_gonio() + + def get_gonio(self): + pin_offset = get_pin_offset() + self.start_task('getGonio', pin_offset) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_gonio() + + def get_aux(self, sample): + self.assert_aux() + self.start_task('getAuxiliary', sample) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_aux() + + def put_aux(self, sample): + self.assert_aux() + self.start_task('putAuxiliary', sample) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_aux() + + def move_scanner(self): + self.start_task('moveScanner') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_scanner() + + def move_scanner(self): + self.start_task('moveScanner') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_scanner() + + #def do_scan(self): + # self.start_task('doScan') + # self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + # self.assert_scan_stop() + + def move_gonio(self): + self.start_task('moveGonio') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_gonio() + + + def move_park(self): + self.start_task('movePark') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_park() + + def move_heater(self, speed=-1, to_bottom=True): + self.start_task('moveHeater', speed, to_bottom) + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + if to_bottom: + self.assert_heater_bottom() + else: + self.assert_heater() + + + def robot_recover(self): + self.start_task('recover') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_home() + + def move_aux(self): + self.start_task('moveAux') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_aux() + + def get_calibration_tool(self): + self.start_task('getCalTool') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_scanner() + + def put_calibration_tool(self): + self.start_task('putCalTool') + self.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + self.assert_scanner() + + + + def toSegmentNumber(self, segment): + if is_string(segment): + segment = ord(segment.upper()) - ord('A') +1 + return segment + + + def on_event(self,ev): + #print "EVT: " + ev + pass + def on_change_working_mode(self, working_mode): + if get_device("hexiposi") is not None: + hexiposi.moved = True #Force image processing on first sample + + def doUpdate(self): + #start = time.time() + RobotTCP.doUpdate(self) + global simulation + if not simulation: + if joint_forces: + if self.state != State.Offline: + self.get_joint_forces() + for dev in [jf1, jf2, jf3, jf4,jf5, jf6, jfc]: + dev.update() + #print time.time() -start + + def start_task(self, program, *args, **kwargs): + #TODO: Check safe position + return RobotTCP.start_task(self, program, *args, **kwargs) + + def stop_task(self): + RobotTCP.stop_task(self) + #TODO: Restore safe position + + + def set_remote_mode(self): + robot.set_profile("remote") + + def set_local(self): + robot.set_profile("default") + + def is_park(self): + return self.is_in_point("pPark") + + def is_cold(self): + return self.is_in_point("pCold") + + def is_home(self): + return self.is_in_point("pHome") + + def is_dewar(self): + return self.is_in_point("pDewar") + + def is_heater(self): + return self.is_in_point("pHeat") + + def is_heater_home(self): + return self.is_in_point("pHeater") + + def is_heater_bottom(self): + return self.is_in_point("pHeatB") + + def is_gonio(self): + return self.is_in_point("pGonio") + + def is_helium(self): + return self.is_in_point("pHelium") + + def is_scanner(self): + return self.is_in_point("pScan") + + def is_aux(self): + return self.is_in_point("pAux") + + #def is_scan_stop(self): + # return self.is_in_point("pScanStop") + + def is_cleared(self): + #return self.is_home() or self.is_park() or self.is_dewar() or self.is_dewar_home() + return self.get_current_point() is not None + + def assert_heater_home(self): + self.assert_in_point("pHeater") + + def assert_cold(self): + self.assert_in_point("pCold") + + def assert_heater(self): + self.assert_in_point("pHeat") + + def assert_heater_bottom(self): + self.assert_in_point("pHeatB") + + def assert_park(self): + self.assert_in_point("pPark") + + def assert_home(self): + self.assert_in_point("pHome") + + def assert_dewar(self): + self.assert_in_point("pDewar") + + def assert_gonio(self): + self.assert_in_point("pGonio") + + def assert_helium(self): + self.assert_in_point("pHelium") + + def assert_scanner(self): + self.assert_in_point("pScan") + + def assert_aux(self): + self.assert_in_point("pAux") + + #def assert_scan_stop(self): + # self.assert_in_point("pScanStop") + + def assert_cleared(self): + if not self.is_cleared(): + raise Exception("Robot not in cleared position") + + def wait_ready(self): + robot.waitState(State.Ready, 1000) #robot.state.assertReady() + +if simulation: + add_device(RobotSC("robot","localhost:1000"),force = True) +else: + #add_device(RobotSC("robot", "129.129.243.120:1000"), force = True) + #add_device(RobotSC("robot", "pcp068129.psi.ch:1000"), force = True) + #add_device(RobotSC("robot", "saresb-cons-06.psi.ch:1000"), force = True) + add_device(RobotSC("robot", "129.129.243.90:1000"), force = True) + + +robot.set_default_desc(DESC_DEFAULT) +robot.default_speed = 20 +robot.set_frame(FRAME_DEFAULT) +robot.set_tool(TOOL_DEFAULT) +robot.setPolling(DEFAULT_ROBOT_POLLING) + +robot.get_current_point() #TODO: REMOVE WHEN CURRENT POINT REPORTED BY POLLING MESSAGE + +class jf1(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[0] +class jf2(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[1] +class jf3(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[2] +class jf4(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[3] +class jf5(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[4] +class jf6(ReadonlyRegisterBase): + def doRead(self): + return None if robot.joint_forces == None else robot.joint_forces[5] +class jfc(ReadonlyRegisterBase): + def doRead(self): + if robot.joint_forces == None: + return float('NaN') + if robot.powered == False: + return float('NaN') + return (robot.joint_forces[1]+74)/4 + (robot.joint_forces[2]+30)/4 + (robot.joint_forces[4]-0.8)/0.2 + +if joint_forces: + add_device(jf1(), force = True) + add_device(jf2(), force = True) + add_device(jf3(), force = True) + add_device(jf4(), force = True) + add_device(jf5(), force = True) + add_device(jf6(), force = True) + add_device(jfc(), force = True) \ No newline at end of file diff --git a/script/devices/RobotTCP.py b/script/devices/RobotTCP.py new file mode 100644 index 0000000..e2a0454 --- /dev/null +++ b/script/devices/RobotTCP.py @@ -0,0 +1,863 @@ +import threading + +FRAME_DEFAULT = "world" +FLANGE = "flange" + +MAX_NUMBER_PARAMETERS = 20 + +run("devices/RobotMotors") + +class RobotTCP(TcpDevice, Stoppable): + def __init__(self, name, server, timeout = 1000, retries = 1): + TcpDevice.__init__(self, name, server) + self.timeout = timeout + self.retries = retries + self.header = None + self.trailer = "\n" + self.array_separator = '|' + self.cmd_separator = ' ' + self.msg_id = 0 + self.working_mode = "invalid" + self.status = "invalid" + self.powered = None + self.settled = None + self.empty = None + self.working_mode = None + self.status = None + self.lock = threading.Lock() + self.joint_forces = None + self.current_task = None + self.current_task_ret = None + self.high_level_tasks = [] + self.known_points = [] + self.current_points = [] + self.cartesian_destination = None + #self.flange_pos = [None] * 6 + self.cartesian_pos = [None] * 6 + self.joint_pos = [None] * 6 + self.cartesian_motors_enabled = False + self.cartesian_motors = [] + self.joint_motors_enabled = False + self.joint_motors = [] + self.tool = None + self.default_desc = None + self.tool_open = None + #self.tool_trsf = [0.0] * 6 + self.frame = FRAME_DEFAULT + self.polling_interval = 0.01 + self.reset = True + self.default_tolerance = 5 + self.default_speed = 100 + + self.task_start_retries = 3 + self.exception_on_task_start_failure = True #Tasks may start and be finished when checked + + + def doInitialize(self): + super(RobotTCP, self).doInitialize() + self.reset = True + + def set_tool(self, tool): + self.tool = tool + #self.tool_trsf = self.get_tool_trsf() + self.evaluate("tcp_curtool=" + tool) + if self.cartesian_motors_enabled: + self.update() + self.set_motors_enabled(True) + self.is_tool_open() + + def get_tool(self): + return self.tool + + def set_frame(self, frame): + self.frame = frame + self.evaluate("tcp_curframe=" + frame) + if self.cartesian_motors_enabled: + self.update() + self.set_motors_enabled(True) + self.waitCacheChange(5000) + + def get_frame(self): + return self.frame + + def set_default_frame(self): + self.set_frame(FRAME_DEFAULT) + + def assert_tool(self, tool=None): + if tool is None: + if self.tool is None: + raise Exception("Tool is undefined") + elif self.tool != tool: + raise Exception("Invalid tool: " + self.tool) + + def set_default_desc(self,default_desc): + self.default_desc=default_desc + + def get_default_desc(self): + return self.default_desc + + def set_tasks(self,tasks): + self.high_level_tasks=tasks + + def get_tasks(self): + return self.high_level_tasks + + def set_known_points(self, points): + self.known_points=points + + def get_known_points(self): + return self.known_points + + def get_current_points(self, tolerance = None): + ret = self.is_in_points(*self.known_points, tolerance = tolerance) + current_points = [] + for i in range(len(ret)): + if ret[i] == True: + current_points.append(self.known_points[i]) + return current_points + + def get_current_point(self, tolerance = None): + current_points = self.get_current_points(tolerance) + if (current_points is not None) and ( len(current_points) >0): + return current_points[0] + return None + + def get_current_points_cached(self): + return self.current_points + + def get_current_point_cached(self): + if (self.current_points is not None) and (len (self.current_points) >0): + return self.current_points[0] + return None + + def assert_in_known_point(self, tolerance = None): + if self.get_current_point(tolerance) is None: + raise Exception ("Robot not in known point") + + def _sendReceive(self, msg_id, msg = "", timeout = None): + tx = self.header if (self.header != None) else "" + tx = tx + msg_id + " " + msg + if (len(tx)>150): + raise Exception("Exceeded maximum message size") + self.getLogger().finer("TX = '" + str(tx)+ "'") + if (self.trailer != None): tx = tx + self.trailer + if self.isSimulated(): + return "" + rx = self.sendReceive(tx, msg_id, self.trailer , 0, self.timeout if timeout is None else timeout, self.retries) + rx=rx[:-1] #Remove 0A + self.getLogger().finer("RX = '" + str(rx) + "'") + if rx[:3] != msg_id: + if (time.time()-start) >= timeout: + raise Exception("Received invalid message id: " + str(rx[:3]) + " - expecting:" + msg_id ) + if len(rx)<4: + raise Exception("Invalid message size: " + str(len(rx)) ) + if rx[3] == "*": + raise Exception(rx[4:]) + return rx[4:] + + def call(self, msg, timeout = None): + self.lock.acquire() + try: + id = "%03d" % self.msg_id + self.msg_id = (self.msg_id+1)%1000 + return self._sendReceive(id, msg, timeout) + finally: + self.lock.release() + + def execute(self, command, *args, **kwargs): + timeout = None if (kwargs is None) or (not kwargs.has_key("timeout")) else kwargs["timeout"] + msg = str(command) + if len(args)>MAX_NUMBER_PARAMETERS: + raise Exception("Exceeded maximum number of parameters") + for i in range(len(args)): + msg += (self.cmd_separator if (i==0) else self.array_separator) + str(args[i]) + rx = self.call(msg, timeout) + if rx.count(self.array_separator)>0: + return rx.split(self.array_separator) + return rx + + def evaluate(self, cmd, timeout=None): + ret = self.execute('eval', cmd, timeout=timeout) + if is_string(ret): + if ret.strip() != "": raise Exception(ret) + + def get_var(self, name): + return self.execute('get_var', name) + + #Makes app crash + #def get_str(self, name='s'): + # return self.execute('get_str', name) + + def get_arr(self, name, size): + return self.execute('get_arr', name, size) + + def get_bool(self, name = "tcp_b"): + return True if (self.execute('get_bool', name).strip() == '1') else False + + def get_int(self, name ="tcp_n"): + return int(self.get_var(name)) + + def get_float(self, name ="tcp_n"): + return float(self.get_var(name)) + + def get_int_arr(self, size, name="tcp_a"): + # not working. A Jython bug in PyUnicaode? + #return [int(x) for x in self.get_arr("tcp_a", size)] + ret = [] + a=self.get_arr(name, size) + for i in range(size): + ret.append(int(a[i])) + return ret + + def get_float_arr(self, size, name="tcp_a"): + #return [float(x) for x in self.get_arr("tcp_a", size)] + a=self.get_arr(name, size) + ret = []; + for i in range(size): ret.append(float(a[i])); + return ret + + def get_trsf(self, name="tcp_t"): + a = self.execute('get_trf', name) + ret = [] + for i in range(6): ret.append(float(a[i])) + return ret + + def set_trsf(self, l, name="tcp_t"): + self.evaluate(name + "={" + str(l[0]) + ","+ str(l[1]) + ","+ str(l[2]) + ","+ str(l[3]) + ","+ str(l[4]) + ","+ str(l[5]) + "}") + + def get_jnt(self, name="tcp_j"): + a = self.execute('get_jnt', name) + ret = [] + for i in range(6): ret.append(float(a[i])) + return ret + + def set_jnt(self, l, name="tcp_j"): + self.evaluate(name + "={" + str(l[0]) + ","+ str(l[1]) + ","+ str(l[2]) + ","+ str(l[3]) + ","+ str(l[4]) + ","+ str(l[5]) + "}") + + def get_pnt(self, name="tcp_p"): + #a = self.execute('get_pnt', name) + #ret = [] + #for i in range(6): ret.append(float(a[i])) + #return ret + return self.get_trsf(name+".trsf") + + #trsf = (x,y,z,rx,ry,rz) + #TODO: config = (shoulder, elbow, wrist) + def set_pnt(self, trsf, name="tcp_p", config=None): + self.set_trsf(trsf, name+".trsf") + + def get_tool_trsf(self, name=None): + if name is None: + self.assert_tool() + name = self.tool + return self.get_trsf(name+".trsf") + + def set_tool_trsf(self, trsf, name=None): + if name is None: + self.assert_tool() + name = self.tool + self.set_trsf(trsf, name+".trsf") + + def eval_int(self, cmd): + if self.isSimulated(): + return 0 + self.evaluate("tcp_n=" + cmd) + return self.get_int() + + def eval_float(self, cmd): + if self.isSimulated(): + return 0.0 + self.evaluate("tcp_n=" + cmd) + return self.get_float() + + def eval_bool(self, cmd): + if self.isSimulated(): + return False + self.evaluate("tcp_b=" + cmd) + return self.get_bool() + + #def eval_str(self, cmd): + # self.evaluate("s=" + cmd) + # return self.get_str() + + def eval_jnt(self, cmd): + self.evaluate("tcp_j=" + cmd) + return self.get_jnt() + + def eval_trf(self, cmd): + self.evaluate("tcp_t=" + cmd) + return self.get_trsf() + + def eval_pnt(self, cmd): + self.evaluate("tcp_p=" + cmd) + return self.get_pnt() + + + #Robot control + def is_powered(self): + self.powered = self.eval_bool("isPowered()") + return self.powered + + def enable(self): + if not self.is_powered(): + self.evaluate("enablePower()") + time.sleep(1.0) + if not self.is_powered(): + raise Exception("Cannot enable power") + + #waits for power to be actually cut off + def disable(self): + self.evaluate("disablePower()", timeout=5000) + + def get_monitor_speed(self): + self.speed = self.eval_int("getMonitorSpeed()") + return self.speed + + def set_monitor_speed(self, speed): + ret = self.eval_int("setMonitorSpeed(" + str(speed) + ")") + if (ret==-1): raise Exception("The robot is not in remote working mode") + if (ret==-2): raise Exception("The monitor speed is under the control of the operator") + if (ret==-3): raise Exception("The specified speed is not supported") + + def set_default_speed(self): + set_monitor_speed(self.default_speed) + + def is_calibrated(self): + return self.eval_bool("isCalibrated()") + + def save_program(self): + ret = self.execute('save', timeout=5000) + if str(ret) != "0": raise Exception("Error saving program: " + str(ret)) + + def _update_working_mode(self, mode, status): + cur_mode = self.working_mode + if mode==1: + self.working_mode = "manual" + self.status = "hold" if status==6 else "move" + elif mode==2: + self.working_mode = "test" + self.status = "hold" if status==3 else "move" + elif mode==3: + self.working_mode = "local" + self.status = "hold" if status==2 else "move" + elif mode==4: + self.working_mode = "remote" + self.status = "hold" if status==2 else "move" + else: + self.working_mode = "invalid" + self.status = "invalid" + if self.working_mode != cur_mode: + try: + self.on_change_working_mode(self.working_mode) + except: + pass + + def read_working_mode(self): + try: + mode = self.eval_int("workingMode(tcp_a)") + status = int(self.get_var("tcp_a[0]")) + self._update_working_mode(mode, status) + self._update_state() + except: + self.working_mode = "invalid" + self.status = "invalid" + return self.working_mode + + def get_emergency_stop_sts(self): + st = self.eval_int("esStatus()") + if (st== 1): return "active" + if (st== 2): return "activated" + return "off" + + def get_safety_fault_signal(self): + fault = self.eval_bool("safetyFault(s)") + #if (fault): + # return get_str() + return fault + + #Motion control + def stop(self): + self.evaluate("stopMove()") + + def resume(self): + self.evaluate("restartMove()") + + def reset_motion(self, joint=None): + self.evaluate("resetMotion()" if (joint is None) else ("resetMotion(" + joint + ")")) + + def is_empty(self): + self.empty = self.eval_bool("isEmpty()") + self._update_state() + return self.empty + + def is_settled(self): + self.settled = self.eval_bool("isSettled()") + self._update_state() + return self.settled + + def get_move_id(self): + return self.eval_int("getMoveId()") + + def set_move_id(self, id): + return self.evaluate("setMoveId(" + str(id) + " )") + + def get_joint_forces(self): + try: + self.evaluate("getJointForce(tcp_a)") + self.joint_forces = self.get_float_arr(6) + return self.joint_forces + except: + self.joint_forces = None + raise + + def movej(self, joint_or_point, tool=None, desc=None, sync=False): + if desc is None: desc = self.default_desc + if tool is None: tool = self.tool + #If joint_or_point is a list assumes ir is a point + if not is_string(joint_or_point): + robot.set_pnt(joint_or_point , "tcp_p") + joint_or_point = "tcp_p" + ret = self.eval_int("movej(" + joint_or_point + ", " + tool + ", " + desc +")") + if sync: + self.wait_end_of_move() + return ret + + def movel(self, point, tool=None, desc=None, sync=False): + if desc is None: desc = self.default_desc + if tool is None: tool = self.tool + if not is_string(point): + robot.set_pnt(point , "tcp_p") + point = "tcp_p" + ret = self.eval_int("movel(" + point + ", " + tool + ", " + desc +")") + if sync: + self.wait_end_of_move() + return ret + + def movec(self, point_interm, point_target, tool=None, desc=None, sync=False): + if desc is None: desc = self.default_desc + if tool is None: tool = self.tool + ret = self.eval_int("movec(" + point_interm + ", " + point_target + ", " + tool + ", " + desc +")") + if sync: + self.wait_end_of_move() + return ret + + def wait_end_of_move(self): + time.sleep(0.05) + self.update() + #time.sleep(0.01) + #self.waitCacheChange(-1) + self.waitReady(-1) + #self.waitState(State.Ready, -1) + + + #Tool - synchronized as can freeze communication + """ + def open_tool(self, tool=None, timeout=3000): + #This function can timeout since it synchronizes move. Checking state before otherwise it can freeze the communication. + self.waitState(State.Ready, -1) + if tool is None: tool = self.tool + return self.evaluate("open(" + tool + " )", timeout=timeout) + + def close_tool(self, tool=None, timeout=3000): + #This function can timeout since it synchronizes move. Checking state before otherwise it can freeze the communication. + self.waitState(State.Ready, -1) + if tool is None: tool = self.tool + return self.evaluate("close(" + tool + " )", timeout=timeout) + """ + #Tool - Not synchronized calls: atention to open/close only when state is Ready + def open_tool(self, tool=None): + if tool is None: tool = self.tool + self.evaluate(tool + ".gripper=true") + self.tool_open = True + + def close_tool(self, tool=None): + if tool is None: tool = self.tool + self.evaluate(tool + ".gripper=false") + self.tool_open = False + + def is_tool_open(self, tool=None): + if tool is None: tool = self.tool + self.tool_open = robot.eval_bool(tool + ".gripper") + return self.tool_open + + + #Arm position + def herej(self): + return self.eval_jnt("herej()") + + def distance_t(self, trsf1, trsf2): + return self.eval_float("distance(" + trsf1 + ", " + trsf2 + ")") + + def distance_p(self, pnt1, pnt2): + return self.eval_float("distance(" + pnt1 + ", " + pnt2 + ")") + + def compose(self, pnt, frame = None, trsf = "tcp_t"): + if frame is None: frame = self.frame + return self.eval_pnt("compose(" + pnt + ", " + frame + ", " + trsf + ")") + + def here(self, tool=None, frame=None): + if tool is None: tool = self.tool + if frame is None: frame = self.frame + return self.eval_pnt("here(" + tool + ", " + frame + ")") + + def joint_to_point(self, tool=None, frame=None, joint="tcp_j"): + if tool is None: tool = self.tool + if frame is None: frame = self.frame + return self.eval_pnt("jointToPoint(" + tool + ", " + frame + ", " + joint +")") + + def point_to_joint(self, tool=None, initial_joint="tcp_j", point="tcp_p"): + if tool is None: tool = self.tool + if self.eval_bool("pointToJoint(" + tool + ", " + initial_joint + ", " + point +", j)"): + return self.get_jnt() + + def position(self, point, frame=None): + if frame is None: frame = self.frame + return self.eval_trf("position(" + point + ", " + frame + ")") + + #Profile + def get_profile(self): + return self.execute('get_profile', timeout=2000) + + def set_profile(self, name, pwd = ""): + self.execute('set_profile', str(name), str(pwd), timeout=5000) + + + #Task control + def task_create(self, program, *args, **kwargs): + program = str(program) + priority = 10 if (kwargs is None) or (not kwargs.has_key("priority")) or (kwargs["priority"] is None) else kwargs["priority"] + name = str(program if (kwargs is None) or (not kwargs.has_key("name")) else kwargs["name"]) + + if self.get_task_status(name)[0] != -1: + raise Exception("Task already exists: " + name) + + #taskCreate "t1", 10, read(sMessage) + cmd = 'taskCreate "' + name + '", ' + str(priority) + ', ' + program + '(' + for i in range(len(args)): + val = args[i] + if type(val) == bool: + if val == True: val = "true" + elif val == False: val = "false" + cmd += str(val) + (',' if (i<(len(args)-1)) else '') + cmd+=')' + self.evaluate(cmd) + + def task_suspend(self, name): + self.evaluate('taskSuspend("' + str(name)+ '")') + + #waits until the task is ready for restart + def task_resume(self, name): + self.evaluate('taskResume("' + str(name)+ '",0)', timeout = 2000) + + #waits for the task to be actually killed + def task_kill(self, name): + #self.evaluate('taskKill("' + str(name)+ '")', timeout = 5000) + self.execute('kill', str(name), timeout=5000) + + def get_task_status(self, name): + if self.isSimulated(): + return (-1,"Stopped") + code = self.eval_int('taskStatus("' + str(name)+ '")') + #TODO: String assignments in $exec causes application to freeze + #status = self + if code== -1: status = "Stopped" + elif code== 0: status = "Paused" + elif code== 1: status = "Running" + #else: status = self.execute('get_help', code) + else: status = "Error" + return (code,status) + + def get_tasks_status(self, *pars): + ret = self.execute("task_sts", *pars) + ret = ret[0:len(pars)] + for i in range(len(ret)): + try: + ret[i] = int(ret[i]) + except: + ret[i] = None + return ret + + def _update_state(self): + #self.setState(State.Busy if self.status=="move" else State.Ready) + if self.state==State.Offline: + print "Communication resumed" + if self.reset or (self.state==State.Offline): + self.check_task() + if self.current_task is not None: + print "Ongoing task: " + self.current_task + if (not self.settled) or (self.current_task is not None): self.setState(State.Busy) + elif not self.empty: self.setState(State.Paused) + else: self.setState(State.Ready) + + def doUpdate(self): + try: + start = time.time() + cur_task = self.current_task #Can change in background so cache it + if self.isSimulated(): + sts = [1, 1,"1", 100, "1", "1", 0, 0, \ + 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, \ + ] + else: + sts = self.execute("get_status", cur_task) + self._update_working_mode(int(sts[0]), int(sts[1])) + self.powered = sts[2] == "1" + self.speed = int(sts[3]) + self.empty = sts[4] == "1" + self.settled = sts[5] == "1" + + #TODO: add tool open + if cur_task is not None: + if int(sts[6]) < 0: + log("Task "+ str(cur_task) + " finished with code: " + str(sts[7]), False) + try: + self.current_task, self.current_task_ret = None, int(sts[7]) + except: + self.current_task, self.current_task_ret = None, None + for i in range(6): + self.joint_pos[i] = float(sts[8 + i]) + for i in range(6): + self.cartesian_pos[i] = float(sts[14 + i]) + + ev_index = 20 #7 + ev = sts[ev_index] if len(sts)>ev_index else "" + if len(ev.strip()) >0: + self.getLogger().info(ev) + self.on_event(ev) + + self._update_state() + self.reset = False + self.setCache({"powered": self.powered, + "speed": self.speed, + "empty": self.empty, + "settled": self.settled, + "task": cur_task, + "mode": self.working_mode, + "status": self.status, + "open": self.tool_open, + "pos": self.get_current_point_cached() if self.state==State.Ready else None #TODO: make it calculated in robot by polling funtion + }, None) + + if self.cartesian_motors_enabled: + for m in self.cartesian_motors: + m.readback.update() + + if self.joint_motors_enabled: + for m in self.joint_motors: + m.readback.update() + + except: + if self.state != State.Offline: + print >> sys.stderr, "Update error: " + str(sys.exc_info()[1]) + self.setState(State.Offline) + + #Cartesian space + def get_flange_pos(self): + return self.eval_pnt("jointToPoint(" +FLANGE + ", " + self.frame + ", herej())") + + def get_cartesian_pos(self): + self.assert_tool() + return self.eval_pnt("jointToPoint(" + self.tool + ", " + self.frame + ", herej())") + #self.set_jnt(self.herej()) + #return self.joint_to_point(tool, frame) + + def get_cartesian_destination(self): + self.assert_tool() + return self.here(self.tool, self.frame) + + def get_distance_to_pnt(self, name): + #self.here(self.tool, self.frame) #??? + self.get_cartesian_pos() + return self.distance_p("tcp_p", name) + + def is_in_point(self, p, tolerance = None): #Tolerance in mm + if (tolerance is None) and p in self.known_points: + #If checking a known point with default tolerance, updates the position cache + return p in self.get_current_points() + tolerance = self.default_tolerance if tolerance == None else tolerance + d = self.get_distance_to_pnt(p) + if d<0: + raise Exception ("Error calculating distance to " + p + " : " + str(d)) + return d<tolerance + + def get_distance_to_pnts(self, *pars): + ret = self.execute("dist_pnt", *pars) + ret = ret[0:len(pars)] + for i in range(len(ret)): + try: + ret[i] = float(ret[i]) + except: + ret[i] = None + return ret + + def is_in_points(self, *pars, **kwargs): #Tolerance in mm + tolerance = self.default_tolerance if (kwargs is None) or (not kwargs.has_key("tolerance")) or (kwargs["tolerance"] is None) else kwargs["tolerance"] + ret = self.get_distance_to_pnts(*pars) + for i in range(len(ret)): + if ret[i]<0: + ret[i] = None + else: + ret[i] = ret[i]<tolerance + if (tolerance == self.default_tolerance) and (set(self.known_points).issubset(set(pars))): #Only update cache if tolerance is default + current_points = [] + for i in range(len(ret)): + if ret[i] == True: + current_points.append(self.known_points[i]) + self.current_points = current_points + return ret + + def assert_in_point(self, p, tolerance = None): #Tolerance in mm + if not self.is_in_point(p, tolerance): + raise Exception ("Not in position " + p) + + + #Cartesian peudo-motors + def set_motors_enabled(self, value): + if value !=self.cartesian_motors_enabled: + self.cartesian_motors_enabled = value + if value: + for i in range(6): + self.cartesian_motors.append(RobotCartesianMotor(self, i)) + add_device(self.cartesian_motors[i], True) + self.cartesian_destination = self.get_cartesian_destination() + else: + for m in self.cartesian_motors: + remove_device(m) + self.cartesian_motors = [] + self.cartesian_destination = None + else: + if value: + self.cartesian_destination = self.get_cartesian_destination() + for m in self.cartesian_motors: + m.initialize() + + + #Cartesian peudo-motors + def set_joint_motors_enabled(self, value): + if value !=self.joint_motors_enabled: + self.joint_motors_enabled = value + if value: + for i in range(6): + self.joint_motors.append(RobotJointMotor(self, i)) + add_device(self.joint_motors[i], True) + else: + for m in self.joint_motors: + remove_device(m) + self.joint_motors = [] + else: + if value: + for m in self.joint_motors: + m.initialize() + #Alignment + def align(self, point = None, frame = None, desc = None): + if frame is None: frame = self.frame + self.assert_tool() + if desc is None: desc = self.default_desc + if point is None: + self.get_cartesian_pos() + else: + self.set_pnt(point) + np=self.eval_trf('align(tcp_p.trsf, ' + frame + '.trsf)') + self.set_pnt(np) + self.movej("tcp_p", self.tool, desc) + #TODO: The first command is not executed (but receive a move id) + self.movej("tcp_p", self.tool, desc, sync = True) + return np + + #High-level, exclusive motion task. + def start_task(self, program, *args, **kwargs): + tasks = [t for t in self.high_level_tasks] + if (self.current_task is not None) and (not self.current_task in tasks): + tasks.append(self.current_task) + if not program in tasks: + tasks.append(program) + #for task in tasks: + # if self.get_task_status(task)[0]>=0: + # raise Exception("Ongoing high-level task: " + task) + ts = self.get_tasks_status(*tasks) + for i in range(len(ts)): + if ts[i] > 0: + raise Exception("Ongoing high-level task: " + tasks[i]) + + self.clear_task_ret() + + for i in range(self.task_start_retries): + self.task_create(program, *args, **kwargs) + (code, status) = self.get_task_status(program) + if code>=0: break + if i < self.task_start_retries-1: + ret = self.get_task_ret(False) + if ret == 0: #Did't start + log("Retrying starting : " + str(program) + str(args) + " - status: " + str(status) + " (" + str(code) + ")", False) + print "Retrying starting : " + str(program) + str(args) + " - status: " + str(status) + " (" + str(code) + ")" + else : + print "Retrying aborted : " + str(program) + str(args) + " - ret: " + str(ret) + " - status: " + str(status) + " (" + str(code) + ")" + break + else: + log("Failed starting : " + str(program) + str(args), False) + print "Failed starting : " + str(program) + str(args) + if self.exception_on_task_start_failure: + raise Exception("Cannot start task: " + program + str(args)) + + log("Task started: " + str(program) + str(args) + " - status: " + str(status) + " (" + str(code) + ")", False) + self.current_task, self.current_task_ret = program, None + self.update() + #self._update_state() + + #TODO: remove + if self.current_task is None: + log("Task finished in first polling : " + str(program) , False) + print "Task finished in first polling : " + str(program) + + return code + + def stop_task(self): + tasks = [t for t in self.high_level_tasks] + if (self.current_task is not None) and (not self.current_task in tasks): + tasks.append(self.current_task) + for task in tasks: + #if self.get_task_status(task)[0]>=0: + self.task_kill(task) + self.reset_motion() + + def get_task_ret(self, cached = True): + return self.current_task_ret if cached else self.eval_int("tcp_ret") + + def clear_task_ret(self): + return self.evaluate("tcp_ret=0") + + def get_task(self): + return self.current_task + + def check_task(self): + if self.current_task is None: + for task in self.high_level_tasks: + if self.get_task_status(task)[0]>=0: + self.current_task, self.current_task_ret = task, None + log("Task detected: " + str(self.current_task), False) + return self.current_task + + def wait_task_finished (self, polling = None): + cur_polling = self.polling + if polling is not None: + self.polling = polling + try: + while self.get_task() != None: + time.sleep(self.polling_interval) + finally: + if polling is not None: + self.polling = cur_polling + ret = self.get_task_ret() + return ret + + def assert_no_task(self): + task = self.check_task() + if task != None: + raise Exception("Ongoing task: " + task) + + def on_event(self,ev): + pass + + def on_change_working_mode(self, working_mode): + pass + \ No newline at end of file diff --git a/script/devices/SmartMagnet.py b/script/devices/SmartMagnet.py new file mode 100644 index 0000000..29e70b7 --- /dev/null +++ b/script/devices/SmartMagnet.py @@ -0,0 +1,122 @@ +class SmartMagnet(DeviceBase): + def __init__(self, name): + #DeviceBase.__init__(self, name, get_context().pluginManager.getDynamicClass("SmartMagnetConfig")()) + DeviceBase.__init__(self, name, DeviceConfig({ + "holdingCurrent":0.0, + "restingCurrent":0.0, + "mountCurrent":0.0, + "unmountCurrent":0.0, + "reverseCurrent":0.0, + "reverseTime":0.0, + })) + + def doInitialize(self): + super(SmartMagnet, self).doInitialize() + self.get_current() + + def set_current(self, current): + self.setCache(current, None) + smc_current.write(current) + + def get_current(self): + cur = smc_current.read() + self.setCache(cur, None) + return cur + + def get_current_rb(self): + self.assert_status() + return smc_current_rb.read() + + def get_status(self): + return smc_magnet_status.read() + + def assert_status(self): + if self.get_status() == False: + raise Exception("Smart Magnet is in faulty status.") + + def is_mounted(self): + self.assert_status() + m1 = smc_mounted_1.read() + m2 = smc_mounted_2.read() + if m2==m1: + raise Exception("Smart Magnet has invalid detection.") + return m2 + + def set_supress(self, value): + smc_sup_det.write(value) + + def get_supress(self): + return smc_sup_det.read() + + def check_mounted(self, idle_time =1.0, timeout = -1, interval = 0.01): + self.assert_status() + start = time.time() + last = None + while True: + try: + det = self.is_mounted() + except: + det = None + if det != last: + settling_timestamp = time.time() + last = det + else: + if det is not None: + if (time.time()-settling_timestamp > idle_time): + return det + if timeout >= 0: + if (time.time() - start) > timeout: + raise Exception("Timeout waiting for Smart Magnet detection.") + time.sleep(interval) + + + def doUpdate(self): + try: + if self.is_mounted(): + self.setState(State.Busy) + else: + self.setState(State.Ready) + except: + self.setState(State.Fault) + + def set_holding_current(self): + self.set_current(self.config.getFieldValue("holdingCurrent")) + + def set_resting_current(self): + self.set_current(self.config.getFieldValue("restingCurrent")) + + def set_mount_current(self): + self.set_current(self.config.getFieldValue("mountCurrent")) + + def set_unmount_current(self): + self.set_current(self.config.getFieldValue("unmountCurrent")) + + def set_reverse_current(self): + self.set_current(self.config.getFieldValue("reverseCurrent")) + + def set_default_current(self): + if self.is_mounted(): + self.set_holding_current() + else: + self.set_resting_current() + + def is_resting_current(self): + return self.get_current() == self.config.getFieldValue("restingCurrent") + + + #Setting resting current to better detect sample + def enforce_sample_detection(self): + reverse_wait = float(self.config.getFieldValue("reverseTime")) + if reverse_wait >0: + self.set_reverse_current() + time.sleep(reverse_wait) + if not self.is_resting_current(): + self.set_resting_current() + time.sleep(0.2) + + +add_device(SmartMagnet("smart_magnet"), force = True) + +smart_magnet.polling = 1000 + +smart_magnet.set_default_current() diff --git a/script/devices/Wago.py b/script/devices/Wago.py new file mode 100644 index 0000000..1ce7931 --- /dev/null +++ b/script/devices/Wago.py @@ -0,0 +1,172 @@ +LED_LEVEL_ROOM_TEMPERATURE = 0.4 +LED_LEVEL_LN2 = 1.0 + + +""" +wago=ch.psi.pshell.modbus.ModbusTCP|wago-mxsc-1:502||| +relays=ch.psi.pshell.modbus.DigitalOutputArray|wago 0 16||1000| +release_local_safety=ch.psi.pshell.modbus.DigitalOutput|wago 0||| +release_psys_safety=ch.psi.pshell.modbus.DigitalOutput|wago 1||| +ln2_main_power=ch.psi.pshell.modbus.DigitalOutput|wago 2||| +rim_heater=ch.psi.pshell.modbus.DigitalOutput|wago 3||| +phase_separator_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 4||| +dewar_ln2=ch.psi.pshell.modbus.DigitalOutput|wago 5|||false +valve_he_chamber=ch.psi.pshell.modbus.DigitalOutput|wago 6||| +gripper_dryer=ch.psi.pshell.modbus.DigitalOutput|wago 7||| +valve_1=ch.psi.pshell.modbus.DigitalOutput|wago 8||| +valve_2=ch.psi.pshell.modbus.DigitalOutput|wago 9||| +valve_3=ch.psi.pshell.modbus.DigitalOutput|wago 10||| +valve_4=ch.psi.pshell.modbus.DigitalOutput|wago 11||| +#spare_do_1=ch.psi.pshell.modbus.DigitalOutput|wago 12||| +#spare_do_2=ch.psi.pshell.modbus.DigitalOutput|wago 13||| +#spare_do_3=ch.psi.pshell.modbus.DigitalOutput|wago 14||| +#spare_do_4=ch.psi.pshell.modbus.DigitalOutput|wago 15||| +phase_separator_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 0||1000| +dewar_level=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 1||1000| +rim_heater_temp=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 2||1000| +air_pressure=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 3||1000| +n2_pressure=ch.psi.pshell.modbus.ReadonlyProcessVariable|wago 4||1000| +#spare_ai_1=ch.psi.pshell.modbus.AnalogInput|wago 5||| +#spare_ai_2=ch.psi.pshell.modbus.AnalogInput|wago 6||| +#spare_ai_3=ch.psi.pshell.modbus.AnalogInput|wago 7||| +led_ctrl_1=ch.psi.pshell.modbus.ProcessVariable|wago 0||| +led_ctrl_2=ch.psi.pshell.modbus.ProcessVariable|wago 1||| +led_ctrl_3=ch.psi.pshell.modbus.ProcessVariable|wago 2||| +""" +################################################################################################### +# Leds +################################################################################################### + +def set_led_level(level): + level = max(min(float(level),100.0),0.0) + set_setting("led_level", level) + led_ctrl_1.write(led_ctrl_1.config.maxValue * level / 100.0) + led_ctrl_2.write(led_ctrl_2.config.maxValue * level / 100.0) + led_ctrl_3.write(led_ctrl_3.config.maxValue * level / 100.0) + +def get_led_level(): + level = get_setting("led_level") + return float(0 if level is None else level) + +def set_led_state(value): + """ + Turn leds on and off + """ + if value: + set_led_level(100.0) + else: + set_led_level(0.0) + +def get_led_state(): + """ + Returns led state (on/off) + """ + return led_ctrl_1.read() > 0 + +#TODO: The range should be set automatically reading LN2 sensor. +def set_led_range(room_temp = True): + """ + Led range should be limitted in room temperature + """ + max_val = LED_LEVEL_ROOM_TEMPERATURE if room_temp else LED_LEVEL_LN2 + led_ctrl_1.config.maxValue = max_val + led_ctrl_1.config.save() + led_ctrl_2.config.maxValue = max_val + led_ctrl_2.config.save() + led_ctrl_3.config.maxValue = max_val + led_ctrl_3.config.save() + led_ctrl_1.initialize() + led_ctrl_2.initialize() + led_ctrl_3.initialize() + if led_ctrl_1.read() > max_val: + led_ctrl_1.write(max_val) + if led_ctrl_2.read() > max_val: + led_ctrl_2.write(max_val) + if led_ctrl_3.read() > max_val: + led_ctrl_3.write(max_val) + set_led_level(get_led_level()) + + +def is_led_room_temp(): + return led_ctrl_1.config.maxValue <= LED_LEVEL_ROOM_TEMPERATURE + + + + +################################################################################################### +# Safety release +################################################################################################### + +def release_local(): + """ + Release local safety + """ + release_local_safety.write(False) + time.sleep(0.01) + release_local_safety.write(True) + time.sleep(0.01) + release_local_safety.write(False) + +def release_psys(): + """ + Release psys safety + """ + if is_manual_mode(): + raise Exception ("Cannot release PSYS in manual mode") + release_psys_safety.write(False) + time.sleep(0.01) + release_psys_safety.write(True) + time.sleep(0.01) + release_psys_safety.write(False) + + + +################################################################################################### +# Drier +################################################################################################### +MAX_HEATER_TIME = 60000 + +def set_air_stream(state): + """ + """ + valve_1.write(state) + valve_2.write(not state) + + +set_heater_chrono = None + +def monitor_heater_time(): + time.sleep(0.5) + try: + while get_heater(): + if set_heater_chrono.isTimeout(MAX_HEATER_TIME): + set_heater(False) + log("Heater timeout expired: turned off", False) + return + time.sleep(0.1) + except: + print sys.exc_info() + + +def get_heater(): + """ + """ + return gripper_dryer.read() + + +def set_heater(state): + """ + """ + global set_heater_chrono + if get_heater() != state: + gripper_dryer.write(state) + if state: + set_heater_chrono = Chrono() + fork(monitor_heater_time) + + +def get_air_stream(): + """ + """ + return valve_1.read() + diff --git a/script/hexiposi_positon.scd b/script/hexiposi_positon.scd new file mode 100644 index 0000000..471fb41 --- /dev/null +++ b/script/hexiposi_positon.scd @@ -0,0 +1,11 @@ +[ + [ [ true, "hexiposi_position", "Device", 1, 1, null ] ], + [ [ "1", null, null, null, null, null, null, null ], + [ "2", null, null, null, null, null, null, null ], + [ "3", null, null, null, null, null, null, null ], + [ "4", null, null, null, null, null, null, null ], + [ "5", null, null, null, null, null, null, null ] ], + [ [ ] ], + [ [ "", 1000, 100 ], + [ "", "" ] ] +] \ No newline at end of file diff --git a/script/imgproc/CameraCalibration.py b/script/imgproc/CameraCalibration.py new file mode 100644 index 0000000..07b123c --- /dev/null +++ b/script/imgproc/CameraCalibration.py @@ -0,0 +1,155 @@ +import ch.psi.pshell.device.Camera as Camera +import ch.psi.pshell.imaging.RendererMode as RendererMode +import ch.psi.pshell.imaging.Calibration as Calibration +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.utils.swing.SwingUtils as SwingUtils +import javax.swing.SwingUtilities as SwingUtilities +from swingutils.threads.swing import callSwing +#SIMULATION = ch.psi.pshell.imaging.FileSource +""" +img.camera.setColorMode(Camera.ColorMode.Mono) +img.camera.setDataType(Camera.DataType.UInt8) +img.camera.setGrabMode(Camera.GrabMode.Continuous) +img.camera.setTriggerMode(Camera.TriggerMode.Fixed_Rate) +img.camera.setExposure(50.00) +img.camera.setAcquirePeriod(200.00) +img.camera.setGain(0.0) +img.config.rotationCrop=True +""" + +MOVE_HEXIPOSI = True +ROTATION_OFFSET = 180.0 + +if MOVE_HEXIPOSI: + release_safety() #enable_motion() + +sensor_width,sensor_height = img.camera.getSensorSize() +img.camera.setROI(0, 0,sensor_width, sensor_height) +img.config.rotation=0 +img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight =0,0,-1,-1 +img.config.setCalibration(None) +img.camera.stop() +img.camera.start() + + +p = show_panel(img) +dlg = SwingUtilities.getWindowAncestor(p) +dlg.setSize(800,800) +frm=SwingUtils.getFrame(p) +dlg.setLocationRelativeTo(frm) + +p.setMode(RendererMode.Fit) +ov_text = Text(Pen(java.awt.Color.GREEN.darker()), "", java.awt.Font("Verdana", java.awt.Font.PLAIN, 24), java.awt.Point(20,20)) +ov_text.setFixed(True) +p.addOverlay(ov_text) + + +try: + #Find image center and Prosilica ROI + ov_text.update("Click on the center of the Dewar...") + p.refresh() + dc = p.waitClick(60000) + print dc + width, height = min(dc.x, sensor_width-dc.x)*2, min(dc.y, sensor_height-dc.y)*2 + width, height = width - width%16, height - height%16 + width, height = min(width,1000), min(height,1000) + print width, height + roi_x = int(dc.x- width/2) + roi_y = int(dc.y- height/2) + roi_w = int(width) + roi_h = int(height) + set_setting("roi_x", roi_x) + set_setting("roi_y", roi_y) + set_setting("roi_w", roi_w) + set_setting("roi_h", roi_h) + img.camera.setROI(roi_x, roi_y, width, height) +except: + img.camera.setROI(int(get_setting("roi_x")), int(get_setting("roi_y")), int(get_setting("roi_w")), int(get_setting("roi_h"))) +finally: + img.camera.stop() + img.camera.start() + + +#Configure source +CC4 = (-129.9, -150) +CD5 = (129.9, -150) +CA5 = (-129.9, 150) +CF4 = (129.9, 150) + +DX = 259.8 +DY = 300.0 + +ROI_X = 470.0 +ROI_Y = 470.0 + +def rotate(x,y, degrees): + rotation = math.radians(degrees) + rw, rh = img.getImage().getWidth(), img.getImage().getHeight() + ox, oy = x - (rw / 2), y - (rh / 2) + x = ox * math.cos(rotation) - oy * math.sin(rotation) + rw / 2; + y = oy * math.cos(rotation) + ox * math.sin(rotation) + rh / 2; + return x,y + + +set_led_state(True) +try: + if MOVE_HEXIPOSI: set_hexiposi("C") + ov_text.update("Click on the center of C4 (19) position...") + p.refresh() + pc4 = p.waitClick(60000) + print pc4 + if MOVE_HEXIPOSI: set_hexiposi("D") + ov_text.update("Click on the center of D5 (13) position...") + p.refresh() + pd5 = p.waitClick(60000) + print pd5 + if MOVE_HEXIPOSI: set_hexiposi("F") + ov_text.update("Click on the center of F4 (04) position...") + p.refresh() + pf4 = p.waitClick(60000) + print pf4 + if MOVE_HEXIPOSI: set_hexiposi("A") + ov_text.update("Click on the center of A5 (28) position...") + p.refresh() + pa5 = p.waitClick(60000) + print pa5 + + + vc1x, vc1y, vc2x, vc2y = (pc4.x + pd5.x )/2.0, (pc4.y + pd5.y )/2.0, (pa5.x + pf4.x )/2.0, (pa5.y + pf4.y )/2.0 + hc1x, hc1y, hc2x, hc2y = (pc4.x + pa5.x )/2.0, (pc4.y + pa5.y )/2.0, (pd5.x + pf4.x )/2.0, (pd5.y + pf4.y )/2.0 + cx, cy = (vc1x + vc2x)/2, (hc1y + hc2y)/2 + + a1 = math.degrees(math.atan((cx-vc1x)/(vc1y-cy))) + a2 = math.degrees(math.atan((cx-vc2x)/(vc2y-cy))) + a = (a1+a2)/2 + + + dy = math.hypot(vc2y - vc1y, vc2x - vc1x) + dx = math.hypot(hc2x - hc1x, hc2y - hc1y) + print dy, dx, cx, cy + sx, sy = DX/dx, DY/dy + + + #Rotating center of puck + rcx, rcy = rotate(cx, cy, -a) + + + + roi_w, roi_h = int(ROI_X / sx), int(ROI_Y / sy) + roi_x, roi_y = int(rcx-roi_w/2), int(rcy-roi_h/2) + + print a, sx, sy, roi_w, roi_h + + img.config.rotation=-a + ROTATION_OFFSET + img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight = roi_x, roi_y, roi_w, roi_h + img.config.setCalibration(Calibration(sx, sy, -roi_w/2, -roi_h/2)) + img.config.save() + + set_return ("Success calibrating the camera") + +finally: + set_led_state(False) + p.removeOverlay(ov_text) + img.refresh() + + \ No newline at end of file diff --git a/script/imgproc/CoverDetection.py b/script/imgproc/CoverDetection.py new file mode 100644 index 0000000..904837a --- /dev/null +++ b/script/imgproc/CoverDetection.py @@ -0,0 +1,98 @@ +################################################################################################### +# Procedure to detect the cover orientation +################################################################################################### +assert_imaging_enabled() + + +#Parameters +FRAMES_INTEGRATION = 3 +STEP_SIZE = 2 +POSITION_NAMES = [ 'A','B','C','D', 'E', 'F'] + +#POSITION_ANGLES = [ 330, 30, 90, 150, 210, 270 ] +POSITION_ANGLES = [ 0, 60, 120, 180, 240, 300 ] +POSITION_TOLERANCE = 3 +MINIMUM_CONFIDENCE = 3 +DEBUG = cover_detection_debug +#REFERENCE_IMG = "ref2" +REFERENCE_IMG = "ref1" +BORDER = 7 + +#Load reference image +ref = load_image(str("{images}/cover/" + REFERENCE_IMG + ".png") , title="Line") + +#Pre-process camera image +#ip = load_image("{images}/cover/Cover_000" + str(index) + ".png", title="Img") +ip = integrate_frames(FRAMES_INTEGRATION) +ip = grayscale(ip, True) +smooth(ip) +#bandpass_filter(ip, 30, 1000) +edges(ip) +auto_threshold(ip, method = "MaxEntropy") +#binary_erode(ip, True) +#binary_dilate(ip, True) +ip.getProcessor().erode(1, 255) +cx,cy = int(ip.width/2), int(ip.height/2) +ip = sub_image(ip, cx-ref.width/2, cy-ref.height/2, ref.width, ref.height) + +if BORDER>0: + sip = sub_image(ip, BORDER,BORDER, ref.width-2*BORDER, ref.height-2*BORDER) + ip = pad_image(sip, BORDER, BORDER, BORDER, BORDER, fill_color=Color.WHITE) + +#Show ROI of pre-processed image +if DEBUG: + image_panel = show_panel(ip.bufferedImage) + + +#Calculate correlation between image and reference, rotating the reference from 0 to 360 +import ch.psi.pshell.imaging.Utils.integrateVertically as integrateVertically +ydata = [] +xdata = range (0,360,STEP_SIZE) +for i in xdata: + r = ref.duplicate() + r.getProcessor().setBackgroundValue(0.0) + r.getProcessor().rotate(float(i)) + op = op_fft(r, ip, "correlate") + bi = op.getBufferedImage() + p = integrateVertically(bi) + ydata.append(sum(p)) + + +#Calculate angle of the highest correlation, and confidence level +peaks = estimate_peak_indexes(ydata, xdata, (min(ydata) + max(ydata))/2, 25.0) +peaks_x = map(lambda x:xdata[x], peaks) +peaks_y = map(lambda x:ydata[x], peaks) +if len(peaks_x) > 1: + #remoce close peaks between 350 deg and 10 deg + if ((peaks_x[0]<10) and (peaks_x[1]>350)) or ((peaks_x[1]<10) and (peaks_x[0]>350)): + peaks.pop(1) + peaks_x.pop(1) + peaks_y.pop(1) + + +confidence = None if len(peaks_x)<2 else int(((float(peaks_y[0])/peaks_y[1])-1) * 1000) +angle = (None if len(peaks_x)==0 else peaks_x[0]) + +#From angle and confidence level estimate hexiposi position +position = None +if angle is not None: + for i in range(len(POSITION_NAMES)): + if abs(POSITION_ANGLES[i] - angle) <= POSITION_TOLERANCE: + position = POSITION_NAMES[i] + +#Plot the correlations values agains angle +if DEBUG: + plot(ydata, xdata=xdata) + +#Output results +if DEBUG: + print "Peaks", peaks + print "Peak indexes: " + str(peaks_x) + print "Peak values: " + str(peaks_y) + print "Angle: " , angle + print "Position: " , position + print "Confidence: " , confidence + +#Set return value +set_return ([position, angle, confidence]) + diff --git a/script/imgproc/CoverDetectionCalibration.py b/script/imgproc/CoverDetectionCalibration.py new file mode 100644 index 0000000..36f6a54 --- /dev/null +++ b/script/imgproc/CoverDetectionCalibration.py @@ -0,0 +1,40 @@ +#Parameters +FRAMES_INTEGRATION = 3 +MINIMUM_CONFIDENCE = 10 +DEBUG = cover_detection_debug +REFERENCE_IMG = "ref1" +ERODE_ITERATIONS = 2 + +#Load reference image +SIZE = [128,128] +BORDER = 7 + +hexiposi.move("A") +#Pre-process camera image +#ip = load_image("{images}/cover/Cover_000" + str(index) + ".png", title="Img") +ip = integrate_frames(FRAMES_INTEGRATION) +ip = grayscale(ip, True) +smooth(ip) +#bandpass_filter(ip, 30, 1000) +edges(ip) + +auto_threshold(ip, method = "MaxEntropy") +#binary_dilate(ip, True, 2) +for i in range(ERODE_ITERATIONS): + ip.getProcessor().erode(1, 255) + +cx,cy = int(ip.width/2), int(ip.height/2) +ip = sub_image(ip, cx-SIZE[0]/2, cy-SIZE[1]/2, SIZE[0], SIZE[1]) + +invert(ip) +ip = grayscale(ip, True) +#smooth(ip) + +if BORDER > 0: + sip = sub_image(ip, BORDER,BORDER, SIZE[0]-2*BORDER, SIZE[1]-2*BORDER) + ip = pad_image(sip, BORDER, BORDER, BORDER, BORDER) +if DEBUG: + image_panel = show_panel(ip.bufferedImage) + +save_image(ip, str("{images}/cover/" + REFERENCE_IMG + ".png") ,"png") + \ No newline at end of file diff --git a/script/imgproc/CreateMask.py b/script/imgproc/CreateMask.py new file mode 100644 index 0000000..98b3498 --- /dev/null +++ b/script/imgproc/CreateMask.py @@ -0,0 +1,29 @@ + +mask_img = new_image(img.getOutput().getWidth(), img.getOutput().getHeight(), image_type="byte", title = "mask_img", fill_color = Color.BLACK) + +mask_radius = 14 +mask_points = [] + + +def to_img_coords(absolute_coords): + return [img.getCalibration().convertToImageX(absolute_coords[0]), img.getCalibration().convertToImageY(absolute_coords[1])] + +for p in _puck_list: + mask_points.append(to_img_coords(p.led_mini)) + mask_points.append(to_img_coords(p.led_uni)) + + + +i = mask_img.getBufferedImage() +for p in mask_points: + #i.setRGB(p[0], p[1], 0xFFFFFF) + for x in range (p[0]-mask_radius, p[0]+mask_radius): + for y in range (p[1]-mask_radius, p[1]+mask_radius): + if math.hypot(x-p[0], y-p[1]) <= mask_radius: + i.setRGB(x,y, 0xFFFFFF) + + +mask_img = load_image(i) +#show_panel( mask_img.getBufferedImage()) + +set_return(mask_img) \ No newline at end of file diff --git a/script/imgproc/LedDetectionFilter.py b/script/imgproc/LedDetectionFilter.py new file mode 100644 index 0000000..a4818d8 --- /dev/null +++ b/script/imgproc/LedDetectionFilter.py @@ -0,0 +1,102 @@ +################################################################################################### +# Example of using ImageJ functionalities through ijutils. +################################################################################################### + +import datetime +from ijutils import * +import java.awt.Color as Color + +import ch.psi.pshell.imaging.Filter as Filter +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.pshell.imaging.Pen as Pen + + +integration_count = 10 +integration_continuous = False +integration_partial = False +frames = [] +roi = get_roi() + + +color_roi = Color(0, 128, 0) + +renderer = show_panel(img) +renderer.clearOverlays() +ov_roi_shape = Ellipse(Pen(color_roi, 0,), java.awt.Point(roi[0], roi[1]), java.awt.Dimension(roi[2], roi[3])) +ov_roi_bound = Rect(Pen(color_roi, 0, Pen.LineStyle.dotted), java.awt.Point(roi[0], roi[1]), java.awt.Dimension(roi[2], roi[3])) +ov_roi_center = Crosshairs(Pen(color_roi, 0), java.awt.Point(roi_center[0],roi_center[1]), java.awt.Dimension(15,15)) + +renderer.addOverlays([ov_roi_shape, ov_roi_bound,ov_roi_center]) + + + + +last_ret = (None, None) +def detect_led(ip): + roi = get_roi() + global roi_center, roi_radius, integration_count, integration_continuous, integration_partial, frames + global count , last_ret + aux = sub_image(ip, roi[0], roi[1], roi[2], roi[3]) + grayscale(aux) + #gaussian_blur(aux) + if (integration_count>1): + frames.append(aux) + if len(frames) >integration_count: + del frames[0] + if not integration_continuous: + if (len(frames)< integration_count): + if last_ret[1] is not None: invert(last_ret[1]) + return last_ret + if (not integration_partial) and len(frames) <integration_count: + return last_ret + aux = integrate(frames) + + #aux = get_channel(aux, "blue") + invert(aux) + #subtract_background(aux) + #Tested ok: Huang, Mean, MaxEntropy, Percentile, Triangle, Yen + auto_threshold(aux, method = "Percentile") + #binary_open(aux) + (results,output) = analyse_particles(aux, 250,1000, + fill_holes = True, exclude_edges = False, print_table=False, + output_image = "outlines", minCirc = 0.3 + , maxCirc = 1.0) + r=results + + + points = "" + npoints = 0 + for row in range (r.counter): + if in_roi(r.getValue("XM",row), r.getValue("YM",row)): + points = points + " (" + str(int(r.getValue("XM", row))+roi[0]) + ", " + str(int(r.getValue("YM", row))+roi[1]) + ")" + npoints = npoints + 1 + print str(npoints) + " - " + points + + last_ret = (results,output) + if not integration_continuous: + frames = [] + + #if npoints!=12: + # save_image(op_image(aux, output,"xor", in_place=False), "{images}/" + str(datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))+".png", "png") + #return (results,aux) + return (results,output) + + + + +ip = None + +class MyFilter(Filter): + def process(self, image, data): + global roi_center, roi_radius, ip + ip = load_image(image) + (results,output) = detect_led(ip) + if output is not None: + invert(output) + output = pad_image(output, roi[0], 0,roi[1], 0) + op_image(ip, output, "xor") + return ip.getBufferedImage() + +#Setting the filter to a source +img.setFilter(MyFilter()) + diff --git a/script/imgproc/LedDetectionProc.py b/script/imgproc/LedDetectionProc.py new file mode 100644 index 0000000..c01673d --- /dev/null +++ b/script/imgproc/LedDetectionProc.py @@ -0,0 +1,106 @@ +################################################################################################### +# Procedure to detect the puck light spots. +################################################################################################### +assert_imaging_enabled() + + +COVER_PRESENT = True +ROOM_TEMP = is_room_temp() +USE_MASK = True + +if get_exec_pars().source == CommandSource.ui: + PLOT = None + RENDERER = None + TEXT = None + +if COVER_PRESENT: + cover_position = hexiposi.readback.take() + if (cover_position is None) or (cover_position == "Unknown"): + raise Exception("Unknown cover position") + else: + block_id = cover_position.upper()[0] +else: + block_id = None +print "Block id: ", block_id + + + +number_frames = 5 if ROOM_TEMP else 10 +number_backgrounds = 5 if ROOM_TEMP else 5 +minimum_size = 78 # r = 5 # 150 +maximum_size = 750 # r = 15 #1500 +min_circ = 0.2 + +threshold_method = "MaxEntropy" if ROOM_TEMP else "Default" #Apparently good for LN2: Default, Intermodes, IsoData, Otsu +threshold_method,threshold_range = "Manual", (0, 215) + +exclude_edges = True +led_latency = 0.5 #0.1 + + + +set_led_state(False) +time.sleep(led_latency) +img.waitNext(2000) + +background = average_frames(number_backgrounds) +#background = integrate_frames(number_backgrounds) + +set_led_state(True) +time.sleep(led_latency) +img.waitNext(2000) +image = average_frames(number_frames) +#image = integrate_frames(number_frames) + +set_led_state(False) + +op_image(image, background, "subtract", float_result=True, in_place=True) +image=grayscale(image) + +if RENDERER is not None and RENDERER.isShowing(): + RENDERER.setImage(None, image.getBufferedImage(), None) +else: + RENDERER = show_panel(image.getBufferedImage()) +RENDERER.clearOverlays() + +if USE_MASK: + mask_img = run("imgproc/CreateMask") + #mask_img=grayscale(mask_img) + #show_panel( mask_img.getBufferedImage()) + op_image(image, mask_img, "and", float_result=False, in_place=True) + RENDERER.setImage(None, image.getBufferedImage(), None) + +invert(image) +if threshold_method == "Manual": + threshold(image, threshold_range[0], threshold_range[1]) +else: + auto_threshold(image, method = threshold_method) #Tested ok: MaxEntropy, Triangle, Yen +(r,output) = analyse_particles(image, minimum_size,maximum_size, + fill_holes = True, exclude_edges = exclude_edges, print_table=False, + output_image = "outlines", minCirc = min_circ + , maxCirc = 1.0) + +points = [] +for row in range (r.counter): + if in_roi(r.getValue("XM",row), r.getValue("YM",row)): + x, y = int(r.getValue("XM", row)), int(r.getValue("YM", row)) + cx, cy = img.getCalibration().convertToAbsoluteX(x), img.getCalibration().convertToAbsoluteY(y) + points.append([cx,cy]) + if RENDERER is not None: + RENDERER.addOverlay(Crosshairs(Pen(java.awt.Color.MAGENTA), java.awt.Point(x,y), java.awt.Dimension(15,15))) + + +clear_detection(block_id) +detect_pucks(points, block_id) +if PLOT is not None: + plot_base_plate(points, p=PLOT) + +ret = get_puck_detection_dict(block_id) + + +if TEXT is not None: + TEXT.setText(str(ret)) + + +set_return(ret) + diff --git a/script/imgproc/Utils.py b/script/imgproc/Utils.py new file mode 100644 index 0000000..addc508 --- /dev/null +++ b/script/imgproc/Utils.py @@ -0,0 +1,113 @@ + +################################################################################################### +# Image processing utilities +################################################################################################### + + +from ijutils import * +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.pshell.imaging.Pen as Pen +import java.awt.Rectangle as Rectangle + +def get_img_cover_pos(): + [position, angle, confidence] = run("imgproc/CoverDetection") + return position + +def assert_img_in_cover_pos(pos = None): + if pos==None: + pos = hexiposi.take() + elif type(pos) is int: + pos = chr( ord('A') + (pos-1)) + elif is_string(pos): + pos = pos.upper() + img_segment = get_img_cover_pos() + if img_segment != pos: + raise Exception ("Image detection of cover does not match position: " + str(img_segment)) + + +def in_roi(x,y): + global roi_center, roi_radius, roi_border + return math.hypot(x-roi_center[0], y-roi_center[1]) < (roi_radius-roi_border) + + +def integrate(ips): + roi = get_roi() + aux = None + for i in range(len(ips)): + if i==0: + aux = new_image(roi[2], roi[3], image_type="float", title = "sum", fill_color = None) + op_image(aux, ips[i], "add", float_result=True, in_place=True) + return aux + +def average (ips): + aux = integrate(ips) + op_const(aux, "divide", len(ips), in_place=True) + return aux + +def grab_frames(samples): + frames = [] + for i in range(samples): + aux = get_image() + frames.append(aux) + return frames + +def average_frames(samples = 1): + return average(grab_frames(samples)) + +def integrate_frames(samples = 1): + return integrate(grab_frames(samples)) + + +roi_center = (600, 600) #(800, 600) +roi_radius = 600 +roi_border = 30 + +def get_roi(): + #roi_center = (img.output.width/2, img.output.height/2) + #roi_radius = min(roi_center[0], roi_center[1]) + #return (roi_center[0] - roi_radius, roi_center[1] - roi_radius, 2* roi_radius, 2*roi_radius) + global roi_center, roi_radius + roi_center = (img.output.width/2, img.output.height/2) + roi_radius = min(roi_center[0], roi_center[1]) + return (0,0,img.output.width, img.output.height) + +def get_image(): + roi = get_roi() + #ip = load_image(img.output) + #ret = ip if (roi is None) else sub_image(ip, roi[0], roi[1], roi[2], roi[3]) + #grayscale(ret, do_scaling=True) + + ret = load_image(Utils.grayscale(img.output, Rectangle(roi[0], roi[1], roi[2], roi[3]) if (roi is not None) else None)) + return ret + +#def detect_pucks(ip): +# """ +# """ +# aux = grayscale(ip, in_place=False) +# threshold(aux,0,50) +# binary_fill_holes(aux) +# return analyse_particles(aux, 10000,50000, +# fill_holes = False, exclude_edges = True,print_table=True, +# output_image = "outlines", minCirc = 0.4, maxCirc = 1.0) +# +#def detect_samples(ip): +# """ +# """ +# aux = grayscale(ip, in_place=False) +# invert(aux) +# subtract_background(aux) +# auto_threshold(aux) +# binary_open(aux) +# return analyse_particles(aux, 250,1000, +# fill_holes = False, exclude_edges = True,print_table=True, + + +r,g,b = [0]*256,[0]*256,[0]*256 +b[0]=0xFF +b[1]=0xFF ; g[1] = 0x80; r[1] = 0x80 +outline_lut1 = (r,g,b) + +r,g,b = [0]*256,[0]*256,[0]*256 +g[0]=0x80;r[0]=0x80; +g[1]=0xFF ; r[1] = 0x80; b[1] = 0x80 +outline_lut2 = (r,g,b) diff --git a/script/local.groovy b/script/local.groovy new file mode 100644 index 0000000..6cd1527 --- /dev/null +++ b/script/local.groovy @@ -0,0 +1,3 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Deployment specific global definitions - executed after startup.groovy +/////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/script/local.js b/script/local.js new file mode 100644 index 0000000..17db863 --- /dev/null +++ b/script/local.js @@ -0,0 +1,4 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Deployment specific global definitions - executed after startup.js +/////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/script/local.py b/script/local.py new file mode 100644 index 0000000..50fe79c --- /dev/null +++ b/script/local.py @@ -0,0 +1,338 @@ +################################################################################################### +# Deployment specific global definitions - executed after startup.py +################################################################################################### +import traceback +from ch.psi.pshell.serial import TcpDevice +from ch.psi.pshell.modbus import ModbusTCP +import ch.psi.mxsc.Controller as Controller +import ch.psi.pshell.core.Nameable as Nameable +import ch.psi.utils.Chrono as Chrono +import ch.psi.mxsc.Controller as Controller + + + +run("setup/Layout") + + + +################################################################################################### +# Configuration +################################################################################################### + +IMAGING_ENABLED_PREFERENCE = "imaging_enabled" +PUCK_TYPES_PREFERENCE = "puck_types" +BARCODE_READER_SCAN_PUCKS = "barcode_reader_scan_pucks" + +def is_imaging_enabled(): + setting = get_setting(IMAGING_ENABLED_PREFERENCE) + return not (str(setting).lower() == 'false') + +def set_imaging_enabled(value): + set_setting(IMAGING_ENABLED_PREFERENCE, (True if value else False) ) + +def assert_imaging_enabled(): + if is_imaging_enabled() == False: + raise Exception ("Imaging is disabled") + +#"unipuck", "minispine" or "mixed" +def set_puck_types(value): + set_setting(PUCK_TYPES_PREFERENCE, True if value else False ) + +def get_puck_types(): + setting = get_setting(PUCK_TYPES_PREFERENCE) + if setting == "unipuck" or setting == "minispine": + return setting + return "mixed" + + +def is_barcode_reader_scan_pucks(): + setting = get_setting(BARCODE_READER_SCAN_PUCKS) + return False if setting is None else setting.lower() == "true" + +def set_barcode_reader_scan_pucks(value): + set_setting(BARCODE_READER_SCAN_PUCKS, True if value else False ) + +def reset_mounted_sample_position(): + set_setting("mounted_sample_position", None) + +#In order to apply current config +set_imaging_enabled(is_imaging_enabled()) +set_puck_types(get_puck_types()) +set_barcode_reader_scan_pucks(is_barcode_reader_scan_pucks()) + +################################################################################################### +# Scripted devices and pseudo-devices +################################################################################################### + +for script in ["devices/RobotSC", "devices/Wago", "devices/BarcodeReader", "devices/LaserDistance", \ + "devices/LedCtrl", "devices/SmartMagnet", "devices/HexiPosi", "devices/Gonio"]: + try: + run(script) + except: + print >> sys.stderr, traceback.format_exc() + +if is_imaging_enabled(): + add_device(img.getContrast(), force = True) + add_device(img.getCamera(), force = True) + + +################################################################################################### +# Utility modules +################################################################################################### + +run("data/samples") +run("data/pucks") +run("motion/tools") +run("motion/mount") +run("motion/unmount") +run("motion/get_dewar") +run("motion/put_dewar") +run("motion/get_gonio") +run("motion/put_gonio") +run("motion/move_dewar") +run("motion/move_gonio") +run("motion/move_heater") +run("motion/move_home") +run("motion/move_park") +run("motion/move_cold") +run("motion/move_scanner") +run("motion/move_aux") +run("motion/get_aux") +run("motion/put_aux") +run("motion/dry") +run("motion/trash") +run("motion/homing_hexiposi") +run("motion/calibrate_tool") +run("motion/scan_pin") +run("motion/robot_recover") +run("motion/recover") +run("tools/Math") +if is_imaging_enabled(): + run("imgproc/Utils") + +def system_check(robot_move=True): + if not air_pressure_ok.read(): + raise Exception("Air pressure is not ok") + if not n2_pressure_ok.read(): + raise Exception("N2 pressure is not ok") + if robot_move: + if not feedback_local_safety.read(): + raise Exception("Local safety not released") + auto = not is_manual_mode() + if auto: + if not feedback_psys_safety.read(): + raise Exception("Psys safety not released") + if not guiding_tool_park.read(): + raise Exception("Guiding tool not parked") + +def get_puck_elect_detection(segment, puck): + return str(Controller.getInstance().getPuck(str(segment).upper() + str(puck)).detection) + +def get_puck_img_detection(segment, puck): + return str(Controller.getInstance().getPuck(str(segment).upper() + str(puck)).imageDetection) + +def assert_puck_detected(segment, puck): + if (segment == AUX_SEGMENT) and (puck == 1): + return + if get_puck_elect_detection(segment, puck) != "Present": + raise Exception ("Puck " + str(segment).upper() + str(puck) + " not present") + + +def start_puck_detection(): + run("tools/RestartPuckDetection") + +def check_puck_detection(): + return run("tools/CheckPuckDetection") + +def stop_puck_detection(): + run("tools/StopPuckDetection") + + + +def get_detected_pucks(): + ret = [] + for i in range(30): + p = BasePlate.getPucks()[i] + if (str(p.getDetection()) == "Present"): + ret.append(str(p.getName())) + return ret + +################################################################################################### +# Device initialization +################################################################################################### + +try: + set_heater(False) + set_air_stream(False) +except: + print >> sys.stderr, traceback.format_exc() + + +try: + release_local_safety.write(False) + release_psys_safety.write(False) +except: + print >> sys.stderr, traceback.format_exc() + +try: + hexiposi.polling=500 +except: + print >> sys.stderr, traceback.format_exc() + +try: + robot.setPolling(DEFAULT_ROBOT_POLLING) + robot.set_tool(TOOL_DEFAULT) + robot.set_frame(FRAME_DEFAULT) + robot.set_motors_enabled(True) + robot.set_joint_motors_enabled(True) +except: + print >> sys.stderr, traceback.format_exc() + +if is_imaging_enabled(): + try: + import ch.psi.pshell.device.Camera as Camera + #img.camera.setColorMode(Camera.ColorMode.Mono) + #img.camera.setDataType(Camera.DataType.UInt8) + img.camera.setGrabMode(Camera.GrabMode.Continuous) + img.camera.setTriggerMode(Camera.TriggerMode.Fixed_Rate) + img.camera.setExposure(25.00) + img.camera.setAcquirePeriod(200.00) + img.camera.setGain(0.0) + #img.camera.setROI(200, 0,1200,1200) + """ + img.camera.setROI(300, 200,1000,1000) + img.config.rotation=17 + img.config.rotationCrop=True + img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight = 50,50,900,900 + """ + img.camera.setROI(int(get_setting("roi_x")), int(get_setting("roi_y")), int(get_setting("roi_w")), int(get_setting("roi_h"))) + + img.camera.stop() + img.camera.start() + except: + print >> sys.stderr, traceback.format_exc() + + +#gripper_cam.paused = True +################################################################################################### +# Device monitoring +################################################################################################### + +DEWAR_LEVEL_RT = 5.0 +is_room_temperature = False + +def is_room_temp(): + return is_room_temperature + + +class DewarLevelListener (DeviceListener): + def onValueChanged(self, device, value, former): + global is_room_temperature + if value is not None: + is_room_temperature = value <= DEWAR_LEVEL_RT +dewar_level_listener = DewarLevelListener() + +for l in dewar_level.listeners: + #if isinstance(l, DewarLevelListener): #Class changes... + if Nameable.getShortClassName(l.getClass()) == "DewarLevelListener": + dewar_level.removeListener(l) + +dewar_level.addListener(dewar_level_listener) +dewar_level_listener.onValueChanged(dewar_level, dewar_level.take(), None) + + + + +class HexiposiListener (DeviceListener): + def onValueChanging(self, device, value, former): + robot.assert_cleared() + +hexiposi_listener = HexiposiListener() +hexiposi.addListener(hexiposi_listener) + +################################################################################################### +# Global variables & application state +################################################################################################### + + +context = get_context() + +cover_detection_debug = False + + +def is_puck_loading(): + return robot.state == State.Ready and robot.take()["pos"] == 'pPark' and \ + feedback_psys_safety.take() == False and \ + not guiding_tool_park.read() + +def set_pin_offset(val): + if abs(val) >5: + raise Exception("Invalid pin offset: " + str(val)) + try: + set_setting("pin_offset",float(val)) + except: + log("Error setting pin offset: " + str(sys.exc_info()[1]), False) + +def get_pin_offset(): + try: + ret = float(get_setting("pin_offset")) + if abs(ret) >5: + raise Exception("Invalid configured pin offset: " + str(ret)) + return ret + except: + log("Error getting pin offset: " + str(sys.exc_info()[1]), False) + return 0.0 + + +def set_pin_angle_offset(val): + if (abs(val) > 180.0) or (abs(val) < -180.0): + raise Exception("Invalid pin angle offset: " + str(val)) + try: + set_setting("pin_angle_offset",float(val)) + except: + log("Error setting pin angle offset: " + str(sys.exc_info()[1]), False) + +def get_pin_angle_offset(): + try: + ret = float(get_setting("pin_angle_offset")) + if (abs(ret) > 180.0) or (abs(ret) < -180.0): + raise Exception("Invalid configured pin angle offset: " + str(ret)) + return ret + except: + log("Error getting pin angle offset: " + str(sys.exc_info()[1]), False) + return 0.0 + +def is_force_dry(): + try: + dry_mount_counter = int(get_setting("dry_mount_counter")) + except: + dry_mount_counter = 0 + + try: + dry_timespan = time.time() - float( get_setting("dry_timestamp")) + except: + dry_timespan = 3600 + + try: + force_dry_mount_count = int(get_setting("force_dry_mount_count")) + if force_dry_mount_count>0 and dry_mount_counter>=force_dry_mount_count: + return True + except: + pass + + try: + force_dry_timeout = float(get_setting("force_dry_timeout")) + if force_dry_timeout>0 and dry_timespan>=force_dry_timeout: + return True + except: + pass + return False + + +update() +add_device(Controller.getInstance().basePlate, True) +restore_samples_info() + + +print "Initialization complete" + \ No newline at end of file diff --git a/script/motion/calibrate_tool.py b/script/motion/calibrate_tool.py new file mode 100644 index 0000000..5357ef0 --- /dev/null +++ b/script/motion/calibrate_tool.py @@ -0,0 +1,32 @@ +def calibrate_tool(): + """ + """ + print "calibrate_tool" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + (detected, dm) = move_scanner() + + if detected: + print "Pin detected, trashing..." + trash() + (detected, dm) = move_scanner() + if detected: + raise Exception("Cannot trash pin") + + robot.open_tool() + robot.get_calibration_tool() + + run("calibration/ToolCalibration3") + + robot.put_calibration_tool() + + robot.save_program() diff --git a/script/motion/dry.py b/script/motion/dry.py new file mode 100644 index 0000000..c7877da --- /dev/null +++ b/script/motion/dry.py @@ -0,0 +1,48 @@ + + +def dry(heat_time=30.0, speed=0.5, wait_cold = 30.0): + """ + heat_time (float): in seconds + speed (float): % of nominal speed + wait_cold(float): if negative, move to dewar after drying + Else move to cold and wait (in seconds) before returning. + """ + print "dry" + + + if robot.simulated: + time.sleep(10.0) + return + + #Initial chec + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + set_status("Drying") + + #Enabling + enable_motion() + + try: + set_heater(True) + robot.move_heater(speed, False) + time.sleep(heat_time) + robot.move_heater(speed, True) + set_air_stream(True) + robot.move_heater(speed, False) + finally: + set_heater(False) + set_air_stream(False) + + + set_setting("dry_mount_counter", 0) + set_setting("dry_timestamp",time.time()) + + if wait_cold >=0 : + robot.move_cold() + time.sleep(wait_cold) + else: + robot.move_park() \ No newline at end of file diff --git a/script/motion/get_aux.py b/script/motion/get_aux.py new file mode 100644 index 0000000..67bfc7d --- /dev/null +++ b/script/motion/get_aux.py @@ -0,0 +1,21 @@ +def get_aux(sample): + """ + """ + print "get_aux: ",sample + + #Initial checks + assert_valid_sample(sample) + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + hexiposi.assert_homed() + + #Enabling + enable_motion() + + if not robot.is_aux(): + robot.move_aux() + + robot.get_aux(sample) diff --git a/script/motion/get_dewar.py b/script/motion/get_dewar.py new file mode 100644 index 0000000..d0559fc --- /dev/null +++ b/script/motion/get_dewar.py @@ -0,0 +1,30 @@ +def get_dewar(segment, puck, sample, force=False): + """ + """ + print "get_dewar: ", segment, puck, sample, force + + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + hexiposi.assert_homed() + #location = robot.get_current_point() + + + #Enabling + enable_motion() + + set_hexiposi(segment) + + if not force: + visual_check_hexiposi(segment) + + if not robot.is_dewar(): + robot.move_dewar() + + robot.get_dewar(segment, puck, sample) diff --git a/script/motion/get_gonio.py b/script/motion/get_gonio.py new file mode 100644 index 0000000..2123e2a --- /dev/null +++ b/script/motion/get_gonio.py @@ -0,0 +1,20 @@ +def get_gonio(force=False): + """ + """ + print "get_gonio: ", force + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_gonio(): + robot.move_gonio() + + robot.get_gonio() diff --git a/script/motion/homing_hexiposi.py b/script/motion/homing_hexiposi.py new file mode 100644 index 0000000..3b91519 --- /dev/null +++ b/script/motion/homing_hexiposi.py @@ -0,0 +1,16 @@ +def homing_hexiposi(): + """ + """ + print "homing_hexiposi" + + #Initial checks + robot.assert_no_task() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + #location = robot.get_current_point() + + set_status("Homing hexiposi") + hexiposi.move_home() + hexiposi.waitState(State.Ready,-1) + \ No newline at end of file diff --git a/script/motion/mount.py b/script/motion/mount.py new file mode 100644 index 0000000..05c322d --- /dev/null +++ b/script/motion/mount.py @@ -0,0 +1,119 @@ +mount_sample_id = None +mount_sample_detected = None + +def mount(segment, puck, sample, force=False, read_dm=False, auto_unmount=False): + """ + """ + global mount_sample_id, mount_sample_detected + print "mount: ", segment, puck, sample, force + + start = time.time() + + is_aux = (segment == AUX_SEGMENT) + puck_address = get_puck_address(puck) + if puck_address is None: + puck_obj = get_puck_obj_by_id(puck) + if puck_obj is not None: + puck_address = puck_obj.name + if puck_address is not None: + print "puck address: ", puck_address + segment = puck_address[:1] + puck = int(puck_address[1:]) + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + + if robot.simulated: + time.sleep(3.0) + mount_sample_detected = True + mount_sample_id = "YYY0001" + update_samples_info_sample_mount(get_puck_name(segment, puck), sample, mount_sample_detected, mount_sample_id) + set_setting("mounted_sample_position", get_sample_name(segment, puck, sample)) + return [mount_sample_detected, mount_sample_id] + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + hexiposi.assert_homed() + + + try: + smart_magnet.enforce_sample_detection() + if smart_magnet.check_mounted(idle_time=0.25, timeout = 1.0) == True: + if auto_unmount and (get_setting("mounted_sample_position") is not None): + unmount(force = True) + else: + raise Exception("Pin detected on gonio") + + set_status("Mounting: " + str(segment) + str(puck) + str(sample)) + #location = robot.get_current_point() + + #Enabling + enable_motion() + + if is_aux: + if not robot.is_aux(): + robot.move_aux() + + robot.get_aux(sample) + + else: + set_hexiposi(segment) + + if not force: + visual_check_hexiposi(segment) + + if not robot.is_dewar(): + robot.move_dewar() + + robot.get_dewar(segment, puck, sample) + + + set_setting("mounted_sample_position", get_sample_name(segment, puck, sample)) + + if read_dm: + barcode_reader.start_read(10.0) + robot.move_scanner() + #time.sleep(1.0) + + robot.move_gonio() + + if read_dm: + mount_sample_id = barcode_reader.get_readout() + print "Datamatrix: " , mount_sample_id + else: + mount_sample_id = None + + smart_magnet.set_mount_current() + + robot.put_gonio() + + + try: + dry_mount_count = int(get_setting("dry_mount_counter")) + except: + dry_mount_count = 0 + set_setting("dry_mount_counter", dry_mount_count+1) + + if is_aux: + robot.move_home() + else: + robot.move_cold() + + mount_sample_detected = smart_magnet.check_mounted(idle_time=0.25, timeout = 1.0) + #TODO: Should do on finally? + update_samples_info_sample_mount(get_puck_name(segment, puck), sample, mount_sample_detected, mount_sample_id) + if mount_sample_detected == False: + raise Exception("No pin detected on gonio") + + if is_force_dry(): + smart_magnet.set_default_current() + print "Auto dry" + log("Starting auto dry", False) + dry() + return [mount_sample_detected, mount_sample_id] + finally: + smart_magnet.set_default_current() + diff --git a/script/motion/move_aux.py b/script/motion/move_aux.py new file mode 100644 index 0000000..94d6468 --- /dev/null +++ b/script/motion/move_aux.py @@ -0,0 +1,18 @@ +def move_aux(): + """ + """ + print "move_aux" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_aux(): + robot.move_aux() \ No newline at end of file diff --git a/script/motion/move_cold.py b/script/motion/move_cold.py new file mode 100644 index 0000000..89c8920 --- /dev/null +++ b/script/motion/move_cold.py @@ -0,0 +1,22 @@ +def move_cold(): + """ + """ + print "move_cold" + + if robot.simulated: + time.sleep(3.0) + return + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_cold(): + robot.move_cold() \ No newline at end of file diff --git a/script/motion/move_dewar.py b/script/motion/move_dewar.py new file mode 100644 index 0000000..3dfcbfe --- /dev/null +++ b/script/motion/move_dewar.py @@ -0,0 +1,18 @@ +def move_dewar(): + """ + """ + print "move_dewar" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_dewar(): + robot.move_dewar() \ No newline at end of file diff --git a/script/motion/move_gonio.py b/script/motion/move_gonio.py new file mode 100644 index 0000000..82397f9 --- /dev/null +++ b/script/motion/move_gonio.py @@ -0,0 +1,18 @@ +def move_gonio(): + """ + """ + print "move_gonio" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_gonio(): + robot.move_gonio() diff --git a/script/motion/move_heater.py b/script/motion/move_heater.py new file mode 100644 index 0000000..000e500 --- /dev/null +++ b/script/motion/move_heater.py @@ -0,0 +1,18 @@ +def move_heater(): + """ + """ + print "move_heater" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_heater(): + robot.move_heater() diff --git a/script/motion/move_home.py b/script/motion/move_home.py new file mode 100644 index 0000000..30592d6 --- /dev/null +++ b/script/motion/move_home.py @@ -0,0 +1,18 @@ +def move_home(): + """ + """ + print "move_home" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_home(): + robot.move_home() diff --git a/script/motion/move_park.py b/script/motion/move_park.py new file mode 100644 index 0000000..e1715c0 --- /dev/null +++ b/script/motion/move_park.py @@ -0,0 +1,18 @@ +def move_park(): + """ + """ + print "move_park" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + + if not robot.is_park(): + robot.move_park() \ No newline at end of file diff --git a/script/motion/move_scanner.py b/script/motion/move_scanner.py new file mode 100644 index 0000000..b8fe41f --- /dev/null +++ b/script/motion/move_scanner.py @@ -0,0 +1,30 @@ + +def move_scanner(): + """ + """ + print "move_scanner" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + barcode_reader.start_read(10.0) + if not robot.is_scanner(): + robot.move_scanner() + + time.sleep(0.25) + dm = barcode_reader.get_readout() + if dm is None: + detected = is_pin_detected_in_scanner() + else: + detected = True + + print ("Detected: " + str( detected) + " - Datamatrix: " + str(dm)) + + return (detected, dm) diff --git a/script/motion/put_aux.py b/script/motion/put_aux.py new file mode 100644 index 0000000..c41ee81 --- /dev/null +++ b/script/motion/put_aux.py @@ -0,0 +1,21 @@ +def put_aux(sample): + """ + """ + print "put_aux: ",sample + + #Initial checks + assert_valid_sample(sample) + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + hexiposi.assert_homed() + + #Enabling + enable_motion() + + if not robot.is_aux(): + robot.move_aux() + + robot.put_aux(sample) diff --git a/script/motion/put_dewar.py b/script/motion/put_dewar.py new file mode 100644 index 0000000..7d5c74d --- /dev/null +++ b/script/motion/put_dewar.py @@ -0,0 +1,30 @@ +def put_dewar(segment, puck, sample, force=False): + """ + """ + print "put_dewar: ", segment, puck, sample, force + + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + hexiposi.assert_homed() + + #Enabling + enable_motion() + + set_hexiposi(segment) + + if not force: + visual_check_hexiposi(segment) + + #location = robot.get_current_point() + + if not robot.is_dewar(): + robot.move_dewar() + + robot.put_dewar(segment, puck, sample) diff --git a/script/motion/put_gonio.py b/script/motion/put_gonio.py new file mode 100644 index 0000000..c23463f --- /dev/null +++ b/script/motion/put_gonio.py @@ -0,0 +1,23 @@ +def put_gonio(force=False): + """ + """ + print "put_gonio: ", force + + + if robot.simulated: + time.sleep(3.0) + return + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + if not robot.is_gonio(): + robot.move_gonio() + robot.put_gonio() diff --git a/script/motion/recover.py b/script/motion/recover.py new file mode 100644 index 0000000..bee6369 --- /dev/null +++ b/script/motion/recover.py @@ -0,0 +1,154 @@ +import org.apache.commons.math3.geometry.euclidean.threed.Segment as Segment +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D as Vector3D +import org.apache.commons.math3.geometry.euclidean.threed.Line as Line3D + +RECOVER_DESC = "mRecovery" +RECOVER_TOOL = TOOL_DEFAULT + +known_segments = [ ("pHome", "pPark", 50), \ + ("pHome", "pGonio", 30), \ + ("pHome", "pScan", 25), \ + ("pHome", "pHeater", 75), \ + ("pHome", "pDewar", 10), \ + ("pHome", "pHelium", 230), \ + ("pGonio", "pGonioG", 10), \ + ("pPark", "pHeat", 40), \ + ("pHeater", "pHeatB", 10), \ + ("pPark", "pAux", 50), \ + ] + +def get_dist_to_line(segment): + tolerance = segment[2] + p1, p2 = robot.get_pnt(segment[0]), robot.get_pnt(segment[1]) + p = robot.get_cartesian_pos() + v = Vector3D(p[0], p[1], p[2]) + v1 = Vector3D(p1[0], p1[1], p1[2]) + v2 = Vector3D(p2[0], p2[1], p2[2]) + l = Line3D(v1, v2, 0.01) + return l.distance(v) + + +def get_dist_to_segment(segment): + tolerance = segment[2] + p1, p2 = robot.get_pnt(segment[0]), robot.get_pnt(segment[1]) + p = robot.get_cartesian_pos() + v = Vector3D(p[0], p[1], p[2]) + v1 = Vector3D(p1[0], p1[1], p1[2]) + v2 = Vector3D(p2[0], p2[1], p2[2]) + l = Line3D(v1, v2, 0.01) + d = l.distance(v) + + pj = get_pojection_at_line(segment) + + d1, d2 = v1.distance(v), v2.distance(v) + dp1, dp2 = v1.distance(pj), v2.distance(pj) + d12 = v1.distance(v2) + + + if (dp1 + dp2) > (d12 + tolerance): + d = max(d,min(d1,d2)) + return d + +def is_on_segment(segment): + tolerance = segment[2] + d = get_dist_to_segment(segment) + + if d > tolerance: + #print "Current robot position " + str(p) + " not on segment " + str(segment) + " - distance=" + str(d) + return False + #print "Current robot position " + str(p) + " on segment " + str(segment) + " - distance=" + str(d) + return True + +def get_pojection_at_line(segment): + tolerance = segment[2] + p1, p2 = robot.get_pnt(segment[0]), robot.get_pnt(segment[1]) + p = robot.get_cartesian_pos() + v = Vector3D(p[0], p[1], p[2]) + v1 = Vector3D(p1[0], p1[1], p1[2]) + v2 = Vector3D(p2[0], p2[1], p2[2]) + l = Line3D(v1, v2, 0.01) + a = l.getAbscissa(v) + lv = l.pointAt(a) + return lv + + +def get_current_segment(): + for segment in known_segments: + if is_on_segment(segment): + return segment + return None + +def get_current_distance(): + for segment in known_segments: + if is_on_segment(segment): + return get_dist_to_segment(segment) + return None + + +def move_to_segment(segment): + tolerance = segment[2] + p = robot.get_cartesian_pos() + v = Vector3D(p[0], p[1], p[2]) + lv = get_pojection_at_line(segment) + dlv = lv.distance(v) + if dlv> (tolerance + 0.1): + raise Exception( "Error moving from " + str(p) + " to segment - distance=" + str(dlv)) + d = [lv.x, lv.y, lv.z, p[3], p[4], p[5]] + print "Moving from " + str(p) + " to segment " + str(segment) + " - distance=" + str(dlv) + " - dest=" + str(d) + + try: + robot.movel(d, tool=RECOVER_TOOL, desc=RECOVER_DESC, sync=True) + print "Done" + except: + print sys.exc_info()[1] + +#Moves to first point of the segment ehich is safer, unless in the vicinity of the second +def move_to_safest_point(segment, vicinity_tolerance = 100): + d1, d2 = robot.get_distance_to_pnt(segment[0]), robot.get_distance_to_pnt(segment[1]) + #Always moving to primary point + if False : #(d2<=d1) and (d2 <= vicinity_tolerance): + print "Moving to secondary point " + str(segment[1] + " - d1=" + str(d1) + " d2=" + str(d2) ) + robot.movel(segment[1], tool=RECOVER_TOOL, desc=RECOVER_DESC, sync=True) + else: + print "Moving to primary point " + str(segment[0] + " - d1=" + str(d1) + " d2=" + str(d2) ) + robot.movel(segment[0], tool=RECOVER_TOOL, desc=RECOVER_DESC, sync=True) + print "Done" + #print "Recovered to point " + str(robot.get_curjoint_or_pointrent_point()) + + +def recover(): + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + + if robot.get_current_point() is not None: + raise Exception("Robot is in known location") + + set_status("Recovering") + + #Enabling + enable_motion() + + + is_on_known_segment = False + for segment in known_segments: + if is_on_segment(segment): + #try: + # robot.set_monitor_speed(5) + is_on_known_segment = True + move_to_segment(segment) + move_to_safest_point(segment) + location = robot.get_current_point() + if location is None: + raise Exception("Robot didn't reach known point") + return "Success recovering to point: " + str(location) + #finally: + # robot.set_default_speed() + if not is_on_known_segment: + raise Exception("Robot is not in known segment") + + + + + \ No newline at end of file diff --git a/script/motion/robot_recover.py b/script/motion/robot_recover.py new file mode 100644 index 0000000..c25d712 --- /dev/null +++ b/script/motion/robot_recover.py @@ -0,0 +1,16 @@ +def robot_recover(): + """ + """ + print "robot_recover" + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + + set_status("Recovering robot") + + #Enabling + enable_motion() + + robot.robot_recover() diff --git a/script/motion/scan_pin.py b/script/motion/scan_pin.py new file mode 100644 index 0000000..7683694 --- /dev/null +++ b/script/motion/scan_pin.py @@ -0,0 +1,94 @@ +def scan_pin(segment, puck, sample, force=False): + pin_name = get_sample_name(segment, puck, sample) + + print "scan pin", pin_name + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + is_aux = (segment == AUX_SEGMENT) + + if robot.simulated: + time.sleep(0.5) + return "Present" + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + + set_status("Scanning pin: " + str(pin_name)) + + enable_motion() + + if is_aux: + if not robot.is_aux(): + robot.move_aux() + + robot.get_aux(sample) + else: + set_hexiposi(segment) + if not force: + visual_check_hexiposi(segment) + + if not robot.is_dewar(): + robot.move_dewar() + + robot.get_dewar(segment, puck, sample) + + (detected, dm) = move_scanner() + update_samples_info_sample_scan(get_puck_name(segment, puck), sample, detected, dm) + + if is_aux: + robot.move_aux() + robot.put_aux( sample) + else: + robot.move_dewar() + robot.put_dewar(segment, puck, sample) + ret = "Empty" + if detected: + if (dm is None) or (len(dm.strip())==0): + ret = "Present" + else: + ret = str(dm) + return ret + + +def scan_puck(segment, puck, force=False): + if segment == AUX_SEGMENT: + raise Exception("Cannot scan auxiliary puck") + ret = [] + for i in range(16): + ret.append(scan_pin (segment, puck, i+1, force)) + return ret + + +def scan_gripper(): + print "scan gripper" + #Initial checks + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + + set_status("Scanning gripper") + + enable_motion() + + (detected, dm) = move_scanner() + + robot.move_home() + + ret = "Empty" + if detected: + if (dm is None) or (len(dm.strip())==0): + ret = "Present" + else: + ret = str(dm) + return ret diff --git a/script/motion/tools.py b/script/motion/tools.py new file mode 100644 index 0000000..efdd5f9 --- /dev/null +++ b/script/motion/tools.py @@ -0,0 +1,177 @@ +POSITION_TOLERANCE = 50 + + +def is_manual_mode(): + """ + return if operating in local mode. TODO: should be based on IO, not on robot flag. + """ + return robot.working_mode == "manual" + +def release_safety(): + """ + Release sefety signals acording to working mode + """ + if air_pressure_ok.take() != True: + raise Exception("Cannot release safety: air preassure not ok") + if n2_pressure_ok.take() != True: + raise Exception("Cannot release safety: n2 pressure not ok") + auto = not is_manual_mode() + if auto: + if feedback_psys_safety.read() == False: + release_psys() + time.sleep(0.5) + if feedback_psys_safety.read() == False: + raise Exception("Cannot enable power: check doors") + + if feedback_local_safety.read() == False: + release_local() + time.sleep(0.5) + if feedback_local_safety.read() == False: + raise Exception("Cannot enable power: check sample changer emergency stop button") + +def enable_motion(): + """ + Check safety and enable arm power if in remote mode + """ + release_safety() + system_check(robot_move=True) + auto = not is_manual_mode() + if auto: + if not robot.state.isNormal(): + raise Exception("Cannot enable power: robot state is " + str(robot.state)) + robot.enable() + +def set_hexiposi(pos, force = False): + """ + Set the hexiposi position in remote mode, or wait for it to be set in manual mode + """ + robot.assert_cleared() + if force == False: + if hexiposi.position == pos: + return + + if is_manual_mode(): + set_status("Move Hexiposi to position " + str(pos) + " ...") + try: + hexiposi.waitInPosition(pos, -1) + finally: + set_status(None) + else: + hexiposi.move(pos) + +#Can be used if cover has following error (no checking readback) +def _set_hexiposi(pos): + hexiposi.moveAsync(pos) + time.sleep(1.0) + hexiposi.waitReady(-1) + + +def visual_check_hexiposi(segment): + if is_imaging_enabled(): + #if is_manual_mode(): ? + if hexiposi.moved: + #Clearing for image processing + if not robot.is_park(): + print "Moving robot to park to clear camera view..." + robot.move_park() + assert_img_in_cover_pos(segment) + hexiposi.moved = False + + + +def wait_end_of_move(): + robot.update() + while (not robot.settled) or (not robot.empty) or (not robot.isReady()) : + time.sleep(0.01) + + +def move_to_home(): + #robot.reset_motion("jHome") + robot.movej("pHome", robot.tool , DESC_SCAN) + wait_end_of_move() + +def move_to_laser(): + robot.reset_motion() + tool = robot.tool + d = robot.get_distance_to_pnt("pLaser") + if d<0: + raise Exception ("Error calculating distance to laser: " + str(d)) + if d<POSITION_TOLERANCE: + print "FROM LASER" + robot.movel("pLaser", robot.tool, DESC_SCAN, sync = True) + return + d = robot.get_distance_to_pnt("pLaserHome") + if d<0: + raise Exception ("Error calculating distance to laser appro: " + str(d)) + if d<POSITION_TOLERANCE: + print "FROM APPRO" + robot.movel("pLaser", robot.tool, DESC_SCAN, sync = True) + return + d = robot.get_distance_to_pnt("pHome") + if d<0: + raise Exception ("Error calculating distance to home: " + str(d)) + if d<POSITION_TOLERANCE: + print "FROM HOME" + robot.movej("pLaserHome", robot.tool, DESC_DEFAULT) + robot.movel("pLaser", robot.tool, DESC_SCAN, sync = True) + return + raise Exception ("Must be in home position to start move to laser") + + +def update_tool(tool=None, x_offset=0.0, y_offset=0.0, z_offset=0.0): + #Updating tool: + t=robot.get_tool_trsf(tool) + t[0]=t[0] - x_offset + t[1]=t[1] - y_offset + t[2]=t[2] - z_offset + robot.set_tool_trsf(t, tool) + print "Updated " + (str(robot.tool) if (tool is None) else tool) + ": " + str(t) + robot.save_program() + + +def assert_valid_address(segment, puck, sample): + if (segment == AUX_SEGMENT) and (puck == 1): + return + if is_string(segment): + segment = ord(segment.upper()) - ord('A') +1 + if segment<=0 or segment >6: + raise Exception ("Invalid segment") + if puck<=0 or puck >5: + raise Exception ("Invalid puck") + if sample<=0 or sample >16: + raise Exception ("Invalid sample") + +def assert_valid_sample(sample): + if sample<=0 or sample >16: + raise Exception ("Invalid sample") + +def get_puck_name(segment, puck): + try: + assert_valid_address(segment, puck, 1) + if type(segment) is int: + segment = chr( ord('A') + (segment-1)) + elif is_string(segment): + segment = segment.upper() + else: + return None + return segment + str(puck) + except: + return None + +def get_sample_name(segment, puck, sample): + puck_name = get_puck_name(segment, puck) + return None if (puck_name is None) else puck_name + str(sample) + + +def is_pin_detected_in_scanner(): + samples = [] + for i in range(10): + samples.append(laser_distance.read()) + time.sleep(0.05) + av = mean(samples) + for s in samples: + if s<=1: + return False + if abs(s-av) > 0.1: + return False + return True \ No newline at end of file diff --git a/script/motion/trash.py b/script/motion/trash.py new file mode 100644 index 0000000..0057a2d --- /dev/null +++ b/script/motion/trash.py @@ -0,0 +1,36 @@ +def trash(): + """ + """ + print "trash" + + if robot.simulated: + time.sleep(3.0) + return + + #Initial checks + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + + #Enabling + enable_motion() + + robot.move_heater(to_bottom = False) + robot.move_heater(to_bottom = True) + + try: + for i in range(3): + robot.open_tool() + time.sleep(0.5) + robot.close_tool() + time.sleep(0.5) + finally: + robot.open_tool() + + + robot.move_heater(to_bottom = False) + robot.move_home() + + \ No newline at end of file diff --git a/script/motion/unmount.py b/script/motion/unmount.py new file mode 100644 index 0000000..41b0401 --- /dev/null +++ b/script/motion/unmount.py @@ -0,0 +1,69 @@ +def unmount(segment = None, puck = None, sample = None, force=False): + """ + """ + print "unmount: ", segment, puck, sample, force + + if (segment is None) or (puck is None) or (sample is None): + pos = get_setting("mounted_sample_position") + if pos is None: + raise Exception("Mounted sample position is not defined") + segment, puck , sample = pos[0:1], int(pos[1]), int(pos[2:]) + print "Mounted sample position: ", segment, puck , sample + is_aux = (segment == AUX_SEGMENT) + + #Initial checks + assert_valid_address(segment, puck, sample) + assert_puck_detected(segment, puck) + + if robot.simulated: + time.sleep(3.0) + update_samples_info_sample_unmount(get_puck_name(segment, puck), sample) + set_setting("mounted_sample_position", None) + return + + robot.assert_no_task() + robot.reset_motion() + robot.wait_ready() + robot.assert_cleared() + #robot.assert_in_known_point() + hexiposi.assert_homed() + + set_status("Umounting: " + str(segment) + str(puck) + str(sample)) + + try: + if not force: + smart_magnet.enforce_sample_detection() + if smart_magnet.check_mounted(idle_time=0.5, timeout = 3.0) == False: + raise Exception("No pin detected on gonio") + + + #Enabling + enable_motion() + + if not is_aux: + set_hexiposi(segment) + + if not force: + visual_check_hexiposi(segment) + + #location = robot.get_current_point() + + if not robot.is_gonio(): + robot.move_gonio() + + smart_magnet.set_unmount_current() + + robot.get_gonio() + + if is_aux: + robot.move_aux() + robot.put_aux( sample) + else: + #TODO: Shuld check if smart magnet detection is off? + update_samples_info_sample_unmount(get_puck_name(segment, puck), sample) + robot.move_dewar() + robot.put_dewar(segment, puck, sample) + set_setting("mounted_sample_position", None) + finally: + smart_magnet.set_default_current() + diff --git a/script/setup/ExposureScan.py b/script/setup/ExposureScan.py new file mode 100644 index 0000000..7a1d438 --- /dev/null +++ b/script/setup/ExposureScan.py @@ -0,0 +1,33 @@ +import java.awt.Rectangle as Rectangle + +import ch.psi.pshell.imaging.Data as Data +class Exposure(Writable): + def write(self,pos): + #cam.setExposure(pos) + img.camera.setExposure(pos) +exposure=Exposure() + + +class Contrast(Readable): + def read(self): + data = img.getData() + #roi = Data(data.getRectSelection(500,300,700,600), False) + #return data.getGradientVariance(False, Rectangle(480,0,600,670)) + return data.getGradientVariance(False, None) +contrast=Contrast() + + +#a= lscan(exposure,img.getContrast(), 0.5, 1.0, 0.01, 0.5) +#a= lscan(exposure,contrast, 0.2, 0.4, 0.01, 0.7) +ret= lscan(exposure,contrast, 10.0, 150.0, 5.0, 0.5) +y, x = ret.getReadable(0), ret.getPositions(0) + +#(n, m, s) = fit(a.getReadable(0), xdata=a.getPositions(0)) +#if m is None: +# m=max(a.getReadable(0)) +m=x[y.index(max(y))] +p=get_plots()[0] +p.addMarker(m, p.AxisId.X, str(m), Color.RED) + +print "Setting exposure = ", m +exposure.write(m) diff --git a/script/setup/Layout.py b/script/setup/Layout.py new file mode 100644 index 0000000..5c584f4 --- /dev/null +++ b/script/setup/Layout.py @@ -0,0 +1,292 @@ +################################################################################################### +#DEFINITIONS +################################################################################################### + +PLATE_SIZE = 480 +BLOCK_ROI_TOLERANCE = 12 #mm +LED_TOLERANCE = 8 #mm Distance between LEDs = 18mm +PUCK_SIZE = 65 + +DET_UNIPUCK = "unipuck" +DET_MINISPINE = "minispine" +DET_ERROR = "error" +DET_EMPTY = "empty" +DET_UNKNOWN = "unknown" + +BLOCKS = ('A', 'B', 'C', 'D', 'E', 'F') + +#Layout table +puck_layout = ( + #Num Elm A0 Index A1 Uni Mini Center Angle Xuni Yuni Xmini=Xc Ymini==Yc + (1 , 'A', 0 , 1, 0.00 , 57.00 , 75.00 , 66.00 , 0.00 , 0.00 , 57.00 , 0.00 , 75.00 ), + (2 , 'A', 0 , 2, 0.00 , 132.00, 150.00, 141.00, 0.00 , 0.00 , 132.00 , 0.00 , 150.00 ), + (3 , 'F', 0 , 5, 19.11, 180.40, 198.40, 189.40, 19.11 , 59.06 , 170.46 , 64.95 , 187.47 ), + (4 , 'F', 0 , 4, 40.89, 180.40, 198.40, 189.40, 40.89 , 118.09 , 136.38 , 129.87 , 149.98 ), + (5 , 'F', 0 , 3, 30.00, 111.90, 129.90, 120.90, 30.00 , 55.95 , 96.91 , 64.95 , 112.50 ), + (6 , 'F', 60 , 1, 0.00 , 57.00 , 75.00 , 66.00 , 60.00 , 49.36 , 28.50 , 64.95 , 37.50 ), + (7 , 'F', 60 , 2, 0.00 , 132.00, 150.00, 141.00, 60.00 , 114.32 , 66.00 , 129.90 , 75.00 ), + (8 , 'E', 60 , 5, 19.11, 180.40, 198.40, 189.40, 79.11 , 177.15 , 34.08 , 194.83 , 37.48 ), + (9 , 'E', 60 , 4, 40.89, 180.40, 198.40, 189.40, 100.89, 177.15 , -34.08 , 194.83 , -37.48 ), + (10, 'E', 60 , 3, 30.00, 111.90, 129.90, 120.90, 90.00 , 111.90 , 0.00 , 129.90 , 0.00 ), + (11, 'E', 120, 1, 0.00 , 57.00 , 75.00 , 66.00 , 120.00, 49.36 , -28.50 , 64.95 , -37.50 ), + (12, 'E', 120, 2, 0.00 , 132.00, 150.00, 141.00, 120.00, 114.32 , -66.00 , 129.90 , -75.00 ), + (13, 'D', 120, 5, 19.11, 180.40, 198.40, 189.40, 139.11, 118.09 , -136.38, 129.87 , -149.98), + (14, 'D', 120, 4, 40.89, 180.40, 198.40, 189.40, 160.89, 59.06 , -170.46, 64.95 , -187.47), + (15, 'D', 120, 3, 30.00, 111.90, 129.90, 120.90, 150.00, 55.95 , -96.91 , 64.95 , -112.50), + (16, 'D', 180, 1, 0.00 , 57.00 , 75.00 , 66.00 , 180.00, 0.00 , -57.00 , 0.00 , -75.00 ), + (17, 'D', 180, 2, 0.00 , 132.00, 150.00, 141.00, 180.00, 0.00 , -132.00, 0.00 , -150.00), + (18, 'C', 180, 5, 19.11, 180.40, 198.40, 189.40, 199.11, -59.06 , -170.46, -64.95 , -187.47), + (19, 'C', 180, 4, 40.89, 180.40, 198.40, 189.40, 220.89, -118.09, -136.38, -129.87, -149.98), + (20, 'C', 180, 3, 30.00, 111.90, 129.90, 120.90, 210.00, -55.95 , -96.91 , -64.95 , -112.50), + (21, 'C', 240, 1, 0.00 , 57.00 , 75.00 , 66.00 , 240.00, -49.36 , -28.50 , -64.95 , -37.50 ), + (22, 'C', 240, 2, 0.00 , 132.00, 150.00, 141.00, 240.00, -114.32, -66.00 , -129.90, -75.00 ), + (23, 'B', 240, 5, 19.11, 180.40, 198.40, 189.40, 259.11, -177.15, -34.08 , -194.83, -37.48 ), + (24, 'B', 240, 4, 40.89, 180.40, 198.40, 189.40, 280.89, -177.15, 34.08 , -194.83, 37.48 ), + (25, 'B', 240, 3, 30.00, 111.90, 129.90, 120.90, 270.00, -111.90, 0.00 , -129.90, 0.00 ), + (26, 'B', 300, 1, 0.00 , 57.00 , 75.00 , 66.00 , 300.00, -49.36 , 28.50 , -64.95 , 37.50 ), + (27, 'B', 300, 2, 0.00 , 132.00, 150.00, 141.00, 300.00, -114.32, 66.00 , -129.90, 75.00 ), + (28, 'A', 300, 5, 19.11, 180.40, 198.40, 189.40, 319.11, -118.09, 136.38 , -129.87, 149.98 ), + (29, 'A', 300, 4, 40.89, 180.40, 198.40, 189.40, 340.89, -59.06 , 170.46 , -64.95 , 187.47 ), + (30, 'A', 300, 3, 30.00, 111.90, 129.90, 120.90, 330.00, -55.95 , 96.91 , -64.95 , 112.5 ), + ) + +################################################################################################### +#Puck class +################################################################################################### +class Puck: + def __init__(self, id, block, index, angle, center, led_uni, led_mini): + self.id = id + self.block = block + self.index = index + self.angle = angle + self.center = center + self.led_uni = led_uni + self.led_mini = led_mini + self.detect = DET_UNKNOWN + + def __str__(self): + return "Number: " + str(self.id) + "\nBlock: " + str(self.block) + "\nIndex: " + str(self.index) + "\nAngle: " + str(self.angle) + \ + "\nCenter: " + str(self.center) + "\nLed Unipuck: " + str(self.led_uni) + "\nLed Minispine: " + str(self.led_mini) + + def get_name(self): + return str(self.block) + str(self.index) + + def match(self, x, y): + if math.hypot(x-self.led_uni[0], y-self.led_uni[1]) <= LED_TOLERANCE: + return DET_UNIPUCK + if math.hypot(x-self.led_mini[0], y-self.led_mini[1]) <= LED_TOLERANCE: + return DET_MINISPINE + return None + + + +_block_ids = [] +_puck_list = [] +_block_list = [] + +for p in(puck_layout): + puck = Puck(p[0], p[1], p[3], p[8], (p[11],p[12]), (p[9],p[10]), (p[11],p[12])) + _puck_list.append(puck) + if puck.block not in (_block_ids): + _block_ids.append(puck.block) + +def get_puck(id): + for p in _puck_list: + if id==p.id: + return p + return None + +def get_pucks(block = None): + ret = [] + for p in _puck_list: + if (block is None) or (block==p.block): + ret.append(p) + return ret + + +################################################################################################### +#Block class +################################################################################################### + +class Block: + def __init__(self, id, angle_range, x_range, y_range): + self.id = id + self.angle_range = angle_range + self.x_range = x_range + self.y_range = y_range + self.roi = (self.x_range[0] - BLOCK_ROI_TOLERANCE, self.y_range[0] - BLOCK_ROI_TOLERANCE, + self.x_range[1] + BLOCK_ROI_TOLERANCE, self.y_range[1] + BLOCK_ROI_TOLERANCE) + + def __str__(self): + return "Id: " + str(self.id) + "\nAngle: " + str(self.angle_range) + "\nX: " + str(self.x_range) + "\nY: " + str(self.y_range) + + +for id in _block_ids: + pucks = get_pucks(id) + angles, x, y = [], [], [] + for p in pucks: + angles.append(p.angle) + x.append(p.led_uni[0]) + x.append(p.led_mini[0]) + y.append(p.led_uni[1]) + y.append(p.led_mini[1]) + el = Block(id,(min(angles), max(angles)), (min(x), max(x)), (min(y), max(y))) + _block_list.append(el) + +def get_block(id): + for e in _block_list: + if id==e.id: + return e + return None + +def get_blocks(): + return _block_list + + + + +################################################################################################### +#Detection utilities +################################################################################################### + + +def _detect_puck(point_list, puck): + puck.detect = DET_ERROR + for point in point_list: + match = puck.match(point[0], point[1]) + if match is not None: + if match==DET_UNIPUCK: + puck.detect = DET_EMPTY if (puck.detect==DET_MINISPINE) else DET_UNIPUCK + elif match==DET_MINISPINE: + puck.detect = DET_EMPTY if (puck.detect==DET_UNIPUCK) else DET_MINISPINE + +def detect_pucks(point_list, id=None): + if (id is None) or (id in BLOCKS): + for puck in get_pucks(id): + _detect_puck(point_list, puck) + else: + puck = get_puck(int(id)) + print puck + _detect_puck(point_list, puck) + + +def clear_detection(block_id=None): + for puck in get_pucks(block_id): + puck.detect = DET_UNKNOWN + return get_puck_detection_dict(block_id) + + +def get_puck_detection(det_type, block_id=None): + ret = [] + for puck in get_pucks(block_id): + if puck.detect == det_type: + ret.append(puck) + return ret + +def get_unipucks(block_id=None): + return get_puck_detection(DET_UNIPUCK, block_id) + +def get_minispines(block_id=None): + return get_puck_detection(DET_MINISPINE, block_id) + +def get_empties(block_id=None): + return get_puck_detection(DET_EMPTY, block_id) + +def get_unknowns(block_id=None): + return get_puck_detection(DET_UNKNOWN, block_id) + +def get_det_errors(block_id=None): + return get_puck_detection(DET_ERROR, block_id) + +def get_puck_detection_dict(block_id): + ret = {} + pucks = [] + for puck in get_unipucks(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Unipuck"] = pucks + pucks = [] + for puck in get_minispines(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Minispine"] = pucks + pucks = [] + for puck in get_det_errors(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Error"] = pucks + pucks = [] + for puck in get_empties(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Empty"] = pucks + pucks = [] + for puck in get_unknowns(block_id): + pucks.append(puck.get_name()) + pucks.sort() + ret["Unknown"] = pucks + return ret + +################################################################################################### +#Plotting +################################################################################################### + +from plotutils import * + +def plot_base_plate(points = None, show_detect = True, title = None, p = None): + colors = (Color.RED, Color.BLUE, Color.MAGENTA, Color(128,0,128), Color(0,128,0), Color(255,128,0)) + if p is None: p = plot(None, title=title)[0] + p.getAxis(p.AxisId.Y).setInverted(True) + plot_circle(p, 0, 0, PLATE_SIZE/2, width = 0, color = Color.GRAY, name = "Plate") + plot_point(p, 0, 0, size = 10, color = Color.GRAY, name = "Center") + #p.setLegendVisible(True) + for block in get_blocks(): + (xmin, xmax) = block.x_range + (ymin, ymax) = block.y_range + (xmin, ymin, xmax, ymax ) = block.roi + index = get_blocks().index(block) + r = plot_rectangle(p, xmin, ymin, xmax, ymax, width =0, color=colors[index], name = block.id) + #In the first time the plot shows, it takes some time for the color to be assigned + #while r.color is None: + # time.sleep(0.001) + + if block.id in ('A', 'F'): + x, y = (xmin + xmax)/2, ymax + 5 + elif block.id in ('C', 'D'): + x, y = (xmin + xmax)/2, ymin - 5 + elif block.id == 'B': + x, y = xmax + 5, (ymin + ymax)/2 + elif block.id == 'E': + x, y = xmin - 5, (ymin + ymax)/2 + + p.addText(x,y, str(block.id), r.color) + + for puck in get_pucks(block.id): + (xu, yu) = puck.led_uni + (xm, ym) = puck.led_mini + plot_point(p, xu, yu, size = 3, color = r.color, name = str(puck.id)+"u") + plot_point(p, xm, ym, size = 7, color = r.color, name = str(puck.id)+"m") + plot_circle(p, xu, yu, LED_TOLERANCE, width = 0, color = r.color, name = str(puck.id)+"uc") + plot_circle(p, xm, ym, LED_TOLERANCE, width = 0, color = r.color, name = str(puck.id)+"mc") + p.addText((xu+xm)/2, (yu+ym)/2, str(puck.id), r.color) + c,w = Color.GRAY,0 + if show_detect: + if puck.detect == DET_UNIPUCK: + c,w = Color.BLACK,1 + elif puck.detect == DET_MINISPINE: + c,w = Color(150, 100, 50),1 + elif puck.detect == DET_ERROR: + c = Color(128,0,0) + plot_circle(p, xm, ym, PUCK_SIZE/2, width = w, color = c , name = str(puck.id)) + if points is not None: + for point in points: + c, w = Color.GRAY, 1 + for puck in get_pucks(): + match = puck.match(point[0], point[1]) + if match is not None: + w=2 + c = Color.DARK_GRAY if match == "minispine" else Color.BLACK + + + plot_cross(p,point[0], point[1], size = 12, width = w, color = c, name = "P"+ str(points.index(point))) + #plot_point(p,point[0], point[1], size = 5, color = Color.BLACK, name = "Pc"+ str(points.index(point))) diff --git a/script/tasks/LedMonitoring.py b/script/tasks/LedMonitoring.py new file mode 100644 index 0000000..5182a77 --- /dev/null +++ b/script/tasks/LedMonitoring.py @@ -0,0 +1,26 @@ +DEWAR_LEVEL_LED = 25.0 + +try: + _level = dewar_level.read() +except: + log("Cannot read Dewar level", False) + _level = 0.0 + +try: + _led_room_temp = is_led_room_temp() +except: + log("Cannot get LED configuration", False) + _led_room_temp = False + +if _level <= DEWAR_LEVEL_LED: + if not _led_room_temp: + log_str="LED Monitoring: Setting LEDs to room temperature range" + log(log_str, False) + print (log_str) + set_led_range(room_temp = True) +else: + if _led_room_temp: + log_str="LED Monitoring: Setting LEDs to LN2 range" + log(log_str, False) + print (log_str) + set_led_range(room_temp = False) diff --git a/script/test/CameraCalibration.py b/script/test/CameraCalibration.py new file mode 100644 index 0000000..02e7d9d --- /dev/null +++ b/script/test/CameraCalibration.py @@ -0,0 +1,71 @@ +import ch.psi.pshell.device.Camera as Camera +import ch.psi.pshell.imaging.RendererMode as RendererMode +from ch.psi.pshell.imaging.Overlays import * + +""" +img.camera.setColorMode(Camera.ColorMode.Mono) +img.camera.setDataType(Camera.DataType.UInt8) +img.camera.setGrabMode(Camera.GrabMode.Continuous) +img.camera.setTriggerMode(Camera.TriggerMode.Fixed_Rate) +img.camera.setExposure(50.00) +img.camera.setAcquirePeriod(200.00) +img.camera.setGain(0.0) +img.config.rotationCrop=True + + +""" +#img.camera.setROI(200, 0,1200,1200) + +img.camera.setROI(0, 0,1600,1200) +img.config.rotation=0 +img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight =0,0,-1,-1 +img.config.setCalibration(None) +img.camera.stop() +img.camera.start() + +#img.camera.setROI(300, 200,1000,1000) +#img.config.rotation=17 +#img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight = 50,50,900,900 + +p = show_panel(img) +p.setMode(RendererMode.Fit) +ov_text = Text(Pen(java.awt.Color.GREEN.darker()), "", java.awt.Font("Verdana", java.awt.Font.PLAIN, 24), java.awt.Point(20,20)) +ov_text.setFixed(True) + + + +p.addOverlay(ov_text) +try: + ov_text.update("Click on upper reference...") + p1 = p.waitClick(60000) + print p1 + ov_text.update("Click on left reference...") + p2 = p.waitClick(60000) + print p2 + ov_text.update("Click on right reference...") + p3 = p.waitClick(60000) + print p3 + + x, y, z = p1.x+p1.y*1j, p2.x+p2.y*1j, p3.x+p3.y*1j + w = z-x + w /= y-x + c = (x-y)*(w-abs(w)**2)/2j/w.imag-x + cx, cy, r = -c.real, -c.imag, abs(c+x) + a = math.degrees(math.atan((cx-p1.x)/(p1.y-cy))) + + print cx, cy, r, a + + #img.camera.setROI(int((1600-cx)/2),int((1200-cy)/2),1000,1000) + img.camera.setROI(int(cx-r),int(cy-r),int(2*r),int(2*r)) + img.config.rotation=-a + #remove rotation border + d=int(r/11) + img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight =d,d, int(2*r-2*d), int(2*r-2*d) + #img.config.setCalibration(None) + img.camera.stop() + img.camera.start() + +finally: + p.removeOverlay(ov_text) + + \ No newline at end of file diff --git a/script/test/CoverDetection.py b/script/test/CoverDetection.py new file mode 100644 index 0000000..24a228b --- /dev/null +++ b/script/test/CoverDetection.py @@ -0,0 +1,116 @@ +################################################################################################### +# Procedure to detect the cover orientation +################################################################################################### +import ch.psi.pshell.imaging.Utils.integrateVertically as integrateVertically +img.backgroundEnabled=False + +REF = (0,96,125) + +line = load_image("{images}/line.png", title="Line") +#line = load_image("{images}/line360.png", title="Line") + +line.getProcessor().setBackgroundValue(0.0) + + +#ip = get_image() +ip = integrate_frames(10) +ip = grayscale(ip, True) + + +smooth(ip) +#bandpass_filter(ip, 30, 1000) +edges(ip) + +#invert(ip) +#auto_threshold(ip, method = "Default") + + +#auto_threshold(ip, method = "Li") +auto_threshold(ip, method = "MaxEntropy") + +""" +for m in AutoThresholder.getMethods(): + print m + aux = ip.duplicate() + auto_threshold(aux, method = m) + binary_fill_holes(aux, dark_background=False) + renderer = show_panel(aux.bufferedImage) + time.sleep(1.0) +""" +#binary_dilate(ip, dark_background=False) +#binary_fill_holes(ip, dark_background=False) +#binary_open(ip, dark_background=Tr) + +renderer = show_panel(ip.bufferedImage) + + + + + + + + +#line = sub_image(line, 325, 325, 512, 512) +#ip = sub_image(ip, 325, 325, 512, 512) +line = sub_image(line, 453, 453, 256, 256) +ip = sub_image(ip, 453, 453, 256, 256) +#op = op_fft(ip, line, "correlate") + + +renderer = show_panel(ip.bufferedImage) + +#renderer = show_panel(op.bufferedImage) +#line.show() +ydata = [] +xdata = range (0,180,1) +for i in xdata: + l = line.duplicate() + l.getProcessor().setBackgroundValue(0.0) + l.getProcessor().rotate(float(i)) + op = op_fft(ip, l, "correlate") + bi = op.getBufferedImage() + p = integrateVertically(bi) + ydata.append(sum(p)) + + #renderer = show_panel(op.bufferedImage) + #time.sleep(0.001) + +def moving_average(arr, n) : + ret = [] + for i in range(len(arr)): + ret.append(mean(arr[max(i-n,0):min(i+n,len(arr)-1)])) + return ret +av = moving_average(ydata, 1) + +p = plot(ydata, xdata=xdata)[0] + +p.addSeries(LinePlotSeries("Moving Average")) +p.getSeries(1).setData(xdata, av) + +peaks = estimate_peak_indexes(ydata, xdata, (min(ydata) + max(ydata))/2, 25.0) +left, right = min(peaks), max(peaks) +if xdata[left]<5 and xdata[right]>(xdata[-1]-5): + #del peaks[0 if ydata[right] > ydata[left] else -1] + peaks.remove(right if ydata[right] > ydata[left] else left) + +peaks = sorted(peaks[:3]) +peaks_x = map(lambda x:xdata[x], peaks) +peaks_y = map(lambda x:ydata[x], peaks) + +print "Peaks", peaks +print "Peak indexes: " + str(peaks_x) +print "Peak values: " + str(peaks_y) + + +for i in range(len(peaks)): + peak = xdata[peaks[i]] + p.addMarker(peak, None, "N="+str(round(peak,2)), Color(80,0,80)) + if ((peaks[i]>160) and (REF[i]<20)): + peaks[i] = peaks[i] - 180.0 + +print "Peaks x: " + str(peaks_x) + + +d = mean(arrabs(arrsub(REF, peaks_x))) + +print "Angle = ", d \ No newline at end of file diff --git a/script/test/PuckDetection.py b/script/test/PuckDetection.py new file mode 100644 index 0000000..003ef68 --- /dev/null +++ b/script/test/PuckDetection.py @@ -0,0 +1,24 @@ +################################################################################################### +# Example of using ImageJ functionalities through ijutils. +################################################################################################### + +from ijutils import * +import java.awt.Color as Color + + +#Image Loading +ip = load_image("{images}/test2.png", title="Image") + + +#Puck Detection +aux = grayscale(ip, in_place=False) +aux.show() +plot(get_histogram(aux)) + +subtract_background(aux) +threshold(aux,0,50); aux.repaintWindow() +binary_fill_holes(aux); aux.repaintWindow() +(results,output_img)=analyse_particles(aux, 10000,50000, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.0, maxCirc = 1.0) +output_img.show() \ No newline at end of file diff --git a/script/test/PuckDetectionTest.py b/script/test/PuckDetectionTest.py new file mode 100644 index 0000000..2995f9a --- /dev/null +++ b/script/test/PuckDetectionTest.py @@ -0,0 +1,11 @@ +import datetime +index = 0 +prefix = str(datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) + +while True: + suffix = "%04d - " % index + print (suffix), + run("imgproc/LedDetectionProc.py") + index=index+1 + save_image(image, "{images}/" +prefix + "_" + suffix +".png", "png") + \ No newline at end of file diff --git a/script/test/RobotCartesianScan.py b/script/test/RobotCartesianScan.py new file mode 100644 index 0000000..4a5225e --- /dev/null +++ b/script/test/RobotCartesianScan.py @@ -0,0 +1,28 @@ +import plotutils +from mathutils import fit_gaussian, Gaussian + +robot.enable() +move_to_laser() + +#robot.reset_motion("jLaser") + +#import ch.psi.pshell.device.Timestamp as Timestamp +#sensor = Timestamp() + +#ret = lscan(robot_z, sensor, -50.0, 0.0, 0.5, latency = 0, relative = True) +#ret = lscan(robot_x, sensor, -50.0, 0.0, 0.5, latency = 0, relative = True) + +robot.set_motors_enabled(True) +ret = lscan(robot_x, ue.readable, -1.5, 1.5, 0.1, latency = 0.01, relative = True) + +x,y = ret.getPositions(0), ret.getReadable(0) +y = [100.0-v for v in y] +(norm, mea, sigma) = fit(y, xdata=x) +print "Maximum at " + str(mea) + + + +robot.set_motors_enabled(True) +ret = lscan(robot_rz, ue.readable, 0.0, 40.0, 1.0, latency = 0.01, relative = True, range = "auto") + + diff --git a/script/test/SampleDataInput.py b/script/test/SampleDataInput.py new file mode 100644 index 0000000..1f00cd6 --- /dev/null +++ b/script/test/SampleDataInput.py @@ -0,0 +1,1861 @@ +USER_NAME = "My User" +DEWAR_NAME = "My Dewar" + +test_sample_data = [ \ + +#Puck A1 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "flat_Base_Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "flat_Base_Pin_2", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "regular_Base_Pin_1", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "A1",\ + "sampleName": "regular_Base_Pin_2", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck B1 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + \"sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck B2 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck B3 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck B4 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "u"dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck C1 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck C2 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck D1 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + +# Puck D2 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus""sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "u"dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ +# Puck D3 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ +# Puck D4 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "XXX", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + ] + + +set_samples_info(test_sample_data) \ No newline at end of file diff --git a/script/test/SampleDataInput_Dominik.py b/script/test/SampleDataInput_Dominik.py new file mode 100644 index 0000000..8ff4ae7 --- /dev/null +++ b/script/test/SampleDataInput_Dominik.py @@ -0,0 +1,1862 @@ +USER_NAME = "My User" +DEWAR_NAME = "My Dewar" + +test_sample_data = [ \ + #Puck A1 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "CA00CF1471", \ + "puckType": "unipuck", \ + "puckAddress": "",\ + "sampleName": "flat_Base_Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "CA00CF1471", \ + "puckType": "unipuck", \ + "puckAddress": "",\ + "sampleName": "flat_Base_Pin_2", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "CA00CF1471", \ + "puckType": "unipuck", \ + "puckAddress": "",\ + "sampleName": "regular_Base_Pin_1", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Isabelle Chip", \ + "puckBarcode": "CA00CF1471", \ + "puckType": "unipuck", \ + "puckAddress": "",\ + "sampleName": "regular_Base_Pin_2", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + # Puck B1 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "IDatamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_1", \ + "puckBarcode": "DMBW1", \ + "puckType": "unipuck", \ + "puckAddress": "B1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck B2 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW2", \ + "puckType": "unipuck", \ + "puckAddress": "B2",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck B3 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_2", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_3", \ + "puckBarcode": "DMBW3", \ + "puckType": "unipuck", \ + "puckAddress": "B3",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck B4 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Black_White_4", \ + "puckBarcode": "DMBW4", \ + "puckType": "unipuck", \ + "puckAddress": "B4",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck C1 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_1", \ + "puckBarcode": "DMGA1", \ + "puckType": "unipuck", \ + "puckAddress": "C1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck C2 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "Datamatrix_Grey_Alu_2", \ + "puckBarcode": "DMGA2", \ + "puckType": "unipuck", \ + "puckAddress": "C2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck D1 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_1", \ + "puckBarcode": "NODM1", \ + "puckType": "unipuck", \ + "puckAddress": "D1",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck D2 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_2", \ + "puckBarcode": "NODM2", \ + "puckType": "unipuck", \ + "puckAddress": "D2",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck D3 \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_3", \ + "puckBarcode": "NODM3", \ + "puckType": "unipuck", \ + "puckAddress": "D3",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + \ + # Puck D4 + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_1", \ + "samplePosition": 1,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_2", \ + "samplePosition": 2,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_3", \ + "samplePosition": 3,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_4", \ + "samplePosition": 4,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_5", \ + "samplePosition": 5,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_6", \ + "samplePosition": 6,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_7", \ + "samplePosition": 7,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_8", \ + "samplePosition": 8,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_9", \ + "samplePosition": 9,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_10", \ + "samplePosition": 10,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_11", \ + "samplePosition": 11,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_12", \ + "samplePosition": 12,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_13", \ + "samplePosition": 13,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_14", \ + "samplePosition": 14,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_15", \ + "samplePosition": 15,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + { "userName": USER_NAME, \ + "dewarName": DEWAR_NAME, \ + "puckName": "No_Datamatrix_4", \ + "puckBarcode": "NODM4", \ + "puckType": "unipuck", \ + "puckAddress": "D4",\ + "sampleName": "Pin_16", \ + "samplePosition": 16,\ + "sampleBarcode": "", \ + "sampleStatus": "Present", \ + "sampleMountCount": 0, + } , \ + ] +set_samples_info(test_sample_data) \ No newline at end of file diff --git a/script/test/SampleDetection.py b/script/test/SampleDetection.py new file mode 100644 index 0000000..4638b7a --- /dev/null +++ b/script/test/SampleDetection.py @@ -0,0 +1,23 @@ +################################################################################################### +# Example of using ImageJ functionalities through ijutils. +################################################################################################### + +from ijutils import * +import java.awt.Color as Color + +#Image Loading +ip = load_image("{images}/test2.png", title="Image") + +aux = grayscale(ip, in_place=False) +aux.show() + +invert(aux); aux.repaintWindow() +#gaussian_blur(aux); aux.repaintWindow() +subtract_background(aux); aux.repaintWindow() +auto_threshold(aux); aux.repaintWindow() +binary_open(aux); aux.repaintWindow() +#binary_fill_holes(aux); aux.repaintWindow() +(results,output_img)=analyse_particles(aux, 250,1000, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.7, maxCirc = 1.0) +output_img.show() diff --git a/script/test/TestAlign.py b/script/test/TestAlign.py new file mode 100644 index 0000000..0cbe1a7 --- /dev/null +++ b/script/test/TestAlign.py @@ -0,0 +1,9 @@ + +v = 2.0 +#while(true): +for i in range(100): + v = v * (-1.0) + robot_j4.initialize() + robot_j4.moveRel(v) + robot.align() + \ No newline at end of file diff --git a/script/test/TestBugPcAPI b/script/test/TestBugPcAPI new file mode 100644 index 0000000..5be0f3e --- /dev/null +++ b/script/test/TestBugPcAPI @@ -0,0 +1,4 @@ +while True: + img.initialize() + img.waitNext(10000) + time.sleep(2.0) \ No newline at end of file diff --git a/script/test/TestBugPcAPI.py b/script/test/TestBugPcAPI.py new file mode 100644 index 0000000..7a3d186 --- /dev/null +++ b/script/test/TestBugPcAPI.py @@ -0,0 +1,30 @@ +import ch.psi.pshell.prosilica.Prosilica as Prosilica +import ch.psi.pshell.device.Camera as Camera + + +add_device(Prosilica("img", 25001, "PacketSize=1522;PixelFormat=Mono8;BinningX=1;BinningY=1;RegionX=300;RegionY=200;Width=1000;Height=1000;MulticastEnable=Off"), True) + +img.camera.setGrabMode(Camera.GrabMode.Continuous) +img.camera.setTriggerMode(Camera.TriggerMode.Fixed_Rate) +img.camera.setExposure(50.00) +img.camera.setAcquirePeriod(200.00) +img.camera.setGain(0.0) +#img.camera.setROI(200, 0,1200,1200) +""" +img.camera.setROI(300, 200,1000,1000) +img.config.rotation=17 +img.config.rotationCrop=True +img.config.roiX,img.config.roiY, img.config.roiWidth,img.config.roiHeight = 50,50,900,900 +""" +img.camera.setROI(int(get_setting("roi_x")), int(get_setting("roi_y")), int(get_setting("roi_w")), int(get_setting("roi_h"))) + +img.camera.stop() +img.camera.start() + + +show_panel(img) +#while True: +# img.initialize() +# img.waitNext(1000) +# time.sleep(0.1) + diff --git a/script/test/TestBugPcAPI2.py b/script/test/TestBugPcAPI2.py new file mode 100644 index 0000000..5e92b37 --- /dev/null +++ b/script/test/TestBugPcAPI2.py @@ -0,0 +1,6 @@ +import ch.psi.pshell.imaging.MjpegSource as MjpegSource +MjpegSource2 = get_context().pluginManager.getDynamicClass("MjpegSource2") +add_device(MjpegSource("gripper_cam", "http://axis-accc8e9cc87b.psi.ch/axis-cgi/mjpg/video.cgi"), True) +#gripper_cam.polling=1000 +gripper_cam.monitored = True +show_panel(gripper_cam) \ No newline at end of file diff --git a/script/test/TestBugPcAPI3.py b/script/test/TestBugPcAPI3.py new file mode 100644 index 0000000..6acb775 --- /dev/null +++ b/script/test/TestBugPcAPI3.py @@ -0,0 +1,4 @@ +while True: + img.initialize() + img.waitNext(1000) + time.sleep(0.1) \ No newline at end of file diff --git a/script/test/TestCalib.py b/script/test/TestCalib.py new file mode 100644 index 0000000..2cc311b --- /dev/null +++ b/script/test/TestCalib.py @@ -0,0 +1,30 @@ + +print "calibrate_tool" + +#Initial checks +robot.assert_no_task() +robot.reset_motion() +robot.wait_ready() +robot.assert_cleared() +#robot.assert_in_known_point() + +#Enabling +enable_motion() + +(detected, dm) = move_scanner() + +if detected: + print "Pin detected, trashing..." + trash() + (detected, dm) = move_scanner() + if detected: + raise Exception("Cannot trash pin") + +robot.open_tool() +robot.get_calibration_tool() + +run("calibration/ToolCalibration3") + +robot.put_calibration_tool() + +robot.save_program() diff --git a/script/test/TestCameraStability1.py b/script/test/TestCameraStability1.py new file mode 100644 index 0000000..e4660e9 --- /dev/null +++ b/script/test/TestCameraStability1.py @@ -0,0 +1,11 @@ +for i in range(10): + time.sleep(2) + move_home() + time.sleep(1) + move_park() + start = time.time() + while get_img_cover_pos() != 'A': + print ".", + time.sleep(0.001) + print "Time = " , ( time.time() - start) + \ No newline at end of file diff --git a/script/test/TestCameraStability2.py b/script/test/TestCameraStability2.py new file mode 100644 index 0000000..c6ef878 --- /dev/null +++ b/script/test/TestCameraStability2.py @@ -0,0 +1,14 @@ +cover_detection_debug=True +while True: + for pos in ['A', 'B', 'C', 'D', 'E', 'F']: + print "Moving to ", pos + hexiposi.move(pos) + move_home() + move_park() + time.sleep(2.0) + ret = run("imgproc/CoverDetection") + det = ret[0] + print "Detected: ", det + if det != pos: + raise Exception("Position error") + diff --git a/script/test/TestCameraStability3.py b/script/test/TestCameraStability3.py new file mode 100644 index 0000000..bcf1327 --- /dev/null +++ b/script/test/TestCameraStability3.py @@ -0,0 +1,9 @@ +for i in range(10): + time.sleep(1) + move_home() + time.sleep(1) + move_park() + start = time.time() + time.sleep(1.0) + print run("imgproc/LedDetectionProc.py") + \ No newline at end of file diff --git a/script/test/TestCmdSynchronization.py b/script/test/TestCmdSynchronization.py new file mode 100644 index 0000000..098998d --- /dev/null +++ b/script/test/TestCmdSynchronization.py @@ -0,0 +1,32 @@ +import java.util.logging.Level + +def get_pos_str(): + return "point: " + str(robot.get_current_point()) + " - here: " + str(robot.here()) + " - herej: " + str(robot.herej()) + +enable_motion() + +get_context().setLogLevel(java.util.logging.Level.FINER) +try: + while True: + #robot.move_dewar() + #robot.move_park() + + log("Moving dewar", False) + flag = robot.start_task('moveDewar') + print "moveDewar: ", flag + log("Waiting", False) + ret = robot.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + log("Moving dewar finished (" + str(ret) + ") - pos: " + get_pos_str(), False) + robot.assert_dewar() + + + log("Moving park", False) + flag = robot.start_task('movePark') + print "movePark: ", flag + log("Waiting", False) + ret = robot.wait_task_finished(TASK_WAIT_ROBOT_POLLING) + log("Moving park finished (" + str(ret) + ") - pos: " + get_pos_str(), False) + robot.assert_park() + +finally: + get_context().setLogLevel(java.util.logging.Level.INFO) \ No newline at end of file diff --git a/script/test/TestCoverDetection.py b/script/test/TestCoverDetection.py new file mode 100644 index 0000000..e21e2c0 --- /dev/null +++ b/script/test/TestCoverDetection.py @@ -0,0 +1,19 @@ + +ca = [] +aa = [] +pa = [] + +#for i in range(6): + #index = i+1 +for i in ['A', 'B', 'C', 'D', 'E', 'F']: + hexiposi.move(i) + [position, angle, confidence] = run("imgproc/CoverDetection") + print [position, angle, confidence] + pa.append(position) + aa.append(angle) + ca.append(confidence) + +print "---" +print "Position: " ,pa +print "Angle: " ,aa +print "Confidence: " ,ca, " mean: ", mean(ca) \ No newline at end of file diff --git a/script/test/TestEuclidean.py b/script/test/TestEuclidean.py new file mode 100644 index 0000000..4376dc7 --- /dev/null +++ b/script/test/TestEuclidean.py @@ -0,0 +1,23 @@ +import org.apache.commons.math3.geometry.euclidean.threed.Segment as Segment +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D as Vector3D +import org.apache.commons.math3.geometry.euclidean.threed.Line as Line + + +p = Vector3D(0, 0, 3) + +p1 = Vector3D(0,0,0) +p2 = Vector3D(0,1,1 ) +tolerance = 0.001 + +l = Line(p1, p2, tolerance) + + +print l.distance(p) +print p1.distance(p) +print p2.distance(p) +print "---" + +print l.getAbscissa(p) +print l.pointAt(l.getAbscissa(p)) + +#print l.closestPoint(Line(p, p, 0.01)) \ No newline at end of file diff --git a/script/test/TestLaserScan.py b/script/test/TestLaserScan.py new file mode 100644 index 0000000..a977ba0 --- /dev/null +++ b/script/test/TestLaserScan.py @@ -0,0 +1,12 @@ +robot.set_motors_enabled(True) +steps_x = 10 +steps_y = 8 +#ret = ascan([robot_x, robot_z], ue.readable, [-10.0, -10.0], [10.0, 10.0], [10,10], latency = 0.01, relative = True , zigzag=True) +ret = ascan([robot_x, robot_z], ue.readable, [-10.0, -10.0], [10.0, 10.0], [steps_y,steps_x], latency = 0.01, relative = True , zigzag=False) +data = Convert.transpose(Convert.toBidimensional(to_array(ret.getReadable(0),'d'),steps_x+1,steps_y+1)) +plot(data, title="data") + +data = ret.getData(0) +plot(data, title="data2") + + diff --git a/script/test/TestLayout.py b/script/test/TestLayout.py new file mode 100644 index 0000000..7404a8e --- /dev/null +++ b/script/test/TestLayout.py @@ -0,0 +1,21 @@ + + + +points = [(100, 140), (130, 77), (120, 130), (110, 100)] +clear_detection() +detect_pucks(points) +#detect_pucks(points, 'A') +#detect_pucks(points, '4') +plot_base_plate(points) + + + +#plot_detected_leds(points) + + + +block_id = None +print get_unipucks(block_id) +print get_minispines(block_id) +print get_empties(block_id) +print get_det_errors(block_id) \ No newline at end of file diff --git a/script/test/TestMicrohawk.py b/script/test/TestMicrohawk.py new file mode 100644 index 0000000..0ea517e --- /dev/null +++ b/script/test/TestMicrohawk.py @@ -0,0 +1,10 @@ +import ch.psi.pshell.serial.TcpDevice as TcpDevice +import ch.psi.pshell.serial.UdpDevice as UdpDevice + + +microscan = TcpDevice("microscan", "MicroHAWK38C528:2001") +#microscan = UdpDevice("microscan", "MicroHAWK38C528:2001") +microscan.initialize() + + + diff --git a/script/test/TestRecover.py b/script/test/TestRecover.py new file mode 100644 index 0000000..340853f --- /dev/null +++ b/script/test/TestRecover.py @@ -0,0 +1,15 @@ +print "Pos=" + str(robot.get_cartesian_pos()) +for p in robot.get_known_points(): + print p + " = " + str(get_pnt(p)) + +print "-------------" + +for segment in known_segments: + is_on_segment(segment) + +print "-------------" +for segment in known_segments: + try: + move_to_segment(segment) + except: + print sys.exc_info()[1] \ No newline at end of file diff --git a/script/test/TestRelays.py b/script/test/TestRelays.py new file mode 100644 index 0000000..adcd828 --- /dev/null +++ b/script/test/TestRelays.py @@ -0,0 +1,12 @@ +for i in range(500): + relay1.write(True) + time.sleep(1.2) + relay1.write(False) + time.sleep(1.2) +""" +for i in range(5): + relays.write(to_array([True,]*16, 'z')) + time.sleep(0.2) + relays.write(to_array([False,]*16, 'z')) + time.sleep(0.2) +""" \ No newline at end of file diff --git a/script/test/TestRemoveBackground.py b/script/test/TestRemoveBackground.py new file mode 100644 index 0000000..7376f07 --- /dev/null +++ b/script/test/TestRemoveBackground.py @@ -0,0 +1,31 @@ +number_frames = 5 +number_backgrounds = 5 +minimum_size = 78 # r = 5 # 150 +maximum_size = 750 # r = 15 #1500 +min_circ = 0.2 + +threshold_method = "MaxEntropy" +threshold_method,threshold_range = "Manual", (0, 215) + +exclude_edges = True +led_latency = 0.5 #0.1 + +set_led_state(False) +time.sleep(led_latency) +img.waitNext(2000) + +background = average_frames(number_backgrounds) +#background = integrate_frames(number_backgrounds) + +set_led_state(True) +time.sleep(led_latency) +img.waitNext(2000) +image = average_frames(number_frames) +#image = integrate_frames(number_frames) + +set_led_state(False) + +op_image(image, background, "subtract", float_result=True, in_place=True) +image=grayscale(image) + +show_panel(image.getBufferedImage()) \ No newline at end of file diff --git a/script/test/TestRobot.py b/script/test/TestRobot.py new file mode 100644 index 0000000..d64599f --- /dev/null +++ b/script/test/TestRobot.py @@ -0,0 +1,41 @@ +robot.task_create("simulateEvents",3, name = "test", priority = 20) +print robot.get_task_status("test") +print robot.get_task_status("tests") + +robot.task_suspend("test") +print robot.get_task_status("test") +robot.task_resume("test") +print robot.get_task_status("test") + +robot.task_kill("test") +print robot.get_task_status("test") + + +print robot.is_powered() +print robot.get_monitor_speed() +#print robot.set_monitor_speed(20) +#print robot.enable() +print robot.disable() +print robot.is_calibrated() +print robot.read_working_mode() +print robot.get_emergency_stop_sts() +print robot.get_safety_fault_signal() +print robot.stop() +print robot.resume() +print robot.reset_motion() +print robot.is_empty() +print robot.is_settled() +print robot.get_move_id() +print robot.set_move_id(10) +print robot.get_joint_forces() +#print robot.open("gripper") +#print robot.close("gripper") +print robot.herej() +print robot.distance_t("t", "t") +print robot.distance_p("p", "p") +print robot.compose( "p", "world", "t") +print robot.here("gripper", "world") +print robot.joint_to_point("gripper", "world", "j") +print robot.point_to_joint("gripper", "j", "p") +print robot.position("p", "world") +print robot.mount(1, 2) diff --git a/script/test/TestRobot2.py b/script/test/TestRobot2.py new file mode 100644 index 0000000..68398b8 --- /dev/null +++ b/script/test/TestRobot2.py @@ -0,0 +1,72 @@ +import traceback + +robot.task_create("simulateEvents",3, name = "test", priority = 20) + +step = 0 +try: + while(True): + start = time.time() + step = 1 + robot.is_powered() + step = 2 + robot.get_task_status("test") + step = 3 + robot.get_monitor_speed() + step = 4 + #robot.set_monitor_speed(20) + #robot.enable() + step = 5 + #robot.disable() + step = 6 + robot.is_calibrated() + step = 7 + robot.read_working_mode() + step = 8 + robot.get_emergency_stop_sts() + step = 9 + robot.get_safety_fault_signal() + step = 10 + robot.stop() + step = 11 + robot.resume() + step = 12 + robot.reset_motion() + step = 13 + robot.is_empty() + step = 14 + robot.is_settled() + step = 15 + robot.get_move_id() + step = 16 + robot.set_move_id(10) + step = 17 + robot.get_joint_forces() + step = 18 + #robot.open_tool("gripper") + #robot.close_tool("gripper") + robot.herej() + step = 19 + robot.distance_t("t", "t") + step = 20 + robot.distance_p("p", "p") + step = 21 + robot.compose( "p", "world", "t") + step = 22 + robot.here("gripper", "world") + step = 23 + robot.joint_to_point("gripper", "world", "j") + step = 24 + robot.point_to_joint("gripper", "j", "p") + step = 25 + robot.position("p", "world") + step = 26 + robot.mount(1, 2) + #print time.time()-start +except: + print >> sys.stderr, traceback.format_exc() +finally: + print "Step: " + str(step) + try: + robot.task_kill("test") + except: + pass \ No newline at end of file diff --git a/script/test/TestRobotCmds.py b/script/test/TestRobotCmds.py new file mode 100644 index 0000000..4225281 --- /dev/null +++ b/script/test/TestRobotCmds.py @@ -0,0 +1,32 @@ + +import java.lang.System as System + +index = 0 +max_time = 0 +while True: + start = System.currentTimeMillis() + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + robot.execute(1,1,1) + time.sleep(0.01) + robot.execute(2,1,1) + time.sleep(0.01) + cur_time = System.currentTimeMillis() - start + max_time = max(cur_time, max_time) + print index, cur_time, max_time + index = index + 1 + \ No newline at end of file diff --git a/script/test/TestRobotCmds2.py b/script/test/TestRobotCmds2.py new file mode 100644 index 0000000..048e20e --- /dev/null +++ b/script/test/TestRobotCmds2.py @@ -0,0 +1,25 @@ +if robot_req.read() != 0: + raise Exception("Ongoing command") +if robot_ack.read() != 0: + raise Exception("Robot is not ready") +robot_cmd.write(1) +args = [0,0,0,0,0,0] + +robot_args.write(to_array(args, 'i')) + + +robot_req.write(1) +while robot_ack.read() == 0: + time.sleep(0.001) + +err = robot_ack.take() +if err == 1: + ret = robot_ret.read() + print ret +if err == 2: + print ("Invalid command: " + str(command)) +print ("Unknown error: " + str(err)) +robot_req.write(0) +while robot_ack.read() != 0: + time.sleep(0.001) + diff --git a/script/test/cycle_time b/script/test/cycle_time new file mode 100644 index 0000000..79c790e --- /dev/null +++ b/script/test/cycle_time @@ -0,0 +1,4 @@ +start =time.time() +unmount('A',2,5, force=True) +mount('A',2,5, force=True, read_dm=False) +print time.time()-start \ No newline at end of file diff --git a/script/test/imgtest.py b/script/test/imgtest.py new file mode 100644 index 0000000..de442c2 --- /dev/null +++ b/script/test/imgtest.py @@ -0,0 +1,47 @@ +################################################################################################### +# Example of using ImageJ functionalities through ijutils. +################################################################################################### + +from ijutils import * +import java.awt.Color as Color + +import ch.psi.pshell.imaging.Filter as Filter +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.pshell.imaging.Pen as Pen + + + +def detect_pucks(ip): + aux = grayscale(ip, in_place=False) + threshold(aux,0,50) + binary_fill_holes(aux) + return analyse_particles(aux, 10000,50000, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.4, maxCirc = 1.0) + +def detect_samples(ip): + aux = grayscale(ip, in_place=False) + invert(aux) + subtract_background(aux) + auto_threshold(aux) + binary_open(aux) + return analyse_particles(aux, 300,800, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.4 + , maxCirc = 1.0) + + +class MyFilter(Filter): + def process(self, image, data): + ip = load_image(image) + (results_puck,output_puck) = detect_pucks(ip) + (results_samples,output_samples) = detect_samples(ip) + set_lut(output_puck, outline_lut1[0], outline_lut1[1], outline_lut1[2]) + set_lut(output_samples, outline_lut2[0], outline_lut2[1], outline_lut2[2]) + op_image(ip, output_samples, "xor") + op_image(ip, output_puck, "xor") + return ip.getBufferedImage() + +#Setting the filter to a source +img.setFilter(MyFilter()) + diff --git a/script/test/ip b/script/test/ip new file mode 100644 index 0000000..e79bb62 --- /dev/null +++ b/script/test/ip @@ -0,0 +1,15 @@ +from ijutils import * +import java.awt.Color as Color + +ip = load_image(img.getImage()) +grayscale(ip) +#ip=binning(ip,2) +gaussian_blur(ip) +#bandpass_filter(ip,20, 100) +auto_threshold(ip) + +#Particle Analysis +(results,output_img)=analyse_particles(ip, 500,2000, print_table=True) +output_img.show() + +ip.show() \ No newline at end of file diff --git a/script/test/onewire.py b/script/test/onewire.py new file mode 100644 index 0000000..5141067 --- /dev/null +++ b/script/test/onewire.py @@ -0,0 +1,122 @@ +import traceback + +class Detector(ReadonlyRegisterBase): + def __init__(self, name): + ReadonlyRegisterBase.__init__(self, name) + self.id = None + self.sn = None + self.status = None + self.type = None + self.set_inputs({}) + + def set_inputs(self, inputs): + self.inputs = inputs + self.setCache(inputs.values(), None) + if (len(self.take()) == 0): + self.setState(State.Offline) + else: + self.setState(State.Ready) + + def set_input(self, index, val): + self.inputs[index] = val + self.set_inputs(self.inputs) + +class Esera(TcpDevice): + def __init__(self, name, server, timeout = 1000, retries = 1): + TcpDevice.__init__(self, name, server) + self.setMode(self.Mode.FullDuplex) + self.detectors = [] + self.complete = False + + def start(self): + self.write("set,sys,run,1\n") + + def stop(self): + self.write("set,sys,run,0\n") + + def list(self): + self.write("get,owb,listall1\n") + + def req_data(self): + self.write("get,sys,data\n") + + def doInitialize(self): + super(Esera, self).doInitialize() + try: + self.setState(State.Ready) #So can communicate + #self.stop() + #time.sleep(0.1) + #self.flush() + self.detectors = [] + for i in range(30): + self.detectors.append(Detector("Detector " + str(i+1))) + self.list() + time.sleep(0.5) + self.start() + self.req_data() + except: + print >> sys.stderr, traceback.format_exc() + getLogger().log(traceback.format_exc()) + raise + + def doUpdate(self): + if not self.complete: + init = True + for det in self.detectors: + if det.id == None: + init = False + break + if init: + self.complete = True + self.start() + + self.req_data() + #def onByte(self, rx): + # print rx + + def onString(self, msg): + print msg + tokens = msg.split("|") + if len(tokens)>1: + try: + if msg[:3] == "LST": + #LST|1_OWD1|3AF361270000009E|S_0|DS2413| + if tokens[1] > 1: + index = int(tokens[1].split("_")[1][3:]) - 1 + if index < len(self.detectors): + det = self.detectors[index] + det.id = tokens[1] + det.sn= tokens[2] if len(tokens)>2 else None + det.status = int(tokens[3][2:]) if len(tokens)>3 else None + det.type = tokens[4] if len(tokens)>4 else None + if det.status!= 0: + det.set_inputs({}) + else: + for det in self.detectors: + if det.id is not None and msg.startswith(det.id): + det_id = int(tokens[0][len(det.id)+1:]) + det.set_input(det_id, int(tokens[1])) + except: + print >> sys.stderr, traceback.format_exc() + getLogger().log(traceback.format_exc()) + + + + +#count = 1 +#while (True): +# print onewire.waitString("\n", 1000)# +# +# print count +# count = count + 1 + + + + + + +add_device(Esera("onewire", "129.129.126.83:5000"), force = True) +onewire.setPolling(1000) +add_device(onewire.detectors[0], force = True) +add_device(onewire.detectors[1], force = True) +add_device(onewire.detectors[2], force = True) diff --git a/script/test/test.py b/script/test/test.py new file mode 100644 index 0000000..92fcaca --- /dev/null +++ b/script/test/test.py @@ -0,0 +1,24 @@ +from ijutils import * +import java.awt.Color as Color + + +#ip = load_array(img.getData().getMatrix()) +ip = load_image(img.getOutput()) +#ip = load_image("{images}/test3.png", title="Image") + + +aux = grayscale(ip, in_place=False) +aux.show() + +#convolve(aux, KERNEL_SOBEL); aux.repaintWindow() + +invert(aux); aux.repaintWindow() +subtract_background(aux); aux.repaintWindow() +auto_threshold(aux); aux.repaintWindow() +binary_open(aux); aux.repaintWindow() + +(table, image) = analyse_particles(aux, 250,1000, + fill_holes = False, exclude_edges = True,print_table=True, + output_image = "outlines", minCirc = 0.82, maxCirc = 1.0) + +image.show() \ No newline at end of file diff --git a/script/test/test_hexiposi.py b/script/test/test_hexiposi.py new file mode 100644 index 0000000..324a480 --- /dev/null +++ b/script/test/test_hexiposi.py @@ -0,0 +1,8 @@ +index = 1 +while(True): + for pos in ['A', 'B', 'C', 'D', 'E', 'F']: + hexiposi.move(pos) + visual_check_hexiposi(pos) + print "Ok: " + pos + print index + index = index + 1 \ No newline at end of file diff --git a/script/test/test_swingutils.py b/script/test/test_swingutils.py new file mode 100644 index 0000000..65b354b --- /dev/null +++ b/script/test/test_swingutils.py @@ -0,0 +1,24 @@ +import ch.psi.pshell.imaging.RendererMode as RendererMode +import ch.psi.pshell.imaging.Calibration as Calibration +from ch.psi.pshell.imaging.Overlays import * +import ch.psi.utils.swing.SwingUtils as SwingUtils +import javax.swing.SwingUtilities as SwingUtilities +from swingutils.threads.swing import callSwing + + +p = show_panel(img) +dlg = SwingUtilities.getWindowAncestor(p) +dlg.setSize(800,800) +frm=SwingUtils.getFrame(p) +dlg.setLocationRelativeTo(frm) + +def update_frame(frm): + SwingUtilities.updateComponentTreeUI(frm) + frm.validate() + frm.repaint() +#$callSwing(update_frame, frm) + + +x=0 +for i in range(0,10000000): + x=x+1 \ No newline at end of file diff --git a/script/tools/CheckPuckDetection.py b/script/tools/CheckPuckDetection.py new file mode 100644 index 0000000..0582bad --- /dev/null +++ b/script/tools/CheckPuckDetection.py @@ -0,0 +1,6 @@ +USR,PWD = "pi", "raspberry" +HOST,PORT = "tell-raspberrypi", 22 +CMD= "sudo systemctl status puck_detection.service" + +ret = run("tools/SshExec") +set_return(ret) \ No newline at end of file diff --git a/script/tools/Math.py b/script/tools/Math.py new file mode 100644 index 0000000..c76ce33 --- /dev/null +++ b/script/tools/Math.py @@ -0,0 +1,68 @@ +################################################################################################### +# Math utilities +################################################################################################### + + +from mathutils import estimate_peak_indexes, fit_gaussians, create_fit_point_list, Gaussian +import java.awt.Color as Color + +import mathutils +mathutils.MAX_ITERATIONS = 100000 + +def fit(ydata, xdata = None, draw_plot = True): + if xdata is None: + xdata = frange(0, len(ydata), 1) + max_y= max(ydata) + index_max = ydata.index(max_y) + max_x= xdata[index_max] + #print "Max index:" + str(index_max), + #print " x:" + str(max_x), + #print " y:" + str(max_y) + + if draw_plot: + plots = plot([ydata],["data"],[xdata], title="Fit" ) + p = None if plots is None else plots[0] + + gaussians = fit_gaussians(ydata, xdata, [index_max,]) + if gaussians[0] is None: + if draw_plot and (p is not None): + p.addMarker(max_x, None, "Max="+str(round(max_x,4)), Color.GRAY) + print "Fitting error" + return (None, None, None) + + (norm, mean, sigma) = gaussians[0] + if draw_plot: + fitted_gaussian_function = Gaussian(norm, mean, sigma) + scale_x = [float(min(xdata)), float(max(xdata)) ] + points = max((len(xdata)+1), 100) + resolution = (scale_x[1]-scale_x[0]) / points + fit_y = [] + fit_x = frange(scale_x[0],scale_x[1],resolution, True) + for x in fit_x: + fit_y.append(fitted_gaussian_function.value(x)) + #Server + if p is None: + plot([ydata,fit_y],["data","fit"],[xdata,fit_x], title="Fit") + draw_plot = False + else: + p.addSeries(LinePlotSeries("fit")) + p.getSeries(1).setData(fit_x, fit_y) + + if abs(mean - xdata[index_max]) < abs((scale_x[0] + scale_x[1])/2): + if draw_plot: + p.addMarker(mean, None, "Mean="+str(round(mean,4)), Color.MAGENTA.darker()) + #print "Mean -> " + str(mean) + return (norm, mean, sigma) + else: + if draw_plot: + p.addMarker(max_x, None, "Max="+str(round(max_x,4)), Color.GRAY) + #print "Invalid gaussian fit: " + str(mean) + return (None, None, None) + + +def enforce_monotonic(x): + epsilon = 1e-8 + for i in range(len(x)-1): + if x[i+1]<=x[i]: + x[i+1] = x[i]+ epsilon + return x \ No newline at end of file diff --git a/script/tools/RestartPuckDetection.py b/script/tools/RestartPuckDetection.py new file mode 100644 index 0000000..2251921 --- /dev/null +++ b/script/tools/RestartPuckDetection.py @@ -0,0 +1,8 @@ +USR,PWD = "pi", "raspberry" +HOST,PORT = "tell-raspberrypi", 22 +CMD= "sudo systemctl stop puck_detection.service;sudo systemctl start puck_detection.service" + +ret = run("tools/SshExec") +set_return(ret) + +puck_detection.initialize() \ No newline at end of file diff --git a/script/tools/SshExec.py b/script/tools/SshExec.py new file mode 100644 index 0000000..c9e4f50 --- /dev/null +++ b/script/tools/SshExec.py @@ -0,0 +1,61 @@ +import com.jcraft.jsch.Channel as Channel +import com.jcraft.jsch.ChannelShell as ChannelShell +import com.jcraft.jsch.JSch as JSch +import com.jcraft.jsch.JSchException as JSchException +import com.jcraft.jsch.Session as Session +import java.lang.System as System +import java.io.PrintStream as PrintStream + + +#Parameters: +#CMD +#USR +#PWD +#HOST +#PORT + +jsch= JSch() +session=jsch.getSession(USR, HOST, PORT) +session.setPassword(PWD) +session.setConfig("StrictHostKeyChecking", "no") +session.connect() + +#channel=session.openChannel("shell") +#input_stream=channel.getInputStream() +#output_stream = channel.getOutputStream() +#print_stream = PrintStream(output_stream, True) +#print_stream.println("ls") + +channel=session.openChannel("exec") +channel.setCommand(CMD) +channel.setInputStream(None) +channel.setOutputStream(System.out) +channel.setErrStream(System.err) +input_stream=channel.getInputStream() + + +def wait_ret(): + global input_stream + rx = "" + while True: + while (input_stream.available() > 0): + i = input_stream.read() + if i < 0: + break + rx=rx+chr(i) + if channel.closed: + break + time.sleep(0.1) + return rx + + +channel.connect() + +try: + ret = wait_ret() +except: + channel.disconnect() + session.disconnect() + raise + +set_return(ret) \ No newline at end of file diff --git a/script/tools/StopPuckDetection.py b/script/tools/StopPuckDetection.py new file mode 100644 index 0000000..1ff6f04 --- /dev/null +++ b/script/tools/StopPuckDetection.py @@ -0,0 +1,8 @@ +USR,PWD = "pi", "raspberry" +HOST,PORT = "tell-raspberrypi", 22 +CMD= "sudo systemctl stop puck_detection.service" + +ret = run("tools/SshExec") +set_return(ret) + +