Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Bliss
bliss
Commits
da64659f
Commit
da64659f
authored
Sep 03, 2020
by
Matias Guijarro
Browse files
motor settings: move code from controller and axis to motor_settings.py
parent
593a3bda
Changes
4
Hide whitespace changes
Inline
Side-by-side
bliss/common/axis.py
View file @
da64659f
...
...
@@ -341,8 +341,7 @@ class GroupMove:
for
motion
in
motions
:
motion
.
axis
.
_set_moving_state
()
for
_
,
chan
in
motion
.
axis
.
_beacon_channels
.
items
():
chan
.
unregister_callback
(
chan
.
_setting_update_cb
)
motion
.
axis
.
settings
.
unregister_channels_callbacks
()
with
capture_exceptions
(
raise_index
=
0
)
as
capture
:
with
capture
():
...
...
@@ -402,10 +401,9 @@ class GroupMove:
for
hook
in
axis
.
motion_hooks
:
hooks
[
hook
].
append
(
motion
)
# set move done
for
_
,
chan
in
axis
.
_beacon_channels
.
items
():
chan
.
register_callback
(
chan
.
_setting_update_cb
)
axis
.
settings
.
register_channels_callbacks
()
# set move done
motion
.
axis
.
_set_move_done
()
if
self
.
_interrupted_move
:
...
...
@@ -676,7 +674,7 @@ class Axis:
self
.
__encoder
.
axis
=
self
self
.
__config
=
StaticConfig
(
config
)
self
.
__settings
=
AxisSettings
(
self
)
self
.
_
_
init_config_properties
()
self
.
_init_config_properties
()
self
.
__no_offset
=
False
self
.
_group_move
=
GroupMove
()
self
.
_lock
=
gevent
.
lock
.
Semaphore
()
...
...
@@ -762,20 +760,20 @@ class Axis:
"""
return
not
self
.
__move_done
.
is_set
()
def
_
_init_config_properties
(
def
_init_config_properties
(
self
,
velocity
=
True
,
acceleration
=
True
,
limits
=
True
,
sign
=
True
,
backlash
=
True
):
self
.
__steps_per_unit
=
self
.
config
.
get
(
"steps_per_unit"
,
float
,
1
)
self
.
__tolerance
=
self
.
config
.
get
(
"tolerance"
,
float
,
1e-4
)
if
velocity
:
if
self
.
controller
.
axis_
settings
.
config_setting
[
"velocity"
]
:
if
"velocity"
in
self
.
settings
.
config_setting
s
:
self
.
__config_velocity
=
self
.
config
.
get
(
"velocity"
,
float
)
if
self
.
controller
.
axis_
settings
.
config_setting
[
"jog_velocity"
]
:
if
"jog_velocity"
in
self
.
settings
.
config_setting
s
:
self
.
__config_jog_velocity
=
self
.
config
.
get
(
"jog_velocity"
,
float
,
self
.
__config_velocity
)
if
acceleration
:
if
self
.
controller
.
axis_
settings
.
config_setting
[
"acceleration"
]
:
if
"acceleration"
in
self
.
settings
.
config_setting
s
:
self
.
__config_acceleration
=
self
.
config
.
get
(
"acceleration"
,
float
)
if
limits
:
self
.
__config_low_limit
=
self
.
config
.
get
(
"low_limit"
,
float
,
float
(
"-inf"
))
...
...
@@ -786,13 +784,11 @@ class Axis:
self
.
__config_backlash
=
self
.
config
.
get
(
"backlash"
,
float
,
0
)
@
property
@
lazy_init
def
steps_per_unit
(
self
):
"""Current steps per unit (:obj:`float`)"""
return
self
.
__steps_per_unit
@
property
@
lazy_init
def
config_backlash
(
self
):
"""Current backlash in user units (:obj:`float`)"""
return
self
.
__config_backlash
...
...
@@ -811,7 +807,6 @@ class Axis:
self
.
settings
.
set
(
"backlash"
,
backlash
)
@
property
@
lazy_init
def
tolerance
(
self
):
"""Current Axis tolerance in dial units (:obj:`float`)"""
return
self
.
__tolerance
...
...
@@ -2056,7 +2051,7 @@ class Axis:
if
any
((
velocity
,
acceleration
,
limits
,
sign
,
backlash
)):
self
.
__config
.
save
()
self
.
_
_
init_config_properties
(
self
.
_init_config_properties
(
velocity
=
velocity
,
acceleration
=
acceleration
,
limits
=
limits
,
...
...
@@ -2079,7 +2074,7 @@ class Axis:
if
reload
:
self
.
config
.
reload
()
self
.
_
_
init_config_properties
(
self
.
_init_config_properties
(
velocity
=
velocity
,
acceleration
=
acceleration
,
limits
=
limits
,
...
...
@@ -2099,7 +2094,7 @@ class Axis:
if
backlash
:
self
.
settings
.
clear
(
"backlash"
)
self
.
controller
.
_init_
settings
(
self
)
self
.
settings
.
init
(
)
# update position (needed for sign change)
pos
=
self
.
dial2user
(
self
.
dial
)
...
...
@@ -2458,5 +2453,5 @@ class ModuloAxis(Axis):
class
NoSettingsAxis
(
Axis
):
def
__init__
(
self
,
*
args
,
**
kwags
):
super
().
__init__
(
*
args
,
**
kwags
)
for
setting_name
in
self
.
settings
:
for
setting_name
in
self
.
settings
.
setting_names
:
self
.
settings
.
disable_cache
(
setting_name
)
bliss/common/motor_settings.py
View file @
da64659f
...
...
@@ -5,11 +5,16 @@
# Copyright (c) 2015-2020 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.
import
collections
import
functools
import
inspect
import
math
import
sys
from
bliss.common
import
event
from
bliss.common.greenlet_utils
import
KillMask
from
bliss.config.channels
import
Channel
from
bliss.config
import
settings
,
settings_cache
import
collections
import
sys
def
setting_update_from_channel
(
value
,
setting_name
=
None
,
axis
=
None
):
...
...
@@ -47,23 +52,24 @@ class ControllerAxisSettings:
self
.
config_setting
=
{}
# 'offset' must be set BEFORE limits to ensure good dial/user conversion.
self
.
add
(
"offset"
,
float
)
self
.
add
(
"sign"
,
int
)
self
.
add
(
"offset"
,
float
)
self
.
add
(
"backlash"
,
float
)
self
.
add
(
"low_limit"
,
floatOrNone
)
self
.
add
(
"high_limit"
,
floatOrNone
)
self
.
add
(
"velocity"
,
float
,
config
=
True
)
self
.
add
(
"jog_velocity"
,
float
)
self
.
add
(
"acceleration"
,
float
,
config
=
True
)
self
.
add
(
"low_limit"
,
floatOrNone
)
self
.
add
(
"high_limit"
,
floatOrNone
)
self
.
add
(
"dial_position"
,
float
)
self
.
add
(
"_set_position"
,
float
)
self
.
add
(
"position"
,
float
)
self
.
add
(
"state"
,
stateSetting
,
persistent
=
False
)
self
.
add
(
"steps_per_unit"
,
float
,
config
=
True
)
@
property
def
config_settings
(
self
):
return
tuple
(
[
setting
for
setting
,
config
in
self
.
config_setting
.
items
()
if
config
]
setting
for
setting
,
config
in
self
.
config_setting
.
items
()
if
config
)
def
add
(
self
,
setting_name
,
convert_func
=
str
,
persistent
=
True
,
config
=
False
):
...
...
@@ -83,6 +89,7 @@ class AxisSettings:
def
__init__
(
self
,
axis
):
self
.
__axis
=
axis
self
.
__state
=
None
self
.
_beacon_channels
=
{}
self
.
_disabled_settings
=
disabled_settings_namedtuple
(
set
(),
dict
(
axis
.
config
.
config_dict
)
)
...
...
@@ -95,26 +102,145 @@ class AxisSettings:
# Activate prefetch
cnx_cache
.
add_prefetch
(
self
.
_hash
)
def
__iter__
(
self
):
for
name
in
self
.
__axis
.
controller
.
axis_settings
.
setting_names
:
yield
name
@
property
def
setting_names
(
self
)
:
yield
from
self
.
__axis
.
controller
.
axis_settings
.
setting_
name
s
def
convert_func
(
self
,
setting_name
):
return
self
.
__axis
.
controller
.
axis_settings
.
convert_func
.
get
(
setting_name
)
@
property
def
config_settings
(
self
):
return
self
.
__axis
.
controller
.
axis_settings
.
config_settings
()
return
self
.
__axis
.
controller
.
axis_settings
.
config_settings
def
register_channels_callbacks
(
self
):
for
chan
in
self
.
_beacon_channels
.
values
():
chan
.
register_callback
(
chan
.
_setting_update_cb
)
def
unregister_channels_callbacks
(
self
):
for
chan
in
self
.
_beacon_channels
.
values
():
chan
.
unregister_callback
(
chan
.
_setting_update_cb
)
def
_create_channel
(
self
,
setting_name
):
chan_name
=
"axis.%s.%s"
%
(
self
.
__axis
.
name
,
setting_name
)
chan
=
Channel
(
chan_name
)
cb
=
functools
.
partial
(
setting_update_from_channel
,
setting_name
=
setting_name
,
axis
=
self
.
__axis
)
chan
.
_setting_update_cb
=
cb
return
chan
def
init_channels
(
self
):
self
.
_beacon_channels
.
clear
()
for
setting_name
in
self
.
__axis
.
controller
.
axis_settings
.
setting_names
:
self
.
_beacon_channels
[
setting_name
]
=
self
.
_create_channel
(
setting_name
)
self
.
register_channels_callbacks
()
def
_get_setting_or_config_value
(
self
,
name
,
default
=
None
):
# return setting or config parameter
converter
=
self
.
convert_func
(
name
)
value
=
self
.
get
(
name
)
if
value
is
None
:
value
=
self
.
__axis
.
config
.
get
(
name
,
converter
,
default
=
default
)
return
value
def
check_config_settings
(
self
):
axis
=
self
.
__axis
props
=
dict
(
inspect
.
getmembers
(
axis
.
__class__
,
lambda
o
:
isinstance
(
o
,
property
))
)
config_settings
=
[]
for
setting_name
in
self
.
config_settings
:
# check if setting is in config
value
=
axis
.
config
.
get
(
setting_name
)
if
value
is
None
:
raise
RuntimeError
(
"Axis %s: missing configuration key '%s`"
%
(
self
.
name
,
setting_name
)
)
if
setting_name
==
"steps_per_unit"
:
# steps_per_unit is read-only
continue
config_settings
.
append
(
setting_name
)
# check if setting has a method to initialize (set) its value,
# without actually executing the property
try
:
assert
callable
(
props
[
setting_name
].
fset
)
except
AssertionError
:
raise
RuntimeError
(
"Axis %s: missing method '%s` to set setting value"
%
(
axis
.
name
,
setting_name
)
)
return
config_settings
def
init
(
self
):
""" Initialize settings
"config settings" are those that **must** be in YML config like
steps per unit, acceleration and velocity ; otherwise settings
can optionally be present in the config file.
Config settings must have a property setter on the Axis object.
"persistent settings" are stored in redis, like position for example;
in any case, when a setting is set its value is emitted via a
dedicated channel.
Some settings can be both config+persistent (like velocity) or
none (like state, which is only emitted when it changes, but not stored
at all)
"""
axis
=
self
.
__axis
config_settings
=
self
.
check_config_settings
()
config_steps_per_unit
=
axis
.
config
.
get
(
"steps_per_unit"
,
float
)
if
axis
.
no_offset
:
sign
=
1
offset
=
0
else
:
sign
=
self
.
_get_setting_or_config_value
(
"sign"
,
1
)
offset
=
self
.
_get_setting_or_config_value
(
"offset"
,
0
)
self
.
set
(
"sign"
,
sign
)
self
.
set
(
"offset"
,
offset
)
self
.
set
(
"backlash"
,
self
.
_get_setting_or_config_value
(
"backlash"
,
0
))
low_limit_dial
=
self
.
_get_setting_or_config_value
(
"low_limit"
)
high_limit_dial
=
self
.
_get_setting_or_config_value
(
"high_limit"
)
if
config_steps_per_unit
:
cval
=
config_steps_per_unit
rval
=
self
.
_hash
.
raw_get
(
"steps_per_unit"
)
# Record steps_per_unit
if
rval
is
None
:
self
.
set
(
"steps_per_unit"
,
cval
)
else
:
rval
=
float
(
rval
)
if
cval
!=
rval
:
ratio
=
rval
/
cval
new_dial
=
axis
.
dial
*
ratio
self
.
set
(
"steps_per_unit"
,
cval
)
if
not
axis
.
no_offset
:
# calculate offset so user pos stays the same
self
.
set
(
"offset"
,
axis
.
position
-
axis
.
sign
*
new_dial
)
self
.
set
(
"dial_position"
,
new_dial
)
if
math
.
copysign
(
rval
,
cval
)
!=
rval
:
ll
,
hl
=
low_limit_dial
,
high_limit_dial
low_limit_dial
,
high_limit_dial
=
-
hl
,
-
ll
self
.
set
(
"low_limit"
,
low_limit_dial
)
self
.
set
(
"high_limit"
,
high_limit_dial
)
for
setting_name
in
config_settings
:
value
=
self
.
_get_setting_or_config_value
(
setting_name
)
setattr
(
axis
,
setting_name
,
value
)
def
set
(
self
,
setting_name
,
value
):
if
setting_name
==
"state"
:
if
self
.
__state
==
value
:
return
self
.
__state
=
value
"""
* set setting
* send event
* write
"""
axis
=
self
.
__axis
axis_settings
=
axis
.
controller
.
axis_settings
if
setting_name
not
in
axis_settings
.
setting_names
:
...
...
@@ -135,9 +261,9 @@ class AxisSettings:
else
:
if
axis_settings
.
persistent_setting
[
setting_name
]:
with
KillMask
():
axis
.
settings
.
_hash
[
setting_name
]
=
value
self
.
_hash
[
setting_name
]
=
value
axis
.
_beacon_channels
[
setting_name
].
value
=
value
self
.
_beacon_channels
[
setting_name
].
value
=
value
event
.
send
(
axis
,
"internal_"
+
setting_name
,
value
)
try
:
...
...
@@ -151,45 +277,42 @@ class AxisSettings:
disabled_settings
=
self
.
_disabled_settings
if
setting_name
not
in
axis_settings
.
setting_names
:
raise
ValueError
(
"No setting '%s` for axis '%s`"
%
(
setting_name
,
axis
.
name
)
)
raise
NameError
(
"No setting '%s` for axis '%s`"
%
(
setting_name
,
axis
.
name
))
if
setting_name
in
disabled_settings
.
names
:
return
disabled_settings
.
config_dict
.
get
(
setting_name
)
if
axis_settings
.
persistent_setting
[
setting_name
]:
with
KillMask
():
value
=
self
.
_hash
.
get
(
setting_name
)
else
:
if
axis_settings
.
persistent_setting
[
setting_name
]:
with
KillMask
()
:
value
=
axis
.
settings
.
_hash
.
get
(
setting_name
)
chan
=
self
.
_beacon_channels
.
get
(
setting_name
)
if
chan
:
value
=
chan
.
value
else
:
chan
=
axis
.
_beacon_channels
.
get
(
setting_name
)
if
chan
:
value
=
chan
.
value
else
:
value
=
None
if
value
is
not
None
:
convert_func
=
self
.
convert_func
(
setting_name
)
if
convert_func
is
not
None
:
value
=
convert_func
(
value
)
return
value
value
=
None
if
value
is
not
None
:
convert_func
=
self
.
convert_func
(
setting_name
)
if
convert_func
is
not
None
:
value
=
convert_func
(
value
)
return
value
def
clear
(
self
,
setting_name
):
axis
=
self
.
__axis
axis_settings
=
axis
.
controller
.
axis_settings
disabled_settings
=
self
.
_disabled_settings
if
setting_name
in
disabled_settings
.
names
:
disabled_settings
.
config_dict
[
setting_name
]
=
None
else
:
axis
.
settings
.
_hash
[
setting_name
]
=
None
self
.
_hash
[
setting_name
]
=
None
# reset beacon channel, if it is there
try
:
channel
=
axis
.
_beacon_channels
[
setting_name
]
channel
=
self
.
_beacon_channels
[
setting_name
]
except
KeyError
:
pass
else
:
channel
.
value
=
channel
.
default_value
channel
.
close
()
self
.
_beacon_channels
[
setting_name
]
=
self
.
_create_channel
(
setting_name
)
def
disable_cache
(
self
,
setting_name
,
flag
=
True
):
"""
...
...
bliss/controllers/motor.py
View file @
da64659f
...
...
@@ -7,14 +7,8 @@
import
math
import
numpy
import
inspect
import
functools
from
bliss.common.motor_config
import
StaticConfig
from
bliss.common.motor_settings
import
(
ControllerAxisSettings
,
setting_update_from_channel
,
floatOrNone
,
)
from
bliss.common.motor_settings
import
ControllerAxisSettings
,
floatOrNone
from
bliss.common.axis
import
Trajectory
from
bliss.common.motor_group
import
Group
,
TrajectoryGroup
from
bliss.common
import
event
...
...
@@ -26,18 +20,6 @@ from bliss.config import settings
from
gevent
import
lock
# apply settings or config parameters
def
get_setting_or_config_value
(
axis
,
name
):
converter
=
axis
.
settings
.
convert_func
(
name
)
value
=
axis
.
settings
.
get
(
name
)
if
value
is
None
:
try
:
value
=
axis
.
config
.
get
(
name
,
converter
)
except
Exception
:
return
None
return
value
class
Controller
:
"""
Motor controller base class
...
...
@@ -171,10 +153,10 @@ class Controller:
def
_initialize_axis
(
self
,
axis
,
*
args
,
**
kwargs
):
"""
"""
if
self
.
__initialized_axis
[
axis
]:
return
with
self
.
__lock
:
if
self
.
__initialized_axis
[
axis
]:
return
# Initialize controller hardware only once.
if
not
self
.
__initialized_hw
.
value
:
self
.
initialize_hardware
()
...
...
@@ -193,90 +175,15 @@ class Controller:
axis_initialized
=
self
.
__initialized_hw_axis
[
axis
]
if
not
axis_initialized
.
value
:
self
.
initialize_hardware_axis
(
axis
)
axis
.
settings
.
check_config_settings
()
axis
.
settings
.
init
()
# get settings, from config or from cache, and apply to hardware
axis_initialized
.
value
=
1
self
.
_init_settings
(
axis
)
except
BaseException
:
# Failed to initialize
self
.
__initialized_axis
[
axis
]
=
False
raise
def
_init_settings
(
self
,
axis
):
""" Initialize hardware with settings
"""
props
=
dict
(
inspect
.
getmembers
(
axis
.
__class__
,
lambda
o
:
isinstance
(
o
,
property
))
)
sign
=
get_setting_or_config_value
(
axis
,
"sign"
)
if
sign
is
None
or
axis
.
no_offset
:
sign
=
1
axis
.
settings
.
set
(
"sign"
,
sign
)
offset
=
get_setting_or_config_value
(
axis
,
"offset"
)
if
offset
is
None
or
axis
.
no_offset
:
offset
=
0
axis
.
settings
.
set
(
"offset"
,
offset
)
backlash
=
get_setting_or_config_value
(
axis
,
"backlash"
)
if
backlash
is
None
:
backlash
=
0
axis
.
backlash
=
backlash
low_limit_dial
=
get_setting_or_config_value
(
axis
,
"low_limit"
)
high_limit_dial
=
get_setting_or_config_value
(
axis
,
"high_limit"
)
axis
.
dial_limits
=
low_limit_dial
,
high_limit_dial
for
setting_name
in
axis
.
settings
.
config_settings
():
# check if setting is in config
if
axis
.
config
.
get
(
setting_name
)
is
None
:
raise
RuntimeError
(
"Axis %s: missing configuration key '%s`"
%
(
axis
.
name
,
setting_name
)
)
# check if setting has a method to initialize (set) its value,
# without actually executing the property
try
:
props
[
setting_name
].
fset
except
AttributeError
:
raise
RuntimeError
(
"Axis %s: missing method '%s` to set setting value"
%
(
axis
.
name
,
setting_name
)
)
for
setting_name
in
axis
.
settings
.
config_settings
():
if
setting_name
==
"steps_per_unit"
:
cval
=
float
(
axis
.
config
.
get
(
setting_name
))
rval
=
axis
.
settings
.
_hash
.
raw_get
(
setting_name
)
# Record steps_per_unit
if
rval
is
None
:
axis
.
settings
.
set
(
setting_name
,
cval
)
continue
else
:
rval
=
float
(
rval
)
if
cval
!=
rval
:
ratio
=
rval
/
cval
new_dial
=
axis
.
dial
*
ratio
axis
.
settings
.
set
(
"steps_per_unit"
,
cval
)
if
not
axis
.
no_offset
:
# calculate offset so user pos stays the same
axis
.
settings
.
set
(
"offset"
,
axis
.
position
-
axis
.
sign
*
new_dial
)
else
:
axis
.
settings
.
set
(
"offset"
,
0
)
axis
.
settings
.
set
(
"dial_position"
,
new_dial
)
if
math
.
copysign
(
rval
,
cval
)
!=
rval
:
ll
=
axis
.
settings
.
get
(
"low_limit"
)
hl
=
axis
.
settings
.
get
(
"high_limit"
)
axis
.
settings
.
set
(
"low_limit"
,
-
hl
)
axis
.
settings
.
set
(
"high_limit"
,
-
ll
)
else
:
value
=
get_setting_or_config_value
(
axis
,
setting_name
)
setattr
(
axis
,
setting_name
,
value
)
def
get_axis
(
self
,
axis_name
):
axis
=
self
.
_axes
.
get
(
axis_name
)
if
axis
is
None
:
# create it
...
...
@@ -303,23 +210,13 @@ class Controller:
# reference axis
return
axis
.
_beacon_channels
.
clear
()
for
setting_name
in
axis
.
settings
:
setting_value
=
get_setting_or_config_value
(
axis
,
setting_name
)
chan_name
=
"axis.%s.%s"
%
(
axis
.
name
,
setting_name
)
cb
=
functools
.
partial
(
setting_update_from_channel
,
setting_name
=
setting_name
,
axis
=
axis
)
chan
=
Channel
(
chan_name
,
default_value
=
setting_value
,
callback
=
cb
)
chan
.
_setting_update_cb
=
cb
axis
.
_beacon_channels
[
setting_name
]
=
chan
if
axis
.
controller
is
self
:
axis_initialized
=
Cache
(
axis
,
"initialized"
,
default_value
=
0
)
self
.
__initialized_hw_axis
[
axis
]
=
axis_initialized
self
.
__initialized_axis
[
axis
]
=
False
self
.
_add_axis
(
axis
)
return
axis
def
_add_axis
(
self
,
axis
):
...
...
bliss/tango/servers/axis_ds.py
View file @
da64659f
...
...
@@ -1442,7 +1442,7 @@ def __create_tango_axis_class(axis):
%
axis
.
name
)
for
setting_name
in
axis
.
settings
:
for
setting_name
in
axis
.
settings
.
setting_names
:
if
setting_name
in
[
"velocity"
,
"position"
,
...
...
@@ -1456,7 +1456,7 @@ def __create_tango_axis_class(axis):
]:
elog
.
debug
(
" BlissAxisManager.py -- std SETTING %s "
%
(
setting_name
))
else
:
_setting_type
=
axis
.
controller
.
axis_
settings
.
convert_func
[
setting_name
]
_setting_type
=
axis
.
settings
.
convert_func
(
setting_name
)
_attr_type
=
types_conv_tab
[
_setting_type
]
elog
.
debug
(
" BlissAxisManager.py -- adds SETTING %s as %s attribute"
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment