Skip to content

Commit

Permalink
Merge branch 'master' of github.com:paulscherrerinstitute/ecmccfg int…
Browse files Browse the repository at this point in the history
…o v9.6.2_RC1
  • Loading branch information
anderssandstrom committed Nov 7, 2024
2 parents 5608083 + d1688ff commit 7c69b54
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 0 deletions.
93 changes: 93 additions & 0 deletions examples/PSI/lab_setup/homing/legacy_axis/cfg/el704X_1.ax
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#General
epicsEnvSet("ECMC_MOTOR_NAME", "Axis1")
epicsEnvSet("ECMC_R", "Axis1-")
epicsEnvSet("ECMC_AXIS_NO", "1")
epicsEnvSet("ECMC_DESC", "Test homing")
epicsEnvSet("ECMC_EGU", "deg") # Motor Record Unit
epicsEnvSet("ECMC_PREC", "3") # Motor Record Precision
epicsEnvSet("ECMC_AXISCONFIG", "") # Extra parameters to driver
epicsEnvSet("ECMC_EC_AXIS_HEALTH", "") # Entry for axis health output (example: ec0.s1.binaryOutput01.0)
epicsEnvSet("ECMC_MOD_RANGE" , "0") # Modulo range (traj setpoints and encoder values will be in range 0..ECMC_MOD_RANGE)
epicsEnvSet("ECMC_MOD_TYPE", "0") # For positioning and MOD_RANGE>0: 0 = Normal, 1 = Always Fwd, 2 = Always Bwd, 3 = Closest Distance

#Encoder
epicsEnvSet("ECMC_ENC_SCALE_NUM" "1")
epicsEnvSet("ECMC_ENC_SCALE_DENOM" "12800")
epicsEnvSet("ECMC_ENC_TYPE" "0") # Type: 0=Incremental, 1=Absolute
epicsEnvSet("ECMC_ENC_BITS" "16") # Total bit count of encoder raw data
epicsEnvSet("ECMC_ENC_ABS_BITS", "0") # Absolute bit count (for absolute encoders) always least significant part of ECMC_ENC_BITS
epicsEnvSet("ECMC_ENC_ABS_OFFSET" "0") # Encoder offset in eng units (for absolute encoders)
epicsEnvSet("ECMC_EC_ENC_ACTPOS", "ec0.s$(DRV_ID).positionActual01") # Ethercat entry for actual position input (encoder)
epicsEnvSet("ECMC_EC_ENC_RESET", "") # Reset handled by DS402 statemachine
epicsEnvSet("ECMC_EC_ENC_ALARM_0", "") # Error 0 handled by DS402 statemachine
epicsEnvSet("ECMC_EC_ENC_ALARM_1", "") # Error 1 handled by DS402 statemachine
epicsEnvSet("ECMC_EC_ENC_ALARM_2", "") # Error 2 handled by DS402 statemachine
epicsEnvSet("ECMC_EC_ENC_WARNING", "") # Warning handled by DS402 statemachine

#Drive
epicsEnvSet("ECMC_DRV_TYPE" "0") # Stepper: 0. DS402: 1 (DS402 = servos and advanced stepper drives)
epicsEnvSet("ECMC_DRV_SCALE_NUM" "10") # Fastest speed in engineering units
epicsEnvSet("ECMC_DRV_SCALE_DENOM" "32768") # I/O range for ECMC_EC_ALIAS_DRV_VELO_SET
epicsEnvSet("ECMC_EC_DRV_CONTROL", "ec0.s$(DRV_ID).driveControl01.0") # Ethercat entry for control word or bit output
epicsEnvSet("ECMC_EC_DRV_STATUS", "ec0.s$(DRV_ID).driveStatus01.1") # Ethercat entry for status word or bit input
epicsEnvSet("ECMC_EC_DRV_VELOCITY", "ec0.s$(DRV_ID).velocitySetpoint01") # Ethercat entry for velocity setpoint output
epicsEnvSet("ECMC_EC_DRV_REDUCE_TORQUE", "ec0.s$(DRV_ID).driveControl01.2") # Ethercat entry for reduce torque output
epicsEnvSet("ECMC_EC_DRV_BRAKE", "") # Ethercat entry for brake output
epicsEnvSet("ECMC_DRV_BRAKE_OPEN_DLY_TIME", "0") # Brake timing parameter in cycles (default 1kHz)
epicsEnvSet("ECMC_DRV_BRAKE_CLOSE_AHEAD_TIME", "0") # Brake timing parameter in cycles (default 1kHz)
epicsEnvSet("ECMC_EC_DRV_RESET", "ec0.s$(DRV_ID).driveControl01.1") # Reset
epicsEnvSet("ECMC_EC_DRV_ALARM_0", "ec0.s$(DRV_ID).driveStatus01.3") # Error
epicsEnvSet("ECMC_EC_DRV_ALARM_1", "")
epicsEnvSet("ECMC_EC_DRV_ALARM_2", "ec0.s$(DRV_ID).driveStatus01.14") # Sync error
epicsEnvSet("ECMC_EC_DRV_WARNING", "ec0.s$(DRV_ID).driveStatus01.2") # Warning

#Trajectory
epicsEnvSet("ECMC_VELO", "5")
epicsEnvSet("ECMC_JOG_VEL", "5")
epicsEnvSet("ECMC_JAR", "0.0") # JAR defaults to VELO/ACCL
epicsEnvSet("ECMC_ACCS_EGU_PER_S2", "10")
epicsEnvSet("ECMC_EMERG_DECEL", "10") # Emergency deceleration

#Homing
epicsEnvSet("ECMC_HOME_PROC", "1")
epicsEnvSet("ECMC_HOME_POS", "0.0")
epicsEnvSet("ECMC_HOME_VEL_TO", "2")
epicsEnvSet("ECMC_HOME_VEL_FRM", "1")
epicsEnvSet("ECMC_HOME_ACC", "10")
epicsEnvSet("ECMC_HOME_DEC", "10")
epicsEnvSet("ECMC_HOME_POS_MOVE_ENA", "1") # Enable move to position after successfull homing
epicsEnvSet("ECMC_HOME_POS_MOVE_TARG_POS","10") # Target position to go to after successfull homing

#Controller
epicsEnvSet("ECMC_CNTRL_KP", "5.0")
epicsEnvSet("ECMC_CNTRL_KI", "0.02")
epicsEnvSet("ECMC_CNTRL_KD", "0.0")
epicsEnvSet("ECMC_CNTRL_KFF", "1.0")

#Monitoring
# Switches
epicsEnvSet("ECMC_EC_MON_LOWLIM", "ec0.s$(DRV_ID).driveStatus01.11") # Ethercat entry for low limit switch input
epicsEnvSet("ECMC_EC_MON_HIGHLIM", "ec0.s$(DRV_ID).driveStatus01.12") # Ethercat entry for high limit switch inpuit
epicsEnvSet("ECMC_EC_MON_HOME_SWITCH", "ec0.s$(DRV_ID).ONE.0") # Ethercat entry for home switch input
epicsEnvSet("ECMC_EC_MON_EXT_INTERLOCK", "ec0.s$(DRV_ID).ONE.0") # Ethercat entry for external interlock input

# Softlimits (disable with 0,0,0)
epicsEnvSet("ECMC_SOFT_LOW_LIM", "0")
epicsEnvSet("ECMC_SOFT_HIGH_LIM", "0")
epicsEnvSet("ECMC_DXLM_ENABLE", "0")

# Position lag
epicsEnvSet("ECMC_MON_LAG_MON_TOL", "0.1")
epicsEnvSet("ECMC_MON_LAG_MON_TIME", "100")
epicsEnvSet("ECMC_MON_LAG_MON_ENA", "1")

# At target
epicsEnvSet("ECMC_MON_AT_TARGET_TOL", "0.01")
epicsEnvSet("ECMC_MON_AT_TARGET_TIME", "100")
epicsEnvSet("ECMC_MON_AT_TARGET_ENA", "1")

# Velocity
epicsEnvSet("ECMC_MON_VELO_MAX", "10.0")
epicsEnvSet("ECMC_MON_VELO_MAX_TRAJ_TIME","100")
epicsEnvSet("ECMC_MON_VELO_MAX_DRV_TIME", "200")
epicsEnvSet("ECMC_MON_VELO_MAX_ENA", "1")
22 changes: 22 additions & 0 deletions examples/PSI/lab_setup/homing/legacy_axis/startup.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
##############################################################################
# Test homing on legacy axis cfg
#
require ecmccfg v9.6.2_RC1 "ENG_MODE=1,ECMC_VER=v9.6.2_RC1"
require ecmccomp

##############################################################################
## Configure hardware

epicsEnvSet("DRV_ID", "13")
${SCRIPTEXEC} ${ecmccfg_DIR}addSlave.cmd, "SLAVE_ID=$(DRV_ID),HW_DESC=EL7041-0052"
${SCRIPTEXEC} ${ecmccomp_DIR}applyComponent.cmd "COMP=Motor-Generic-2Phase-Stepper, MACROS='I_MAX_MA=1000, I_STDBY_MA=200, U_NOM_MV=48000, R_COIL_MOHM=1230,SPEED_RANGE=1'"

##############################################################################
## AXIS 1
epicsEnvSet("DEV", "$(IOC)")
$(SCRIPTEXEC) $(ecmccfg_DIR)configureAxis.cmd, CONFIG=./cfg/el704X_1.ax

#- ###########################################################################
#- go active
${SCRIPTEXEC} ${ecmccfg_DIR}applyConfig.cmd
${SCRIPTEXEC} ${ecmccfg_DIR}setAppMode.cmd
98 changes: 98 additions & 0 deletions examples/PSI/lab_setup/homing/yaml_axis/cfg/axis_open_loop.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
axis:
id: ${AXIS_ID=1} # Axis id
#feedSwitchesOutput: ec0.s${BO_SID}.binaryOutput${BO_CH=01} # Ethercat entry for feed switches

epics:
name: ${AX_NAME=M1} # Axis anme
precision: 3 # Decimal count
description: Test cfg # Axis description
unit: mm # Unit
motorRecord:
fieldInit: 'RTRY=0,FOFF=Frozen' # Extra config for Motor record

drive:
numerator: 10 # Fastest speed in eng. units (2000 Fullsteps/s==10mm/s)
denominator: 32768 # I/O range for ECMC_EC_ALIAS_DRV_VELO_SET (normally +-16bit)
type: 0 # Stepper: 0. DS402: 1 (DS402 = servos and advanced stepper drives)
setpoint: ec0.s$(DRV_SID).velocitySetpoint01 # Velocity setpoint if CSV. Position setpoint if CSP
control: ec0.s$(DRV_SID).driveControl01 # Control word ethercat entry
enable: 0 # Enable bit index in control word (not used if DS402)
reset: 1 # Reset bit in control word (if no drive reset bit then leave empty)
reduceTorque: 2 # Reduce torque bit in drive control word
reduceTorqueEnable: True # Enable reduce torque functionality
status: ec0.s$(DRV_SID).driveStatus01 # Status word ethercat entry
enabled: 1 # Enabled bit index in status word (not used if DS402)
warning: 2 # Warning bit in status word (if no drive warning bit then leave empty)
error: # max 3 error bits in status word
- 3 # Error 0 (if no drive error bit then leave empty)
- 7 # Error 1 (if no drive error bit then leave empty)
- 14 # Error 2 (if no drive error bit then leave empty)

encoder:
desc: Openloop
numerator: 1 # Scaling numerator example 1 mm/rev
denominator: 12800 # Scaling denominator example 4096 ticks per 360 degree
type: 0 # Type: 0=Incremental, 1=Absolute
bits: 16 # Total bit count of encoder raw data
absBits: 0 # Absolute bit count (for absolute encoders) always least significant part of 'bits'
position: ec0.s$(ENC_SID).positionActual${ENC_CH=01} # Ethercat entry for actual position input (encoder)
status: ec0.s$(ENC_SID).encoderStatus${ENC_CH=01} # mandatory only if 'warning' or 'error' are used
primary: 1 # Use this encoder as primary (for control)
homing:
type: 1 # Homing sequence type
position: 0 # Position to reference encoder to
velocity:
to: 2 # Velocity to cam/sensor (used for some homing seqs)
from: 1 # Velocity from cam/sensor (used for some homing seqs)
acceleration: 10 # Acceleration during homing
deceleration: 10 # Deceleration during homing
refToEncIDAtStartup: 1 # At startup then set the start value of this encoder to actpos of this encoder id
refAtHome: 1 # If homing is executed then set position of this encoder
tolToPrim: 0 # If set then this is the max allowed tolerance between prim encoder and this encoder
postMoveEnable: yes # Enable move after successfull homing
postMovePosition: 10 # Position to move to after successfull homing

controller:
Kp: 10 # Kp proportinal gain
Ki: 0 # Ki integral gain
Kd: 0 # Kd derivative gain

trajectory:
axis:
velocity: 3 # Default velo for axis
acceleration: 10 # Default acc for axis
deceleration: 10 # Default dec for axis
emergencyDeceleration: 10 # Deceleration when axis in error state
jerk: 20 # Default jerk for axis
jog:
velocity: 1 # Default velo fro JOG (motor record)

input:
limit:
forward: ec0.s$(DRV_SID).driveStatus01.12 # Ethercat entry for low limit switch input
backward: ec0.s$(DRV_SID).driveStatus01.11 # Ethercat entry for high limit switch input
home: 'ec0.s$(DRV_SID).ONE.0' # Ethercat entry for home switch
interlock: 'ec0.s$(DRV_SID).ONE.0' # Ethercat entry for interlock switch input

softlimits:
enable: false # Enable soft limits
forward: 100 # Soft limit position fwd
forwardEnable: false # Soft limit position fwd enable
backward: -100 # Soft limit position bwd
backwardEnable: false # Soft limit position bwd enable

monitoring:
lag:
enable: true # Enable position lag monitoring (following error)
tolerance: 0.1 # Allowed tolerance
time: 100 # Allowed time outside tolerance target:
velocity:
enable: true # Enable velocity monitoring
max: 8 # Allowed max velocity
time:
trajectory: 100 # Time allowed outside max velo before system init halt
drive: 200 # Time allowed outside max velo before system disables drive
target:
enable: true # Enable at target monitoring (needs to be enabled if using motor record)
tolerance: 0.01 # Allowed tolerance
time: 10 # Filter time inside tolerance to be at target
17 changes: 17 additions & 0 deletions examples/PSI/lab_setup/homing/yaml_axis/startup.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
##############################################################################
## Example config for open loop only

require ecmccfg v9.6.2_RC1 "ENG_MODE=1,ECMC_VER=v9.6.2_RC1"
require ecmccomp

# 0:13 - EL7041 1Ch Stepper
epicsEnvSet("DRV_SID", "13")
${SCRIPTEXEC} ${ecmccfg_DIR}addSlave.cmd, "SLAVE_ID=$(DRV_SID),HW_DESC=EL7041-0052"
${SCRIPTEXEC} ${ecmccomp_DIR}applyComponent.cmd "COMP=Motor-Generic-2Phase-Stepper, MACROS='I_MAX_MA=1000, I_STDBY_MA=200, U_NOM_MV=48000, R_COIL_MOHM=1230,SPEED_RANGE=1'"
epicsEnvSet(DRV_SID,${ECMC_EC_SLAVE_NUM})
${SCRIPTEXEC} ${ecmccfg_DIR}loadYamlAxis.cmd, "FILE=./cfg/axis_open_loop.yaml, DEV=${IOC}, AX_NAME=Axis1, AXIS_ID=1, DRV_SID=${DRV_SID}, ENC_SID=${DRV_SID}, ENC_CH=01"

#- ###########################################################################
#- go active
${SCRIPTEXEC} ${ecmccfg_DIR}applyConfig.cmd
${SCRIPTEXEC} ${ecmccfg_DIR}setAppMode.cmd
107 changes: 107 additions & 0 deletions examples/PSI/lab_setup/plcs_autosave/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# PLC best practice
* Macros
* MSI include, substitute
* Printouts

## Macros
Use of macros makes the code more generic. When loading a PLC file with "loadPLCFile.cmd", custom macros can be defined in "PLC\_MACROS":
```
${SCRIPTEXEC} ${ecmccfg_DIR}loadPLCFile.cmd, "FILE=./cfg/main.plc, INC=.:./cfg/, SAMPLE_RATE_MS=1000, PLC_MACROS='BO_S_ID=${ECMC_EC_SLAVE_NUM}'"
```
NOTE: ECMC\_EC\_SLAVE\_NUM expands to the ID of the last added slave.

In addition to the custom macros, a few macros, that are often needed, are predefined:
1. SELF\_ID : Id of current PLC
2. SELF : plc<SELF\_ID>
3. M\_ID : EtherCAT master ID
4. M : ec<M\_ID>

### SELF_ID and SELF example
A common usecase is that some initiation is needed, could be triggering of a custom homing sequence:

```
if(${SELF}.firstscan) {
var plc:=${SELF_ID};
${DBG=#}println('PLC ',plc,' is starting up');
};
```
After macro expansion the code would look like this (for PLC id=0,DBG=''):
```
if(plc0.firstscan) {
var plc:=0;
println('PLC ',plc,' is starting up');
};
```
### M_ID and M example
All EtherCAT related information/data is accessible through the pattern "ec<master_id>.s<slave_id>.<name>".
To allow the same code to be loaded on different masters it's a good idea to use the predefined macros,"M" and "M_ID".

Toggle an output:
```
${M}.s${BO_S_ID}.binaryOutput${BO_CH=01}:=not(${M}.s${BO_S_ID}.binaryOutput${BO_CH=01});
${DBG=#}println('State: ', ${M}.s${BO_S_ID}.binaryOutput${BO_CH});
```
After macro expansion with the following macros the code would look like this:
* BO\_S\_ID = 10
* BO\_CH = Not defined (defaults to "01")
* DBG = Not defined (defaults to "#")
```
ec0.s10.binaryOutput01:=not(ec0.s10.binaryOutput01);
#println('State: ', ec0.s10.binaryOutput01);
```

## Include and substitute
Since all PLC files and PLC libs are parsed through MSI the "include" and "substitute" commands can be used.

When using the include command, the file location dir of the file must be added in the INC parameter when loading the PLC:
```
${SCRIPTEXEC} ${ecmccfg_DIR}loadPLCFile.cmd, "FILE=./cfg/main.plc, INC=.:./cfg/, SAMPLE_RATE_MS=1000, PLC_MACROS='BO_S_ID=${ECMC_EC_SLAVE_NUM}'"
```
The "INC" parameter can contain several directories separated with a ":", making it possible to include PLC files from several locations/modules.

### Example: Toggle a few outputs
As a demo usecase let's consider that a few outputs needs to be toggled.
NOTE: There are simpler ways to write this specifc code but it's used to demo how code can be divided.

Lets first define some code that toggles a bit (toggle\_output.plc\_inc):
```
# Example of simple include file that toggles an binary output
${M}.s${BO_S_ID}.binaryOutput${BO_CH}:=not(${M}.s${BO_S_ID}.binaryOutput${BO_CH});
${DBG=#}println('State: ', ${M}.s${BO_S_ID}.binaryOutput${BO_CH});
```
This code snippet then can be included in a main plc-file by using the "include" keyword.
Each include can then be included with different macros by using the "substitute" keyword:
```
substitute "BO_CH=01"
include "toggle_output.plc_inc"
substitute "BO_CH=02, DBG="
include "toggle_output.plc_inc"
```
The above code would expand to:
```
ec0.s10.binaryOutput01:=not(ec0.s10.binaryOutput01);
#println('State:', ec0.s10.binaryOutput01);
ec0.s10.binaryOutput02:=not(ec0.s10.binaryOutput02);
println('State: ', ec0.s10.binaryOutput02);
```
The resulting code will toggle two different outputs, the state of the last output will be printed.

NOTE: Macros cannot be used in the filename when including a file. Instead the dir should be defined in the INC param when loading the PLC, see above.

## Printouts
Adding a DBG macro can be usefull to be able to turn on/off printouts. Typically during commsioning it can be usefull to have many printouts but later when system goes into production, it could be a good idea to turn (some) printouts off.

Example of a printout that can be turned on/off (default off)
```
${DBG=#}println('Value: ', ${M}.s${BO_S_ID}.binaryOutput${BO_CH});
```
Will result in the below if setting the DBG='' (and some other macros, see above):
```
println('Value: ', ec0.s10.binaryOutput01);
```

14 changes: 14 additions & 0 deletions examples/PSI/lab_setup/plcs_autosave/cfg/main.plc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
if(${SELF}.firstscan) {
# do some inits
var plc:=${SELF_ID};
${DBG=#}println('PLC ',plc,' is starting up');
};

substitute "BO_CH=01"
#include "toggle_output.plc_inc"

substitute "BO_CH=02, DBG="
#include "toggle_output.plc_inc"

println('BIN: ',static.restoreVariableBin);
println('ANA: ', static.restoreVariableAnalog);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
${M}.s${BO_S_ID}.binaryOutput${BO_CH}:=not(${M}.s${BO_S_ID}.binaryOutput${BO_CH});
${DBG=#}println('State: ', ${M}.s${BO_S_ID}.binaryOutput${BO_CH});

10 changes: 10 additions & 0 deletions examples/PSI/lab_setup/plcs_autosave/db/ecmc_test.req
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#UPDATE-FREQ=10
#ENABLE-PASS=1
#--------------------------------
# this file contains ASR PVs of the motion controller
# see startup.cmd
#--------------------------------

# Test
$(IOC):Set-Ana-RB
$(IOC):Set-Bin-RB
Loading

0 comments on commit 7c69b54

Please sign in to comment.