From 9ef973fa49cdd4afa082934d96b64a77150d4710 Mon Sep 17 00:00:00 2001 From: gac-S_Changer Date: Wed, 8 Aug 2018 16:01:05 +0200 Subject: [PATCH] --- config/devices.properties | 12 +- devices/dewar_level.properties | 2 +- devices/img.properties | 18 +-- devices/led_ctrl_1.properties | 2 +- devices/led_ctrl_2.properties | 2 +- devices/led_ctrl_3.properties | 2 +- plugins/MXSC-1.10.0.jar | Bin 201500 -> 202223 bytes plugins/Recovery.form | 63 ++++++++--- plugins/Recovery.java | 190 ++++++++++++++++++++------------ script/data/get_samples_info.py | 4 + script/data/samples.py | 23 ++++ script/data/set_samples_info.py | 4 + script/devices/Hexiposi.py | 2 +- script/devices/RobotSC.py | 14 ++- script/devices/RobotTCP.py | 31 +++++- script/local.py | 39 ++++++- script/motion/recover.py | 112 ++++++++++++++++++- script/test/TestBugPcAPI2.py | 2 +- script/test/TestEuclidean.py | 23 ++++ script/test/TestMicrohawk.py | 4 +- script/test/TestRecover.py | 15 +++ 21 files changed, 436 insertions(+), 128 deletions(-) create mode 100644 script/data/get_samples_info.py create mode 100644 script/data/samples.py create mode 100644 script/data/set_samples_info.py create mode 100644 script/test/TestEuclidean.py create mode 100644 script/test/TestRecover.py diff --git a/config/devices.properties b/config/devices.properties index 2ab3f36..8a2c023 100644 --- a/config/devices.properties +++ b/config/devices.properties @@ -1,12 +1,12 @@ 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://129.129.110.114/axis-cgi/mjpg/video.cgi||-1| -microscan=ch.psi.pshell.serial.TcpDevice|129.129.110.200:2001||| -microscan_cmd=ch.psi.pshell.serial.TcpDevice|129.129.110.200:2003||| +gripper_cam=ch.psi.pshell.imaging.MjpegSource|http://axis-accc8e9cc87b.psi.ch/axis-cgi/mjpg/video.cgi?camera=1||-1| +microscan=ch.psi.pshell.serial.TcpDevice|MicroHAWK38C528:2001||| +microscan_cmd=ch.psi.pshell.serial.TcpDevice|MicroHAWK38C528: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||| +#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| diff --git a/devices/dewar_level.properties b/devices/dewar_level.properties index 92a5279..38fab62 100644 --- a/devices/dewar_level.properties +++ b/devices/dewar_level.properties @@ -1,4 +1,4 @@ -#Tue Jun 19 16:41:20 CEST 2018 +#Wed Aug 08 14:23:54 CEST 2018 offset=-25.81632 precision=2 scale=0.003888 diff --git a/devices/img.properties b/devices/img.properties index cb23248..db77fa4 100644 --- a/devices/img.properties +++ b/devices/img.properties @@ -1,4 +1,4 @@ -#Thu Jun 14 10:54:07 CEST 2018 +#Wed Aug 08 11:53:16 CEST 2018 colormap=Grayscale colormapAutomatic=false colormapMax=18.133 @@ -9,16 +9,16 @@ grayscale=false invert=false rescaleFactor=1.0 rescaleOffset=0.0 -roiHeight=872 -roiWidth=869 -roiX=74 +roiHeight=-1 +roiWidth=-1 +roiX=0 roiY=0 -rotation=17.93079800677477 +rotation=0.0 rotationCrop=true scale=1.0 -spatialCalOffsetX=-435.0 -spatialCalOffsetY=-436.0 -spatialCalScaleX=0.540300793168967 -spatialCalScaleY=0.5385447475747382 +spatialCalOffsetX=NaN +spatialCalOffsetY=NaN +spatialCalScaleX=NaN +spatialCalScaleY=NaN spatialCalUnits=mm transpose=false diff --git a/devices/led_ctrl_1.properties b/devices/led_ctrl_1.properties index ff1c589..c0cba8a 100644 --- a/devices/led_ctrl_1.properties +++ b/devices/led_ctrl_1.properties @@ -1,4 +1,4 @@ -#Fri Jun 29 16:49:51 CEST 2018 +#Wed Aug 08 14:23:56 CEST 2018 maxValue=0.4 minValue=0.0 offset=0.0 diff --git a/devices/led_ctrl_2.properties b/devices/led_ctrl_2.properties index ff1c589..c0cba8a 100644 --- a/devices/led_ctrl_2.properties +++ b/devices/led_ctrl_2.properties @@ -1,4 +1,4 @@ -#Fri Jun 29 16:49:51 CEST 2018 +#Wed Aug 08 14:23:56 CEST 2018 maxValue=0.4 minValue=0.0 offset=0.0 diff --git a/devices/led_ctrl_3.properties b/devices/led_ctrl_3.properties index ff1c589..c0cba8a 100644 --- a/devices/led_ctrl_3.properties +++ b/devices/led_ctrl_3.properties @@ -1,4 +1,4 @@ -#Fri Jun 29 16:49:51 CEST 2018 +#Wed Aug 08 14:23:56 CEST 2018 maxValue=0.4 minValue=0.0 offset=0.0 diff --git a/plugins/MXSC-1.10.0.jar b/plugins/MXSC-1.10.0.jar index 0c137d23339575ed0f25a5154ddd1e1d1d4cdc21..f3f63157b223f5582924fc24b95aada424497349 100644 GIT binary patch delta 15113 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 W$nb^)0QBJhKokJL#5ueJ0RA89r|bv- delta 14804 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

@PVhC^ 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 R7{mWH!gXtK3ZEpD{|7sT{h9y( diff --git a/plugins/Recovery.form b/plugins/Recovery.form index 0a89edd..15e9571 100644 --- a/plugins/Recovery.form +++ b/plugins/Recovery.form @@ -18,27 +18,36 @@ - - + + - - + + + + - - + + + + + - - + + + + + + - + @@ -47,44 +56,66 @@ - + + - + + - + + + - + - + - + + + + + + + + + - + + + + + + + + + + + diff --git a/plugins/Recovery.java b/plugins/Recovery.java index d6bd7a3..8f34918 100644 --- a/plugins/Recovery.java +++ b/plugins/Recovery.java @@ -5,6 +5,8 @@ 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; /** * @@ -13,6 +15,7 @@ public class Recovery extends Panel { public Recovery() { initComponents(); + startTimer(3000, 200); } //Overridable callbacks @@ -23,83 +26,80 @@ public class Recovery extends Panel { @Override public void onStateChange(State state, State former) { + 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) { } - //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; - }); + protected void onTimer() { + 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]"); } catch (Exception ex) { - showException(ex); + System.out.println(ex); + ledValidSegment.setColor(Color.BLACK); + textSegment.setText(""); } - } - - void execute(String script, Object args){ - try { - runAsync(script, args).handle((ret, ex) -> { - if (ex != null){ - showException((Exception)ex); - } - return ret; - }); + try{ + String point = (String) eval("robot.get_current_point()", true); + ledKnownPosition.setColor((point == null) ? Color.RED : Color.GREEN); + textPosition.setText((point == null) ? "": point); } catch (Exception ex) { - showException(ex); - } - } - - - + System.out.println(ex); + ledKnownPosition.setColor(Color.BLACK); + textPosition.setText(""); + } + updateButton(); + } + + @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { - ledLidControlActive = new ch.psi.pshell.swing.Led(); + ledKnownPosition = new ch.psi.pshell.swing.Led(); jLabel6 = new javax.swing.JLabel(); - ledLidInitialized = new ch.psi.pshell.swing.Led(); + ledValidSegment = new ch.psi.pshell.swing.Led(); jLabel7 = new javax.swing.JLabel(); - buttonInitHexiposi = new javax.swing.JButton(); + buttonRecover = new javax.swing.JButton(); + buttonAbort = new javax.swing.JButton(); + textPosition = new javax.swing.JTextField(); + textSegment = new javax.swing.JTextField(); jLabel6.setText("Known position"); jLabel7.setText("Valid segment"); - buttonInitHexiposi.setText("Recover"); - buttonInitHexiposi.setEnabled(false); - buttonInitHexiposi.addActionListener(new java.awt.event.ActionListener() { + buttonRecover.setText("Recover"); + buttonRecover.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonInitHexiposiActionPerformed(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); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -110,48 +110,98 @@ public class Recovery extends Panel { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(ledLidControlActive, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .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)) + .addComponent(jLabel6) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(textPosition)) .addGroup(layout.createSequentialGroup() - .addComponent(ledLidInitialized, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .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)))) + .addComponent(jLabel7) + .addGap(16, 16, 16) + .addComponent(textSegment))) + .addGap(8, 8, 8)) .addGroup(layout.createSequentialGroup() - .addContainerGap(96, Short.MAX_VALUE) - .addComponent(buttonInitHexiposi))) - .addContainerGap(116, Short.MAX_VALUE)) + .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)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 144, Short.MAX_VALUE))) + .addContainerGap()) ); + + 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(ledLidControlActive, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel6)) + .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(ledLidInitialized, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel7)) + .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)) .addGap(18, 18, 18) - .addComponent(buttonInitHexiposi) + .addComponent(buttonRecover) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonAbort) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents - private void buttonInitHexiposiActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonInitHexiposiActionPerformed + private void buttonRecoverActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRecoverActionPerformed try{ - this.showDevicePanel("hexiposi"); + 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_buttonInitHexiposiActionPerformed + }//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 buttonInitHexiposi; + private javax.swing.JButton buttonAbort; + private javax.swing.JButton buttonRecover; private javax.swing.JLabel jLabel6; private javax.swing.JLabel jLabel7; - private ch.psi.pshell.swing.Led ledLidControlActive; - private ch.psi.pshell.swing.Led ledLidInitialized; + private ch.psi.pshell.swing.Led ledKnownPosition; + private ch.psi.pshell.swing.Led ledValidSegment; + private javax.swing.JTextField textPosition; + private javax.swing.JTextField textSegment; // End of variables declaration//GEN-END:variables } 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/samples.py b/script/data/samples.py new file mode 100644 index 0000000..7db91a4 --- /dev/null +++ b/script/data/samples.py @@ -0,0 +1,23 @@ +import json +import org.python.core.PyDictionary as PyDictionary + + +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)) + ")") + #for sample in info: + # if not (type(sample) is PyDictionary): + # raise Exception("Sample info element must be a dictionary (given object type is " + str(type(sample)) + ")") + samples_info = info + return samples_info + + + +def get_samples_info(as_json=True): + global sample_info + return json.dumps(samples_info) if as_json else samples_info \ 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/Hexiposi.py b/script/devices/Hexiposi.py index 77794db..01f5a1e 100644 --- a/script/devices/Hexiposi.py +++ b/script/devices/Hexiposi.py @@ -127,7 +127,7 @@ class Hexiposi(DiscretePositionerBase): -#http://129.129.110.83:8002/hexiposi/get +#http://myriotell:8002/hexiposi/get dev = Hexiposi("hexiposi", "myriotell:8002/hexiposi") add_device(dev, True) diff --git a/script/devices/RobotSC.py b/script/devices/RobotSC.py index a8e3a21..7bd8b14 100644 --- a/script/devices/RobotSC.py +++ b/script/devices/RobotSC.py @@ -210,13 +210,19 @@ class RobotSC(RobotTCP): robot.waitState(State.Ready, 1000) #robot.state.assertReady() if simulation: - #add_device(RobotSC("robot","129.129.126.92:1000"),force = True) - add_device(RobotSC("robot","129.129.110.81:1000"),force = True) + add_device(RobotSC("robot","localhost:1000"),force = True) else: - add_device(RobotSC("robot", "129.129.110.100:1000"), force = True) + #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_monitor_speed(20) robot.set_default_desc(DESC_DEFAULT) +robot.default_speed = 20 +robot.set_tool(TOOL_DEFAULT) +robot.setPolling(DEFAULT_ROBOT_POLLING) + class jf1(ReadonlyRegisterBase): diff --git a/script/devices/RobotTCP.py b/script/devices/RobotTCP.py index 662a2b5..fb8616c 100644 --- a/script/devices/RobotTCP.py +++ b/script/devices/RobotTCP.py @@ -45,7 +45,8 @@ class RobotTCP(TcpDevice, Stoppable): self.frame = FRAME_DEFAULT self.polling_interval = 0.01 self.reset = True - self.default_tolerance = 10 + self.default_tolerance = 10 + self.default_speed = 100 self.task_start_retries = 3 self.exception_on_task_start_failure = True #Tasks may start and be finished when checked @@ -68,8 +69,11 @@ class RobotTCP(TcpDevice, Stoppable): return self.tool - def assert_tool(self, tool): - if self.tool != tool: + 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): @@ -213,11 +217,13 @@ class RobotTCP(TcpDevice, Stoppable): 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") @@ -275,9 +281,12 @@ class RobotTCP(TcpDevice, Stoppable): 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()") + return self.eval_bool("isCalibrated()") def save_program(self): ret = self.execute('save', timeout=5000) @@ -367,6 +376,10 @@ class RobotTCP(TcpDevice, Stoppable): 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(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() @@ -375,6 +388,9 @@ class RobotTCP(TcpDevice, Stoppable): 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() @@ -588,13 +604,15 @@ class RobotTCP(TcpDevice, Stoppable): def get_flange_pos(self): return self.eval_pnt("jointToPoint(" +FLANGE + ", " + self.frame + ", herej())") - def get_cartesian_pos(self): + 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): - return self.here(self.tool, self.frame) + self.assert_tool() + return self.here(self.tool, self.frame) def get_distance_to_pnt(self, name): #self.here(self.tool, self.frame) #??? @@ -672,6 +690,7 @@ class RobotTCP(TcpDevice, Stoppable): m.initialize() #Alignment def align(self, point = None, frame = FRAME_DEFAULT, desc = None): + self.assert_tool() if desc is None: desc = self.default_desc if point is None: self.get_cartesian_pos() diff --git a/script/local.py b/script/local.py index e7b45da..df1ab13 100644 --- a/script/local.py +++ b/script/local.py @@ -5,6 +5,7 @@ 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 run("setup/Layout") @@ -29,6 +30,7 @@ add_device(img.getCamera(), force = True) # Utility modules ################################################################################################### +run("data/samples") run("motion/tools") run("motion/mount") run("motion/unmount") @@ -45,6 +47,7 @@ run("motion/move_scanner") run("motion/dry") run("motion/homing_hexiposi") run("motion/robot_recover") +run("motion/recover") run("imgproc/Utils") run("tools/Math") @@ -81,10 +84,6 @@ def check_puck_detection(): def stop_puck_detection(): run("tools/StopPuckDetection") -DEWAR_LEVEL_RT = 5.0 - -def is_room_temp(): - return dewar_level.read() <= DEWAR_LEVEL_RT ################################################################################################### @@ -111,7 +110,7 @@ except: try: robot.setPolling(DEFAULT_ROBOT_POLLING) - robot.set_tool(TOOL_CALIBRATION) + robot.set_tool(TOOL_DEFAULT) robot.set_motors_enabled(True) robot.set_joint_motors_enabled(True) except: @@ -143,6 +142,36 @@ except: #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) + + + ################################################################################################### # Global variables ################################################################################################### diff --git a/script/motion/recover.py b/script/motion/recover.py index 37e7d77..d3690d1 100644 --- a/script/motion/recover.py +++ b/script/motion/recover.py @@ -1,5 +1,109 @@ -def recover(): - """ - """ - print "recover" +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 + + +known_segments = [ ("pHome", "pPark", 10), \ + ("pHome", "pDewarHome", 10), \ + ("pHome", "pGonioHome", 10), \ + ("pHome", "pScanHome", 10), \ + ("pHome", "pHeaterHome", 10), \ + ("pDewarHome", "pDewarWait", 10), \ + ("pGonioHome", "pGonioGet", 10), \ + ("pHeaterHome", "pHeater", 10), \ + ("pHeater", "pHeaterBottom", 10), \ + ] + + +def is_on_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) + + #Check if on segment + d = l.distance(v) + if d > tolerance: + #print "Current robot position " + str(p) + " not on segment " + str(segment) + " - distance=" + str(d) + return False + + # Check if inside segment + d1, d2 = v1.distance(v), v2.distance(v) + if d1>d2: + d1, d2 = d2, d1 + d1, d2 = d1, d2 + if d<(d1-tolerance) or d>(d2+tolerance): + #print "Current robot position " + str(p) + " not on segment " + str((d1, d2)) + " of 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_current_segment(): + for segment in known_segments: + if is_on_segment(segment): + return segment + return None + +def move_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) + a = l.getAbscissa(v) + lv = l.pointAt(a) + 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) + robot.movel(d, tool=None, desc=DESC_SLOW, sync=True) + + +#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]) + if (d2<=d1) and (d2 <= vicinity_tolerance): + robot.movel(segment[1], tool=None, desc=DESC_SLOW, sync=True) + else: + robot.movel(segment[0], tool=None, desc=DESC_SLOW, sync=True) + #print "Recovered to point " + str(robot.get_current_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") + + #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) + return "Success recovering to point: " + str(robot.get_current_point()) + #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/test/TestBugPcAPI2.py b/script/test/TestBugPcAPI2.py index 0747cd0..5e92b37 100644 --- a/script/test/TestBugPcAPI2.py +++ b/script/test/TestBugPcAPI2.py @@ -1,6 +1,6 @@ import ch.psi.pshell.imaging.MjpegSource as MjpegSource MjpegSource2 = get_context().pluginManager.getDynamicClass("MjpegSource2") -add_device(MjpegSource("gripper_cam", "http://129.129.110.114/axis-cgi/mjpg/video.cgi"), True) +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/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/TestMicrohawk.py b/script/test/TestMicrohawk.py index fbe8471..0ea517e 100644 --- a/script/test/TestMicrohawk.py +++ b/script/test/TestMicrohawk.py @@ -2,8 +2,8 @@ import ch.psi.pshell.serial.TcpDevice as TcpDevice import ch.psi.pshell.serial.UdpDevice as UdpDevice -microscan = TcpDevice("microscan", "129.129.126.200:2001") -#microscan = UdpDevice("microscan", "129.129.126.200:2001") +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