Contiki 2.5
stepper-move.c
1 #include <stdio.h>
2 #include <stepper-interrupt.h>
3 #include <stepper-move.h>
4 #include <limits.h>
5 
6 #if 0
7 #define PRINTF(...) printf(__VA_ARGS__)
8 #else
9 #define PRINTF(...) do {} while (0)
10 #endif
11 
12 static unsigned int
13 isqrt(unsigned long x)
14 {
15  unsigned int r;
16  unsigned int b2 = 0x40000000;
17  unsigned int b = 0x8000;
18  while(x < b2) {
19  b2 >>= 2;
20  b >>= 1;
21  }
22  if (b == 0) return 0;
23  r = b;
24  b >>= 1;
25  while(b > 0) {
26  r += b;
27  unsigned int t = r*r;
28  if (t > x) {
29  r -= b;
30  }
31  b >>=1;
32  }
33  return r;
34 }
35 
36 #define ACC_FIRST_UP 0
37 #define ACC_K1_UP 1
38 #define ACC_LAST_UP 2
39 #define ACC_TOP 3
40 #define ACC_FIRST_DOWN 4
41 #define ACC_K1_DOWN 5
42 #define ACC_LAST_DOWN 6
43 #define ACC_END 7
44 
45 typedef struct _AccDiff AccDiff;
46 struct _AccDiff
47 {
48  long diff;
49  unsigned long pos;
50 };
51 
52 
53 static inline long
54 base_acc(unsigned long t,unsigned long n, unsigned long l, unsigned long a_max)
55 {
56  long a;
57  if (t >= n) {
58  if (t >= n+l) {
59  a = -a_max;
60  } else {
61  a = 0;
62  }
63  } else {
64  a = a_max;
65  }
66  return a;
67 }
68 
69 static AccDiff acc[ACC_END+1];
70 StepperResult
71 stepper_move(unsigned int stepper_index, unsigned long *periodp,
72  unsigned long a_max,unsigned long v_max, long s_end)
73 {
74  unsigned long start_period = *periodp;
75  unsigned long s;
76  unsigned long ds;
77  unsigned long l;
78  unsigned long da0;
79  unsigned long k1 = 0;
80  unsigned long n = (v_max+a_max-1)/a_max;
81  unsigned long a_speed_adj = v_max - (n-1)*a_max;
82  unsigned long s_res;
83  long d;
84  if (s_end >= 0) {
85  s_res = s_end/2;
86  } else {
87  s_res = (-s_end)/2;
88  }
89  d = s_res - (long)a_max*(n*n-1) - (long)a_speed_adj;
90 
91  acc[ACC_END].diff = 0;
92  acc[ACC_END].pos = UINT_MAX;
93  if (d < 0) {
94  l = 0;
95  n = isqrt(s_res/a_max);
96  if (n*(unsigned long long)n*a_max < s_res) n++;
97  a_speed_adj = a_max;
98  acc[ACC_LAST_UP].diff=0;
99  acc[ACC_FIRST_DOWN].diff=0;
100  } else {
101  l = (d+v_max-1)/v_max;
102  acc[ACC_LAST_UP].diff= a_speed_adj - a_max;
103  acc[ACC_FIRST_DOWN].diff= a_max - a_speed_adj;
104  }
105  acc[ACC_LAST_UP].pos = n-1;
106  acc[ACC_FIRST_DOWN].pos = n+l;
107 
108  s = a_max*(n*n-1) + a_speed_adj + l * (a_max*(n-1) + a_speed_adj);
109  ds = s-s_res;
110 
111  da0 = ds/(2*n+l-1);
112  acc[ACC_FIRST_UP].diff = -da0;
113  acc[ACC_LAST_DOWN].diff = da0;
114  acc[ACC_FIRST_UP].pos = 0;
115  acc[ACC_LAST_DOWN].pos = 2*n+l-1;
116  ds -= da0*(2*n+l-1);
117 
118  acc[ACC_K1_UP].diff = 0;
119  acc[ACC_K1_DOWN].diff = 0;
120  acc[ACC_K1_UP].pos = 0;
121  acc[ACC_K1_DOWN].pos = 2*n+l-1;
122 
123  acc[ACC_TOP].diff = 0;
124  acc[ACC_TOP].pos = n;
125 
126  if (ds > 0) {
127  k1 = (2*n+l -ds)/2;
128  if (k1 < n) {
129 
130  acc[ACC_K1_UP].diff = -1;
131  acc[ACC_K1_DOWN].diff = 1;
132  acc[ACC_K1_UP].pos = k1;
133  acc[ACC_K1_DOWN].pos = 2*n+l-1 - k1;
134  ds -= (2*(n-k1)+l-1);
135  }
136  if (ds > 0) {
137  acc[ACC_LAST_UP].diff--;
138  acc[ACC_TOP].diff = 1;
139  acc[ACC_TOP].pos = n+ds-1;
140  }
141  }
142 #if 0
143  {
144  unsigned int k;
145  PRINTF("n=%ld l=%ld a_max=%ld v_max=%ld s_res=%ld\n",
146  n,l ,a_max, v_max, s_res);
147  for (k = 0; k < 7; k++) {
148  PRINTF(" %ld@%ld", acc[k].diff, acc[k].pos);
149  }
150  PRINTF("\n");
151  }
152 #endif
153  {
154  StepperResult res;
155  unsigned int k;
156  unsigned long t = 0;
157  long da = 0;
158  long a_prev = ULONG_MAX;
159  for (k = 0; k < ACC_END; k++) {
160  long a;
161  da += acc[k].diff;
162  if (acc[k].pos != acc[k+1].pos) { /* Next position is different */
163  if (t != acc[k].pos) {
164  a = base_acc(t,n,l,a_max);
165  if (s_end < 0) a = -a;
166  if (a_prev != a) {
167  res = stepper_add_acc(stepper_index, t+start_period, a);
168  if (res != STEPPER_OK) return res;
169  PRINTF("%d: %ld@%ld\n", stepper_index, a, t+start_period);
170  a_prev = a;
171  }
172  t = acc[k].pos;
173  }
174  a = da + base_acc(t,n,l,a_max);
175  if (s_end < 0) a = -a;
176  if (a_prev != a) {
177  res = stepper_add_acc(stepper_index, t+start_period, a);
178  if (res != STEPPER_OK) return res;
179  PRINTF("%d: %ld@%ld\n", stepper_index, a, t+start_period);
180  a_prev = a;
181  }
182  t++;
183  da = 0;
184  }
185  }
186  res = stepper_add_acc(stepper_index, t+start_period, 0);
187  PRINTF("%d: %d@%ld\n", stepper_index, 0, t+start_period);
188  if (res != STEPPER_OK) return res;
189  *periodp += t;
190  }
191  return STEPPER_OK;
192 }
193