PID tuning: one vs multiple loops, gain scheduling
25 Oct 2014 04:52 - 25 Oct 2014 05:11 #52372
by DaBit
Replied by DaBit on topic PID tuning: one vs multiple loops, gain scheduling
OK. so the answer to my original question is 'both'. I implemented an inner velocity loop, outer position loop, and used gain scheduling on the position loop based on position error.
Inner velocity loop, response to a small velocity step. That one is the worst case situation as PCW explained earlier. Resonances are mechanical; this servo uses a fairly long belt to drive the ballscrew.
I used a biquad filter on the velocity signal to smooth out the worst jitter without introducing much delay so I could use a bit more Dgain. Dgain is important in torque mode.
Current Fcutoff is 800Hz, Q=0,707 to get a flat response.
Positioning error when doing a 10 meter/minute (~400ipm) move. Scale is 0,02mm/division (0.00078"/div).
The cheap 5um Chinese scale on the X axis attaches it's carriage with a thin spring. That is clearly visible in the plot
With this low resolution and compliancy I decided to reduce the correction speed of the scale a lot.
When doing a slower move the error is much less.
www.icecoldcomputing.com/misc/xservopiv_ferror_10metermin.png
The amount of tuning parameters for a single axis is growing rapidly
I have no hard measurement data, but the positioning speed and stiffness have increased at least an order of magnitude over a single non-gain-scheduling PID loop.
I am happy
I did not yet implement notching of mechanical resonances. I changed the mechanics a bit and I need a new belt. Before that one is mounted it makes no sense. However, I did improve the sinesweep component to include a log sweep also. I will post it on the wiki.
3 more servos to go and one 7i77 to modify....
Inner velocity loop, response to a small velocity step. That one is the worst case situation as PCW explained earlier. Resonances are mechanical; this servo uses a fairly long belt to drive the ballscrew.
I used a biquad filter on the velocity signal to smooth out the worst jitter without introducing much delay so I could use a bit more Dgain. Dgain is important in torque mode.
Current Fcutoff is 800Hz, Q=0,707 to get a flat response.
Positioning error when doing a 10 meter/minute (~400ipm) move. Scale is 0,02mm/division (0.00078"/div).
The cheap 5um Chinese scale on the X axis attaches it's carriage with a thin spring. That is clearly visible in the plot
With this low resolution and compliancy I decided to reduce the correction speed of the scale a lot.
When doing a slower move the error is much less.
www.icecoldcomputing.com/misc/xservopiv_ferror_10metermin.png
The amount of tuning parameters for a single axis is growing rapidly
I have no hard measurement data, but the positioning speed and stiffness have increased at least an order of magnitude over a single non-gain-scheduling PID loop.
I am happy
I did not yet implement notching of mechanical resonances. I changed the mechanics a bit and I need a new belt. Before that one is mounted it makes no sense. However, I did improve the sinesweep component to include a log sweep also. I will post it on the wiki.
3 more servos to go and one 7i77 to modify....
Last edit: 25 Oct 2014 05:11 by DaBit.
Please Log in or Create an account to join the conversation.
- Todd Zuercher
- Offline
- Platinum Member
Less
More
- Posts: 5007
- Thank you received: 1441
25 Oct 2014 07:23 #52374
by Todd Zuercher
Replied by Todd Zuercher on topic PID tuning: one vs multiple loops, gain scheduling
Sounds promising. Would your dual loop set up work with only a single input form an encoder, or is the linear scale required?
Please Log in or Create an account to join the conversation.
25 Oct 2014 13:48 #52382
by DaBit
Replied by DaBit on topic PID tuning: one vs multiple loops, gain scheduling
The linear scale is not required, that is an extra loop.
Also in my situation the normal servo loop does all the positioning, the scale only says 'on average you are a little bit off, let's move to target slowly'. That 'you are a little bit off' can have multiple causes. For example: by comparing the position of the scale and ballscrew I can calculate the temperature in my shed
Also in my situation the normal servo loop does all the positioning, the scale only says 'on average you are a little bit off, let's move to target slowly'. That 'you are a little bit off' can have multiple causes. For example: by comparing the position of the scale and ballscrew I can calculate the temperature in my shed
Please Log in or Create an account to join the conversation.
26 Oct 2014 02:33 #52393
by DaBit
Replied by DaBit on topic PID tuning: one vs multiple loops, gain scheduling
Please Log in or Create an account to join the conversation.
27 Oct 2014 05:33 #52415
by DaBit
Replied by DaBit on topic PID tuning: one vs multiple loops, gain scheduling
Made a small change to the HAL file, and got a much improved response. Servos are silent also.
Wat did I do? I put the addf()'s in the correct order so execution of the various loops is correct. First read from the 7i77, then scale PID, then servo position, then servo velocity, then write to 7i77.
Andy once noticed that things are executed strictly in order, but somehow I still had the addf()'s in a nicely human-readable sort order. That costed me 3 servo periods to have everything ripple through.
I think that by now I proved well that torque mode control loop execution rate is very important. For my servos I would consider 3kHz the absolute minimum.
Now, I do want to try an even higher rate than 5kHz. Limiting factor is the 7i77; choose a 150usec servo thread rate and the error boxes about the serial IO start popping up.
But if I look at this list (halcmd show all | grep '\.time')
then it shows that the hm2_5i25.0.read function seems to consume a lot of CPU cycles, which limits maximum servo thread rate anyway.
@PCW: Would that improve when the smart serial bitrate is increased to 5Mbit or 10Mbit? If so, is this something I can do myself? I do have a PicKIT3 myself, access to an ICD3, and making a serial port that talks RS422 so I can communicate at 115k2 with the board wouldn't be a problem either.
Wat did I do? I put the addf()'s in the correct order so execution of the various loops is correct. First read from the 7i77, then scale PID, then servo position, then servo velocity, then write to 7i77.
Andy once noticed that things are executed strictly in order, but somehow I still had the addf()'s in a nicely human-readable sort order. That costed me 3 servo periods to have everything ripple through.
I think that by now I proved well that torque mode control loop execution rate is very important. For my servos I would consider 3kHz the absolute minimum.
Now, I do want to try an even higher rate than 5kHz. Limiting factor is the 7i77; choose a 150usec servo thread rate and the error boxes about the serial IO start popping up.
But if I look at this list (halcmd show all | grep '\.time')
25 s32 RO 456 SnSMill-correction.time
13 s32 RO 28 coolant_or2.time
28 s32 RO 32 flipflop_pause.time
28 s32 RO 120 flipflop_resume.time
28 s32 RO 32 flipflop_run.time
23 s32 RO 36 hm2_5i25.0.pet_watchdog.time
23 s32 RO 145296 hm2_5i25.0.read.time
23 s32 RO 0 hm2_5i25.0.read_gpio.time
23 s32 RO 4544 hm2_5i25.0.write.time
23 s32 RO 0 hm2_5i25.0.write_gpio.time
24 s32 RO 172 millturn-helper.0.time
9 s32 RO 232 motion-command-handler.time
9 s32 RO 3648 motion-controller.time
16 s32 RO 60 offset_yjoints.update-feedback.time
16 s32 RO 120 offset_yjoints.update-output.time
21 s32 RO 212 sampler.0.time
20 s32 RO 92 sinesweep.0.time
12 s32 RO 68 xhomed_not.time
14 s32 RO 68 xmaxsw_and2.time
14 s32 RO 120 xminsw_and2.time
18 s32 RO 132 xposerr_abs.time
19 s32 RO 160 xposgain_lincurve.time
10 s32 RO 904 xposition_pid.do-pid-calcs.time
10 s32 RO 248 xscale_pid.do-pid-calcs.time
15 s32 RO 136 xscale_sum2.time
17 s32 RO 1836 xvelocity_filter.time
10 s32 RO 1656 xvelocity_pid.do-pid-calcs.time
18 s32 RO 44 y1poserr_abs.time
19 s32 RO 44 y1posgain_lincurve.time
10 s32 RO 192 y1position_pid.do-pid-calcs.time
10 s32 RO 156 y1scale_pid.do-pid-calcs.time
15 s32 RO 80 y1scale_sum2.time
17 s32 RO 48 y1velocity_filter.time
10 s32 RO 232 y1velocity_pid.do-pid-calcs.time
18 s32 RO 88 y2poserr_abs.time
19 s32 RO 128 y2posgain_lincurve.time
10 s32 RO 320 y2position_pid.do-pid-calcs.time
10 s32 RO 220 y2scale_pid.do-pid-calcs.time
15 s32 RO 64 y2scale_sum2.time
17 s32 RO 72 y2velocity_filter.time
10 s32 RO 204 y2velocity_pid.do-pid-calcs.time
12 s32 RO 32 yhomed_not.time
13 s32 RO 108 yjoint_faultgen_or2_1.time
13 s32 RO 56 yjoint_faultgen_or2_2.time
11 s32 RO 96 yjoints_comp.time
12 s32 RO 100 yjointscomp_not.time
14 s32 RO 28 ymaxsw_and2.time
14 s32 RO 32 yminsw_and2.time
10 s32 RO 144 zscale_pid.do-pid-calcs.time
15 s32 RO 80 zscale_sum2.time
10 s32 RO 132 zservo_pid.do-pid-calcs.time
then it shows that the hm2_5i25.0.read function seems to consume a lot of CPU cycles, which limits maximum servo thread rate anyway.
@PCW: Would that improve when the smart serial bitrate is increased to 5Mbit or 10Mbit? If so, is this something I can do myself? I do have a PicKIT3 myself, access to an ICD3, and making a serial port that talks RS422 so I can communicate at 115k2 with the board wouldn't be a problem either.
Please Log in or Create an account to join the conversation.
27 Oct 2014 08:34 - 27 Oct 2014 08:43 #52417
by PCW
Replied by PCW on topic PID tuning: one vs multiple loops, gain scheduling
Before you get too excited about increasing the loop rate, you might halscope the read /write and
perhaps motion controller times (your readout of those times is a snapshot of some very noisy signals)
(resetting the corresponding tmax's and watching them is interesting also)
you will likely find that you have latencies in them that will prevent much higher rates
(unless you have a PC with very low _actual_ latencies)
(that is the latency test doesn't tell the whole story)
The remote sserial baud rate is changed by setting the remotes baud rate setting in its EEPROM (via a serial command)
and changing the host interface baud rate. I will have to look into how the host interface baud rate can be changed
for a test
perhaps motion controller times (your readout of those times is a snapshot of some very noisy signals)
(resetting the corresponding tmax's and watching them is interesting also)
you will likely find that you have latencies in them that will prevent much higher rates
(unless you have a PC with very low _actual_ latencies)
(that is the latency test doesn't tell the whole story)
The remote sserial baud rate is changed by setting the remotes baud rate setting in its EEPROM (via a serial command)
and changing the host interface baud rate. I will have to look into how the host interface baud rate can be changed
for a test
Last edit: 27 Oct 2014 08:43 by PCW.
Please Log in or Create an account to join the conversation.
27 Oct 2014 15:52 #52422
by DaBit
Replied by DaBit on topic PID tuning: one vs multiple loops, gain scheduling
I do not strictly need to increase thread rate; I am definitely on the path of diminishing returns. It is unrealistic to expect a dynamic positioning error much below, say, +/- 8 encoder counts and that's where I am now. It is just that nagging voice between my ears....
I ran that command multiple times, and the .time signals are indeed very noisy (do-pid-calcs varies between 200 and 1800 cycles, for example), but hm2_5i25.0.read is quite consistent in being high.
BTW: basically all I want to run at a high thread rate is the I/O, the velocity-PID's with their accompanying logic and possibly the servo position PID.
Linear scale PID, motion controller, additional signal juggling, etc. can all run at a lower rate.
Except for a single issue the PC (Asus P8Z77 mainboard+Celeron G550) is very good in the latency department. Plotting motion.servo.last-period-ns reveals that 99.99% of the time the jitter on the thread scheduling is very low (<5us) but once in a while there is a +30usec spike in the timing. It happens only once in a few seconds, for a single cycle only and I cannot measure or notice any influence on LinuxCNC operation or servo performance.
I ran that command multiple times, and the .time signals are indeed very noisy (do-pid-calcs varies between 200 and 1800 cycles, for example), but hm2_5i25.0.read is quite consistent in being high.
BTW: basically all I want to run at a high thread rate is the I/O, the velocity-PID's with their accompanying logic and possibly the servo position PID.
Linear scale PID, motion controller, additional signal juggling, etc. can all run at a lower rate.
Except for a single issue the PC (Asus P8Z77 mainboard+Celeron G550) is very good in the latency department. Plotting motion.servo.last-period-ns reveals that 99.99% of the time the jitter on the thread scheduling is very low (<5us) but once in a while there is a +30usec spike in the timing. It happens only once in a few seconds, for a single cycle only and I cannot measure or notice any influence on LinuxCNC operation or servo performance.
Please Log in or Create an account to join the conversation.
- Todd Zuercher
- Offline
- Platinum Member
Less
More
- Posts: 5007
- Thank you received: 1441
27 Oct 2014 20:29 #52428
by Todd Zuercher
Replied by Todd Zuercher on topic PID tuning: one vs multiple loops, gain scheduling
Would you mind sharing your configuration files? ( For the curious to look at.)
Please Log in or Create an account to join the conversation.
27 Oct 2014 21:48 #52435
by DaBit
Replied by DaBit on topic PID tuning: one vs multiple loops, gain scheduling
No problem. Just keep in mind that it is still a work in progress although I am quite happy with the current state.
I'll post them here in code blocks for easy viewability. If you prefer a .tar.gz, just shout.
If you need information about the construction of the mill: here is a topic in Dutch: www.cnczone.nl/viewtopic.php?f=8&t=8410.
SnSMill.ini
SnSMill.hal:
And for completeness:
postgui.hal
SnS-xhc-hb04.hal
I'll post them here in code blocks for easy viewability. If you prefer a .tar.gz, just shout.
If you need information about the construction of the mill: here is a topic in Dutch: www.cnczone.nl/viewtopic.php?f=8&t=8410.
SnSMill.ini
# INI file for DaBit's Stone-'n-Steel mill
[HOSTMOT2]
DRIVER=hm2_pci
BOARD=5i25
CONFIG="num_encoders=8 num_stepgens=2 sserial_port_0=0000xxxx"
[EMC]
# Name of machine, for use with display, etc.
MACHINE = SnS_Mill
# Debug level, 0 means no messages. See src/emc/nml_int/emcglb.h for others
#DEBUG = 0x00000003
#DEBUG = 0x00000007
DEBUG = 0x0
[DISPLAY]
DISPLAY = gmoccapy
PREFERENCE_FILE_PATH = gmoccapy_preferences
DEFAULT_LINEAR_VELOCITY = 100.0
DEFAULT_ANGULAR_VELOCITY = 360.0
MAX_LINEAR_VELOCITY = 300.0
MAX_ANGULAR_VELOCITY = 30000.0
MAX_FEED_OVERRIDE = 2.5
MAX_SPINDLE_OVERRIDE = 2.0
MIN_SPINDLE_OVERRIDE = 0.5
EDITOR = leafpad
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
#POSITION_FEEDBACK = COMMANDED
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 5
PROGRAM_PREFIX = /home/dabit/linuxcnc/nc_files
INCREMENTS = 10mm 1mm .5mm .1mm .05mm .01mm .005mm
GEOMETRY = XYYZ
CYCLE_TIME = 0.0500
#EMBED_TAB_NAME = Subroutines
#EMBED_TAB_COMMAND = halcmd loadusr -Wn gladevcp gladevcp -c bvh_subs -x {XID} bvh_subs.ui
#EMBED_TAB_NAME = Camera
#EMBED_TAB_COMMAND = mplayer -cache 128 -vf bmovl=0:0:tfifo -tv driver=v4l2:width=640:height=480 -wid {XID} tv://0
#GLADEVCP = sidepanel.ui
[FILTER]
PROGRAM_EXTENSION = .png,.gif,.jpg Grayscale Depth Image
PROGRAM_EXTENSION = .py Python Script
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[RS274NGC]
PARAMETER_FILE = SnSMill.var
SUBROUTINE_PATH = /home/dabit/linuxcnc/ngc_lib:/home/dabit/linuxcnc/m_codes
USER_M_PATH = /home/dabit/linuxcnc/m_codes
[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 1.0
COMM_WAIT = 0.010
SERVO_PERIOD = 200000
BASE_PERIOD = 200000
[HAL]
HALUI = halui
HALFILE = SnSMill.hal
HALFILE = SnS-xhc-hb04.hal
HALFILE = spindle.hal
POSTGUI_HALFILE = postgui.hal
[TRAJ]
AXES = 4
COORDINATES = X Y Z A
LINEAR_UNITS = mm
ANGULAR_UNITS = degree
CYCLE_TIME = 0.010
DEFAULT_VELOCITY = 100.00
MAX_VELOCITY = 300.00
DEFAULT_ACCELERATION = 2500.0
MAX_ACCELERATION = 2500.0
NO_FORCE_HOMING = 1
POSITION_FILE = machine_position.txt
ARC_BLEND_ENABLE = 1
ARC_BLEND_FALLBACK_ENABLE = 0
ARC_BLEND_OPTIMIZATION_DEPTH = 50
ARC_BLEND_GAP_CYCLES = 4
ARC_BLEND_RAMP_FREQ = 200
[EMCIO]
EMCIO = io
CYCLE_TIME = 0.100
TOOL_TABLE = tool.tbl
# X-axis:
# - 8192 pulses/rev @ motor, 8192 pulses/rev @ leadscrew, leadscrew pitch=10mm = 819.2 pulses/mm
# - PID tuning params. Deadband is set to +/- 3 pulses.
[AXIS_0]
TYPE = LINEAR
MAX_VELOCITY = 300.0
MAX_ACCELERATION = 2500.0
BACKLASH = 0.000
FERROR = 200
MIN_FERROR = 200
INPUT_SCALE = -1259.492
INPUT_SCALE_LINEAR = -200
OUTPUT_SCALE = 3
OUTPUT_SCALE_NEG = -3
OUTPUT_OFFSET = 0.0
MIN_LIMIT = -518.0
MAX_LIMIT = 10.0
HOME = 0.0
HOME_OFFSET = 0.0
HOME_SEARCH_VEL = 200.0
HOME_LATCH_VEL = -2.0
HOME_USE_INDEX = NO
HOME_IGNORE_LIMITS = YES
HOME_SEQUENCE = 2
VEL_P = 0.018
VEL_I = 1.5
VEL_D = 0.000011
VEL_FF0 = 0.0005
VEL_FF1 = 8e-05
VEL_MAX_OUTPUT = 3
VEL_FILTER_FC = 800
POS_P_LO = 110
POS_P_HI = 500
POS_P_ERR = 0.03
POS_I = 0
POS_D = 0
POS_FF0 = 0
POS_FF1 = 1
POS_FF2 = 0
POS_DEADBAND= 0.003
POS_MAX_OUTPUT = 700
SCALE_P = 0
SCALE_I = 0
SCALE_DEADBAND = 0.0051
SCALE_MAXCORR = 2
# Y-axes:
# - 8192 pulses/rev @ motor, 12288 pulses/rev @ leadscrew, leadscrew pitch=10mm = 1228.8 pulses/mm
# - Allow +/- 0,5mm (== 1mm) deviation between the two Y axes
[AXIS_1]
TYPE = LINEAR
MAX_VELOCITY = 300.0
MAX_ACCELERATION = 2500.0
BACKLASH = 0.000
FERROR = 5
MIN_FERROR = 1
INPUT_SCALE = -1227.6
INPUT_SCALE_LINEAR_Y1 = -1000
INPUT_SCALE_LINEAR_Y2 = -1000
OUTPUT_SCALE = 3
OUTPUT_SCALE_NEG = -3
OUTPUT_OFFSET = 0.0
VEL_MAX_OUTPUT = 3
MIN_LIMIT = -630.0
MAX_LIMIT = 25.0
HOME = 0.000
HOME_OFFSET = 0.0
HOME_SEARCH_VEL = 200.0
HOME_LATCH_VEL = -2.0
HOME_USE_INDEX = NO
HOME_IGNORE_LIMITS = YES
HOME_SEQUENCE = 1
VEL_P = 0.045
VEL_I = 8
VEL_D = 0.000012
VEL_FF0 = 0.005
VEL_FF1 = 9e-05
VEL_MAX_OUTPUT = 3
VEL_FILTER_FC = 1000
POS_P_LO = 250
POS_P_HI = 900
POS_P_ERR = 0.03
POS_I = 0
POS_D = 0
POS_FF0 = 0
POS_FF1 = 1
POS_FF2 = 0
POS_DEADBAND= 0.0015
POS_MAX_OUTPUT = 700
SLAVEAXES_MAXDEVIATION= 1
SCALE_P = 0
SCALE_I = 20
SCALE_D = 0
SCALE_DEADBAND = 0.0015
SCALE_MAXCORR = 2
# Z-axis:
# - 200 fullsteps/rev, 16usteps = 3200 steps/rev. lead pitch = 5mm, coupling 1:1. Steps/mm = 6400/5=640
[AXIS_2]
TYPE = LINEAR
MAX_VELOCITY = 70.0
MAX_ACCELERATION = 800.0
STEPGEN_MAX_VELOCITY = 80
STEPGEN_MAXACCEL = 1200
BACKLASH = 0.000
FERROR = 5.0
MIN_FERROR = 2.0
MIN_LIMIT = -199.0
MAX_LIMIT = 6.0
DIRSETUP = 10000
DIRHOLD = 10000
STEPLEN = 5000
STEPSPACE = 5000
STEP_SCALE = 641
INPUT_SCALE_LINEAR = -1000
P = 150
I = 0
D = 0
FF0 = 0
FF1 = 1
FF2 = 1e-06
BIAS = 0
SCALE_P = 0
SCALE_I = 60
SCALE_DEADBAND = 0.003
SCALE_MAXCORR = 5
HOME = 0.000
HOME_OFFSET = 0
HOME_SEARCH_VEL = 75.0
HOME_LATCH_VEL = -2.0
HOME_USE_INDEX = NO
HOME_IGNORE_LIMITS = YES
HOME_SEQUENCE = 0
[AXIS_3]
TYPE = ANGULAR
MAX_VELOCITY = 18000
MAX_ACCELERATION = 30000
STEPGEN_MAX_VELOCITY = 25000
STEPGEN_MAXACCEL = 32000
BACKLASH = 0.000
FERROR = 50.0
MIN_FERROR = 10.0
MIN_LIMIT = -858993.4592
MAX_LIMIT = 858993.4592
DIRSETUP = 1000
DIRHOLD = 1000
STEPLEN = 1000
STEPSPACE = 1000
STEP_SCALE = 1.736111
HOME = 0.000
HOME_OFFSET = 0
HOME_SEARCH_VEL = 0.0
HOME_LATCH_VEL = 0.0
HOME_USE_INDEX = NO
HOME_IGNORE_LIMITS = YES
HOME_SEQUENCE = 0
SnSMill.hal:
# #######################################
#
# HAL file for DaBit's Stone-'n-Steel mill
# Derived from Ted Hyde's original hm2-servo config
#
# #####################################################################
# ###################################
# Core EMC/HAL Loads
# ###################################
# kinematics
loadrt trivkins
# motion controller, get name and thread periods from ini file
loadrt [EMCMOT]EMCMOT servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[TRAJ]AXES
# standard components
loadrt pid names=xvelocity_pid,xposition_pid,xscale_pid,y1velocity_pid,y1position_pid,y1scale_pid,y2velocity_pid,y2position_pid,y2scale_pid,zservo_pid,zscale_pid
loadrt comp names=yjoints_comp
loadrt not names=yjointscomp_not,xhomed_not,yhomed_not
loadrt or2 names=yjoint_faultgen_or2_1,yjoint_faultgen_or2_2,coolant_or2
loadrt and2 names=xminsw_and2,xmaxsw_and2,yminsw_and2,ymaxsw_and2
loadrt sum2 names=xscale_sum2,y1scale_sum2,y2scale_sum2,zscale_sum2
loadrt offset names=offset_yjoints
loadrt biquad names=xvelocity_filter,y1velocity_filter,y2velocity_filter
loadrt abs names=xposerr_abs,y1poserr_abs,y2poserr_abs
loadrt lincurve names=xposgain_lincurve,y1posgain_lincurve,y2posgain_lincurve personality=2,2,2
loadrt sinesweep
loadrt sampler depth=16 cfg=ff
# hostmot2 driver
loadrt hostmot2
# load low-level driver
loadrt [HOSTMOT2](DRIVER) config=[HOSTMOT2](CONFIG)
setp hm2_[HOSTMOT2](BOARD).0.watchdog.timeout_ns 10000000
# load millturn helper component and correction component
loadrt millturn_helper
loadrt SnSMill_correction
# ################################################
# THREADS
# ################################################
addf hm2_[HOSTMOT2](BOARD).0.read servo-thread
addf motion-command-handler servo-thread
addf motion-controller servo-thread
addf SnSMill-correction servo-thread
addf millturn-helper.0 servo-thread
addf xvelocity_filter servo-thread
addf y1velocity_filter servo-thread
addf y2velocity_filter servo-thread
addf xscale_pid.do-pid-calcs servo-thread
addf xscale_sum2 servo-thread
addf xposerr_abs servo-thread
addf xposgain_lincurve servo-thread
addf xposition_pid.do-pid-calcs servo-thread
addf xvelocity_pid.do-pid-calcs servo-thread
addf offset_yjoints.update-output servo-thread
addf offset_yjoints.update-feedback servo-thread
addf y1scale_pid.do-pid-calcs servo-thread
addf y1scale_sum2 servo-thread
addf y1poserr_abs servo-thread
addf y1posgain_lincurve servo-thread
addf y1position_pid.do-pid-calcs servo-thread
addf y1velocity_pid.do-pid-calcs servo-thread
addf y2scale_pid.do-pid-calcs servo-thread
addf y2scale_sum2 servo-thread
addf y2poserr_abs servo-thread
addf y2posgain_lincurve servo-thread
addf y2position_pid.do-pid-calcs servo-thread
addf y2velocity_pid.do-pid-calcs servo-thread
addf zscale_pid.do-pid-calcs servo-thread
addf zscale_sum2 servo-thread
addf zservo_pid.do-pid-calcs servo-thread
addf yjoints_comp servo-thread
addf yjointscomp_not servo-thread
addf xhomed_not servo-thread
addf yhomed_not servo-thread
addf yjoint_faultgen_or2_1 servo-thread
addf yjoint_faultgen_or2_2 servo-thread
addf coolant_or2 servo-thread
addf xminsw_and2 servo-thread
addf xmaxsw_and2 servo-thread
addf yminsw_and2 servo-thread
addf ymaxsw_and2 servo-thread
addf sinesweep.0 servo-thread
addf sampler.0 servo-thread
addf hm2_[HOSTMOT2](BOARD).0.write servo-thread
addf hm2_[HOSTMOT2](BOARD).0.pet_watchdog servo-thread
# ################
# X [0] Axis
# ################
# axis enable chain
net xenable <= axis.0.amp-enable-out
net xenable => xvelocity_filter.enable => xvelocity_pid.enable => xposition_pid.enable => xscale_pid.enable
net xenable => hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogena
# encoder feedback, rotary
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.scale [AXIS_0]INPUT_SCALE
net xpos-servo-fb hm2_[HOSTMOT2](BOARD).0.encoder.00.position => xposition_pid.feedback
net xvel <= hm2_[HOSTMOT2](BOARD).0.encoder.00.velocity => xvelocity_filter.in
net xvel-filt xvelocity_filter.out => xposition_pid.feedback-deriv => xvelocity_pid.feedback
setp xvelocity_filter.type 1
setp xvelocity_filter.f0 [AXIS_0]VEL_FILTER_FC
setp xvelocity_filter.Q 0.707
# encoder feedback, linear
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.scale [AXIS_0]INPUT_SCALE_LINEAR
# index homing, position feedback
net xindex_enable hm2_[HOSTMOT2](BOARD).0.encoder.03.index-enable <=> hm2_[HOSTMOT2](BOARD).0.encoder.00.index-enable <=> axis.0.index-enable <=> xposition_pid.index-enable <=> xscale_pid.index-enable
net xscalepos <= hm2_[HOSTMOT2](BOARD).0.encoder.03.position => xscale_pid.feedback => axis.0.motor-pos-fb
# set PID loop gains from inifile
setp xvelocity_pid.Pgain [AXIS_0]VEL_P
setp xvelocity_pid.Igain [AXIS_0]VEL_I
setp xvelocity_pid.Dgain [AXIS_0]VEL_D
setp xvelocity_pid.FF0 [AXIS_0]VEL_FF0
setp xvelocity_pid.FF1 [AXIS_0]VEL_FF1
setp xvelocity_pid.FF2 0.0
setp xvelocity_pid.maxoutput [AXIS_0]VEL_MAX_OUTPUT
setp xvelocity_pid.error-previous-target 1
net xpos-err xposition_pid.error xposerr_abs.in
net xpos-err-abs xposerr_abs.out xposgain_lincurve.in
setp xposgain_lincurve.x-val-00 0.0
setp xposgain_lincurve.y-val-00 [AXIS_0]POS_P_LO
setp xposgain_lincurve.x-val-01 [AXIS_0]POS_P_ERR
setp xposgain_lincurve.y-val-01 [AXIS_0]POS_P_HI
net xpospidP xposgain_lincurve.out xposition_pid.Pgain
setp xposition_pid.Igain [AXIS_0]POS_I
setp xposition_pid.Dgain [AXIS_0]POS_D
setp xposition_pid.FF0 [AXIS_0]POS_FF0
setp xposition_pid.FF1 [AXIS_0]POS_FF1
setp xposition_pid.FF2 [AXIS_0]POS_FF2
setp xposition_pid.deadband [AXIS_0]POS_DEADBAND
setp xposition_pid.maxoutput [AXIS_0]POS_MAX_OUTPUT
setp xposition_pid.error-previous-target 1
setp xscale_pid.Pgain [AXIS_0]SCALE_P
setp xscale_pid.Igain [AXIS_0]SCALE_I
setp xscale_pid.deadband [AXIS_0]SCALE_DEADBAND
setp xscale_pid.FF0 0.0
setp xscale_pid.maxerrorI [AXIS_0]SCALE_MAXCORR
setp xscale_pid.maxoutput [AXIS_0]SCALE_MAXCORR
setp xscale_pid.error-previous-target 1
# position command signals
# linear scale position PID
net xpos-cmd axis.0.motor-pos-cmd => SnSMill-correction.x-motorposcmd-in
net xjoint-cmd axis.0.joint-pos-cmd => SnSMill-correction.x-jointposcmd-in
net xpos-cmd-corrected SnSMill-correction.x-motorposcmd-out xscale_pid.command xscale_sum2.in0
net xpos-scalepidoutput xscale_pid.output => xscale_sum2.in1
net xpos-corrected xscale_sum2.out => xposition_pid.command
# X position PID -> X velocity PID -> Mesa 7i77
net xvel-cmd xposition_pid.output => xvelocity_pid.command
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout0-scalemax [AXIS_0]OUTPUT_SCALE
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout0-maxlim [AXIS_0]OUTPUT_SCALE
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout0-minlim [AXIS_0]OUTPUT_SCALE_NEG
net xmotor-command xvelocity_pid.output => hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout0
# Home switch/index logic
net homesw-x <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-08-not => axis.0.home-sw-in
# X-axis limit switch logic
net xminsw-x hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-09-not => xminsw_and2.in0
net homesw-x xmaxsw_and2.in0
net x-is-homed <= axis.0.homed => xhomed_not.in
net x-not-homed <= xhomed_not.out => xminsw_and2.in1 => xmaxsw_and2.in1
net x-minlimsw <= xminsw_and2.out => axis.0.neg-lim-sw-in
net x-maxlimsw <= xmaxsw_and2.out => axis.0.pos-lim-sw-in
# ################
# Y [1] Axis, joint 1 (left)
# ################
# axis enable chain
net yenable1 <= axis.1.amp-enable-out
net yenable1 => y1velocity_filter.enable => y1velocity_pid.enable => y1position_pid.enable => y1scale_pid.enable
# encoder feedback, rotary
setp hm2_[HOSTMOT2](BOARD).0.encoder.01.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.01.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.01.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.01.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.01.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.01.scale [AXIS_1]INPUT_SCALE
net y1pos-servo-fb hm2_[HOSTMOT2](BOARD).0.encoder.01.position => y1position_pid.feedback
net y1vel-uf <= hm2_[HOSTMOT2](BOARD).0.encoder.01.velocity => y1velocity_filter.in
net y1vel y1velocity_filter.out => y1position_pid.feedback-deriv => y1velocity_pid.feedback
setp y1velocity_filter.type 1
setp y1velocity_filter.f0 [AXIS_1]VEL_FILTER_FC
setp y1velocity_filter.Q 0.707
# encoder feedback, linear
setp hm2_[HOSTMOT2](BOARD).0.encoder.06.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.06.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.06.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.06.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.06.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.06.scale [AXIS_1]INPUT_SCALE_LINEAR_Y1
net y1scalepos <= hm2_[HOSTMOT2](BOARD).0.encoder.06.position => y1scale_pid.feedback => axis.1.motor-pos-fb
# set PID loop gains from inifile
setp y1velocity_pid.Pgain [AXIS_1]VEL_P
setp y1velocity_pid.Igain [AXIS_1]VEL_I
setp y1velocity_pid.Dgain [AXIS_1]VEL_D
setp y1velocity_pid.FF0 [AXIS_1]VEL_FF0
setp y1velocity_pid.FF1 [AXIS_1]VEL_FF1
setp y1velocity_pid.FF2 0.0
setp y1velocity_pid.maxoutput [AXIS_1]VEL_MAX_OUTPUT
setp y1velocity_pid.error-previous-target 1
net y1pos-err y1position_pid.error y1poserr_abs.in
net y1pos-err-abs y1poserr_abs.out y1posgain_lincurve.in
setp y1posgain_lincurve.x-val-00 0.0
setp y1posgain_lincurve.y-val-00 [AXIS_1]POS_P_LO
setp y1posgain_lincurve.x-val-01 [AXIS_1]POS_P_ERR
setp y1posgain_lincurve.y-val-01 [AXIS_1]POS_P_HI
net y1pospidP y1posgain_lincurve.out y1position_pid.Pgain
setp y1position_pid.Igain [AXIS_1]POS_I
setp y1position_pid.Dgain [AXIS_1]POS_D
setp y1position_pid.FF0 [AXIS_1]POS_FF0
setp y1position_pid.FF1 [AXIS_1]POS_FF1
setp y1position_pid.FF2 [AXIS_1]POS_FF2
setp y1position_pid.deadband [AXIS_1]POS_DEADBAND
setp y1position_pid.maxoutput [AXIS_1]POS_MAX_OUTPUT
setp y1position_pid.error-previous-target 1
setp y1scale_pid.Pgain [AXIS_1]SCALE_P
setp y1scale_pid.Igain [AXIS_1]SCALE_I
setp y1scale_pid.Dgain [AXIS_1]SCALE_D
setp y1scale_pid.deadband [AXIS_1]SCALE_DEADBAND
setp y1scale_pid.FF0 0.0
setp y1scale_pid.maxerrorI [AXIS_1]SCALE_MAXCORR
setp y1scale_pid.maxoutput [AXIS_1]SCALE_MAXCORR
setp y1scale_pid.error-previous-target 1
# position command signals; correction from the scale and Z axis slant
net y1pos-cmd axis.1.motor-pos-cmd => SnSMill-correction.y-motorposcmd-in
net y1joint-cmd axis.1.joint-pos-cmd => SnSMill-correction.y-jointposcmd-in
net y1pos-cmd-corrected SnSMill-correction.y-motorposcmd-out => y1scale_pid.command => y1scale_sum2.in0
net y1pos-scalepidoutput y1scale_pid.output => y1scale_sum2.in1
net y1pos-corrected y1scale_sum2.out => y1position_pid.command
net y1vel-cmd y1position_pid.output => y1velocity_pid.command
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout1-scalemax [AXIS_1]OUTPUT_SCALE
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout1-maxlim [AXIS_1]OUTPUT_SCALE
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout1-minlim [AXIS_1]OUTPUT_SCALE_NEG
net y1motor-command y1velocity_pid.output => hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout1
# Home switch/index logic
net homesw-y <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-10-not => axis.1.home-sw-in
#net yindex_enable hm2_[HOSTMOT2](BOARD).0.encoder.06.index-enable <=> hm2_[HOSTMOT2](BOARD).0.encoder.01.index-enable <=> axis.1.index-enable <=> y1servo_pid.index-enable <=> y1scale_pid.index-enable
# Y-axis limit switch logic
net yminsw-y hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-11-not => yminsw_and2.in0
net homesw-y ymaxsw_and2.in0
net y-is-homed <= axis.1.homed => yhomed_not.in
net y-not-homed <= yhomed_not.out => yminsw_and2.in1 => ymaxsw_and2.in1
net y-minlimsw <= yminsw_and2.out => axis.1.neg-lim-sw-in
net y-maxlimsw <= ymaxsw_and2.out => axis.1.pos-lim-sw-in
# ################
# Y [2] Axis, joint 2 (right)
# ################
# axis enable chain
net yenable1 => y2velocity_filter.enable => y2velocity_pid.enable => y2position_pid.enable => y2scale_pid.enable
# encoder feedback
setp hm2_[HOSTMOT2](BOARD).0.encoder.02.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.02.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.02.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.02.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.02.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.02.scale [AXIS_1]INPUT_SCALE
net ypos-fb2-int hm2_[HOSTMOT2](BOARD).0.encoder.02.position => y2position_pid.feedback =>
net y2vel-uf <= hm2_[HOSTMOT2](BOARD).0.encoder.02.velocity => y2velocity_filter.in
net y2vel y2velocity_filter.out => y2position_pid.feedback-deriv => y2velocity_pid.feedback
setp y2velocity_filter.type 1
setp y2velocity_filter.f0 [AXIS_1]VEL_FILTER_FC
setp y2velocity_filter.Q 0.707
# scale feedback
setp hm2_[HOSTMOT2](BOARD).0.encoder.05.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.05.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.05.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.05.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.05.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.05.scale [AXIS_1]INPUT_SCALE_LINEAR_Y2
net y2scalepos-offsetted <= hm2_[HOSTMOT2](BOARD).0.encoder.05.position => y2scale_pid.feedback => offset_yjoints.fb-in
net y2scalepos offset_yjoints.fb-out
# set PID loop gains from inifile
setp y2velocity_pid.Pgain [AXIS_1]VEL_P
setp y2velocity_pid.Igain [AXIS_1]VEL_I
setp y2velocity_pid.Dgain [AXIS_1]VEL_D
setp y2velocity_pid.FF0 [AXIS_1]VEL_FF0
setp y2velocity_pid.FF1 [AXIS_1]VEL_FF1
setp y2velocity_pid.FF2 0.0
setp y2velocity_pid.maxoutput [AXIS_1]VEL_MAX_OUTPUT
setp y2velocity_pid.error-previous-target 1
net y2pos-err y2position_pid.error y2poserr_abs.in
net y2pos-err-abs y2poserr_abs.out y2posgain_lincurve.in
setp y2posgain_lincurve.x-val-00 0.0
setp y2posgain_lincurve.y-val-00 [AXIS_1]POS_P_LO
setp y2posgain_lincurve.x-val-01 [AXIS_1]POS_P_ERR
setp y2posgain_lincurve.y-val-01 [AXIS_1]POS_P_HI
net y2pospidP y2posgain_lincurve.out y2position_pid.Pgain
setp y2position_pid.Igain [AXIS_1]POS_I
setp y2position_pid.Dgain [AXIS_1]POS_D
setp y2position_pid.FF0 [AXIS_1]POS_FF0
setp y2position_pid.FF1 [AXIS_1]POS_FF1
setp y2position_pid.FF2 [AXIS_1]POS_FF2
setp y2position_pid.deadband [AXIS_1]POS_DEADBAND
setp y2position_pid.maxoutput [AXIS_1]POS_MAX_OUTPUT
setp y2position_pid.error-previous-target 1
setp y2scale_pid.Pgain [AXIS_1]SCALE_P
setp y2scale_pid.Igain [AXIS_1]SCALE_I
setp y2scale_pid.Dgain [AXIS_1]SCALE_D
setp y2scale_pid.deadband [AXIS_1]SCALE_DEADBAND
setp y2scale_pid.FF0 0.0
setp y2scale_pid.maxerrorI [AXIS_1]SCALE_MAXCORR
setp y2scale_pid.maxoutput [AXIS_1]SCALE_MAXCORR
setp y2scale_pid.error-previous-target 1
# position command signals
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout2-scalemax [AXIS_1]OUTPUT_SCALE
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout2-maxlim [AXIS_1]OUTPUT_SCALE
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout2-minlim [AXIS_1]OUTPUT_SCALE_NEG
net y1pos-cmd-corrected => offset_yjoints.in
net y2pos_offsetted <= offset_yjoints.out => y2scale_pid.command => y2scale_sum2.in0
net y2pos-scalepidoutput y2scale_pid.output => y2scale_sum2.in1
net y2pos-corrected y2scale_sum2.out => y2position_pid.command
net y2vel-cmd y2position_pid.output => y2velocity_pid.command
net y2motor-command y2velocity_pid.output => hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout2
# Y-axis joint2 offset/squaring logic
setp offset_yjoints.offset 0.0
# index
#net yindex_enable hm2_[HOSTMOT2](BOARD).0.encoder.02.index-enable <=> hm2_[HOSTMOT2](BOARD).0.encoder.05.index-enable <=> y2servo_pid.index-enable <=> y2scale_pid.index-enable
# ################
# Z Axis
# ################
setp hm2_5i25.0.stepgen.00.dirsetup [AXIS_2]DIRSETUP
setp hm2_5i25.0.stepgen.00.dirhold [AXIS_2]DIRHOLD
setp hm2_5i25.0.stepgen.00.steplen [AXIS_2]STEPLEN
setp hm2_5i25.0.stepgen.00.stepspace [AXIS_2]STEPSPACE
setp hm2_5i25.0.stepgen.00.position-scale [AXIS_2]STEP_SCALE
setp hm2_5i25.0.stepgen.00.step_type 0
setp hm2_5i25.0.stepgen.00.control-type 1
setp hm2_5i25.0.stepgen.00.maxaccel [AXIS_2]STEPGEN_MAXACCEL
setp hm2_5i25.0.stepgen.00.maxvel [AXIS_2]STEPGEN_MAX_VELOCITY
# encoder feedback, linear
setp hm2_[HOSTMOT2](BOARD).0.encoder.04.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.04.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.04.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.04.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.04.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.04.scale [AXIS_2]INPUT_SCALE_LINEAR
# set PID loop gains from inifile
setp zservo_pid.Pgain [AXIS_2]P
setp zservo_pid.Igain [AXIS_2]I
setp zservo_pid.Dgain [AXIS_2]D
setp zservo_pid.bias [AXIS_2]BIAS
setp zservo_pid.FF0 [AXIS_2]FF0
setp zservo_pid.FF1 [AXIS_2]FF1
setp zservo_pid.FF2 [AXIS_2]FF2
setp zservo_pid.maxoutput [AXIS_2]STEPGEN_MAX_VELOCITY
setp zservo_pid.error-previous-target 1
setp zscale_pid.Pgain [AXIS_2]SCALE_P
setp zscale_pid.Igain [AXIS_2]SCALE_I
setp zscale_pid.deadband [AXIS_2]SCALE_DEADBAND
setp zscale_pid.FF0 0.0
setp zscale_pid.maxerrorI [AXIS_2]SCALE_MAXCORR
setp zscale_pid.maxoutput [AXIS_2]SCALE_MAXCORR
setp zscale_pid.error-previous-target 1
net z-pos-cmd axis.2.motor-pos-cmd => SnSMill-correction.z-motorposcmd-in
net z-joint-cmd axis.2.joint-pos-cmd => SnSMill-correction.z-jointposcmd-in
net zpos-cmd-corrected SnSMill-correction.z-motorposcmd-out => zscale_pid.command => zscale_sum2.in0
net z-pos-fb axis.2.motor-pos-fb <= hm2_[HOSTMOT2](BOARD).0.encoder.04.position => zscale_pid.feedback
net z-pos-pidout zscale_pid.output => zscale_sum2.in1
net z-pos-summed zscale_sum2.out => zservo_pid.command
net z-servo-pos-fb hm2_5i25.0.stepgen.00.position-fb => zservo_pid.feedback
net z-vel zservo_pid.output => hm2_5i25.0.stepgen.00.velocity-cmd
net z-enable axis.2.amp-enable-out => hm2_5i25.0.stepgen.00.enable => zscale_pid.enable => zservo_pid.enable
net homesw-z <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-14-not => axis.2.home-sw-in
# ################
# Mill/turn helper component to allow A-axis to function as lathe
# ################
setp millturn-helper.0.joint-max-acceleration [AXIS_3]MAX_ACCELERATION
setp millturn-helper.0.joint-max-velocity [AXIS_3]MAX_VELOCITY
# The speed scale is used to go from rev/min to units/sec
setp millturn-helper.0.speed-scale 6
# And we need to know the unit system. Standard is degrees: 360 per rev.
setp millturn-helper.0.units-per-rev 360
net apos-cmd-in axis.3.motor-pos-cmd => millturn-helper.0.position-cmd
net apos-fb-out millturn-helper.0.position-fb => axis.3.motor-pos-fb
net millturn-helper-mode millturn-helper.0.mode
net millturn-helper-secspindlespeed millturn-helper.0.secondary-spindle-speed
net millturn-helper-isbusy millturn-helper.0.is-busy
# ################
# A Axis
# ################
setp hm2_5i25.0.stepgen.01.dirsetup [AXIS_3]DIRSETUP
setp hm2_5i25.0.stepgen.01.dirhold [AXIS_3]DIRHOLD
setp hm2_5i25.0.stepgen.01.steplen [AXIS_3]STEPLEN
setp hm2_5i25.0.stepgen.01.stepspace [AXIS_3]STEPSPACE
setp hm2_5i25.0.stepgen.01.position-scale [AXIS_3]STEP_SCALE
setp hm2_5i25.0.stepgen.01.step_type 2
setp hm2_5i25.0.stepgen.01.control-type 0
setp hm2_5i25.0.stepgen.01.maxaccel [AXIS_3]STEPGEN_MAXACCEL
setp hm2_5i25.0.stepgen.01.maxvel [AXIS_3]STEPGEN_MAX_VELOCITY
net a-enable axis.3.amp-enable-out => hm2_5i25.0.stepgen.01.enable
net a-pos-cmd millturn-helper.0.joint-position-cmd => hm2_5i25.0.stepgen.01.position-cmd
net a-pos-fb hm2_5i25.0.stepgen.01.position-fb => millturn-helper.0.joint-position-fb
# ################
# Y-axis position verification: check if the Y-axes don't deviate too much
# ################
net y1scalepos => yjoints_comp.in0
net y2scalepos => yjoints_comp.in1
setp yjoints_comp.hyst [AXIS_1]SLAVEAXES_MAXDEVIATION
net yaxes_equal yjoints_comp.equal => yjointscomp_not.in
net slavedaxes_err <= yjointscomp_not.out
# ################
# Amplifier fault logic. Also (mis)used to signal slaved Y-axes position deviation
# sets-es are there until servos are wired completely
# ################
net jointXampfault <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-01-not => axis.0.amp-fault-in
net jointY1ampfault <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-02-not => yjoint_faultgen_or2_1.in0
net jointY2ampfault <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-03-not => yjoint_faultgen_or2_1.in1
net yjoints-ampfault <= yjoint_faultgen_or2_1.out => yjoint_faultgen_or2_2.in0
net slavedaxes_err => yjoint_faultgen_or2_2.in1
net jointYampfault_p <= yjoint_faultgen_or2_2.out => axis.1.amp-fault-in
net jointZampfault => axis.2.amp-fault-in
sets jointZampfault 0
# ################
# EStop chain.
# ################
net estop-out <= iocontrol.0.user-enable-out
net estop-ext => iocontrol.0.emc-enable-in <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-00
# ################
# Motor power relay control
# ################
#net motor-power => hm2_[HOSTMOT2](BOARD).0.7i77.0.0.output-00
#sets motor-power FALSE
net estop-ext <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.output-00
# ################
# Mist coolant solenoid
# ################
net mistcoolant <= iocontrol.0.coolant-mist => coolant_or2.in0
net floodcoolant <= iocontrol.0.coolant-flood => coolant_or2.in1
net mister-enable <= coolant_or2.out => hm2_[HOSTMOT2](BOARD).0.7i77.0.0.output-04 => hm2_[HOSTMOT2](BOARD).0.7i77.0.0.output-05
# ################
# Toolchanger
# ################
#loadusr -W hal_manualtoolchange
#net tool-change iocontrol.0.tool-change => hal_manualtoolchange.change
#net tool-changed iocontrol.0.tool-changed <= hal_manualtoolchange.changed
#net tool-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number
#net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared
And for completeness:
postgui.hal
# MPG buttons to gmoccapy jog
net jog-x-plus xhc-hb04.button-macro3 => gmoccapy.jog-x-plus
net jog-x-minus xhc-hb04.button-macro1 => gmoccapy.jog-x-minus
net jog-y-plus xhc-hb04.button-iszero => gmoccapy.jog-y-plus
net jog-y-minus xhc-hb04.button-macro6 => gmoccapy.jog-y-minus
net jog-z-plus xhc-hb04.button-safe-z => gmoccapy.jog-z-plus
net jog-z-minus xhc-hb04.button-macro7 => gmoccapy.jog-z-minus
# Use gmoccapy toolchanger..
net tool-change gmoccapy.toolchange-change <= iocontrol.0.tool-change
net tool-changed gmoccapy.toolchange-changed <= iocontrol.0.tool-changed
net tool-prep-number gmoccapy.toolchange-number <= iocontrol.0.tool-prep-number
net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared
# display tool offsets in gmoccapy
net tooloffset-x gmoccapy.tooloffset-x <= motion.tooloffset.x
net tooloffset-z gmoccapy.tooloffset-z <= motion.tooloffset.z
# spindle stuff
loadusr -W vlt5000_vfd --device=/dev/ttyUSB3
setp vlt5000-vfd.0.devslaveaddr 1
setp vlt5000-vfd.0.speedscale 0.05
net spindlespeed motion.spindle-speed-out-abs => vlt5000-vfd.0.commanded-speed
net spindleon motion.spindle-on => vlt5000-vfd.0.run
net spindleatspeed vlt5000-vfd.0.is-at-speed => motion.spindle-at-speed
# gmoccapy spindle bar
net spindlespeed => gmoccapy.spindle_feedback_bar
net spindleatspeed => gmoccapy.spindle_at_speed_led
SnS-xhc-hb04.hal
loadusr -W xhc-hb04 -I xhc-hb04-layoutbvh.ini -H
# Home button
net home halui.home-all <= xhc-hb04.button-home
# Absolute position LCD
net pos-x halui.axis.0.pos-feedback => xhc-hb04.x.pos-absolute
net pos-y halui.axis.1.pos-feedback => xhc-hb04.y.pos-absolute
net pos-z halui.axis.2.pos-feedback => xhc-hb04.z.pos-absolute
# Relative position LCD
net pos-rel-x halui.axis.0.pos-relative => xhc-hb04.x.pos-relative
net pos-rel-y halui.axis.1.pos-relative => xhc-hb04.y.pos-relative
net pos-rel-z halui.axis.2.pos-relative => xhc-hb04.z.pos-relative
# Jog wheel and axis selection button
net jog-x axis.0.jog-enable <= xhc-hb04.jog.enable-x
net jog-y axis.1.jog-enable <= xhc-hb04.jog.enable-y
net jog-z axis.2.jog-enable <= xhc-hb04.jog.enable-z
net jog-a axis.3.jog-enable <= xhc-hb04.jog.enable-a
net jog-scale xhc-hb04.jog.scale => axis.0.jog-scale axis.1.jog-scale axis.2.jog-scale axis.3.jog-scale
net jog-counts xhc-hb04.jog.counts => axis.0.jog-counts axis.1.jog-counts axis.3.jog-counts
net jog-counts-neg xhc-hb04.jog.counts-neg => axis.2.jog-counts
net jog-speed halui.jog-speed <= halui.max-velocity.value
net jog-stepup xhc-hb04.button-step xhc-hb04.stepsize-up
# Wheel for feedrate and spindle
setp halui.feed-override.scale 0.01
net jog-counts => halui.feed-override.counts
net jog-feed halui.feed-override.count-enable <= xhc-hb04.jog.enable-feed-override
net jog-feed2 halui.feed-override.value => xhc-hb04.feed-override
#BvH: spindle stop
net stop-spindle halui.spindle.stop <= xhc-hb04.button-spindle
setp halui.spindle-override.scale 0.01
net jog-counts => halui.spindle-override.counts
net jog-spindle halui.spindle-override.count-enable <= xhc-hb04.jog.enable-spindle-override
net jog-spindle2 halui.spindle-override.value => xhc-hb04.spindle-override
net spindle-rps motion.spindle-speed-cmd-rps => xhc-hb04.spindle-rps
# RESET/ESTOP button
net estop xhc-hb04.button-reset => halui.estop.activate
# Program control
loadrt flipflop names=flipflop_resume,flipflop_pause,flipflop_run
addf flipflop_resume servo-thread
addf flipflop_pause servo-thread
addf flipflop_run servo-thread
net button-stop xhc-hb04.button-stop => halui.program.stop
net button-start-pause xhc-hb04.button-start-pause => flipflop_pause.clk flipflop_resume.clk flipflop_run.clk
net is-paused halui.program.is-paused => flipflop_resume.data flipflop_pause.reset
net is-running halui.program.is-running => flipflop_pause.data flipflop_run.reset flipflop_resume.reset
net is-idle halui.program.is-idle => flipflop_run.data
net resume flipflop_resume.out => halui.program.resume
net pause flipflop_pause.out => halui.program.pause
net run flipflop_run.out => halui.program.run
#net step xhc-hb04.button-rewind => halui.program.step
# X=0, Y=0, Z=0
#net x0 halui.mdi-command-06 xhc-hb04.button-x0
#net y0 halui.mdi-command-07 xhc-hb04.button-y0
#net z0 halui.mdi-command-08 xhc-hb04.button-z0
#net origin halui.mdi-command-09 xhc-hb04.button-goto-zero
#net safe-z halui.mdi-command-10 xhc-hb04.button-safe-z
#net park halui.mdi-command-11 xhc-hb04.button-x2
Please Log in or Create an account to join the conversation.
27 Oct 2014 23:44 #52447
by PCW
Replied by PCW on topic PID tuning: one vs multiple loops, gain scheduling
BTW tested a 7I77 with a fast host machine (Pentium G3258/H81 MB), 8 KHz is achievable with stock serial baud rate (2.5 MB)
This system shows very good RTAI latency (~4 usec base, ~3 usec servo thread latencies) and very consistent function times
This system shows very good RTAI latency (~4 usec base, ~3 usec servo thread latencies) and very consistent function times
Please Log in or Create an account to join the conversation.
Time to create page: 0.087 seconds