Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / libdragonfly / encoders.c @ 1461

History | View | Annotate | Download (9.52 KB)

1 868 justin
#include "encoders.h"
2
#include "spi.h"
3
#include "ring_buffer.h"
4 1452 dsschult
#include <avr/io.h>
5 868 justin
6 1461 bneuman
unsigned char encoders_initd=0;
7
8 868 justin
unsigned int left_data_buf;
9
unsigned int right_data_buf;
10
char encoder_buf_index;
11
12
unsigned int left_data;
13
unsigned int right_data;
14
15
unsigned int left_data_array[BUFFER_SIZE];
16
unsigned int right_data_array[BUFFER_SIZE];
17
int left_data_idx;
18
int right_data_idx;
19
20
int left_dx;
21
int right_dx;
22
long int timecount;
23
24
volatile short int data_ready;
25
26 1461 bneuman
int encoder_recv(char data);
27 868 justin
28
//Helper Function Prototypes
29
inline void left_data_array_put(unsigned short int value);
30
inline unsigned int left_data_array_top(void);
31
inline unsigned int left_data_array_prev(void);
32
inline unsigned int left_data_array_bottom(void);
33
34
inline void right_data_array_put(unsigned short int value);
35
inline unsigned int right_data_array_top(void);
36
inline unsigned int right_data_array_prev(void);
37
inline unsigned int right_data_array_bottom(void);
38
39 1418 chihsiuh
//encoder_get_v helper function prototypes
40
int left_data_at(int index);
41
int right_data_at(int index);
42
int get_dx(char encoder, int index);
43 868 justin
44 890 justin
void encoder_recv_complete(void){
45 868 justin
          encoder_buf_index = 0;
46
        data_ready++;
47
48
           spi_transfer(5);
49
}
50
51
/**
52
* @brief Initializes encoder variables and the hardware interface.
53
*/
54 1461 bneuman
int encoders_init(void){
55
  int i;
56 868 justin
57 1461 bneuman
  if(encoders_initd)
58
    return ERROR_INIT_ALREADY_INITD;
59 868 justin
60 1461 bneuman
  data_ready=0;
61
62
  if(spi_init(encoder_recv, encoder_recv_complete))
63
    return -1; //if spi was inited for something else, bail out
64
  encoder_buf_index = 0;
65
  left_data_buf = 0;
66
  right_data_buf= 0;
67
  left_data = -1;
68
  right_data = -1;
69
70
  //RING_BUFFER_INIT(enc_buffer,BUFFER_SIZE);
71
  left_data_idx = 0;
72
  right_data_idx = 0;
73
74
  for(i = 0; i < BUFFER_SIZE; i++) {
75
    left_data_array[i] = 0;
76
  }
77
  for(i = 0; i < BUFFER_SIZE; i++) {
78
    right_data_array[i] = 0;
79
  }
80
81
  spi_transfer(5);
82
83
  encoders_initd=1;
84
  return 0;
85 868 justin
}
86
87
/**
88
 * @brief Returns the specified encoders value
89
 *
90
 * @param encoder this is the encoder that you want to read. Valid arguments
91
 *          are LEFT and RIGHT
92
 *
93 1418 chihsiuh
 * @return the value of the specified encoder.
94
 *         -1 usually means low battery.
95 1461 bneuman
 *         -2 means the library was not properly initialized
96 1418 chihsiuh
 *         values above ENCODER_MAX usually means phyiscal problems with
97
 *         the encoder.
98 868 justin
 **/
99
int encoder_read(char encoder){
100 1461 bneuman
  if(!encoders_initd)
101
    return -2;
102
103
  if(encoder==LEFT) {
104
    return left_data;
105
  }
106
  else if(encoder==RIGHT){
107
    return right_data;
108
  }
109
  else{
110
    return -1;
111
  }
112 868 justin
}
113
114
/**
115 1418 chihsiuh
 * @brief Get total distance travelled by the specified encoder (in encoder ticks)
116
 *
117
 * @param encoder the encoder that you want to read, either LEFT or RIGHT
118
 *
119
 * @return The distance covered by the specified encoder.
120
 *
121
 * @note Simply calls encoder_get_dx.
122
 **/
123
int encoder_get_x(char encoder) {
124
        return encoder_get_dx(encoder);
125
}
126
127
/**
128 868 justin
 * Gets the total distance covered by the specified encoder (in encoder clicks)
129
 *
130
 * @param encoder the encoder that you want to read, use LEFT or RIGHT
131
 *
132 1461 bneuman
 * @return The distance covered by the specified encoder, -2 if the library is not initialized
133 868 justin
 **/
134
int encoder_get_dx(char encoder) {
135 1461 bneuman
  if(!encoders_initd)
136
    return -2;
137
138
  if(encoder==LEFT)
139
    return left_dx;
140
  else if(encoder==RIGHT)
141
    return right_dx;
142
  else
143
    return -1;
144 868 justin
}
145
146 1418 chihsiuh
/**
147
 * @brief Returns the approximated instantaneous velocity of the robot
148
 * in terms of encoder clicks.
149
 *
150
 * @param encoder RIGHT or LEFT - the wheel you want the velocity for.
151
 *
152
 * @return The instantaneous velocity for the given wheel or twice the ERR_VEL
153
 *         if an error occurs (1024 * 2 = 2048)
154
 *
155
 * @bug This uses hard coded values and results are inconsistent.
156
 *      Use at your own risk.
157
 */
158
int encoder_get_v(char encoder){
159
    int vel1, vel2;
160 1461 bneuman
161 1418 chihsiuh
    vel1 = get_dx(encoder, 0);
162
    vel2 = get_dx(encoder, 1);
163
164
    if (vel1 == ERR_VEL && vel2 == ERR_VEL)
165
        return ERR_VEL << 1;
166
    else if (vel2 == ERR_VEL)
167
        return vel1 << 1;
168
    else if (vel1 == ERR_VEL)
169
        return vel2 << 1;
170
    else
171
        return vel1 + vel2;
172
}
173
174 868 justin
/**
175
 * Resets the distance accumulator for the specified
176
 *  encoder.
177
 *
178
 * @param encoder the encoder that you want to reset distance for
179
 **/
180 1461 bneuman
int encoder_rst_dx(char encoder) {
181
182
  if(!encoders_initd)
183
    return ERROR_LIBRARY_NOT_INITD;
184
185
  if(encoder==LEFT)
186
    left_dx = 0;
187
  else if(encoder==RIGHT)
188
    right_dx = 0;
189
190
  return 0;
191 868 justin
}
192
193
/**
194
* @brief Returns the number of encoder reads that have occurred.
195
*
196
* @return The time count.
197
*/
198
int encoder_get_tc(void) {
199
        return timecount;
200
}
201
202
/**
203
* @brief Resets the encoder read counter.
204 1461 bneuman
* @return 0 if init succesfull, an error code otherwise
205 868 justin
*/
206 1461 bneuman
int encoder_rst_tc(void) {
207
  if(!encoders_initd)
208
    return ERROR_LIBRARY_NOT_INITD;
209
210
  timecount = 0;
211
212
  return 0;
213 868 justin
}
214
215
/**
216
* @brief Waits until n encoder reads have occurred.
217
* Counter is reset on functions exit.
218
*
219
* @param n
220 1461 bneuman
*
221
* @return 0 if init succesfull, an error code otherwise
222 868 justin
*/
223 1461 bneuman
int encoder_wait(int n){
224
  if(!encoders_initd)
225
    return ERROR_LIBRARY_NOT_INITD;
226
227
  while(data_ready<n);
228
  data_ready=0;
229
230
  return 0;
231 868 justin
}
232
233 1461 bneuman
/**
234
 * @brief This functions recieves data from the encoders directly
235
 *
236
 * @note Full reads occur every 40 microseconds. This function should be called every 8 microseconds.
237
 *
238
 * @return 0 if init succesfull, an error code otherwise
239
 */
240
int encoder_recv(char data){
241
  short int dx;
242 868 justin
243 1461 bneuman
  if(!encoders_initd)
244
    return ERROR_LIBRARY_NOT_INITD;
245
246
  //Parse the encoder data, comes in over 5 bytes 16 bits per encoder,
247
  // second is offset by 1 bit.
248
  switch(encoder_buf_index){
249
  case 0:
250
    right_data_buf |= ((short)data)<<8 & 0xff00;
251
    break;
252
  case 1:
253
    right_data_buf |= ((short)data) & 0xff;
254
    break;
255
  case 2:
256
    left_data_buf |= (((short)data) << 9) & (0x7F << 9);
257
    break;
258
  case 3:
259
    left_data_buf |= (((short)data) << 1) & (0xFF<<1);
260
    break;
261
  case 4: left_data_buf |= (((short)data)>>7) & 0x1;
262
  }
263 868 justin
264 1461 bneuman
  encoder_buf_index = (encoder_buf_index + 1) % 5;
265 868 justin
266 1461 bneuman
  if(encoder_buf_index==0) {
267 868 justin
268 1461 bneuman
    /*Error handling for the left encoder*/
269
    if(!(left_data_buf & OCF))
270
      left_data = ENCODER_DATA_NOT_READY;
271
    if(left_data_buf & (COF | LIN))
272
      left_data = ENCODER_MISALIGNED;
273
    else if((left_data_buf & MagINCn) && (left_data_buf & MagDECn))
274
      left_data = ENCODER_MAGNET_FAILURE;
275
    else left_data = (left_data_buf>>5) & 1023;
276 868 justin
277 1461 bneuman
    /*Error handling for the right encoder*/
278
    if(!(right_data_buf & OCF))
279
      right_data = ENCODER_DATA_NOT_READY;
280
    if(right_data_buf & (COF | LIN))
281
      right_data = ENCODER_MISALIGNED;
282
    else if ((right_data_buf & MagINCn)  && (right_data_buf & MagDECn))
283
      right_data = ENCODER_MAGNET_FAILURE;
284
    else right_data = (right_data_buf>>5) & 1023;
285 868 justin
286 1461 bneuman
    left_data_buf = 0;
287
    right_data_buf = 0;
288 868 justin
289 1461 bneuman
    /*Note: Above 1023 is invalid data*/
290
    if(!(left_data > 1023)) {
291
      //Reverse the left wheel since encoders are necessarily mounted backwards.
292
      left_data = 1023 - left_data;
293
      left_data_array_put(left_data);
294 868 justin
295 1461 bneuman
      //Adjust left accumulator
296
      dx = left_data - left_data_array_prev();
297 868 justin
298 1461 bneuman
      if(left_data_array_prev()==0)  dx=0;
299 868 justin
300 1461 bneuman
      if(dx > 512) left_dx += dx - 1023; //Underflow
301
      else if(dx < -512) left_dx += dx + 1023; //Overflow
302
      else left_dx += dx;
303
    }
304 868 justin
305 1461 bneuman
    /*Above 1023 is invalid data*/
306
    if(!(right_data > 1023)) {
307
      right_data_array_put(right_data);
308 868 justin
309 1461 bneuman
      //Adjust right accumulator
310
      dx = right_data - right_data_array_prev();
311 868 justin
312 1461 bneuman
      if(right_data_array_prev()==0) dx=0;
313 868 justin
314 1461 bneuman
      if(dx > 512) right_dx += dx - 1023; //underflow
315
      else if(dx < -512) right_dx += dx + 1023; //overflow
316
      else right_dx += dx;
317
    }
318
  }
319 868 justin
320 1461 bneuman
  //Increment timecount accumulator
321
  timecount++;
322
323
  return 0;
324 868 justin
}
325
326
327
//Helper Functions
328
inline void left_data_array_put(unsigned short int value) {
329
        if(left_data_idx == BUFFER_SIZE-1)
330
                left_data_idx = 0;
331
        else
332
                left_data_idx++;
333
        left_data_array[left_data_idx] = value;
334
}
335
336
inline unsigned int left_data_array_top(void) {
337
        return left_data_array[left_data_idx];
338
}
339
340
inline unsigned int left_data_array_prev(void) {
341
        if(left_data_idx == 0)
342
                return left_data_array[BUFFER_SIZE-1];
343
        else
344
                return left_data_array[left_data_idx - 1];
345
}
346
347
inline unsigned int left_data_array_bottom(void) {
348
        if(left_data_idx == BUFFER_SIZE-1)
349
                return left_data_array[0];
350
        else
351
                return left_data_array[left_data_idx + 1];
352
}
353
354
inline void right_data_array_put(unsigned short int value) {
355
        if(right_data_idx == BUFFER_SIZE-1)
356
                right_data_idx = 0;
357
        else
358
                right_data_idx++;
359
        right_data_array[right_data_idx] = value;
360
}
361
362
inline unsigned int right_data_array_top(void) {
363
        return right_data_array[right_data_idx];
364
}
365
366
inline unsigned int right_data_array_prev(void) {
367
        if(right_data_idx == 0)
368
                return right_data_array[BUFFER_SIZE-1];
369
        else
370
                return right_data_array[right_data_idx - 1];
371
}
372
373
inline unsigned int right_data_array_bottom(void) {
374
        if(right_data_idx == BUFFER_SIZE-1)
375
                return right_data_array[0];
376
        else
377
                return right_data_array[right_data_idx + 1];
378
}
379
380 1418 chihsiuh
/* Helper functions for encoder_get_v */
381
int left_data_at(int index) {
382
    int tmp_idx = left_data_idx - index;
383
    if (tmp_idx < 0)
384
        tmp_idx += BUFFER_SIZE;
385
    return left_data_array[tmp_idx];
386
}
387
388
int right_data_at(int index) {
389
    int tmp_idx = right_data_idx - index;
390
    if (tmp_idx < 0)
391
        tmp_idx += BUFFER_SIZE;
392
    return right_data_array[tmp_idx];
393
}
394
395
int get_dx(char encoder, int index) {
396
    int dx, ctr;
397
    ctr = 0;
398
    dx = 1024;
399
    do {
400
        if (encoder == LEFT)
401
            dx = left_data_at(index+ctr) - left_data_at(index+ctr+38);
402
        else
403
            dx = right_data_at(index+ctr) - right_data_at(index+ctr+38);
404
        ctr++;
405
    } while ((dx > 30 || dx < -30) && ctr < 3);
406
    if (dx > 30 || dx < -30)
407
        return ERR_VEL;
408
    return dx;
409
}