-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
trajgen.h
1654 lines (1494 loc) · 51.6 KB
/
trajgen.h
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
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*******************************************************************************
* @file trajgen.h
*
* Allows to move the machine tool tip to specified positions, velocities and
* accelerations by modifying a virtual machine position every generator cycle.
* The output is always an updated position for every joint. The closed loop
* controllers of the joints follow this position or, if the cannot, raise a
* trailing error fault.
*
* @author: Stefan Wilhelm (c erberos@atwillys.de)
* @license: BSD (see below)
* @version: 1.0b
* @standard C99
*
* -----------------------------------------------------------------------------
*
* Coordinated motion (coord planer, manual) are related the planer pose (tool
* tip position and direction), t.m. a new pose is calculated first, then the
* joint position are determined using inverse kinematics. The joint planers
* update the scalar position of every joint individually, the planer pose is
* updated (for status or equivalence) using forward kinematics. After the new
* joint positions are computed, they are used to feed the interpolators. The
* output of the interpolatoes is the final output of the trajgen and can be
* used as command position for the closed loop controllers.
*
* As wrapper for the different trajectory planers, the main trajgen organises
* the initialisation, reset and synchronisation of the submodules. It is based
* on a finite state machine. This means the generator can be only in one defined
* state, and switching between states causes leaving the current state (wait
* for the current motion to be finished and cleanup after the sub modules), and
* entering a new state (initialise and switch to module run state). Hence,
* switching takes at least one tick (cycle period).
*
* Usage:
*
* Variables:
*
* All data of the trajgen are stored in one single data structure of the
* type trajgen_t. This structure contains the configuration, the current
* state, the (requested) state to switch to, the last error occurred,
* current pose, kinematic data, coordinated planer data, manual op data,
* as well as data for individual joints. Latter are joint data structures
* containing data of the interpolators, joint planers, and the
* joint command position outputs.
*
* You can decide how and where this structure is located, either as part
* of a bigger data structure, global, local, stack, heap, etc. Only few
* aspects are important:
*
* (1) The location must not change, as the pointer is saved in a
* static variable.
*
* (2) There can be only one main trajgen (but multiple sub-planers
* e.g. for simulation purposes).
*
* Synchronisation and threading
*
* Thread safety is not implemented due to platform dependencies. You must
* take care yourself that no other thread or shared memory write process
* interferes with any function of the trajgen. It absolutely assumes that
* the data are not changed during a function call.
*
* Configuration and initialisation:
*
* The trajgen is configured once in the startup phase of the machine.
* Create a variable of type trajgen_config_t and pass it together with
* the pointer to the main trajgen structure to trajgen_initialize();
* The config will not be modified by any internal function.
*
* Reset:
*
* Calling trajgen_reset() will reset the internal state and internal
* variables of the trajgen and all submodules to a "clean" disabled state.
* The config will not be changed. The state will be 0 (TRAJ_STATE_DISABLED)
* and is_done will be 1 (true).
*
* Cyclic function:
*
* Call trajgen_tick() with the sample rate that the servo position
* need to be updated. The configuration variable "interpolation_rate"
* decides how frequently the trajectory needs to be recalculated. For a
* closed loop sample rate of 2KHz and an interpolation rate of 4, the
* trajectory will be recalculated with 500Hz, the missing cycles will be
* filled by the cubic interpolator of each joint. This means also that
* synchronous outputs and condition handling will be done with 500Hz.
*
* State switching:
*
* Use trajgen_switch_state() to switch between the submodules. After calling
* the function, is_done will be 0 and remain zero until the current planer
* stopped moving, is cleaned up and the new state is in running state.
* However, the state might remain zero if the newly selected generator
* started moving already.
*
* States:
*
* TRAJ_STATE_DISABLED:
*
* The trajgen is idle and does not perform any calculations or
* position updates.
*
* TRAJ_STATE_COORDINATED:
*
* The coordinated motion planer is running and processes its
* queue.
*
* TRAJ_STATE_MAN:
*
* The (coordinated) teleoperation planer is running and processes
* according its given input velocities.
*
* TRAJ_STATE_JOINT:
*
* The joint individual planers are active.
*
* Submodule access:
*
* You have full access to the individual planners and get in touch with
* each you want to use if you define the export-enable macros described
* below.
*
* Errors:
*
* Each of the trajgen and submodule functions that can cause errors return
* an error code. The convention is: code 0 (zero) means OK, nonzero means
* error. You should always treat trajgen errors that are called cyclic in
* trajgen_coord_tick(), as well as initialisation errors, as fatal and cause
* an e-stop by opening the machine's intermediate circuit immediately.
*
* Every generator has a variable last_error, where you can query the last
* error occurred. This values are only valid if a function returned nonzero
* before (the variable is not explicitly reset to 0 if a function returns
* OK). The main trajgen's last_error is a structure containing one single
* encoded 16bit error value (type trajgen_error_details_t). This error
* code contains the
*
* (1) the code
* (2) the joint, which is only valid if an interpolator or joint planer
* failed.
*
* This error code allows to identify quite accurately what went wrong using
* a single number that can be saved or passed to the user space easily.
*
* -----------------------------------------------------------------------------
* License header: Copyright (c) 2008-2014, Stefan Wilhelm. All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met: (1) Redistributions
* of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer. (2) Redistributions in binary form must reproduce
* the above copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the distribution.
* (3) Neither the name of atwillys.de nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
******************************************************************************/
#ifndef SW_TRAJGEN_H
#define SW_TRAJGEN_H
#ifdef __cplusplus
extern "C" {
#endif
/* <editor-fold defaultstate="collapsed" desc="Build config: types and libraries"> */
#if defined __linux__
#include <stdint.h>
#include <sys/types.h>
#elif defined __MACH__
#include <stdint.h>
#include <sys/types.h>
#else
#error "Can you please define the rttypes for this platform and send a patch? :)"
/*
#define int8_t char
#define uint8_t unsigned char
#define int16_t short
#define uint16_t unsigned short
#define int32_t int
#define uint32_t unsigned int
#define int64_t long
#define uint64_t unsigned long
#define float32_t float
#define float64_t double
#define size_t unsigned int
*/
#endif
/**
* Allows to specify 32 bit or 64 bot float, unfortunately "float_t" is already
* reserved on many frames, so "real_t" is used instead. Can be also redefined
* as typedef. The macro is used to be able to switch it easily using the pre
* compiler.
*/
#ifndef real_t
#define real_t double
#endif
#ifndef float32_t
#define float32_t float
#endif
/**
* Explicit declaration of a boolean type. Can be switched for memory optimizsation
* (e.g. char) or best data type for the processor (e.g. int)
*/
#ifndef bool_t
#define bool_t unsigned
#endif
/**
* Explicit declaration of a byte, no matter if signed or unsigned. Normally
* used for bit operations or 8bit port i/o.
*/
#ifndef byte_t
#define byte_t uint8_t
#endif
/**
* "Auto include" float.h
* Note: This allows you to include float.h or a RT optimised one yourself.
*/
#ifndef FLT_MAX
#include <float.h>
#endif
/**
* "Auto include" math.h, characteristic macro: M_PI
* Note: This allows you to include math.h or a RT optimised one yourself.
*/
#ifndef M_PI
#include <math.h>
#endif
/*
* Defines the maximum number of joints the program can handle.
*/
#ifndef JOINT_MAX_JOINTS
#define JOINT_MAX_JOINTS 9
#endif
/*
* The maximum number of joints that the trajectory generator supports
*/
#ifndef TG_MAX_JOINTS
#define TG_MAX_JOINTS JOINT_MAX_JOINTS
#endif
/*
* The maximum size if the coordinated motion generator queue (fixed allocated)
* Note: This is an intermediate fifo with big data structures and should be small.
* You are supposed to dispatch and push new values from a realtime fifo whenever
* possible.
*/
#ifndef TG_QUEUE_SIZE
#define TG_QUEUE_SIZE 32
#endif
/*
* Defines then threshold when the coordinated motion planer sees numbers as
* zero or not.
*/
#ifndef TG_RESOLUTION
#define TG_RESOLUTION 1e-6
#endif
/*
* Smallest floating point number that is not zero. (Epsilon)
*/
#ifndef FLOAT_EPS
#define FLOAT_EPS (sizeof(real_t) == sizeof(double) ? FLT_EPSILON : DBL_EPSILON)
#endif
/*
* Spline/bezier iterations to find the length
*/
#ifndef TG_CURVE_ACC
#define TG_CURVE_ACC (16)
#endif
/*
* Sin/cos, can be replaced platform dependent with the corresponding builtin.
* #define SINCOS(x, sx, cx) do { *(sx)=sin((x)); *(cx)=cos((x)); } while(0);
*/
/*
* You can set your own memory clear (set to 0) function. By default a static
* inline function is used that is independent of any external library.
* #define ZERO_MEMORY(ptr, size)
*/
/*
* Define this to force the trajgen to check argument pointers
* #define ARG_POINTER_CHECKS
*/
/*
* Normally you like to define your own joint type and config for the machine,
* but if you to it has to be compliant with the joint_t here.
* #define JOINT_DECL_NONE
*/
/*
* You can switch off the interpolator feature here. Any settings related to
* it will be ignored. The interpolation rate must be set to 1.
* #define NO_INTERPOLATION
*/
/*
* You can switch off the trajectory position/velocity synchronisation using:
* #define NO_TRAJECTORY_SYNC
*/
/*
* You can optionally export the interpolators or leave them
* inline static in the implementation file to improve code optimisation.
* Interpolator types and error definitions are not affected by this setting,
* they are always exported.
* #define EXPORT_INTERPOLATORS
*/
/*
* You can optionally not export the joint planers or leave them
* inline static in the implementation file to improve code optimisation.
* Types and error definitions are not affected by this setting, only functions.
* #define EXPORT_JOINT_TG
*/
/*
* You can optionally not export the manual/joystick generator or leave it
* inline static in the implementation file to improve code optimisation.
* Types and error definitions are not affected by this setting, only functions.
* #define EXPORT_MANUAL_TG
*/
/*
* You can optionally not export the coordinated motion generator or leave it
* inline static in the implementation file to improve code optimisation.
* Types and error definitions are not affected by this setting, only functions.
* #define EXPORT_COORD_TG
*/
/*
* You can switch off the interpolator feature here. Any settings related to
* it will be ignored. The interpolation rate must be set to 1.
* #define NO_MOTION_BLENDING
*/
/*
* Defining this will enable stderr debug messages. Note: this can be quite
* detailed. (command line option -DTG_DEBUG_LEVEL=<1,2,3>)
* #define TG_DEBUG_LEVEL <0,1,2...> (default undefined)
*/
/*
* Math "resolution", values define when a dimension or angle is treated
* as zero.
* #define TG_D_RES (default TG_RESOLUTION)
* #define TG_A_RES (default TG_RESOLUTION)
*/
/* </editor-fold> */
/* <editor-fold defaultstate="collapsed" desc="pose_*: Robot pose types and operations"> */
/********************************************************************
*
* Data structure defining a position of logical axes:
*
* Translation : x,z,y
* Rotation : a,b,c
* Auxiliary translation: u,v,w
*
********************************************************************/
/* Axis enumerators for double vector access */
typedef enum
{
POSE_X_AXIS = 0, POSE_Y_AXIS, POSE_Z_AXIS, POSE_A_AXIS, POSE_B_AXIS,
POSE_C_AXIS, POSE_U_AXIS, POSE_V_AXIS, POSE_W_AXIS
} pose_axis_t;
/* Pose by axes */
typedef struct { real_t x, y, z, a, b, c, u, v, w; } pose_t;
typedef struct { real_t x, y, z; } pose_vector_t;
#define pose_position_t pose_vector_t
/* Line definition */
typedef struct
{
pose_position_t start, end; /* Start/end point */
pose_vector_t u; /* Unit vector of translation */
real_t tm; /* Magnitude /length */
} pose_line_t;
/* Circle definition */
typedef struct
{
pose_position_t cp; /* Circle centre point */
pose_vector_t nv; /* Circle normal vector */
pose_vector_t rt,rp,rh; /* radius vectors: tangent, perpendicular, helix */
real_t l, r, a, s; /* Length, start radius, angle, parallel component coeff */
} pose_circle_t;
/* Curve (bezier/spline) definition */
typedef struct
{
#ifdef WITH_CURVES
pose_position_t start,end; /* End point */
pose_vector_t suv, euv; /* Start/end unit vectors */
real_t len; /* Length of the segment */
real_t c[3][4]; /* Path component coefficients */
real_t d[TG_CURVE_ACC]; /* Correction */
#endif
} pose_curve_t;
typedef real_t pose_array_t[9];
/**
* Inliners (These macros are not upper case)
* Using byval for sources and by pointer for dst, so if somthing is switched
* the compiler will raise an error.
*/
/* Assignment p=0 */
#define pose_set_zero(p) { \
(p)->x=(p)->y=(p)->z=(p)->a=(p)->b=(p)->c=(p)->u=(p)->v=(p)->w= 0.0; \
}
#define pose_set_all(p, val) { \
(p)->x=(p)->y=(p)->z=(p)->a=(p)->b=(p)->c=(p)->u=(p)->v=(p)->w=val; \
}
/**
* Checks if all elements are valid numbers (not nan) and finite.
*/
#define pose_isfinite(p) ( \
isfinite((p).x) && isfinite((p).y) && isfinite((p).z) && \
isfinite((p).a) && isfinite((p).b) && isfinite((p).c) && \
isfinite((p).u) && isfinite((p).v) && isfinite((p).w) \
)
/* Assignment dst = src */
/* stfwi: no memcpy, let the compiler handle optimisation */
#define pose_set(dst, src) { \
(dst)->x = (src).x; (dst)->y = (src).y; (dst)->z = (src).z; \
(dst)->a = (src).a; (dst)->b = (src).b; (dst)->c = (src).c; \
(dst)->u = (src).u; (dst)->v = (src).v; (dst)->w = (src).w; \
}
/* Difference po = p1-p2 */
#define pose_diff(p1, p2, po) { \
(po)->x = (p1).x-(p2).x; (po)->y = (p1).y-(p2).y; (po)->z=(p1).z - (p2).z; \
(po)->a = (p1).a-(p2).a; (po)->b = (p1).b-(p2).b; (po)->c=(p1).c - (p2).c; \
(po)->u = (p1).u-(p2).u; (po)->v = (p1).v-(p2).v; (po)->w=(p1).w - (p2).w; \
}
/* Sum po = p1+p2 */
#define pose_sum(p1, p2, po){ \
(po)->x = (p1).x+(p2).x; (po)->y = (p1).y+(p2).y; (po)->z = (p1).z+(p2).z; \
(po)->a = (p1).a+(p2).a; (po)->b = (p1).b+(p2).b; (po)->c = (p1).c+(p2).c; \
(po)->u = (p1).u+(p2).u; (po)->v = (p1).v+(p2).v; (po)->w = (p1).w+(p2).w; \
}
/* Accumulate po += p2 */
#define pose_acc(po, p2){ \
(po)->x += (p2).x; (po)->y += (p2).y; (po)->z += (p2).z; \
(po)->a += (p2).a; (po)->b += (p2).b; (po)->c += (p2).c; \
(po)->u += (p2).u; (po)->v += (p2).v; (po)->w += (p2).w; \
}
/* Substract po -= p2 */
#define pose_sub(po, p2){ \
(po)->x -= (p2).x; (po)->y -= (p2).y; (po)->z -= (p2).z; \
(po)->a -= (p2).a; (po)->b -= (p2).b; (po)->c -= (p2).c; \
(po)->u -= (p2).u; (po)->v -= (p2).v; (po)->w -= (p2).w; \
}
/* Negation po = -po */
#define pose_neg(po){ \
(po)->x = -(po)->x; (po)->y = -(po)->y; (po)->z = -(po)->z; \
(po)->a = -(po)->a; (po)->b = -(po)->b; (po)->c = -(po)->c; \
(po)->u = -(po)->u; (po)->v = -(po)->v; (po)->w = -(po)->w; \
}
/* Scalar multiply po *= (double) d */
#define pose_scale(po, d){ \
(po)->x *= (d); (po)->y *= (d); (po)->z *= (d); \
(po)->a *= (d); (po)->b *= (d); (po)->c *= (d); \
(po)->u *= (d); (po)->v *= (d); (po)->w *= (d); \
}
/* Trim every axis to a maximum value (defined for every axis) */
#define pose_trim_all_upper(po, max) { \
if ((po)->x > (max).x) (po)->x = (max).x; \
if ((po)->y > (max).y) (po)->y = (max).y; \
if ((po)->z > (max).z) (po)->z = (max).z; \
if ((po)->a > (max).a) (po)->a = (max).a; \
if ((po)->b > (max).b) (po)->b = (max).b; \
if ((po)->c > (max).c) (po)->c = (max).c; \
if ((po)->u > (max).u) (po)->u = (max).u; \
if ((po)->v > (max).v) (po)->v = (max).v; \
if ((po)->w > (max).w) (po)->w = (max).w; \
}
/* Trim every axis to a minimum value (defined for every axis) */
#define pose_trim_all_lower(po, min) { \
if ((po)->x < (min).x) (po)->x = (min).x; \
if ((po)->y < (min).y) (po)->y = (min).y; \
if ((po)->z < (min).z) (po)->z = (min).z; \
if ((po)->a < (min).a) (po)->a = (min).a; \
if ((po)->b < (min).b) (po)->b = (min).b; \
if ((po)->c < (min).c) (po)->c = (min).c; \
if ((po)->u < (min).u) (po)->u = (min).u; \
if ((po)->v < (min).v) (po)->v = (min).v; \
if ((po)->w < (min).w) (po)->w = (min).w; \
}
/* Scalar multiply po *= (double) d */
/* StfWi: memcmp() with reference 0[9]? */
#define pose_is_zero(p) ( \
((p).x == 0.0 && (p).y == 0.0 && (p).z == 0.0 && \
(p).a == 0.0 && (p).b == 0.0 && (p).c == 0.0 && (p).u == 0.0 && \
(p).v == 0.0 && (p).w == 0.0) \
)
/* Scalar multiply po *= (double) d */
#define pose_is_all_greater_equal_zero(p) ( \
((p).x >= 0.0 && (p).y >= 0.0 && \
(p).z >= 0.0 && (p).a >= 0.0 && (p).b >= 0.0 && (p).c >= 0.0 && \
(p).u >= 0.0 && (p).v >= 0.0 && (p).w >= 0.0) \
)
/* </editor-fold> */
/* <editor-fold defaultstate="collapsed" desc="joint_*: Robot joint decls"> */
/*******************************************************************************
*
* Represents one joint of the machine, including configuration, status and
* command transfer.
*
******************************************************************************/
#ifdef JOINT_DECL_NONE
/*
* NOTE: You have to define the joints compatible to the minimum settings
*/
#elif defined JOINT_DECL_FULL
/**
* Type of joint
*/
typedef enum
{
JOINT_TYPE_NONE = 0, /* Not defined */
JOINT_AXIS_TYPE_LINEAR, /* Linear axis, unit will be meters */
JOINT_AXIS_TYPE_ROTARY /* Polar axis, unit will be degrees */
} joint_axis_type_t;
/**
* Feedback type of a joint
*/
typedef enum
{
/* E.g. stepper without encoder */
JOINT_POSITION_FEEDBACK_NONE = 0,
/* Incremental encoder, requires homing for all except axis free motion */
JOINT_POSITION_FEEDBACK_INCREMENTAL,
/* Incremental encoder, requires no homing */
JOINT_POSITION_FEEDBACK_ABSOLUTE
} joint_position_feedback_t;
/**
* I/O logic of various joint inputs/outputs, e.g. limit switches, index ...
*/
typedef enum
{
JOINT_LOGIC_ACTIVE_HIGH = 0x00,
JOINT_LOGIC_ACTIVE_LOW = 0x01, /* used with xor */
JOINT_LOGIC_DISABLED
} joint_logic_t;
/**
* Bit field of joint-related
*/
typedef union
{
uint16_t all;
struct
{
/* The joint/axis is enabled */
unsigned enabled : 1;
/* The amplifier is enabled */
unsigned amplifier_enabled : 1;
/* The joint is homed */
unsigned homed : 1;
/* The trajectory planer is at the goal position */
unsigned trajectory_done : 1;
/* The joint is in the position tolerance of the goal position */
unsigned in_position : 1;
/* The joint does not move (in standstill velocity tolerance) */
unsigned standstill : 1;
/* The joint amplifier has an error */
unsigned amplifier_fault : 1;
/* The joint encoder has an error */
unsigned encoder_fault : 1;
/* The home switch is activated (also depends on config) */
unsigned home_index : 1;
/* The positive limit switch is activated (depends also on config) */
unsigned positive_limit : 1;
/* The negative limit switch is activated (depends also on config) */
unsigned negative_limit : 1;
/* Fill up remaining bits */
unsigned reserved : 5;
} bits;
} joint_status_t;
typedef struct
{
/* Joint type, linear or polar/rotary */
joint_axis_type_t type;
/* The type of feedback */
joint_position_feedback_t feedback_type;
/* The positive software limit in meters/degrees */
real_t positive_software_limit;
/* The negative software limit in meters/degrees */
real_t negative_software_limit;
/* Scales the axis position (normally increments) to meters/degrees */
real_t position_to_meters_scaler;
/* The maximum velocity the joint can do in m/s / degrees/s */
real_t max_velocity;
/* The maximum acceleration the joint can do in m/s / degrees/s */
real_t max_acceleration;
/* Max trailing error at speed=0 in meters/degrees */
real_t max_trailing_error_min;
/* Max trailing error at speed=max_velocity in meters/degrees */
real_t max_trailing_error_max;
/* The deceleration used for ESTOP full break. It can exceed the max_acceleration. */
real_t estop_deceleration;
/* Max position deviation at standstill to say the measured joint position is */
/* accurate enough, in m/s / degrees/s */
real_t in_position_tolerance;
/* Max speed deviation at standstill to say the joint does not move anymore, */
/* m/s / degrees/s */
real_t standstill_tolerance;
/* 1 = a limit switch exists and has to be respected */
joint_logic_t positive_hardware_limit;
/* 1 = a limit switch exists and has to be respected */
joint_logic_t negative_hardware_limit;
/* If not, a limit switch will be used OR, if not limit switch, the mechanical */
/* joint endpoint (measured using trailing error) */
joint_logic_t home_index;
} joint_config_t;
typedef struct
{
/* Axis configuration */
joint_config_t config;
/* State of the joint, see joint_state_t */
joint_status_t status;
/* The interpolated position of the trajectory generator (for all kinds of trajgen) */
real_t command_position;
/* The interpolated velocity of the trajectory generator (for all kinds of trajgen) */
real_t command_velocity;
/* The interpolated acceleration of the trajectory generator (for all kinds of trajgen) */
real_t command_acceleration;
/* The scaled position measured with the encoders */
real_t position;
/* Position captured by a latch operation, e.g. homing index */
real_t latched_position;
} joint_t;
#else
/**
* Minimum joint definition required to use the trajgen
*/
typedef struct
{
struct { real_t max_velocity, max_acceleration; } config;
real_t command_position, command_velocity, command_acceleration, position;
} joint_t;
#endif
/* </editor-fold> */
/* <editor-fold defaultstate="collapsed" desc="trajgen_error_*: Trajgen error main decls"> */
/*******************************************************************************
*
*
* Main trajectory generator error types and definitions.
*
*
******************************************************************************/
/**
* Error declarations for the trajgen itself. However, because this is the "master"
* File of the generator, it will return error codes defined in trajgen_error.h,
* which includes joint, code and error source.
*/
enum
{
/* Main controller */
TRAJ_ERROR_OK = 0,
TRAJ_ERROR_ERROR,
TRAJ_ERROR_NULL_POINTER,
TRAJ_ERROR_NUMERIC,
TRAJ_ERROR_CONFIG_LAST_USED_JOINT_INVALID,
TRAJ_ERROR_CONFIG_INTERPOLATION_RATE_INVALID,
TRAJ_ERROR_CONFIG_OVERRIDE_INVALID,
TRAJ_ERROR_CONFIG_COMPILE_SETTING_INVALID,
TRAJ_ERROR_INVALID_STATE, /* The motion state is not valid (Internal problem) */
TRAJ_ERROR_INVALID_SWITCHING_STATE, /* The operating mode to set is invalid */
TRAJ_ERROR_INVALID_JOINT_NO,
/* Kinematics */
KINEMATICS_ERR_ERROR,
KINEMATICS_ERR_NULL_POINTER,
KINEMATICS_ERR_INIT_FUNCTION_NULL,
KINEMATICS_ERR_FORWARD_FAILED,
KINEMATICS_ERR_INVERSE_FAILED,
KINEMATICS_ERR_RESET_FAILED,
/* Interpolators */
INTERPOLATOR_ERROR,
INTERPOLATOR_ERROR_INIT_ARG_INVALID,
INTERPOLATOR_ERROR_QUEUE_FULL,
INTERPOLATOR_ERROR_OFFSET_IP_NULLPOINTER,
INTERPOLATOR_ERROR_INTERPOLATE_ARG_NULLPOINTER,
INTERPOLATOR_ERROR_NOT_RESET,
INTERPOLATOR_ERROR_NULLPOINTER,
/* Coordinated planer */
TP_ERR_ERROR,
TP_ERR_TP_NULL_POINTER,
TP_ERR_ABORTING,
TP_ERR_QUEUE_PUT_FAILED,
TP_ERR_INVALID_PARAM,
TP_ERR_QUEUE_FULL,
TP_ERR_QUEUE_TO_MANY_ELEMENTS_TO_REMOVE,
TP_ERR_INVALID_MOTION_TYPE,
TP_ERR_INVALID_SPEED,
TP_ERR_INVALID_ACCEL,
TP_ERR_INVALID_POSE,
TP_ERR_SEGMENT_LENGTH_ZERO,
TP_ERR_INVALID_SAMPLE_INTERVAL,
TP_ERR_ALREADY_MOVING,
TP_ERR_UNIT_VECTOR_CALC_INVALID_TYPE,
TP_ERR_REF_POSITION_INVALIDATED_DURING_MOTION,
/* Joint planers */
TRAJGEN_FREE_ERROR_ERROR,
TRAJGEN_FREE_ERROR_INIT_NULLPOINTER,
TRAJGEN_FREE_ERROR_INIT_INVALID_MAX_ACCEL,
TRAJGEN_FREE_ERROR_INIT_INVALID_MAX_VELOCITY,
TRAJGEN_FREE_ERROR_INIT_INVALID_SAMPLE_INTERVAL,
TRAJGEN_FREE_ERROR_INVALID_ACCELERATION,
/* Manual operation planer */
TG_MAN_ERROR_ERROR,
TG_MAN_ERROR_INIT_NULLPOINTER,
TG_MAN_ERROR_INIT_INVALID_MAX_ACCEL,
TG_MAN_ERROR_INIT_INVALID_MAX_VELOCITY,
TG_MAN_ERROR_INIT_INVALID_SAMPLE_INTERVAL,
TG_MAN_ERROR_INVALID_ACCELERATION
};
enum { KINEMATICS_ERR_OK=0 };
enum { INTERPOLATOR_OK=0 };
enum { TP_ERR_OK=0 };
enum { TRAJGEN_FREE_ERROR_OK=0 };
enum { TG_MAN_ERROR_OK=0 };
typedef uint16_t trajgen_error_t;
#define kinematics_error_t trajgen_error_t
#define trajgen_coord_error_t trajgen_error_t
#define interpolator_error_t trajgen_error_t
#define interpolator_error_t trajgen_error_t
#define trajgen_jointtg_error_t trajgen_error_t
#define trajgen_man_error_t trajgen_error_t
/**
* Main error type
*/
typedef union
{
int16_t errnom;
struct
{
unsigned code : 12;
unsigned joint : 4;
} sel;
} trajgen_error_details_t;
/**
* Writes a text version of a trajgen error into *errstr
* @param uint16_t errnum
* @param char* errstr
* @param unsigned length
*/
extern const char* trajgen_errstr(uint16_t errnum, char* errstr, unsigned length);
/* </editor-fold> */
/* <editor-fold defaultstate="collapsed" desc="interpolator_*: Interpolation"> */
/********************************************************************
* Cyclic Cubic interpolation, used to interpolate joint command position for
* the closed loop controllers between the way points produced by the trajectory
* generators. This allows to enhance the system performance, especially when
* high filter sample rates are required.
*
********************************************************************/
/**
* Cubic interpolator
*/
typedef struct
{
uint16_t n; /* Specifies number of queued points */
real_t T; /* The trajectory planer sample time */
real_t Ti; /* The time between two interpolated points */
real_t t; /* Current time, reset on push */
real_t x0, x1, x2, x3;/* Buffer for the interpolation, used like a FIFO */
real_t w0, w1; /* Way points */
real_t v0, v1; /* Velocities at the way points */
real_t a, b, c, d; /* Coefficients polynomial, a*x^3 + b*x^2 + c*x + d */
} interpolator_t;
#ifdef EXPORT_INTERPOLATORS
/**
* Initialise the interpolator.
*/
extern interpolator_error_t interpolator_init(interpolator_t*, real_t sample_interval,
unsigned interpolation_rate);
/**
* Reset the interpolator, clear the queue to the specified position value.
*/
extern interpolator_error_t interpolator_reset(interpolator_t*, real_t initial_position);
/**
* Performs one interpolation tick. All pointer argument must refer to existing
* variables (not NULL).
*/
extern interpolator_error_t interpolator_interpolate(interpolator_t*, real_t *x,
real_t *v, real_t *a, real_t *j);
/**
* Push a new position into the fifo. That is only allowed when the fifo is not full.
*/
extern interpolator_error_t interpolator_push(interpolator_t*, real_t point);
/**
* Returns nonzero if the fifo is not full. You must push a value before the
* next interpolation step, or the last value in the fifo will be pushed
* automatically.
*/
extern bool_t interpolator_need_update(interpolator_t*);
#endif
/* </editor-fold> */
/* <editor-fold defaultstate="collapsed" desc="kinematics_*: Kinematics"> */
/*******************************************************************************
*
* Calculates the position and direction of the end effector (where the tool is
* mounted) in three dimensional space based in the position of all relevant
* machine joints and vice versa. Several kinematic machine models are available
* and implementing own models is possible.
*
******************************************************************************/
typedef struct
{
/**
* The reset kinematics function sets all its arguments to their proper
* values at the known initial position. When called, these should be set,
* when known, to initial values, e.g., from an INI file. If the home
* kinematics can accept arbitrary starting points, these initial values
* should be used.
*/
kinematics_error_t(*reset)(pose_t *pose, real_t *joint_positions[]);
/**
* The forward kinematics take joint values and determine world coordinates,
* given forward kinematics flags to resolve any ambiguities. The inverse
* flags are set to indicate their value appropriate to the joint values
* passed in.
*/
kinematics_error_t(*forward)(real_t *joint_positions[], pose_t *pose);
/**
* The inverse kinematics take world coordinates and determine joint values,
* given the inverse kinematics flags to resolve any ambiguities. The forward
* are set to indicate their value appropriate to the world coordinates
* passed in.
*/
kinematics_error_t(*inverse)(pose_t *pose, real_t *joint_positions[]);
} kinematics_t;
extern kinematics_error_t kinematics_initialize(kinematics_t *kin, kinematics_t
device_kinematics);
/* </editor-fold> */
/* <editor-fold defaultstate="collapsed" desc="trajgen_coord_*, trajgen_sg_*: Coordinated Motion"> */
/********************************************************************
*
* Planer for coordinated queued motion with blending, i/o synchronisation and
* motion synchronisation.
*
********************************************************************/
/**
* Naming of motion task types (typedef is int'ed for bit packing)
*/
#define trajgen_sg_motion_type_t int
enum
{
SG_INVALID = 0x00,
SG_LINEAR = 0x01,
SG_CIRCULAR = 0x02,
SG_CURVE = 0x03,
SG_END_OF_MOTION
};
/**
* Type naming of motion synchronisation (typedef is int'ed for bit packing)
*/
#define trajgen_coord_motion_sync_type_t int
enum
{
TP_SYNC_NONE = 0x00,
TP_SYNC_VELOCITY = 0x01,
TP_SYNC_POSITION = 0x02
};
/**
* Type for specification of synchronised motion (motion dependent on external
* positions/velocities).
*/
typedef struct
{
/**
* Scales from the reference position/velocity (e.g. spindle position/speed)
* to the scalar position/velocity of the trajectory when multiplied.
*/
real_t scaler;
/*
* Position sync: The current (input) reference position
* Velocity sync: The current (input) reference velocity
*/
real_t reference;
/* INTERNAL USE: Accumulates the position-synchronized segment lengths of
* all surpassed segments for position sync.
*/
real_t i_offset;
/**
* The type of synchronisation, for subsequent motion, default is TP_SYNC_NONE
*/
trajgen_coord_motion_sync_type_t type: 4;
/**
* INTERNAL USE: Saves if the position offset does not require to be updated
* before starting a position synced motion.
*/
bool_t i_isset: 1;
} trajgen_coord_motion_sync_t;
/**
* Coordinated planer configuration
*/
typedef struct
{
/* Sample interval (cycle interval time) */
real_t sample_interval;
/* Max velocity allowed by machine constraints (normally set in a config file) */
real_t max_velocity;
/* Max acceleration allowed by machine constraints (normally set in a config file) */
real_t max_acceleration;
} trajgen_coord_config_t;
/**
* Mask type for synchronised digital I/O states (bit field)