This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
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
|
||||
#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|
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Mon Oct 15 11:33:41 CEST 2018
|
||||
maxValue=1.0
|
||||
#Thu Oct 25 15:44:44 CEST 2018
|
||||
maxValue=0.4
|
||||
minValue=0.0
|
||||
offset=0.0
|
||||
precision=2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Mon Oct 15 11:33:41 CEST 2018
|
||||
maxValue=1.0
|
||||
#Thu Oct 25 15:44:44 CEST 2018
|
||||
maxValue=0.4
|
||||
minValue=0.0
|
||||
offset=0.0
|
||||
precision=2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Mon Oct 15 11:33:41 CEST 2018
|
||||
maxValue=1.0
|
||||
#Thu Oct 25 15:44:44 CEST 2018
|
||||
maxValue=0.4
|
||||
minValue=0.0
|
||||
offset=0.0
|
||||
precision=2
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#Wed Oct 17 16:51:06 CEST 2018
|
||||
#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
|
||||
|
||||
369
script/client/PShellClient.py
Normal file
369
script/client/PShellClient.py
Normal file
@@ -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
|
||||
|
||||
167
script/client/TellClient.py
Normal file
167
script/client/TellClient.py
Normal file
@@ -0,0 +1,167 @@
|
||||
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 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):
|
||||
#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)
|
||||
|
||||
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(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 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 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 ("")
|
||||
|
||||
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()))
|
||||
42
script/client/tell.py
Normal file
42
script/client/tell.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import sys
|
||||
from TellClient import TellClient
|
||||
import code
|
||||
|
||||
tell = TellClient("http://Alexandres-MBP.psi.ch:8080")
|
||||
|
||||
def info():
|
||||
tell.print_info()
|
||||
|
||||
def help():
|
||||
print ("Commands: help(), info(), mount(segment, puck, sample), unmount(), scan(segment, puck, sample=None), move_cold(), trash(), abort()\n")
|
||||
|
||||
def mount(segment, puck, sample):
|
||||
tell.mount(segment, puck, sample, True, True)
|
||||
|
||||
def move_cold():
|
||||
tell.mount(force=True)
|
||||
|
||||
def unmount():
|
||||
tell.move_cold()
|
||||
|
||||
def trash():
|
||||
tell.trash()
|
||||
|
||||
def abort():
|
||||
tell.abort_cmd()
|
||||
|
||||
def scan(segment, puck, sample=None):
|
||||
if sample is None:
|
||||
tell.scan_pin(segment, puck, True)
|
||||
else:
|
||||
tell.scan_pin(segment, puck, sample, True)
|
||||
|
||||
info()
|
||||
help()
|
||||
|
||||
#for line in sys.stdin:
|
||||
# tell.print_info()
|
||||
#print ("", end='\r> ')
|
||||
|
||||
code.interact(local=locals())
|
||||
|
||||
@@ -48,8 +48,8 @@ def restore_samples_info():
|
||||
set_samples_info(info)
|
||||
|
||||
def get_samples_info(as_json=True):
|
||||
global sample_info
|
||||
return json.dumps(samples_info) if as_json else samples_info
|
||||
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:
|
||||
|
||||
@@ -5,15 +5,19 @@ 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 = 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()
|
||||
@@ -25,40 +29,46 @@ class Hexiposi(DiscretePositionerBase):
|
||||
return json.loads(response.text)
|
||||
|
||||
def get_status(self):
|
||||
self.status = self.get_response(requests.get(url=self.url+"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
|
||||
return self.status
|
||||
|
||||
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+"setDeadband?deadband=" + str(value), timeout=self.timeout))
|
||||
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?pos=" + str(pos), timeout=self.timeout))
|
||||
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?home=1", timeout=self.timeout))
|
||||
ret = self.get_response(requests.get(url=self.url_set+"set?home=1", timeout=self.timeout))
|
||||
try:
|
||||
self.waitState(self.homing_state,1200)
|
||||
except:
|
||||
@@ -66,10 +76,10 @@ class Hexiposi(DiscretePositionerBase):
|
||||
return ret
|
||||
|
||||
def stop_move(self):
|
||||
return self.get_response(requests.get(url=self.url+"set?stop=1", timeout=self.timeout))
|
||||
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+"setOffset?offset="+str(offset), timeout=self.timeout))
|
||||
return self.get_response(requests.get(url=self.url_set+"setOffset?offset="+str(offset), timeout=self.timeout))
|
||||
|
||||
def doUpdate(self):
|
||||
self.get_status()
|
||||
@@ -124,7 +134,9 @@ class Hexiposi(DiscretePositionerBase):
|
||||
# return self.moving == False
|
||||
|
||||
def updateState(self):
|
||||
if self.homed == False:
|
||||
if self.offline:
|
||||
self.setState(State.Offline)
|
||||
elif self.homed == False:
|
||||
self.setState(self.homing_state)
|
||||
elif self.moving:
|
||||
self.setState(State.Busy)
|
||||
@@ -133,8 +145,8 @@ class Hexiposi(DiscretePositionerBase):
|
||||
|
||||
|
||||
|
||||
#http://myriotell:8002/hexiposi/get
|
||||
dev = Hexiposi("hexiposi", "myriotell:8002/hexiposi")
|
||||
#http://myriotell:8003/hexiposi/get
|
||||
dev = Hexiposi("hexiposi", "myriotell")
|
||||
|
||||
add_device(dev, True)
|
||||
hexiposi.polling=1000
|
||||
|
||||
@@ -28,7 +28,8 @@ class RobotSC(RobotTCP):
|
||||
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.setPolling(DEFAULT_ROBOT_POLLING)
|
||||
self.setSimulated()
|
||||
|
||||
def move_dewar(self):
|
||||
self.start_task('moveDewar')
|
||||
|
||||
@@ -141,6 +141,8 @@ class RobotTCP(TcpDevice, Stoppable):
|
||||
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) + "'")
|
||||
@@ -257,14 +259,20 @@ class RobotTCP(TcpDevice, Stoppable):
|
||||
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()
|
||||
|
||||
@@ -547,6 +555,8 @@ class RobotTCP(TcpDevice, Stoppable):
|
||||
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
|
||||
@@ -575,7 +585,6 @@ class RobotTCP(TcpDevice, Stoppable):
|
||||
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)
|
||||
@@ -584,12 +593,19 @@ class RobotTCP(TcpDevice, Stoppable):
|
||||
try:
|
||||
start = time.time()
|
||||
cur_task = self.current_task #Can change in background so cache it
|
||||
sts = self.execute("get_status", cur_task)
|
||||
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:
|
||||
@@ -602,14 +618,14 @@ class RobotTCP(TcpDevice, Stoppable):
|
||||
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._update_state()
|
||||
self.reset = False
|
||||
self.setCache({"powered": self.powered,
|
||||
"speed": self.speed,
|
||||
@@ -621,6 +637,7 @@ class RobotTCP(TcpDevice, Stoppable):
|
||||
"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()
|
||||
|
||||
@@ -6,6 +6,8 @@ class SmartMagnet(DeviceBase):
|
||||
"restingCurrent":0.0,
|
||||
"mountCurrent":0.0,
|
||||
"unmountCurrent":0.0,
|
||||
"reverseCurrent":0.0,
|
||||
"reverseTime":0.0,
|
||||
}))
|
||||
|
||||
def doInitialize(self):
|
||||
@@ -89,8 +91,8 @@ class SmartMagnet(DeviceBase):
|
||||
def set_unmount_current(self):
|
||||
self.set_current(self.config.getFieldValue("unmountCurrent"))
|
||||
|
||||
def set_remanence_current(self):
|
||||
self.set_current(self.config.getFieldValue("remanenceCurrent"))
|
||||
def set_reverse_current(self):
|
||||
self.set_current(self.config.getFieldValue("reverseCurrent"))
|
||||
|
||||
def set_default_current(self):
|
||||
if self.is_mounted():
|
||||
@@ -104,6 +106,10 @@ class SmartMagnet(DeviceBase):
|
||||
|
||||
#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)
|
||||
|
||||
@@ -25,10 +25,10 @@ BARCODE_READER_SCAN_PUCKS = "barcode_reader_scan_pucks"
|
||||
|
||||
def is_imaging_enabled():
|
||||
setting = get_setting(IMAGING_ENABLED_PREFERENCE)
|
||||
return not (str(setting) == 'False')
|
||||
return not (str(setting).lower() == 'false')
|
||||
|
||||
def set_imaging_enabled(value):
|
||||
set_setting(IMAGING_ENABLED_PREFERENCE, True if value else False )
|
||||
set_setting(IMAGING_ENABLED_PREFERENCE, (True if value else False) )
|
||||
|
||||
def assert_imaging_enabled():
|
||||
if is_imaging_enabled() == False:
|
||||
@@ -69,8 +69,9 @@ for script in ["devices/RobotSC", "devices/Wago", "devices/BarcodeReader", "devi
|
||||
except:
|
||||
print >> sys.stderr, traceback.format_exc()
|
||||
|
||||
add_device(img.getContrast(), force = True)
|
||||
add_device(img.getCamera(), force = True)
|
||||
if is_imaging_enabled():
|
||||
add_device(img.getContrast(), force = True)
|
||||
add_device(img.getCamera(), force = True)
|
||||
|
||||
|
||||
###################################################################################################
|
||||
@@ -103,8 +104,9 @@ run("motion/calibrate_tool")
|
||||
run("motion/scan_pin")
|
||||
run("motion/robot_recover")
|
||||
run("motion/recover")
|
||||
run("imgproc/Utils")
|
||||
run("tools/Math")
|
||||
if is_imaging_enabled():
|
||||
run("imgproc/Utils")
|
||||
|
||||
def system_check(robot_move=True):
|
||||
if not air_pressure_ok.read():
|
||||
@@ -176,7 +178,8 @@ try:
|
||||
except:
|
||||
print >> sys.stderr, traceback.format_exc()
|
||||
|
||||
try:
|
||||
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)
|
||||
@@ -196,7 +199,7 @@ try:
|
||||
|
||||
img.camera.stop()
|
||||
img.camera.start()
|
||||
except:
|
||||
except:
|
||||
print >> sys.stderr, traceback.format_exc()
|
||||
|
||||
|
||||
|
||||
@@ -29,4 +29,4 @@ def calibrate_tool():
|
||||
|
||||
robot.put_calibration_tool()
|
||||
|
||||
#robot.save_program()
|
||||
robot.save_program()
|
||||
|
||||
@@ -8,7 +8,12 @@ def dry(heat_time=30.0, speed=0.5, wait_cold = 30.0):
|
||||
Else move to cold and wait (in seconds) before returning.
|
||||
"""
|
||||
print "dry"
|
||||
|
||||
|
||||
|
||||
if robot.simulated:
|
||||
time.sleep(3.0)
|
||||
return
|
||||
|
||||
#Initial chec
|
||||
robot.assert_no_task()
|
||||
robot.reset_motion()
|
||||
|
||||
@@ -22,6 +22,15 @@ def mount(segment, puck, sample, force=False, read_dm=False):
|
||||
#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()
|
||||
@@ -84,8 +93,7 @@ def mount(segment, puck, sample, force=False, read_dm=False):
|
||||
except:
|
||||
dry_mount_count = 0
|
||||
set_setting("dry_mount_counter", dry_mount_count+1)
|
||||
#TODO: Auto-dry procedure
|
||||
|
||||
|
||||
if is_aux:
|
||||
robot.move_home()
|
||||
else:
|
||||
@@ -98,6 +106,7 @@ def mount(segment, puck, sample, force=False, read_dm=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()
|
||||
|
||||
@@ -3,6 +3,10 @@ def move_cold():
|
||||
"""
|
||||
print "move_cold"
|
||||
|
||||
if robot.simulated:
|
||||
time.sleep(3.0)
|
||||
return
|
||||
|
||||
#Initial checks
|
||||
robot.assert_no_task()
|
||||
robot.reset_motion()
|
||||
|
||||
@@ -2,6 +2,11 @@ def put_gonio(force=False):
|
||||
"""
|
||||
"""
|
||||
print "put_gonio: ", force
|
||||
|
||||
|
||||
if robot.simulated:
|
||||
time.sleep(3.0)
|
||||
return
|
||||
|
||||
#Initial checks
|
||||
robot.assert_no_task()
|
||||
|
||||
@@ -6,6 +6,10 @@ def scan_pin(segment, puck, sample, force=False):
|
||||
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()
|
||||
|
||||
@@ -2,6 +2,10 @@ def trash():
|
||||
"""
|
||||
"""
|
||||
print "trash"
|
||||
|
||||
if robot.simulated:
|
||||
time.sleep(3.0)
|
||||
return
|
||||
|
||||
#Initial checks
|
||||
robot.assert_no_task()
|
||||
|
||||
@@ -14,6 +14,12 @@ def unmount(segment = None, puck = None, sample = None, force=False):
|
||||
#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()
|
||||
|
||||
30
script/test/TestCalib.py
Normal file
30
script/test/TestCalib.py
Normal file
@@ -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()
|
||||
Reference in New Issue
Block a user