Project

General

Profile

Statistics
| Revision:

root / branches / init_refactor / code / projects / libdragonfly / encoders.c @ 1543

History | View | Annotate | Download (11.3 KB)

1 1462 dsschult
/**
2
 * Copyright (c) 2007 Colony Project
3
 *
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25
26
27
/**
28
 * @file encoders.c
29
 * @brief Encoders
30
 *
31
 * Implementation of functions for encoders.
32
 *
33
 * @author Colony Project, CMU Robotics Club
34
 **/
35
36
#include <avr/io.h>
37
38
#include "dragonfly_defs.h"
39 868 justin
#include "spi.h"
40
#include "ring_buffer.h"
41 1462 dsschult
#include "encoders.h"
42 868 justin
43 1461 bneuman
unsigned char encoders_initd=0;
44
45 868 justin
unsigned int left_data_buf;
46
unsigned int right_data_buf;
47
char encoder_buf_index;
48
49
unsigned int left_data;
50
unsigned int right_data;
51
52
unsigned int left_data_array[BUFFER_SIZE];
53
unsigned int right_data_array[BUFFER_SIZE];
54
int left_data_idx;
55
int right_data_idx;
56
57
int left_dx;
58
int right_dx;
59
long int timecount;
60
61
volatile short int data_ready;
62
63 1461 bneuman
int encoder_recv(char data);
64 868 justin
65
//Helper Function Prototypes
66
inline void left_data_array_put(unsigned short int value);
67
inline unsigned int left_data_array_top(void);
68
inline unsigned int left_data_array_prev(void);
69
inline unsigned int left_data_array_bottom(void);
70
71
inline void right_data_array_put(unsigned short int value);
72
inline unsigned int right_data_array_top(void);
73
inline unsigned int right_data_array_prev(void);
74
inline unsigned int right_data_array_bottom(void);
75
76 1418 chihsiuh
//encoder_get_v helper function prototypes
77
int left_data_at(int index);
78
int right_data_at(int index);
79
int get_dx(char encoder, int index);
80 868 justin
81 890 justin
void encoder_recv_complete(void){
82 868 justin
          encoder_buf_index = 0;
83
        data_ready++;
84
85
           spi_transfer(5);
86
}
87
88
/**
89
* @brief Initializes encoder variables and the hardware interface.
90
*/
91 1461 bneuman
int encoders_init(void){
92
  int i;
93 868 justin
94 1543 bneuman
  if(encoders_initd) {
95
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders already init'd\r\n");
96 1461 bneuman
    return ERROR_INIT_ALREADY_INITD;
97 1543 bneuman
  }
98 868 justin
99 1461 bneuman
  data_ready=0;
100
101 1543 bneuman
  if(spi_init(encoder_recv, encoder_recv_complete)) {
102
    DRAGONFLY_DEBUG_PRINT("ERROR: SPI was already init'd, bailing out\r\n");
103 1461 bneuman
    return -1; //if spi was inited for something else, bail out
104 1543 bneuman
  }
105 1461 bneuman
  encoder_buf_index = 0;
106
  left_data_buf = 0;
107
  right_data_buf= 0;
108
  left_data = -1;
109
  right_data = -1;
110
111
  //RING_BUFFER_INIT(enc_buffer,BUFFER_SIZE);
112
  left_data_idx = 0;
113
  right_data_idx = 0;
114
115
  for(i = 0; i < BUFFER_SIZE; i++) {
116
    left_data_array[i] = 0;
117
  }
118
  for(i = 0; i < BUFFER_SIZE; i++) {
119
    right_data_array[i] = 0;
120
  }
121
122
  spi_transfer(5);
123
124
  encoders_initd=1;
125
  return 0;
126 868 justin
}
127
128
/**
129
 * @brief Returns the specified encoders value
130
 *
131
 * @param encoder this is the encoder that you want to read. Valid arguments
132
 *          are LEFT and RIGHT
133
 *
134 1418 chihsiuh
 * @return the value of the specified encoder.
135
 *         -1 usually means low battery.
136 1461 bneuman
 *         -2 means the library was not properly initialized
137 1418 chihsiuh
 *         values above ENCODER_MAX usually means phyiscal problems with
138
 *         the encoder.
139 868 justin
 **/
140
int encoder_read(char encoder){
141 1543 bneuman
  if(!encoders_initd) {
142
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
143 1461 bneuman
    return -2;
144 1543 bneuman
  }
145 1461 bneuman
146
  if(encoder==LEFT) {
147
    return left_data;
148
  }
149
  else if(encoder==RIGHT){
150
    return right_data;
151
  }
152
  else{
153
    return -1;
154
  }
155 868 justin
}
156
157
/**
158 1418 chihsiuh
 * @brief Get total distance travelled by the specified encoder (in encoder ticks)
159
 *
160
 * @param encoder the encoder that you want to read, either LEFT or RIGHT
161
 *
162
 * @return The distance covered by the specified encoder.
163
 *
164
 * @note Simply calls encoder_get_dx.
165
 **/
166
int encoder_get_x(char encoder) {
167
        return encoder_get_dx(encoder);
168
}
169
170
/**
171 868 justin
 * Gets the total distance covered by the specified encoder (in encoder clicks)
172
 *
173
 * @param encoder the encoder that you want to read, use LEFT or RIGHT
174
 *
175 1461 bneuman
 * @return The distance covered by the specified encoder, -2 if the library is not initialized
176 868 justin
 **/
177
int encoder_get_dx(char encoder) {
178 1461 bneuman
  if(!encoders_initd)
179
    return -2;
180
181
  if(encoder==LEFT)
182
    return left_dx;
183
  else if(encoder==RIGHT)
184
    return right_dx;
185
  else
186
    return -1;
187 868 justin
}
188
189 1418 chihsiuh
/**
190
 * @brief Returns the approximated instantaneous velocity of the robot
191
 * in terms of encoder clicks.
192
 *
193
 * @param encoder RIGHT or LEFT - the wheel you want the velocity for.
194
 *
195
 * @return The instantaneous velocity for the given wheel or twice the ERR_VEL
196
 *         if an error occurs (1024 * 2 = 2048)
197
 *
198
 * @bug This uses hard coded values and results are inconsistent.
199
 *      Use at your own risk.
200
 */
201
int encoder_get_v(char encoder){
202
    int vel1, vel2;
203 1461 bneuman
204 1418 chihsiuh
    vel1 = get_dx(encoder, 0);
205
    vel2 = get_dx(encoder, 1);
206
207
    if (vel1 == ERR_VEL && vel2 == ERR_VEL)
208
        return ERR_VEL << 1;
209
    else if (vel2 == ERR_VEL)
210
        return vel1 << 1;
211
    else if (vel1 == ERR_VEL)
212
        return vel2 << 1;
213
    else
214
        return vel1 + vel2;
215
}
216
217 868 justin
/**
218
 * Resets the distance accumulator for the specified
219
 *  encoder.
220
 *
221
 * @param encoder the encoder that you want to reset distance for
222
 **/
223 1461 bneuman
int encoder_rst_dx(char encoder) {
224
225 1543 bneuman
  if(!encoders_initd) {
226
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
227 1461 bneuman
    return ERROR_LIBRARY_NOT_INITD;
228 1543 bneuman
  }
229 1461 bneuman
230
  if(encoder==LEFT)
231
    left_dx = 0;
232
  else if(encoder==RIGHT)
233
    right_dx = 0;
234
235
  return 0;
236 868 justin
}
237
238
/**
239
* @brief Returns the number of encoder reads that have occurred.
240
*
241
* @return The time count.
242
*/
243
int encoder_get_tc(void) {
244
        return timecount;
245
}
246
247
/**
248
* @brief Resets the encoder read counter.
249 1461 bneuman
* @return 0 if init succesfull, an error code otherwise
250 868 justin
*/
251 1461 bneuman
int encoder_rst_tc(void) {
252 1543 bneuman
  if(!encoders_initd) {
253
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
254 1461 bneuman
    return ERROR_LIBRARY_NOT_INITD;
255 1543 bneuman
  }
256 1461 bneuman
257
  timecount = 0;
258
259
  return 0;
260 868 justin
}
261
262
/**
263
* @brief Waits until n encoder reads have occurred.
264
* Counter is reset on functions exit.
265
*
266
* @param n
267 1461 bneuman
*
268
* @return 0 if init succesfull, an error code otherwise
269 868 justin
*/
270 1461 bneuman
int encoder_wait(int n){
271 1543 bneuman
  if(!encoders_initd) {
272
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
273 1461 bneuman
    return ERROR_LIBRARY_NOT_INITD;
274 1543 bneuman
  }
275 1461 bneuman
276
  while(data_ready<n);
277
  data_ready=0;
278
279
  return 0;
280 868 justin
}
281
282 1461 bneuman
/**
283
 * @brief This functions recieves data from the encoders directly
284
 *
285
 * @note Full reads occur every 40 microseconds. This function should be called every 8 microseconds.
286
 *
287
 * @return 0 if init succesfull, an error code otherwise
288
 */
289
int encoder_recv(char data){
290
  short int dx;
291 868 justin
292 1543 bneuman
  if(!encoders_initd) {
293
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
294 1461 bneuman
    return ERROR_LIBRARY_NOT_INITD;
295 1543 bneuman
  }
296 1461 bneuman
297
  //Parse the encoder data, comes in over 5 bytes 16 bits per encoder,
298
  // second is offset by 1 bit.
299
  switch(encoder_buf_index){
300
  case 0:
301
    right_data_buf |= ((short)data)<<8 & 0xff00;
302
    break;
303
  case 1:
304
    right_data_buf |= ((short)data) & 0xff;
305
    break;
306
  case 2:
307
    left_data_buf |= (((short)data) << 9) & (0x7F << 9);
308
    break;
309
  case 3:
310
    left_data_buf |= (((short)data) << 1) & (0xFF<<1);
311
    break;
312
  case 4: left_data_buf |= (((short)data)>>7) & 0x1;
313
  }
314 868 justin
315 1461 bneuman
  encoder_buf_index = (encoder_buf_index + 1) % 5;
316 868 justin
317 1461 bneuman
  if(encoder_buf_index==0) {
318 868 justin
319 1461 bneuman
    /*Error handling for the left encoder*/
320
    if(!(left_data_buf & OCF))
321
      left_data = ENCODER_DATA_NOT_READY;
322
    if(left_data_buf & (COF | LIN))
323
      left_data = ENCODER_MISALIGNED;
324
    else if((left_data_buf & MagINCn) && (left_data_buf & MagDECn))
325
      left_data = ENCODER_MAGNET_FAILURE;
326
    else left_data = (left_data_buf>>5) & 1023;
327 868 justin
328 1461 bneuman
    /*Error handling for the right encoder*/
329
    if(!(right_data_buf & OCF))
330
      right_data = ENCODER_DATA_NOT_READY;
331
    if(right_data_buf & (COF | LIN))
332
      right_data = ENCODER_MISALIGNED;
333
    else if ((right_data_buf & MagINCn)  && (right_data_buf & MagDECn))
334
      right_data = ENCODER_MAGNET_FAILURE;
335
    else right_data = (right_data_buf>>5) & 1023;
336 868 justin
337 1461 bneuman
    left_data_buf = 0;
338
    right_data_buf = 0;
339 868 justin
340 1461 bneuman
    /*Note: Above 1023 is invalid data*/
341
    if(!(left_data > 1023)) {
342
      //Reverse the left wheel since encoders are necessarily mounted backwards.
343
      left_data = 1023 - left_data;
344
      left_data_array_put(left_data);
345 868 justin
346 1461 bneuman
      //Adjust left accumulator
347
      dx = left_data - left_data_array_prev();
348 868 justin
349 1461 bneuman
      if(left_data_array_prev()==0)  dx=0;
350 868 justin
351 1461 bneuman
      if(dx > 512) left_dx += dx - 1023; //Underflow
352
      else if(dx < -512) left_dx += dx + 1023; //Overflow
353
      else left_dx += dx;
354
    }
355 868 justin
356 1461 bneuman
    /*Above 1023 is invalid data*/
357
    if(!(right_data > 1023)) {
358
      right_data_array_put(right_data);
359 868 justin
360 1461 bneuman
      //Adjust right accumulator
361
      dx = right_data - right_data_array_prev();
362 868 justin
363 1461 bneuman
      if(right_data_array_prev()==0) dx=0;
364 868 justin
365 1461 bneuman
      if(dx > 512) right_dx += dx - 1023; //underflow
366
      else if(dx < -512) right_dx += dx + 1023; //overflow
367
      else right_dx += dx;
368
    }
369
  }
370 868 justin
371 1461 bneuman
  //Increment timecount accumulator
372
  timecount++;
373
374
  return 0;
375 868 justin
}
376
377
378
//Helper Functions
379
inline void left_data_array_put(unsigned short int value) {
380
        if(left_data_idx == BUFFER_SIZE-1)
381
                left_data_idx = 0;
382
        else
383
                left_data_idx++;
384
        left_data_array[left_data_idx] = value;
385
}
386
387
inline unsigned int left_data_array_top(void) {
388
        return left_data_array[left_data_idx];
389
}
390
391
inline unsigned int left_data_array_prev(void) {
392
        if(left_data_idx == 0)
393
                return left_data_array[BUFFER_SIZE-1];
394
        else
395
                return left_data_array[left_data_idx - 1];
396
}
397
398
inline unsigned int left_data_array_bottom(void) {
399
        if(left_data_idx == BUFFER_SIZE-1)
400
                return left_data_array[0];
401
        else
402
                return left_data_array[left_data_idx + 1];
403
}
404
405
inline void right_data_array_put(unsigned short int value) {
406
        if(right_data_idx == BUFFER_SIZE-1)
407
                right_data_idx = 0;
408
        else
409
                right_data_idx++;
410
        right_data_array[right_data_idx] = value;
411
}
412
413
inline unsigned int right_data_array_top(void) {
414
        return right_data_array[right_data_idx];
415
}
416
417
inline unsigned int right_data_array_prev(void) {
418
        if(right_data_idx == 0)
419
                return right_data_array[BUFFER_SIZE-1];
420
        else
421
                return right_data_array[right_data_idx - 1];
422
}
423
424
inline unsigned int right_data_array_bottom(void) {
425
        if(right_data_idx == BUFFER_SIZE-1)
426
                return right_data_array[0];
427
        else
428
                return right_data_array[right_data_idx + 1];
429
}
430
431 1418 chihsiuh
/* Helper functions for encoder_get_v */
432
int left_data_at(int index) {
433
    int tmp_idx = left_data_idx - index;
434
    if (tmp_idx < 0)
435
        tmp_idx += BUFFER_SIZE;
436
    return left_data_array[tmp_idx];
437
}
438
439
int right_data_at(int index) {
440
    int tmp_idx = right_data_idx - index;
441
    if (tmp_idx < 0)
442
        tmp_idx += BUFFER_SIZE;
443
    return right_data_array[tmp_idx];
444
}
445
446
int get_dx(char encoder, int index) {
447
    int dx, ctr;
448
    ctr = 0;
449
    dx = 1024;
450
    do {
451
        if (encoder == LEFT)
452
            dx = left_data_at(index+ctr) - left_data_at(index+ctr+38);
453
        else
454
            dx = right_data_at(index+ctr) - right_data_at(index+ctr+38);
455
        ctr++;
456
    } while ((dx > 30 || dx < -30) && ctr < 3);
457
    if (dx > 30 || dx < -30)
458
        return ERR_VEL;
459
    return dx;
460
}