Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions configs/sim/axis/lathe_multispindle/lathe.hal
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ net spindle-phase-A sim_encoder_0.phase-A => encoder_0.phase-A
net spindle-phase-B sim_encoder_0.phase-B => encoder_0.phase-B
net spindle-phase-Z sim_encoder_0.phase-Z => encoder_0.phase-Z

# assume 120 ppr = 480 counts/rev for the spindle
setp sim_encoder_0.ppr 120
# quadrature encoder gives 4 * ppr counts/rev
# the count rate (rpm/60 * ppr * 4) must stay below the base thread
# frequency, ppr 6 works up to 25000 rpm at a 100000 ns base period
setp sim_encoder_0.ppr 6
# iocontrol output is in rpm, but sim-encoder speed is rps
setp sim_encoder_0.scale 60
# scale encoder output to read in revolutions
# (that way thread pitches can be straightforward,
# a 20 tpi thread would multiply the encoder output
# by 1/20, etc)
setp encoder_0.position-scale 480
setp encoder_0.position-scale 24

# encoder reset control
# hook up motion controller's sync output
Expand All @@ -46,15 +48,17 @@ net spindle-phase-A1 sim_encoder_1.phase-A => encoder_1.phase-A
net spindle-phase-B1 sim_encoder_1.phase-B => encoder_1.phase-B
net spindle-phase-Z1 sim_encoder_1.phase-Z => encoder_1.phase-Z

# assume 120 ppr = 480 counts/rev for the spindle
setp sim_encoder_1.ppr 120
# quadrature encoder gives 4 * ppr counts/rev
# the count rate (rpm/60 * ppr * 4) must stay below the base thread
# frequency, ppr 6 works up to 25000 rpm at a 100000 ns base period
setp sim_encoder_1.ppr 6
# iocontrol output is in rpm, but sim-encoder speed is rps
setp sim_encoder_1.scale 60
# scale encoder output to read in revolutions
# (that way thread pitches can be straightforward,
# a 20 tpi thread would multiply the encoder output
# by 1/20, etc)
setp encoder_1.position-scale 480
setp encoder_1.position-scale 24

# encoder reset control
# hook up motion controller's sync output
Expand Down
8 changes: 5 additions & 3 deletions configs/sim/gmoccapy/lathe_configs/spindle_sim.hal
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ net spindle-phase-A sim_encoder_0.phase-A => encoder_0.phase-A
net spindle-phase-B sim_encoder_0.phase-B => encoder_0.phase-B
net spindle-phase-Z sim_encoder_0.phase-Z => encoder_0.phase-Z

# assume 120 ppr = 480 counts/rev for the spindle
setp sim_encoder_0.ppr 12
# quadrature encoder gives 4 * ppr counts/rev
# the count rate (rpm/60 * ppr * 4) must stay below the base thread
# frequency, ppr 6 works up to 25000 rpm at a 100000 ns base period
setp sim_encoder_0.ppr 6
# iocontrol output is in rpm, but sim-encoder speed is rps
setp sim_encoder_0.scale 60
# scale encoder output to read in revolutions
# (that way thread pitches can be straightforward,
# a 20 tpi thread would multiply the encoder output
# by 1/20, etc)
setp encoder_0.position-scale 48
setp encoder_0.position-scale 24

# encoder reset control
# hook up motion controller's sync output
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ net spindle-phase-A sim_encoder_0.phase-A => encoder_0.phase-A
net spindle-phase-B sim_encoder_0.phase-B => encoder_0.phase-B
net spindle-phase-Z sim_encoder_0.phase-Z => encoder_0.phase-Z

# assume 120 ppr = 480 counts/rev for the spindle
setp sim_encoder_0.ppr 12
# quadrature encoder gives 4 * ppr counts/rev
# the count rate (rpm/60 * ppr * 4) must stay below the base thread
# frequency, ppr 2 works up to 75000 rpm at a 100000 ns base period
setp sim_encoder_0.ppr 2
# iocontrol output is in rpm, but sim-encoder speed is rps
setp sim_encoder_0.scale 60
# scale encoder output to read in revolutions
# (that way thread pitches can be straightforward,
# a 20 tpi thread would multiply the encoder output
# by 1/20, etc)
setp encoder_0.position-scale 48
setp encoder_0.position-scale 8

# encoder reset control
# hook up motion controller's sync output
Expand Down
8 changes: 5 additions & 3 deletions configs/sim/gmoccapy/spindle_sim.hal
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ net spindle-phase-A sim_encoder_0.phase-A => encoder_0.phase-A
net spindle-phase-B sim_encoder_0.phase-B => encoder_0.phase-B
net spindle-phase-Z sim_encoder_0.phase-Z => encoder_0.phase-Z

# assume 120 ppr = 480 counts/rev for the spindle
setp sim_encoder_0.ppr 12
# quadrature encoder gives 4 * ppr counts/rev
# the count rate (rpm/60 * ppr * 4) must stay below the base thread
# frequency, ppr 2 works up to 75000 rpm at a 100000 ns base period
setp sim_encoder_0.ppr 2
# iocontrol output is in rpm, but sim-encoder speed is rps
setp sim_encoder_0.scale 60
# scale encoder output to read in revolutions
# (that way thread pitches can be straightforward,
# a 20 tpi thread would multiply the encoder output
# by 1/20, etc)
setp encoder_0.position-scale 48
setp encoder_0.position-scale 8

# encoder reset control
# hook up motion controller's sync output
Expand Down
7 changes: 7 additions & 0 deletions docs/src/man/man9/sim_encoder.9.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ The *sim-encoder.N.* format is shown in the following descriptions.
The desired speed of the encoder, in user units per per second. This
is divided by *scale*, and the result is used as the encoder speed in
revolutions per second.
**sim-encoder.**_N_**.saturated** bit out::
True while the commanded *speed* exceeds the maximum the pulse
generator can produce, which is one quadrature count per execution of
*make-pulses*. The outputs then keep toggling at that maximum rate
instead of following the command. The maximum speed in user units is
the *make-pulses* thread frequency divided by 4 times *ppr*,
multiplied by *scale*.

== PARAMETERS

Expand Down
50 changes: 40 additions & 10 deletions src/hal/components/sim_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,10 @@ typedef struct {
hal_real_t scale; /* pin: pulses per revolution */
hal_real_t speed; /* pin: speed in revs/second */
hal_sint_t rawcounts; /* pin: raw counts */
hal_bool_t saturated; /* pin: speed capped at thread rate limit */
double old_scale; /* internal, used to detect changes */
double scale_mult; /* internal, reciprocal of scale */
char clamp_warned; /* internal, one-shot frequency cap warning */
} sim_enc_t;

/* ptr to array of sim_enc_t structs in shared memory, 1 per channel */
Expand Down Expand Up @@ -231,9 +233,10 @@ void rtapi_app_exit(void)
to frequency to an accumulator. When the accumulator overflows (or
underflows), it is time to increment (or decrement) the state of the
output pins.
The add value is limited to +/-2^30, and overflows are detected
at bit 30, not bit 31. This means that with add_val at it's max
(or min) value, and overflow (or underflow) occurs on every cycle.
The add value is limited to a magnitude of less than 2^31, and
overflows are detected at bit 31. This means that with add_val at
it's max (or min) value, and overflow (or underflow) occurs on every
cycle.
*/

static void make_pulses(void *arg, long period)
Expand Down Expand Up @@ -349,14 +352,34 @@ static void update_speed(void *arg, long period)
rev_sec = hal_get_real(sim_enc->speed) * sim_enc->scale_mult;
/* convert speed command (revs per sec) to counts/sec */
freq = rev_sec * (hal_get_ui32(sim_enc->ppr)) * 4.0;
/* limit the commanded frequency */
if (freq > maxf) {
freq = maxf;
} else if (freq < -maxf) {
freq = -maxf;
/* calculate new addval, limiting its magnitude to less than 2^31.
make_pulses() uses bit 31 of addval as the direction bit, so an
addval of +2^31 (freq = +maxf, the old freq clamp value) would
be misread as negative and the generated counts would run
backwards (negative velocity at high commanded speed) */
double aval = freq * freqscale;
int clamped = 0;
if (aval > 2147483647.0) {
aval = 2147483647.0;
clamped = 1;
} else if (aval < -2147483648.0) {
aval = -2147483648.0;
clamped = 1;
}
/* calculate new addval */
sim_enc->addval = freq * freqscale;
if (clamped && !sim_enc->clamp_warned) {
double maxspeed = maxf * 0.25 / hal_get_ui32(sim_enc->ppr)
* hal_get_real(sim_enc->scale);
if (freq < 0.0) {
maxspeed = -maxspeed;
}
sim_enc->clamp_warned = 1;
rtapi_print_msg(RTAPI_MSG_WARN,
"SIM_ENCODER: WARNING: channel %d speed %.3f exceeds maximum %.3f for ppr %d at %ld ns thread period, output capped\n",
n, hal_get_real(sim_enc->speed), maxspeed,
hal_get_ui32(sim_enc->ppr), periodns);
}
hal_set_bool(sim_enc->saturated, clamped);
sim_enc->addval = aval;
sim_enc++;
}
/* done */
Expand Down Expand Up @@ -416,9 +439,16 @@ static int export_sim_enc(sim_enc_t * addr, char *prefix)
if (retval != 0) {
return retval;
}
/* export pin for speed cap indication */
retval = hal_pin_new_bool(comp_id, HAL_OUT, &(addr->saturated), 0,
"%s.saturated", prefix);
if (retval != 0) {
return retval;
}
/* init internal vars */
addr->old_scale = 0.0;
addr->scale_mult = 1.0;
addr->clamp_warned = 0;
/* init the state variables */
addr->accum = 0;
addr->addval = 0;
Expand Down
Loading