aboutsummaryrefslogtreecommitdiffstats
path: root/src/emc/motion/axis.c
blob: 05ebf97ccd3f7428dc6fa7deaa51d5341292981c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685

#include "axis.h"
#include "emcmotcfg.h"      // EMCMOT_MAX_AXIS
#include "rtapi.h"
#include "rtapi_math.h"
#include "simple_tp.h"

typedef struct {
    double pos_cmd;                 /* commanded axis position */
    double teleop_vel_cmd;          /* commanded axis velocity */
    double max_pos_limit;           /* upper soft limit on axis pos */
    double min_pos_limit;           /* lower soft limit on axis pos */
    double vel_limit;               /* upper limit of axis speed */
    double acc_limit;               /* upper limit of axis accel */
    simple_tp_t teleop_tp;          /* planner for teleop mode motion */

    int old_ajog_counts;            /* prior value, used for deltas */
    int kb_ajog_active;             /* non-zero during a keyboard jog */
    int wheel_ajog_active;          /* non-zero during a wheel jog */
    int locking_joint;              /* locking_joint number, -1 ==> notused */

    double ext_offset_vel_limit;    /* upper limit of axis speed for ext offset */
    double ext_offset_acc_limit;    /* upper limit of axis accel for ext offset */
    int old_eoffset_counts;
    simple_tp_t ext_offset_tp;      /* planner for external coordinate offsets*/
} emcmot_axis_t;

typedef struct {
    hal_float_t *pos_cmd;           /* RPI: commanded position */
    hal_float_t *teleop_vel_cmd;    /* RPI: commanded velocity */
    hal_float_t *teleop_pos_cmd;    /* RPI: teleop traj planner pos cmd */
    hal_float_t *teleop_vel_lim;    /* RPI: teleop traj planner vel limit */
    hal_bit_t   *teleop_tp_enable;  /* RPI: teleop traj planner is running */

    hal_s32_t   *ajog_counts;       /* WPI: jogwheel position input */
    hal_bit_t   *ajog_enable;       /* RPI: enable jogwheel */
    hal_float_t *ajog_scale;        /* RPI: distance to jog on each count */
    hal_float_t *ajog_accel_fraction;  /* RPI: to limit wheel jog accel */
    hal_bit_t   *ajog_vel_mode;     /* RPI: true for "velocity mode" jogwheel */
    hal_bit_t   *kb_ajog_active;    /* RPI: executing keyboard jog */
    hal_bit_t   *wheel_ajog_active; /* RPI: executing handwheel jog */

    hal_bit_t   *eoffset_enable;
    hal_bit_t   *eoffset_clear;
    hal_s32_t   *eoffset_counts;
    hal_float_t *eoffset_scale;
    hal_float_t *external_offset;
    hal_float_t *external_offset_requested;
} axis_hal_t;


typedef struct {
    axis_hal_t axis[EMCMOT_MAX_AXIS];   /* data for each axis */
} axis_hal_data_t;

static emcmot_axis_t axis_array[EMCMOT_MAX_AXIS];
static axis_hal_data_t *hal_data = NULL;


// Mark strings for translation, but defer translation to userspace
#define _(s) (s)

void axis_init_all(void)
{
    int n;
    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        emcmot_axis_t *axis = &axis_array[n];
        axis->locking_joint = -1;
    }
}

void axis_initialize_external_offsets(void)
{
    int n;
    axis_hal_t *axis_data;

    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        axis_data = &hal_data->axis[n];

        *(axis_data->external_offset) = 0;
        *(axis_data->external_offset_requested) = 0;
        axis_array[n].ext_offset_tp.pos_cmd  = 0;
        axis_array[n].ext_offset_tp.curr_pos = 0;
        axis_array[n].ext_offset_tp.curr_vel = 0;
    }
}

#define CALL_CHECK(expr) do {           \
        int _retval;                    \
        _retval = expr;                 \
        if (_retval) return _retval;    \
    } while (0);

static int export_axis(int mot_comp_id, char c, axis_hal_t * addr)
{
    int msg;

    msg = rtapi_get_msg_level();
    rtapi_set_msg_level(RTAPI_MSG_WARN);

    CALL_CHECK(hal_pin_bit_newf(HAL_IN, &(addr->ajog_enable), mot_comp_id,"axis.%c.jog-enable", c));
    CALL_CHECK(hal_pin_float_newf(HAL_IN, &(addr->ajog_scale), mot_comp_id,"axis.%c.jog-scale", c));
    CALL_CHECK(hal_pin_s32_newf(HAL_IN, &(addr->ajog_counts), mot_comp_id,"axis.%c.jog-counts", c));
    CALL_CHECK(hal_pin_bit_newf(HAL_IN, &(addr->ajog_vel_mode), mot_comp_id,"axis.%c.jog-vel-mode", c));
    CALL_CHECK(hal_pin_bit_newf(HAL_OUT, &(addr->kb_ajog_active), mot_comp_id,"axis.%c.kb-jog-active", c));
    CALL_CHECK(hal_pin_bit_newf(HAL_OUT, &(addr->wheel_ajog_active), mot_comp_id,"axis.%c.wheel-jog-active", c));

    CALL_CHECK(hal_pin_float_newf(HAL_IN,&(addr->ajog_accel_fraction), mot_comp_id,"axis.%c.jog-accel-fraction", c));
    *addr->ajog_accel_fraction = 1.0; // fraction of accel for wheel ajogs

    rtapi_set_msg_level(msg);
    return 0;
}

int axis_init_hal_io(int mot_comp_id)
{
    int n, retval;

    hal_data = hal_malloc(sizeof(axis_hal_data_t));
    if (!hal_data) {
        rtapi_print_msg(RTAPI_MSG_ERR, _("MOTION: axis_hal_data hal_malloc() failed\n"));
        return -1;
    }

    // export axis pins and parameters
    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        char c = "xyzabcuvw"[n];
        axis_hal_t *axis_data = &(hal_data->axis[n]);
        CALL_CHECK(hal_pin_float_newf(HAL_OUT, &axis_data->pos_cmd, mot_comp_id, "axis.%c.pos-cmd", c));
        CALL_CHECK(hal_pin_float_newf(HAL_OUT, &axis_data->teleop_vel_cmd, mot_comp_id, "axis.%c.teleop-vel-cmd", c));
        CALL_CHECK(hal_pin_float_newf(HAL_OUT, &axis_data->teleop_pos_cmd, mot_comp_id, "axis.%c.teleop-pos-cmd", c));
        CALL_CHECK(hal_pin_float_newf(HAL_OUT, &axis_data->teleop_vel_lim, mot_comp_id, "axis.%c.teleop-vel-lim", c));
        CALL_CHECK(hal_pin_bit_newf(HAL_OUT, &axis_data->teleop_tp_enable, mot_comp_id, "axis.%c.teleop-tp-enable",c));
        CALL_CHECK(hal_pin_bit_newf(HAL_IN, &axis_data->eoffset_enable, mot_comp_id, "axis.%c.eoffset-enable", c));
        CALL_CHECK(hal_pin_bit_newf(HAL_IN, &axis_data->eoffset_clear, mot_comp_id, "axis.%c.eoffset-clear", c));
        CALL_CHECK(hal_pin_s32_newf(HAL_IN, &axis_data->eoffset_counts, mot_comp_id, "axis.%c.eoffset-counts", c));
        CALL_CHECK(hal_pin_float_newf(HAL_IN, &axis_data->eoffset_scale, mot_comp_id, "axis.%c.eoffset-scale", c));
        CALL_CHECK(hal_pin_float_newf(HAL_OUT, &axis_data->external_offset, mot_comp_id, "axis.%c.eoffset", c));
        CALL_CHECK(hal_pin_float_newf(HAL_OUT, &axis_data->external_offset_requested,
           mot_comp_id, "axis.%c.eoffset-request", c));

        retval = export_axis(mot_comp_id, c, axis_data);
        if (retval) {
            rtapi_print_msg(RTAPI_MSG_ERR, _("MOTION: axis %c pin/param export failed\n"), c);
            return -1;
        }
    }

    return 0;
}

void axis_output_to_hal(double *pcmd_p[])
{
    int n;

    // output axis info to HAL for scoping, etc
    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        emcmot_axis_t *axis = &axis_array[n];
        axis_hal_t *axis_data = &hal_data->axis[n];
        *(axis_data->teleop_vel_cmd)    = axis->teleop_vel_cmd;
        *(axis_data->teleop_pos_cmd)    = axis->teleop_tp.pos_cmd;
        *(axis_data->teleop_vel_lim)    = axis->teleop_tp.max_vel;
        *(axis_data->teleop_tp_enable)  = axis->teleop_tp.enable;
        *(axis_data->kb_ajog_active)    = axis->kb_ajog_active;
        *(axis_data->wheel_ajog_active) = axis->wheel_ajog_active;

        // hal pins: axis.L.pos-cmd reported without applied offsets:
        *(axis_data->pos_cmd) = *pcmd_p[n]
                              - axis->ext_offset_tp.curr_pos;
     }
}

void axis_set_max_pos_limit(int axis_num, double maxLimit)
{
    axis_array[axis_num].max_pos_limit = maxLimit;
}

void axis_set_min_pos_limit(int axis_num, double minLimit)
{
    axis_array[axis_num].min_pos_limit = minLimit;
}

void axis_set_vel_limit(int axis_num, double vel)
{
    axis_array[axis_num].vel_limit = vel;
}

void axis_set_acc_limit(int axis_num, double acc)
{
    axis_array[axis_num].acc_limit = acc;
}

void axis_set_ext_offset_vel_limit(int axis_num, double vel)
{
    axis_array[axis_num].ext_offset_vel_limit = vel;
}

void axis_set_ext_offset_acc_limit(int axis_num, double acc)
{
    axis_array[axis_num].ext_offset_acc_limit = acc;
}

void axis_set_locking_joint(int axis_num, int joint)
{
    axis_array[axis_num].locking_joint = joint;
}


double axis_get_min_pos_limit(int axis_num)
{
    return axis_array[axis_num].min_pos_limit;
}

double axis_get_max_pos_limit(int axis_num)
{
    return axis_array[axis_num].max_pos_limit;
}

double axis_get_vel_limit(int axis_num)
{
    return axis_array[axis_num].vel_limit;
}

double axis_get_acc_limit(int axis_num)
{
    return axis_array[axis_num].acc_limit;
}

double axis_get_teleop_vel_cmd(int axis_num)
{
    return axis_array[axis_num].teleop_vel_cmd;
}

int axis_get_locking_joint(int axis_num)
{
    return axis_array[axis_num].locking_joint;
}

double axis_get_compound_velocity(void)
{
    double v2 = 0.0;
    int n;

    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        emcmot_axis_t *axis = &axis_array[n];
        if (axis->teleop_tp.active) {
            v2 += axis->teleop_vel_cmd * axis->teleop_vel_cmd;
        }
    }

    if (v2 > 0.0)
        return sqrt(v2);
    return 0.0;
}

double axis_get_ext_offset_curr_pos(int axis_num)
{
    return axis_array[axis_num].ext_offset_tp.curr_pos;
}


void axis_jog_cont(int axis_num, double vel, long servo_period)
{
    emcmot_axis_t *axis = &axis_array[axis_num];

    if (vel > 0.0) {
        axis->teleop_tp.pos_cmd = axis->max_pos_limit;
    } else {
        axis->teleop_tp.pos_cmd = axis->min_pos_limit;
    }

    axis->teleop_tp.max_vel = fabs(vel);
    axis->teleop_tp.max_acc = axis->acc_limit;
    axis->kb_ajog_active = 1;
    axis->teleop_tp.enable = 1;
}

void axis_jog_incr(int axis_num, double offset, double vel, long servo_period)
{
    emcmot_axis_t *axis = &axis_array[axis_num];
    double tmp1;

    if (vel > 0.0) {
        tmp1 = axis->teleop_tp.pos_cmd + offset;
    } else {
        tmp1 = axis->teleop_tp.pos_cmd - offset;
    }

    if (tmp1 > axis->max_pos_limit) { return; }
    if (tmp1 < axis->min_pos_limit) { return; }

    axis->teleop_tp.pos_cmd = tmp1;
    axis->teleop_tp.max_vel = fabs(vel);
    axis->teleop_tp.max_acc = axis->acc_limit;
    axis->kb_ajog_active = 1;
    axis->teleop_tp.enable = 1;
}

void axis_jog_abs(int axis_num, double offset, double vel)
{
    emcmot_axis_t *axis = &axis_array[axis_num];
    double tmp1;

    axis->kb_ajog_active = 1;
    if (axis->wheel_ajog_active) { return; }
    if (vel > 0.0) {
        tmp1 = axis->teleop_tp.pos_cmd + offset;
    } else {
        tmp1 = axis->teleop_tp.pos_cmd - offset;
    }
    if (tmp1 > axis->max_pos_limit) { return; }
    if (tmp1 < axis->min_pos_limit) { return; }
    axis->teleop_tp.pos_cmd = tmp1;
    axis->teleop_tp.max_vel = fabs(vel);
    axis->teleop_tp.max_acc = axis->acc_limit;
    axis->kb_ajog_active = 1;
    axis->teleop_tp.enable = 1;
}

bool axis_jog_abort(int axis_num, bool immediate)
{
    bool aborted = 0;
    emcmot_axis_t *axis = &axis_array[axis_num];
    if (axis->teleop_tp.enable) {
        aborted = 1;
    }
    axis->teleop_tp.enable = 0;
    axis->kb_ajog_active = 0;
    axis->wheel_ajog_active = 0;
    if (immediate) {
        axis->teleop_tp.curr_vel = 0.0;
    }
    return aborted;
}

bool axis_jog_abort_all(bool immediate)
{
    int n;
    bool aborted = 0;
    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        if (axis_jog_abort(n, immediate)) {aborted = 1;}
    }
    return aborted;
}

bool axis_jog_is_active(void)
{
    int n;
    emcmot_axis_t *axis;
    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        axis = &axis_array[n];
        if (axis->kb_ajog_active || axis->wheel_ajog_active) {
            return 1;
        }
    }
    return 0;
}

void axis_handle_jogwheels(bool motion_teleop_flag, bool motion_enable_flag, bool homing_is_active)
{
    int axis_num;
    emcmot_axis_t *axis;
    axis_hal_t *axis_data;
    int new_ajog_counts, delta;
    double distance, pos, stop_dist;
    static int first_pass = 1;	/* used to set initial conditions */

    for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num++) {
        double aaccel_limit;
        axis = &axis_array[axis_num];
        axis_data = &hal_data->axis[axis_num];

        // disallow accel bogus fractions
        if (   (*(axis_data->ajog_accel_fraction) > 1)
            || (*(axis_data->ajog_accel_fraction) < 0) ) {
            aaccel_limit = axis->acc_limit;
        } else {
            aaccel_limit = *(axis_data->ajog_accel_fraction) * axis->acc_limit;
        }

        new_ajog_counts = *(axis_data->ajog_counts);
        delta = new_ajog_counts - axis->old_ajog_counts;
        axis->old_ajog_counts = new_ajog_counts;
        if ( first_pass ) { continue; }
        if ( delta == 0 ) {
            //just update counts
            continue;
        }
        if (!motion_teleop_flag) {
            axis->teleop_tp.enable = 0;
            return;
        }
        if (!motion_enable_flag)              { continue; }
        if ( *(axis_data->ajog_enable) == 0 ) { continue; }
        if (homing_is_active)                 { continue; }
        if (axis->kb_ajog_active)             { continue; }

        if (axis->locking_joint >= 0) {
            rtapi_print_msg(RTAPI_MSG_ERR,
            "Cannot wheel jog a locking indexer AXIS_%c\n",
            "XYZABCUVW"[axis_num]);
            continue;
        }

        distance = delta * *(axis_data->ajog_scale);
        pos = axis->teleop_tp.pos_cmd + distance;
        if ( *(axis_data->ajog_vel_mode) ) {
            double v = axis->vel_limit;
            /* compute stopping distance at max speed */
            stop_dist = v * v / ( 2 * aaccel_limit);
            /* if commanded position leads the actual position by more
               than stopping distance, discard excess command */
            if ( pos > axis->pos_cmd + stop_dist ) {
                pos = axis->pos_cmd + stop_dist;
            } else if ( pos < axis->pos_cmd - stop_dist ) {
                pos = axis->pos_cmd - stop_dist;
            }
        }
        if (pos > axis->max_pos_limit) { break; }
        if (pos < axis->min_pos_limit) { break; }
        axis->teleop_tp.pos_cmd = pos;
        axis->teleop_tp.max_vel = axis->vel_limit;
        axis->teleop_tp.max_acc = aaccel_limit;
        axis->wheel_ajog_active = 1;
        axis->teleop_tp.enable  = 1;
    }
    first_pass = 0;
}

void axis_sync_teleop_tp_to_carte_pos(int extfactor, double *pcmd_p[])
{
    int n;
    // expect extfactor =  -1 || 0 || +1
    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        axis_array[n].teleop_tp.curr_pos = *pcmd_p[n]
                            + extfactor * axis_array[n].ext_offset_tp.curr_pos;
    }
}

void axis_sync_carte_pos_to_teleop_tp(int extfactor, double *pcmd_p[])
{
    int n;
    // expect extfactor =  -1 || 0 || +1
    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        *pcmd_p[n] = axis_array[n].teleop_tp.curr_pos
                            + extfactor * axis_array[n].ext_offset_tp.curr_pos;
    }
}

void axis_apply_ext_offsets_to_carte_pos(int extfactor, double *pcmd_p[])
{
    int n;
    // expect extfactor =  -1 || 0 || +1
    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        *pcmd_p[n] = *pcmd_p[n]
                            + extfactor * axis_array[n].ext_offset_tp.curr_pos;
    }
}

hal_bit_t axis_plan_external_offsets(double servo_period, bool motion_enable_flag, bool all_homed)
{
    static int first_pass = 1;
    int n;
    emcmot_axis_t *axis;
    axis_hal_t *axis_data;
    int new_eoffset_counts, delta;
    static int last_eoffset_enable[EMCMOT_MAX_AXIS];
    double ext_offset_epsilon;
    hal_bit_t eoffset_active;

    eoffset_active = 0;

    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        axis = &axis_array[n];
        // coord,teleop updates done in get_pos_cmds()
        axis->ext_offset_tp.max_vel = axis->ext_offset_vel_limit;
        axis->ext_offset_tp.max_acc = axis->ext_offset_acc_limit;

        axis_data = &hal_data->axis[n];

        new_eoffset_counts       = *(axis_data->eoffset_counts);
        delta                    = new_eoffset_counts - axis->old_eoffset_counts;
        axis->old_eoffset_counts = new_eoffset_counts;

        *(axis_data->external_offset)  = axis->ext_offset_tp.curr_pos;
        axis->ext_offset_tp.enable = 1;
        if ( first_pass ) {
            *(axis_data->external_offset) = 0;
            continue;
        }

        // Use stopping criterion of simple_tp.c:
        ext_offset_epsilon = TINY_DP(axis->ext_offset_tp.max_acc, servo_period);
        if (fabs(*(axis_data->external_offset)) > ext_offset_epsilon) {
            eoffset_active = 1;
        }
        if ( !*(axis_data->eoffset_enable) ) {
            axis->ext_offset_tp.enable = 0;
            // Detect disabling of eoffsets:
            //   At very high accel, simple planner may terminate with
            //   a larger position value than occurs at more realistic accels.
            if (last_eoffset_enable[n]
                && (fabs(*(axis_data->external_offset)) > ext_offset_epsilon)
                && motion_enable_flag
                && axis->ext_offset_tp.enable) {
                // to stdout only:
                rtapi_print_msg(RTAPI_MSG_NONE,
                           "*** Axis_%c External Offset=%.4g eps=%.4g\n"
                           "*** External Offset disabled while NON-zero\n"
                           "*** To clear: re-enable & zero or use Machine-Off\n",
                           "XYZABCUVW"[n],
                           *(axis_data->external_offset),
                           ext_offset_epsilon);
            }
            last_eoffset_enable[n] = 0;
            continue; // Note: if   not eoffset_enable
                      //       then planner disabled and no pos_cmd updates
                      //       useful for eoffset_pid hold
        }
        last_eoffset_enable[n] = 1;
        if (*(axis_data->eoffset_clear)) {
            axis->ext_offset_tp.pos_cmd             = 0;
            *(axis_data->external_offset_requested) = 0;
            continue;
        }
        if (delta == 0)           { continue; }
        if (!all_homed)           { continue; }
        if (!motion_enable_flag)  { continue; }

        axis->ext_offset_tp.pos_cmd   += delta *  *(axis_data->eoffset_scale);
        *(axis_data->external_offset_requested) = axis->ext_offset_tp.pos_cmd;
    } // for n
    first_pass = 0;

    return eoffset_active;
}

/* For each axis, return -1 if over negative limit, 1 if over positive limit,
   or 0 if in range */
void axis_check_constraints(double pos[], int failing_axes[])
{
    int axis_num;
    double eps = 1e-308;

    for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num += 1) {
        double nl = axis_array[axis_num].min_pos_limit;
        double pl = axis_array[axis_num].max_pos_limit;
        failing_axes[axis_num] = 0;

        if (   (fabs(pos[axis_num]) < eps)
            && (fabs(axis_array[axis_num].min_pos_limit) < eps)
            && (fabs(axis_array[axis_num].max_pos_limit) < eps) ) {
            continue;
        }

        if (pos[axis_num] < (nl - 0.000000000001)) { // see pull request #1047
            failing_axes[axis_num] = -1;
        }

        if (pos[axis_num] > (pl + 0.000000000001)) { // see pull request #1047
            failing_axes[axis_num] = 1;
        }
    }
}

int axis_update_coord_with_bound(double *pcmd_p[], double servo_period)
{
    int n;
    int ans = 0;
    emcmot_axis_t *axis;
    double save_pos_cmd[EMCMOT_MAX_AXIS];
    double save_offset_cmd[EMCMOT_MAX_AXIS];

    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        axis = &axis_array[n];
        save_pos_cmd[n]     = *pcmd_p[n];
        save_offset_cmd[n]  = axis->ext_offset_tp.pos_cmd;
        simple_tp_update(&(axis->ext_offset_tp), servo_period);
    }
    axis_apply_ext_offsets_to_carte_pos(+1, pcmd_p); // add external offsets

    for (n = 0; n < EMCMOT_MAX_AXIS; n++) {
        axis = &axis_array[n];
        //workaround: axis letters not in [TRAJ]COORDINATES
        //            have min_pos_limit == max_pos_lim == 0
        if ( (0 == axis->max_pos_limit) && (0 == axis->min_pos_limit) ) {
            continue;
        }
        if (axis->ext_offset_tp.curr_pos == 0) {
           continue; // don't claim violation if no offset
        }

        if (*pcmd_p[n] >= axis->max_pos_limit) {
            // hold carte_pos_cmd at the limit:
            *pcmd_p[n]  = axis->max_pos_limit;
            // stop growth of offsetting position:
            axis->ext_offset_tp.curr_pos = axis->max_pos_limit
                                         - save_pos_cmd[n];
            if (axis->ext_offset_tp.pos_cmd > save_offset_cmd[n]) {
                axis->ext_offset_tp.pos_cmd = save_offset_cmd[n];
            }
            axis->ext_offset_tp.curr_vel = 0;
            ans++;
            continue;
        }
        if (*pcmd_p[n] <= axis->min_pos_limit) {
            *pcmd_p[n]  = axis->min_pos_limit;
            axis->ext_offset_tp.curr_pos = axis->min_pos_limit
                                         - save_pos_cmd[n];
            if (axis->ext_offset_tp.pos_cmd < save_offset_cmd[n]) {
                axis->ext_offset_tp.pos_cmd = save_offset_cmd[n];
            }
            axis->ext_offset_tp.curr_vel = 0;
            ans++;
        }
    }
    if (ans > 0) { return 1; }
    return 0;
}

static int update_teleop_with_check(int axis_num, simple_tp_t *the_tp, double servo_period)
{
    // 'the_tp' is the planner to update
    // the tests herein apply to the sum of the offsets for both
    // planners (teleop_tp and ext_offset_tp)
    double save_curr_pos;
    emcmot_axis_t *axis = &axis_array[axis_num];

    save_curr_pos = the_tp->curr_pos;
    simple_tp_update(the_tp, servo_period);

    //workaround: axis letters not in [TRAJ]COORDINATES
    //            have min_pos_limit == max_pos_lim == 0
    if  ( (0 == axis->max_pos_limit) && (0 == axis->min_pos_limit) ) {
        return 0;
    }
    if  ( (axis->ext_offset_tp.curr_pos + axis->teleop_tp.curr_pos)
          >= axis->max_pos_limit) {
        // positive error, restore save_curr_pos
        the_tp->curr_pos = save_curr_pos;
        the_tp->curr_vel = 0;
        return 1;
    }
    if  ( (axis->ext_offset_tp.curr_pos + axis->teleop_tp.curr_pos)
           <= axis->min_pos_limit) {
        // negative error, restore save_curr_pos
        the_tp->curr_pos = save_curr_pos;
        the_tp->curr_vel = 0;
        return 1;
    }
    return 0;
}

int axis_calc_motion(double servo_period)
{
    int axis_num;
    int violated_teleop_limit = 0;
    emcmot_axis_t *axis;

    for (axis_num = 0; axis_num < EMCMOT_MAX_AXIS; axis_num++) {
        axis = &axis_array[axis_num];
        // teleop_tp.max_vel is always positive
        if (axis->teleop_tp.max_vel > axis->vel_limit) {
            axis->teleop_tp.max_vel = axis->vel_limit;
        }
        if (update_teleop_with_check(axis_num, &(axis->teleop_tp), servo_period)) {
            violated_teleop_limit = 1;
        } else {
            axis->teleop_vel_cmd = axis->teleop_tp.curr_vel;
            axis->pos_cmd = axis->teleop_tp.curr_pos;
        }

        if (!axis->teleop_tp.active) {
            axis->kb_ajog_active = 0;
            axis->wheel_ajog_active = 0;
        }

        if (axis->ext_offset_tp.enable) {
            if (update_teleop_with_check(axis_num, &(axis->ext_offset_tp), servo_period)) {
                violated_teleop_limit = 1;
            }
        }
    }
    return violated_teleop_limit;
}
bues.ch cgit interface