Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Bliss
bliss
Commits
2cd10321
Commit
2cd10321
authored
Jun 21, 2021
by
Cyril Guilloud
Browse files
communication of PI E727 + HW tests + comments + ignore error on STP
parent
7fd531b0
Pipeline
#49328
passed with stages
in 154 minutes and 48 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
bliss/common/motor_group.py
View file @
2cd10321
...
...
@@ -126,6 +126,9 @@ class _Group(object):
@
property
def
position_with_reals
(
self
):
"""
???
"""
return
self
.
_dial_or_position
(
"position"
,
with_reals
=
True
)
@
property
...
...
@@ -133,6 +136,9 @@ class _Group(object):
return
self
.
_dial_or_position
(
"dial"
,
with_reals
=
True
)
def
_dial_or_position
(
self
,
attr
,
with_reals
=
False
):
"""
???
"""
positions_dict
=
dict
()
if
with_reals
:
...
...
bliss/controllers/motors/pi_e51x.py
View file @
2cd10321
...
...
@@ -41,7 +41,8 @@ responses to them are).
class
PI_E51X
(
pi_gcs
.
Communication
,
pi_gcs
.
Recorder
,
Controller
):
""" Base class for E517 and E518
"""
Base class for E517 and E518
"""
CHAN_LETTER
=
{
1
:
"A"
,
2
:
"B"
,
3
:
"C"
}
...
...
@@ -96,6 +97,9 @@ class PI_E51X(pi_gcs.Communication, pi_gcs.Recorder, Controller):
# acceleration is not mandatory in config
self
.
axis_settings
.
config_setting
[
"acceleration"
]
=
False
# should have been set at init of inherited classes.
log_debug
(
self
,
"model=%s"
,
self
.
model
)
def
close
(
self
):
"""
Called at session exit. 6 times ???
...
...
@@ -106,7 +110,7 @@ class PI_E51X(pi_gcs.Communication, pi_gcs.Recorder, Controller):
def
initialize_hardware
(
self
):
"""
Called once per controller at first
axis use
.
Called once per controller at first
use of any of the axes
.
"""
# Initialize socket communication.
self
.
com_initialize
()
...
...
@@ -119,6 +123,8 @@ class PI_E51X(pi_gcs.Communication, pi_gcs.Recorder, Controller):
def
initialize_axis
(
self
,
axis
):
"""
Called at first access to <axis> (eg: __info__())
- Reads specific config
- Adds specific methods
- Switches piezo to ONLINE mode so that axis motion can be caused
...
...
bliss/controllers/motors/pi_e727.py
View file @
2cd10321
...
...
@@ -6,72 +6,82 @@
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from
bliss.controllers.motor
import
Controller
from
bliss.common.utils
import
object_method
from
bliss.common.utils
import
object_attribute_get
,
object_attribute_set
,
object_method
from
bliss.common.axis
import
AxisState
from
bliss.common.logtools
import
log_debug
,
log_error
from
bliss.common.logtools
import
log_debug
,
log_error
,
log_info
from
bliss
import
global_map
from
.
import
pi_gcs
from
bliss.comm.util
import
TCP
"""
Bliss controller for ethernet PI E727 piezo controller.
"""
class
PI_E727
(
pi_gcs
.
Communication
,
pi_gcs
.
Recorder
,
Controller
):
"""
Bliss controller for ethernet PI E727 piezo controller.
"""
model
=
None
class
PI_E727
(
Controller
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
# Called at session startup
# No hardware access
pi_gcs
.
Communication
.
__init__
(
self
)
pi_gcs
.
Recorder
.
__init__
(
self
)
Controller
.
__init__
(
self
,
*
args
,
**
kwargs
)
self
.
cname
=
"E727"
# Init of controller.
def
initialize
(
self
):
"""
Controller intialization : open a single socket for all 3 axes.
Controller intialization.
Called at session startup.
Called Only once per controller even if more than
one axis is declared in config.
"""
# acceleration is not mandatory in config
self
.
axis_settings
.
config_setting
[
"acceleration"
]
=
False
self
.
trace
(
"controller initialize"
)
self
.
host
=
self
.
config
.
get
(
"host"
)
self
.
trace
(
"opening socket"
)
self
.
sock
=
pi_gcs
.
get_pi_comm
(
self
.
config
,
TCP
)
global_map
.
register
(
self
,
children_list
=
[
self
.
sock
])
# model of the controller.
self
.
model
=
"E727"
log_debug
(
self
,
"model=%s"
,
self
.
model
)
def
finaliz
e
(
self
):
def
clos
e
(
self
):
"""
C
lose the controller socket.
C
alled at session exit. many times ???
"""
# not called at end of device server ??? :(
# called on a new axis creation ???
self
.
trace
(
"controller finalize"
)
try
:
self
.
trace
(
"closing socket"
)
self
.
sock
.
close
()
except
:
pass
def
trace
(
self
,
str
):
log_debug
(
self
,
"{s:{c}<{n}}"
.
format
(
s
=
str
,
n
=
80
,
c
=
"-"
))
# Init of each axis.
def
initialize_axis
(
self
,
axis
):
self
.
trace
(
"axis initialization"
)
self
.
com_close
()
def
initialize_hardware
(
self
):
"""
Called once per controller at first use of any of the axes.
NB: not initialized if accessing to the controller before the axis:
ex: LILAB [1]: napix.controller.command("CCL 1 advanced")
!!! === AttributeError: 'NoneType' object has no attribute 'lock' === !!!
"""
# Initialize socket communication.
self
.
com_initialize
()
def
initialize_hardware_axis
(
self
,
axis
):
"""
Called once per axis at first use of the axis
"""
pass
def
initialize_axis
(
self
,
axis
):
"""
Called at first access to <axis> (eg: __info__())
"""
axis
.
channel
=
axis
.
config
.
get
(
"channel"
,
int
)
# check communication
try
:
_ans
=
self
.
get_identifier
(
axis
,
0.1
)
except
Exception
as
ex
:
_str
=
'%r
\n
ERROR on "%s": switch on the controller'
%
(
ex
,
self
.
host
)
# by default, an exception will be raised
log_error
(
self
,
_str
)
_ans
=
self
.
get_identifier
(
axis
)
# Enables the closed-loop.
# To be imporved.
self
.
_set_closed_loop
(
axis
,
True
)
# supposed that we are on target on init
axis
.
_last_on_target
=
True
def
initialize_encoder
(
self
,
encoder
):
pass
...
...
@@ -85,17 +95,31 @@ class PI_E727(Controller):
def
set_off
(
self
,
axis
):
pass
"""
POSITION
"""
def
read_position
(
self
,
axis
):
_ans
=
self
.
_get_target_pos
(
axis
)
log_debug
(
self
,
"read_position = %f"
%
_ans
)
return
_ans
"""
Return position of the axis.
After movement is finished, return the target position.
"""
if
axis
.
_last_on_target
:
_pos
=
self
.
_get_target_pos
(
axis
)
log_debug
(
self
,
"position read : %g"
%
_pos
)
else
:
# if moving return real position
_pos
=
self
.
_get_pos
(
axis
)
return
_pos
def
read_encoder
(
self
,
encoder
):
_ans
=
self
.
_get_pos
(
axis
)
_ans
=
self
.
_get_pos
(
encoder
.
axis
)
log_debug
(
self
,
"read_position measured = %f"
%
_ans
)
return
_ans
""" VELOCITY """
"""
VELOCITY
"""
def
read_velocity
(
self
,
axis
):
return
self
.
_get_velocity
(
axis
)
...
...
@@ -103,15 +127,16 @@ class PI_E727(Controller):
def
set_velocity
(
self
,
axis
,
new_velocity
):
log_debug
(
self
,
"set_velocity new_velocity = %f"
%
new_velocity
)
_cmd
=
"VEL %s %f"
%
(
axis
.
channel
,
new_velocity
)
self
.
send_no_ans
(
_cmd
)
self
.
check_error
(
_cmd
)
self
.
command
(
_cmd
)
return
self
.
read_velocity
(
axis
)
""" STATE """
"""
STATE
"""
def
state
(
self
,
axis
):
self
.
trace
(
"axis state"
)
#
self.trace("axis state")
if
self
.
_get_closed_loop_status
(
axis
):
if
self
.
_get_on_target_status
(
axis
):
return
AxisState
(
"READY"
)
...
...
@@ -120,7 +145,9 @@ class PI_E727(Controller):
else
:
raise
RuntimeError
(
"closed loop disabled"
)
""" MOVEMENTS """
"""
MOVEMENTS
"""
def
prepare_move
(
self
,
motion
):
pass
...
...
@@ -128,106 +155,53 @@ class PI_E727(Controller):
def
start_one
(
self
,
motion
):
log_debug
(
self
,
"start_one target_pos = %f"
%
motion
.
target_pos
)
# the controller latches the previous error
self
.
clear_error
()
axis
=
motion
.
axis
_cmd
=
"MOV %s %g"
%
(
axis
.
channel
,
motion
.
target_pos
)
self
.
send_no_ans
(
_cmd
)
self
.
check_error
(
_cmd
)
_cmd
=
f
"MOV
{
axis
.
channel
}
{
motion
.
target_pos
}
"
self
.
command
(
_cmd
)
def
stop
(
self
,
axis
):
log_debug
(
self
,
"stop requested"
)
self
.
send_no_ans
(
"STP %s"
%
(
axis
.
channel
))
""" COMMUNICATIONS"""
def
send
(
self
,
cmd
,
timeout
=
None
):
_cmd
=
self
.
_append_eoc
(
cmd
)
_ans
=
self
.
sock
.
write_readline
(
_cmd
.
encode
(),
timeout
=
timeout
).
decode
()
_ans
=
self
.
_remove_eoc
(
_ans
)
return
_ans
def
clear_error
(
self
):
self
.
_get_error
()
def
check_error
(
self
,
cmd
):
# Check error code
(
_err_nb
,
_err_str
)
=
self
.
_get_error
()
if
_err_nb
!=
0
:
_str
=
'ERROR on cmd "%s": #%d(%s)'
%
(
cmd
,
_err_nb
,
_err_str
)
# by default, an exception will be raised
log_error
(
self
,
_str
)
raise
RuntimeError
(
_str
)
def
send_no_ans
(
self
,
cmd
):
_cmd
=
self
.
_append_eoc
(
cmd
)
self
.
sock
.
write
(
_cmd
.
encode
())
@
object_method
(
types_info
=
(
"None"
,
"None"
))
def
raw_flush
(
self
,
axis
):
self
.
sock
.
flush
()
""" RAW COMMANDS """
def
raw_write
(
self
,
cmd
):
_cmd
=
self
.
_append_eoc
(
cmd
)
self
.
sock
.
write
(
_cmd
.
encode
())
def
raw_write_read
(
self
,
cmd
):
_cmd
=
self
.
_append_eoc
(
cmd
)
return
self
.
sock
.
write_readline
(
_cmd
.
encode
()).
decode
()
def
raw_write_readlines
(
self
,
cmd
,
lines
):
_cmd
=
self
.
_append_eoc
(
cmd
)
ans
=
"
\n
"
.
join
(
[
r
.
decode
().
strip
()
for
r
in
self
.
sock
.
write_readlines
(
_cmd
.
encode
(),
lines
)
]
)
_ans
=
self
.
_remove_eoc
(
ans
)
return
_ans
def
_append_eoc
(
self
,
cmd
):
_cmd
=
cmd
.
strip
()
if
not
_cmd
.
endswith
(
"
\n
"
):
_cmd
=
cmd
+
"
\n
"
log_debug
(
self
,
">>>> %s"
%
(
_cmd
.
strip
(
"
\n
"
)))
return
_cmd
def
_remove_eoc
(
self
,
ans
):
_ans
=
ans
.
strip
()
log_debug
(
self
,
"<<<< %s"
%
_ans
)
return
_ans
"""
* STP -> stop asap
* 24 -> stop asap
* HLT -> stop smoothly
* Copy of current position into target position at stop
* all 3 commands generate (by default) a 'Disable Error 10'.
(This can be disabled via parameter 0x0E000301)
"""
log_debug
(
self
,
"stop (HLT) requested"
)
self
.
command
(
"HLT %s"
%
(
axis
.
channel
))
"""
E727 specific
"""
@
object_method
(
types_info
=
(
"None"
,
"str"
))
def
get_identifier
(
self
,
axis
,
timeout
=
None
):
return
self
.
se
nd
(
"IDN?"
,
timeout
)
def
get_identifier
(
self
,
axis
):
return
self
.
comma
nd
(
"IDN?"
)
@
object_method
(
types_info
=
(
"None"
,
"float"
))
def
get_voltage
(
self
,
axis
):
""" Return voltage read from controller."""
_ans
=
self
.
se
nd
(
"SVA?"
)
_voltage
=
float
(
_ans
.
split
(
"="
)[
1
]
)
_ans
=
self
.
comma
nd
(
f
"SVA?
{
axis
.
channel
}
"
)
_voltage
=
float
(
_ans
)
return
_voltage
@
object_method
(
types_info
=
(
"None"
,
"float"
))
def
get_output_voltage
(
self
,
axis
):
""" Return output voltage read from controller. """
return
float
(
self
.
command
(
f
"VOL?
{
axis
.
channel
}
"
))
def
set_voltage
(
self
,
axis
,
new_voltage
):
""" Set Voltage to the controller."""
_cmd
=
"SVA %s %g"
%
(
axis
.
channel
,
new_voltage
)
self
.
send_no_ans
(
_cmd
)
self
.
check_error
(
_cmd
)
self
.
command
(
_cmd
)
def
_get_velocity
(
self
,
axis
):
"""
Return velocity taken from controller.
"""
_ans
=
self
.
se
nd
(
"VEL?
%s"
%
(
axis
.
channel
)
)
_velocity
=
float
(
_ans
.
split
(
"="
)[
1
]
)
_ans
=
self
.
comma
nd
(
f
"VEL?
{
axis
.
channel
}
"
)
_velocity
=
float
(
_ans
)
return
_velocity
...
...
@@ -235,57 +209,50 @@ class PI_E727(Controller):
"""
Return real position read by capacitive sensor.
"""
_ans
=
self
.
se
nd
(
"POS?
%s"
%
(
axis
.
channel
)
)
_pos
=
float
(
_ans
.
split
(
"="
)[
1
]
)
_ans
=
self
.
comma
nd
(
f
"POS?
{
axis
.
channel
}
"
)
_pos
=
float
(
_ans
)
return
_pos
""" ON TARGET """
"""
CLOSED LOOP
"""
def
_get_target_pos
(
self
,
axis
):
"""
Return last target position (setpoint value).
"""
_ans
=
self
.
send
(
"MOV? %s"
%
(
axis
.
channel
))
# _ans should looks like "1=-8.45709419e+01"
_pos
=
float
(
_ans
.
split
(
"="
)[
1
])
_ans
=
self
.
command
(
f
"MOV?
{
axis
.
channel
}
"
)
_pos
=
float
(
_ans
)
return
_pos
def
_get_on_target_status
(
self
,
axis
):
_ans
=
self
.
send
(
"ONT? %s"
%
(
axis
.
channel
))
_status
=
_ans
.
split
(
"="
)[
1
]
if
_status
==
"1"
:
return
True
elif
_status
==
"0"
:
return
False
else
:
log_error
(
self
,
"ERROR on _get_on_target_status, _ans=%r"
%
_ans
)
return
-
1
""" CLOSED LOOP"""
"""
Return 'On-target status' (ONT? command) indicating
if movement is finished and measured position is within
on-target window.
"""
last_on_target
=
bool
(
int
(
self
.
command
(
f
"ONT?
{
axis
.
channel
}
"
)))
axis
.
_last_on_target
=
last_on_target
return
last_on_target
def
_get_closed_loop_status
(
self
,
axis
):
_ans
=
self
.
send
(
"SVO? %s"
%
(
axis
.
channel
))
_status
=
_ans
.
split
(
"="
)[
1
]
_status
=
self
.
command
(
f
"SVO?
{
axis
.
channel
}
"
)
if
_status
==
"1"
:
return
True
elif
_status
==
"0"
:
if
_status
==
"0"
:
return
False
else
:
log_error
(
self
,
"ERROR on _get_closed_loop_status, _
an
s=%r"
%
_
an
s
)
return
-
1
log_error
(
self
,
"ERROR on _get_closed_loop_status, _
statu
s=%r"
%
_
statu
s
)
return
-
1
def
_set_closed_loop
(
self
,
axis
,
state
):
if
state
:
_cmd
=
"SVO
%s 1"
%
(
axis
.
channel
)
_cmd
=
f
"SVO
{
axis
.
channel
}
1"
else
:
_cmd
=
"SVO %s 0"
%
(
axis
.
channel
)
self
.
send_no_ans
(
_cmd
)
self
.
check_error
(
_cmd
)
_cmd
=
f
"SVO
{
axis
.
channel
}
0"
self
.
command
(
_cmd
)
@
object_method
(
types_info
=
(
"None"
,
"None"
))
def
open_loop
(
self
,
axis
):
...
...
@@ -295,45 +262,49 @@ class PI_E727(Controller):
def
close_loop
(
self
,
axis
):
self
.
_set_closed_loop
(
axis
,
True
)
def
_get_error
(
self
):
# Does not use send() to be able to call _get_error in send().
_error_number
=
int
(
self
.
raw_write_read
(
"ERR?"
))
_error_str
=
pi_gcs
.
get_error_str
(
int
(
_error_number
))
@
object_attribute_get
(
type_info
=
"bool"
)
def
get_closed_loop
(
self
,
axis
):
return
self
.
_get_closed_loop_status
(
axis
)
return
(
_error_number
,
_error_str
)
"""
INFO
"""
def
__info__
(
self
):
_tab
=
30
@
object_attribute_get
(
type_info
=
"str"
)
def
get_model
(
self
,
axis
):
return
self
.
model
(
_err_nb
,
_err_str
)
=
self
.
_get_error
()
_txt
=
"%*s: %d (%s)
\n
"
%
(
_tab
,
"Last Error"
,
_err_nb
,
_err_str
)
def
get_id
(
self
,
axis
):
"""
Return controller identifier.
"""
return
self
.
command
(
"*IDN?"
)
_txt
=
_txt
+
"%*s:
\n
%s
\n
"
%
(
_tab
,
"Communication parameters"
,
","
.
join
(
self
.
raw_write_readlines
(
"IFC?"
,
5
).
split
(
"
\n
"
)),
)
_infos
=
[
(
"Identifier"
,
"IDN?"
),
(
"Com level"
,
"CCL?"
),
(
"Firmware developer"
,
"SEP? 1 0xffff000f"
),
(
"Firmware name"
,
"SEP? 1 0xffff0007"
),
(
"Firmware version"
,
"SEP? 1 0xffff0008"
),
(
"Firmware description"
,
"SEP? 1 0xffff000d"
),
(
"Firmware date"
,
"SEP? 1 0xffff000e"
),
(
"Firmware developer"
,
"SEP? 1 0xffff000f"
),
]
def
get_axis_info
(
self
,
axis
):
"""
Return Controller specific info about <axis> for user.
Detailed infos are in get_info().
"""
info_str
=
"PI AXIS INFO:
\n
"
info_str
+=
f
" voltage (SVA) =
{
self
.
get_voltage
(
axis
)
}
\n
"
info_str
+=
f
" output voltage (VOL) =
{
self
.
get_output_voltage
(
axis
)
}
\n
"
info_str
+=
f
" closed loop =
{
self
.
get_closed_loop
(
axis
)
}
\n
"
for
i
in
_infos
:
_cmd
=
i
[
1
]
_ans
=
self
.
send
(
_cmd
)
_txt
=
_txt
+
"%*s: %s
\n
"
%
(
_tab
,
i
[
0
],
_ans
)
self
.
check_error
(
_cmd
)
return
_txt
return
info_str
def
__info__
(
self
):
info_str
=
"CONTROLLER:
\n
"
(
_err_nb
,
_err_str
)
=
self
.
get_error
()
info_str
=
f
"Last Error:
{
_err_nb
}
(
{
_err_str
}
)
\n
"
info_str
+=
"COMMUNICATION CONFIG:
\n
"
info_str
+=
self
.
sock
.
__info__
()
return
info_str
@
object_method
(
types_info
=
(
"None"
,
"string"
))
def
get_info
(
self
,
axis
):
"""
Return information about controller.
Return
detailed
information about controller.
Helpful to tune the device.
"""
axis
.
position
# force axis initialization
...
...
@@ -342,6 +313,10 @@ class PI_E727(Controller):
_txt
=
""
# use command "HPA?" to get parameters address + description
# NB: 0x7000000 used and not 0x07000000
# because PI 727 remove first 0 in the command answer
# -> cause problem in answer check.
_infos
=
[
(
"Real Position"
,
"POS? %s"
),
(
"Setpoint Position"
,
"MOV? %s"
),
...
...
@@ -352,23 +327,19 @@ class PI_E727(Controller):
(
"Analog input setpoint"
,
"AOS? %s"
),
(
"ADC value of analog input"
,
"TAD? %s"
),
(
"Analog setpoints"
,
"TSP? %s"
),
(
"AutoZero Low Voltage"
,
"SPA?
1
0x
0
7000A00"
),
(
"AutoZero High Voltage"
,
"SPA?
1
0x
0
7000A01"
),
(
"Range Limit min"
,
"SPA?
1
0x
0
7000000"
),
(
"Range Limit max"
,
"SPA?
1
0x
0
7000001"
),
(
"ON Target Tolerance"
,
"SPA?
1
0x
0
7000900"
),
(
"Settling time"
,
"SPA?
1
0X
0
7000901"
),
(
"AutoZero Low Voltage"
,
"SPA?
%s
0x7000A00"
),
(
"AutoZero High Voltage"
,
"SPA?
%s
0x7000A01"
),
(
"Range Limit min"
,
"SPA?
%s
0x7000000"
),
(
"Range Limit max"
,
"SPA?
%s
0x7000001"
),
(
"ON Target Tolerance"
,
"SPA?
%s
0x7000900"
),
(
"Settling time"
,
"SPA?
%s
0X7000901"
),
]
for
i
in
_infos
:
_cmd
=
i
[
1
]
if
"%s"
in
_cmd
:
_cmd
=
_cmd
%
(
axis
.
channel
)
_ans
=
self
.
se
nd
(
_cmd
)
_ans
=
self
.
comma
nd
(
_cmd
)
_txt
=
_txt
+
"%*s: %s
\n
"
%
(
_tab
,
i
[
0
],
_ans
)
self
.
check_error
(
_cmd
)
return
_txt
def
get_axis_info
(
self
,
axis
):
return
self
.
get_info
(
axis
)
bliss/controllers/motors/pi_e753.py
View file @
2cd10321
...
...
@@ -11,10 +11,11 @@ from bliss.controllers.motor import Controller
from
bliss.common.utils
import
object_attribute_get
,
object_attribute_set
,
object_method
from
bliss.common.axis
import
AxisState
from
bliss.common
import
axis
as
axis_module
from
bliss.common.logtools
import
log_debug
,
log_info
from
bliss.common.logtools
import
log_debug
,
log_error
,
log_info
import
gevent
from
.
import
pi_gcs
import
gevent.lock
"""
...
...
@@ -35,16 +36,24 @@ responses to them are).
class
PI_E753
(
pi_gcs
.
Communication
,
pi_gcs
.
Recorder
,
Controller
):
"""
Bliss controller for ethernet PI E753 / E754 piezo controllers.
"""
def
__init__
(
self
,
*
args
,
**
kwargs
):
pi_gcs
.
Communication
.
__init__
(
self
)
pi_gcs
.
Recorder
.
__init__
(
self
)
Controller
.
__init__
(
self
,
*
args
,
**
kwargs
)
self
.