Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (11.3 KB)

1
/**
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
#include "spi.h"
40
#include "ring_buffer.h"
41
#include "encoders.h"
42

    
43
unsigned char encoders_initd=0;
44

    
45
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
int encoder_recv(char data);
64

    
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
//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

    
81
void encoder_recv_complete(void){
82
          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
int encoders_init(void){
92
  int i;
93
        
94
  if(encoders_initd) {
95
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders already init'd\r\n");
96
    return ERROR_INIT_ALREADY_INITD;
97
  }
98

    
99
  data_ready=0;
100

    
101
  if(spi_init(encoder_recv, encoder_recv_complete)) {
102
    DRAGONFLY_DEBUG_PRINT("ERROR: SPI was already init'd, bailing out\r\n");
103
    return -1; //if spi was inited for something else, bail out
104
  }
105
  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
}
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
 * @return the value of the specified encoder.
135
 *         -1 usually means low battery.
136
 *         -2 means the library was not properly initialized
137
 *         values above ENCODER_MAX usually means phyiscal problems with
138
 *         the encoder.
139
 **/
140
int encoder_read(char encoder){
141
  if(!encoders_initd) {
142
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
143
    return -2;
144
  }
145

    
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
}
156

    
157
/**
158
 * @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
 * 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
 * @return The distance covered by the specified encoder, -2 if the library is not initialized
176
 **/
177
int encoder_get_dx(char encoder) {
178
  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
}
188

    
189
/** 
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

    
204
    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
/**
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
int encoder_rst_dx(char encoder) {
224

    
225
  if(!encoders_initd) {
226
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
227
    return ERROR_LIBRARY_NOT_INITD;
228
  }
229

    
230
  if(encoder==LEFT)
231
    left_dx = 0;
232
  else if(encoder==RIGHT)
233
    right_dx = 0;
234

    
235
  return 0;
236
}
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
* @return 0 if init succesfull, an error code otherwise
250
*/
251
int encoder_rst_tc(void) {
252
  if(!encoders_initd) {
253
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
254
    return ERROR_LIBRARY_NOT_INITD;
255
  }
256

    
257
  timecount = 0;
258

    
259
  return 0;
260
}
261

    
262
/** 
263
* @brief Waits until n encoder reads have occurred.
264
* Counter is reset on functions exit.
265
* 
266
* @param n 
267
*
268
* @return 0 if init succesfull, an error code otherwise
269
*/
270
int encoder_wait(int n){
271
  if(!encoders_initd) {
272
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
273
    return ERROR_LIBRARY_NOT_INITD;
274
  }
275

    
276
  while(data_ready<n);
277
  data_ready=0;
278

    
279
  return 0;
280
}
281

    
282
/**
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

    
292
  if(!encoders_initd) {
293
    DRAGONFLY_DEBUG_PRINT("ERROR: encoders not init'd\r\n");
294
    return ERROR_LIBRARY_NOT_INITD;
295
  }
296

    
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
                
315
  encoder_buf_index = (encoder_buf_index + 1) % 5;
316

    
317
  if(encoder_buf_index==0) {
318
                
319
    /*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
                        
328
    /*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
                        
337
    left_data_buf = 0;
338
    right_data_buf = 0;
339

    
340
    /*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

    
346
      //Adjust left accumulator
347
      dx = left_data - left_data_array_prev();
348
                        
349
      if(left_data_array_prev()==0)  dx=0;
350

    
351
      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

    
356
    /*Above 1023 is invalid data*/        
357
    if(!(right_data > 1023)) {
358
      right_data_array_put(right_data);
359

    
360
      //Adjust right accumulator
361
      dx = right_data - right_data_array_prev();
362

    
363
      if(right_data_array_prev()==0) dx=0;
364
                          
365
      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

    
371
  //Increment timecount accumulator
372
  timecount++;
373

    
374
  return 0;
375
}
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
/* 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
}