Commit 90150e08 authored by Alejandro Homs Puron's avatar Alejandro Homs Puron
Browse files

Merge branch 'ID31_robot' into 'ID31_reflectometry'

Id31 robot

See merge request !325
parents b0c48e52 e0c7e31d
......@@ -15,7 +15,7 @@ from gevent import lock
from .libnienet import EnetSocket
from ..tcp import Socket
from ..exceptions import CommunicationError, CommunicationTimeout
from ...common.greenlet_utils import KillMask
from ...common.greenlet_utils import KillMask, protect_from_kill
try:
from collections import OrderedDict
......@@ -285,12 +285,14 @@ class Gpib:
def _write(self,msg) :
return self._raw_handler.ibwrt(msg)
@protect_from_kill
def write_read(self,msg,write_synchro = None,size = 1,timeout = None) :
with self._lock:
self._write(msg)
if write_synchro: write_synchro.notify()
return self._read(size)
@protect_from_kill
def write_readline(self,msg,write_synchro = None,
eol = None,timeout = None) :
with self._lock:
......@@ -298,6 +300,7 @@ class Gpib:
if write_synchro: write_synchro.notify()
return self._readline(eol)
@protect_from_kill
def write_readlines(self,msg,nb_lines,write_synchro = None,
eol = None,timeout = None):
with self._lock:
......
......@@ -22,6 +22,7 @@ class KillMask:
self.__greenlet,
self.__exception,
self.__waiter)
gevent.sleep(0)
elif self.__exception is not None:
get_hub().loop.run_callback(self.__greenlet.throw,
self.__exception)
......
# -*- coding: utf-8 -*-
#
# This file is part of the bliss project
#
# Copyright (c) 2016 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.
import time
import serial
from bliss.controllers.motor import Controller
from bliss.common import log as elog
from bliss.common.axis import AxisState
from bliss.common.utils import object_attribute_get, object_attribute_set
from StaubPy import id31Controller
"""
Bliss controller for ID31Robot.
"""
class ID31Robot(Controller):
Cache = {}
def initialize(self):
"""
"""
# opens communication
print("Initialisation of ID31 robot.")
host = self.config.get('host')
try:
self.id31 = ID31Robot.Cache[host]
except KeyError:
ID31Robot.Cache[host] = id31Controller.ID31Controller(controllerAssociated=self.config.get('host'))
self.id31 = ID31Robot.Cache[host]
print("Creating robot 'firmware' and shipping to controller. (fast)")
self.id31.makeOnly()
print("Starting new robot controller 'firmware' (takes time (5-25sec))")
self.id31.loadOnly()
print("Initialising values in controller. (fast)")
self.id31.initValues()
self.movingStatus="initialised"
print("Post Init Actions in controller. (fast)")
self.id31.postInit()
self.id31.scanSpeed.velocity = self.config.get('speed')
self.id31.printDebug=False
def finalize(self):
"""
"""
# Closes communication
def initialize_axis(self, axis):
"""
Reads specific config
Adds specific methods
"""
axis.role = axis.config.get('role')
def read_position(self, axis):
"""
Returns position's setpoint or measured position.
Args:
- <axis> : bliss axis.
- [<measured>] : boolean : if True, function returns
measured position in ???
Returns:
- <position> : float : axis setpoint in ???.
"""
return getattr(self.id31, axis.role)
def read_encoder(self, encoder):
raise NotImplementedError
# def read_velocity(self, axis):
# """
# Args:
# - <axis> : Bliss axis object.
# Returns:
# - <velocity> : float
# """
# return self.id31.scanSpeed.velocity
# def set_velocity(self, axis, new_velocity):
# #But bliss do not know that other axis velocity changed also.
@object_attribute_get(type_info="float")
def get_speed(self, axis):
return self.id31.scanSpeed.velocity
@object_attribute_set(type_info="float")
def set_speed(self, axis, new_speed):
self.id31.scanSpeed.velocity = new_speed
def state(self, axis):
if self.id31.hasMovesProgrammed:
return AxisState("MOVING")
else:
return AxisState("READY")
def prepare_move(self, motion):
setattr(self.id31, motion.axis.role, motion.target_pos)
def start_one(self, motion):
"""
"""
print("START one", motion)
self.id31.moveToPosition()
def start_all(self, *motion_list):
print("START ALL", motion_list)
self.id31.moveToPosition()
def stop(self, axis):
i = 0
while self.id31.hasMovesProgrammed and i < 5:
self.id31.resetMotion()
i += 1
if self.id31.hasMovesProgrammed:
logging.error('robot still has programmed moves after 5 attempts to stop')
......@@ -9,9 +9,11 @@
Scan a Spec config file to detect instances of a Eurotherm 2400 temp controller.
"""
import os
import struct
import logging
import datetime
import collections
__all__ = ['SpecConfig', 'Device', 'Motor', 'Counter']
......@@ -34,6 +36,8 @@ HEADER_TEMPLATE = """\
# ID Bliss generated config at {timestamp}. All changes will be overwritten!
"""
MotorSettings = collections.namedtuple('Settings', 'accumulator offset, low_limit, high_limit')
class Device:
"""A device controller, can be PSE_MAC_C, PSE_MAC_MOT, HW_GPIBENET_L SDEV_0 etc."""
......@@ -282,8 +286,8 @@ class Motor:
MOTPAR:step_size_neg = 2.3
"""
def __init__(self, line = None, ctrl = None, steps = 2000, sign = 1, \
slew = 2000, base = 200, backl = 50, accel = 125, nada = '0', \
flags = '0x003', mne = None, name = None):
slew = 2000, base = 200, backl = 50, accel = 125, nada = '0', \
flags = '0x003', mne = None, name = None):
self.__objecttype = 'Motor'
MotCorr = { 'MAXE_E':'MAXE', 'MAXE_D':'MAXE' }
......@@ -338,6 +342,7 @@ class Motor:
self.umc = unitchan.split('/')
if self.ctrl in MotCorr:
self.type = MotCorr[self.ctrl]
self.settings = MotorSettings(0, 0., 0., 0.)
def setMotNum(self, num):
'''
......@@ -392,6 +397,8 @@ class Motor:
else:
return None
def setSettings(self, accumulator=0, offset=0., low_limit=0., high_limit=0.):
self.settings = MotorSettings(int(accumulator), offset, low_limit, high_limit)
class Counter:
......@@ -751,8 +758,20 @@ class SpecConfig:
except:
print "Unexpected error:", sys.exc_info()[0]
raise
f.write(self.__str__())
f.write(str(self))
f.close()
os.chmod(file_name, 0666)
def writeSettings(self, file_name):
fmt = 'ifdd'
fmt_size = struct.calcsize(fmt)
settings = bytearray((320 * fmt_size)*'\0')
for i, motor in enumerate(self.motors):
motor.setMotNum(i)
struct.pack_into(fmt, settings, i*fmt_size, *motor.settings)
with open(file_name, 'wb') as settings_file:
settings_file.write(settings)
os.chmod(file_name, 0666)
def printalltypes(self):
for x in self.devicenodes:
......
......@@ -26,8 +26,10 @@ Usage:
import os
import socket
import struct
import logging
import datetime
import platform
import collections
try:
......@@ -38,7 +40,7 @@ except AttributeError:
import tango
from bliss.config.static import get_config
from bliss.config.settings import HashSetting
from ..utils import get_config_path
from .config import SpecConfig, Device, Motor, Counter
......@@ -217,6 +219,7 @@ class WagoSetup:
setup.append(att)
return '\n'.join(setup) + '\n'
#
# Tango constants
#
......@@ -270,6 +273,20 @@ def TLimaServer(name, host, camera_type, domain):
return TServer('LimaCCDs', name, host, devices)
def get_os():
system = platform.system()
if system == 'Linux':
dist, ver, did = platform.linux_distribution()
if dist == 'redhat':
result = 'redhat4'
else:
ver = ver.split('.', 1)
result = dist+ver[0]
else:
result = system
return result.lower()
class Generator(object):
def __init__(self, spec_name, config=None, **kwargs):
......@@ -444,18 +461,35 @@ class Generator(object):
# Emotion
####################
def __settings_to_spec(self, mot_config, settings):
sign = int(mot_config.get('sign', 1))
dial = float(settings.get('dial_position', 0))
accum = int(dial * float(mot_config.get('steps_per_unit', 1)))
offset = float(settings.get('offset', 0.0))
try:
low_limit = (float(settings['low_limit']) - offset) / sign
except KeyError:
low_limit = float(mot_config.get('low_limit', 0.0))
try:
high_limit = (float(settings['high_limit']) - offset) / sign
except KeyError:
high_limit = float(mot_config.get('high_limit', 0.0))
return accum, offset, low_limit, high_limit
def __add_emotion_axis_to_spec_controller(self, name, config_name, ctrl):
mot_config = self.config.get_config(config_name)
chan = ctrl.num
ctrl_addr = 'MAC_MOT:{0}/{1}'.format(ctrl.getCtrlIndex(), chan)
sign = mot_config.get('sign') or 1
sign = int(mot_config.get('sign', 1))
spec_motor = Motor(ctrl=ctrl_addr, steps=int(1E6), mne=name,
name=name, sign=sign, backl=0)
spec_motor.addPar('MOTPAR:read_mode = 7')
if config_name != name:
spec_motor.addPar('MOTPAR:axis_name = %s' % config_name)
settings = HashSetting('axis.' + config_name)
spec_motor.setSettings(*self.__settings_to_spec(mot_config, settings))
self.spec_config.addMotor(spec_motor)
ctrl.addChannel(chan)
self.__spec_macros.add('tango_mot.mac')
......@@ -494,6 +528,7 @@ class Generator(object):
self.spec_config.addDevice(ctrl)
self.__spec_setup_icepaps[icepap] = ctrl
addr = cfg.pop('address')
cfg.pop('user_tag', None) # remove user tag so that MOTPAR is not generated
module, chan = addr.split('/')
addr = 'MAC_MOT:{0}/{1}'.format(ctrl.getCtrlIndex(), addr)
spec_motor = Motor(ctrl=addr, mne=name, name=name,
......@@ -503,12 +538,15 @@ class Generator(object):
base = cfg.pop('base', 0),
backl = cfg.pop('backl', 0),
accel = cfg.pop('accel'))
settings = HashSetting('axis.' + config_name)
spec_motor.setSettings(*self.__settings_to_spec(config, settings))
for k, v in cfg.items():
spec_motor.addPar('MOTPAR:{0} = {1}'.format(k, v))
self.spec_config.addMotor(spec_motor)
ctrl.addChannel(chan)
self.__spec_macros.add('ice.mac')
self.__spec_macros.add('blissspecmotor.mac')
self.__spec_setup.append('motorsettingssetup %s' % name)
####################
# Wago
......@@ -1029,7 +1067,9 @@ class Generator(object):
unit = len(gpibs)
host = url.strip(head)
conf = '@gpib_%s' % unit
gpib_ctrl = Device(ltype='HW_GPIBENET_L', addr=host, num='', conf=conf)
# do not use shared (ie HW_GPIBENET_L) because spec has problems
# with ENET 1000
gpib_ctrl = Device(ltype='HW_GPIBENET', addr=host, num='', conf=conf)
self.spec_config.addDevice(gpib_ctrl)
gpibs[url] = unit
return unit
......@@ -1112,6 +1152,7 @@ class Generator(object):
os.makedirs(output_dir)
self.__generate_spec_config(output_dir)
self.__generate_spec_setup(output_dir)
self.__generate_spec_settings(output_dir)
def __generate_spec_config(self, spec_dir):
config_file = os.path.join(spec_dir, 'config')
......@@ -1139,6 +1180,15 @@ class Generator(object):
self._log.debug('writting spec setup file %s', setup_file)
with open(setup_file, 'w') as sf:
sf.write(setup_content)
os.chmod(setup_file, 0666)
def __generate_spec_settings(self, spec_dir):
output_dir = os.path.join(spec_dir, get_os())
if not os.path.isdir(output_dir):
os.makedirs(output_dir)
settings_file = os.path.join(output_dir, 'settings')
self._log.debug('writting settings file %s', settings_file)
self.spec_config.writeSettings(settings_file)
def main():
......
need bliss
#################################
# Spec motor settings
#################################
# <motor-mne> ...
def motorsettingssetup '{
local i mne args[] nargs mnum motor_class
if (!BLISS["device"])
blisssetup
nargs = split("$*", args)
if (nargs == 0) {
args[0] = getval("Enter the motor mnemonic", "")
nargs = 1
}
for (i = 0; i < nargs; i++) {
mne = args[i]
mnum = motor_num(mne)
if ((mnum < 0) || (motor_mne(mnum) != mne)) {
printf("Invalid motor: %s\n", mne)
exit
}
}
motor_class = "axis"
bliss_register_settings_class(motor_class, "motor_dump_object_settings", \
"motor_load_object_settings")
for (i = 0; i < nargs; i++) {
mne = args[i]
bliss_add_settings_object(motor_class, mne)
}
setup_tail("motorsettings", "$*")
}'
def motorsettingsunsetup '{
local i mne args[] nargs motor_class
motor_class = "axis"
nargs = split("$*", args)
for (i = 0; i < nargs; i++) {
mne = args[i]
if (bliss_del_settings_object(mne, motor_class))
bliss_unregister_settings_class(motor_class)
}
}'
def motor_dump_object_settings(motor_class, mne) '{
local mnum obj_settings[]
mnum = motor_num(mne)
obj_settings["dial_position"] = dial(mnum, A[mnum])
obj_settings["offset"] = user(mnum, 0)
obj_settings["low_limit"] = user(mnum, get_lim(mnum, -1))
obj_settings["high_limit"] = user(mnum, get_lim(mnum, 1))
return obj_settings
}'
def motor_load_object_settings(motor_class, mne, obj_settings) '{
local mnum
mnum = motor_num(mne)
if (bliss_is_default_settings(obj_settings)) {
printf("Warning: ignoring default settings load for %s!\n", mne)
} else {
local m_dial s_m_dial m_offset s_m_offset
local m_low_limit s_m_low_limit m_high_limit s_m_high_limit
m_dial = dial(mnum, A[mnum])
m_offset = user(mnum, 0)
m_low_limit = user(mnum, get_lim(mnum, -1))
m_high_limit = user(mnum, get_lim(mnum, 1))
s_m_dial = obj_settings["dial_position"]
s_m_offset = obj_settings["offset"]
s_m_low_limit = obj_settings["low_limit"]
s_m_high_limit = obj_settings["high_limit"]
if (s_m_dial != m_dial)
printf("Warning: %s dial_position mismatch: set=%.4f, spec=%.4f\n",\
mne, s_m_dial, m_dial)
if (s_m_offset != offset)
printf("Warning: %s offset mismatch: set=%.4f, spec=%.4f\n",\
mne, s_m_offset, m_offset)
if (s_m_low_limit != m_low_limit)
printf("Warning: %s low_lim mismatch: set=%.4f, spec=%.4f\n",\
mne, s_m_low_limit, m_low_limit)
if (s_m_high_limit != m_high_limit)
printf("Warning: %s high_lim mismatch: set=%.4f, spec=%.4f\n",\
mne, s_m_high_limit, m_high_limit)
}
}'
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment