Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / linefollowing / lineFollow.c @ 1961

History | View | Annotate | Download (10.7 KB)

1
/**
2
 * @file lineFollow.c
3
 * @defgroup lineFollwing Line Following
4
 *
5
 * Takes care of following a line. Running this program is done by calling the
6
 * init() function and then the lineFollow(speed) command.  However, direct use
7
 * of this class is discouraged as its behavior is used by lineDrive.c, which
8
 * extends this class to provide behavior functionality.
9
 *
10
 * @author Dan Jacobs and the Colony Project
11
 * @date 11-1-2010
12
 */
13

    
14
#include "lineFollow.h"
15

    
16
//! The number of bits expected in a barcode
17
#define CODESIZE 5 
18
#define LINE_COLOR 200
19

    
20

    
21
int countHi = 0;
22
int countLo = 0;
23
int maxAvg, avg;
24

    
25
// Everything has a dimension of 2 for left and right readings
26
int barCode[2][ CODESIZE ];
27
int barCodePosition[2]={0};
28

    
29
int duration[2] = {0};
30
int lastColor[2] = {0};
31
char isReset[2] = {1};
32
int lastReadings[2][ NUM_READINGS ] = {{0}};
33
int lastReadingsPtr[2] = {0};
34
int numLast[2][3] = { {NUM_READINGS, 0, 0}, {NUM_READINGS, 0, 0} };
35
int bitColor[2] = {0};
36

    
37
int turnDistance=0;
38
//! Counts the number of full line readings before we determine an intersection
39
int intersectionFilter=0;
40
int disableBarCode=0;
41

    
42
//! Keeps track of where the encoder of one motor started, for use in turns.
43
int encoderStart = -1;
44
int encoderReset = 0;   // 0 if encoderStart has no value set
45

    
46

    
47
void lineFollow_init()
48
{
49
        analog_init(0);
50
    encoders_init();
51
        lost = 0;
52
        intersectionFilter=0;
53
        disableBarCode=0;
54
}
55

    
56

    
57
/** 
58
 * Follows a line at the given speed.
59
 * @param speed The speed with which to follow the line.
60
 */
61
int lineFollow(int speed)
62
{
63
        int colors[5];
64
        int position;
65
        
66

    
67
        updateLine(colors);
68
        position = lineLocate(colors);         
69
        
70
        //not on line
71
        if(position == NOLINE)
72
        {
73
                if(lost++ > 20)
74
                {
75
                        orb2_set_color(GREEN);
76
                        motors_off();
77
                        return LINELOST;
78
                }
79
        }
80
        else if(position == FULL_LINE)
81
        {
82
                if(intersectionFilter++ > 4)
83
                {
84
                        orb2_set_color(RED);
85
                        barCodePosition[0]=0;
86
            barCodePosition[1]=0;
87
                        disableBarCode=50;
88
                }
89
        }
90
        //on line
91
        else
92
        {
93
                position*=30;
94
                orb2_set_color(ORB_OFF);
95
                motorLeft(min(speed+position, 255));
96
                motorRight(min(speed-position, 255));
97
                lost=0;
98
                intersectionFilter=0;
99
        }
100

    
101
    // If we're running over a line, stop reading barcodes for a sec
102
        if(disableBarCode-- > 0)
103
        {
104
        // Return intersection once we cross the line
105
                if(disableBarCode) return NOBARCODE;
106
                return INTERSECTION;
107
        }
108
        updateBarCode();
109
        return getBarCode();
110
}
111

    
112

    
113
/**
114
 * Implements the left merge, assuming a line exists to the left.  Works by
115
 * turning off the line at an increasing angle and waiting to hit another line
116
 * on the left.
117
 */
118
int mergeLeft()
119
{
120
        motor_l_set(FORWARD, 200);
121
        if(turnDistance!=21)motor_r_set(FORWARD, 230);
122
        else motor_r_set(FORWARD, 210);
123
        int colors[5];
124
        updateLine(colors);
125
        int position = lineLocate(colors);
126
        if(position>3 || position<-3)turnDistance++;
127

    
128
        if(turnDistance>20)
129
        {
130
        turnDistance=21;
131
        
132
                if(position<3 && position>-3)
133
                {
134
                        turnDistance = 0;
135
                        return 0;
136
                }        
137
        }
138
        return 1;
139
}
140

    
141

    
142
/**
143
 * Implements the right merge, assuming a line exists to the right.  Works by
144
 * turning off the line at an increasing angle and waiting to hit another line
145
 * on the right.
146
 */
147
int mergeRight()
148
{
149
        motor_r_set(FORWARD, 200);
150
        if(turnDistance!=21)motor_l_set(FORWARD, 230);
151
        else motor_l_set(FORWARD, 210);
152
        int colors[5];
153
        updateLine(colors);
154
        int position = lineLocate(colors);
155
        if(position>3 || position<-3)turnDistance++;
156

    
157
        if(turnDistance>20)
158
        {
159
        turnDistance=21;
160

    
161
                if(position<3 && position>-3)
162
                {
163
                        turnDistance = 0;
164
                        return 0;
165
                } 
166
        }
167
        return 1;
168
}
169

    
170

    
171

    
172
/**
173
 * Turns left at a cross of two lines.  Assumes that we are at lines in a cross
174
 * pattern, and turns until it sets straight on the new line.
175
 * @return 0 if turn finishes otherwise return 1
176
 */
177
int turnLeft()
178
{
179
        /*motor_l_set(BACKWARD, 200);
180
        motor_r_set(FORWARD, 200);
181
        int colors[5];
182
        updateLine(colors);
183
        int position = lineLocate(colors);
184
        if(position>2 || position<-2)turnDistance++;
185
        if(turnDistance>1)
186
        {
187
                if(position<3 && position>-3)
188
                {
189
                        turnDistance = 0;
190
                         return 0;
191
                }
192
        }
193
        return 1;*/
194

    
195
        motor_l_set(BACKWARD,200);
196
        motor_r_set(FORWARD,200);
197
        if(!encoderReset)
198
        {
199
            encoderStart = encoder_get_x(RIGHT);
200
            encoderReset = 1;
201
        }
202

    
203
        if(encoder_get_x(RIGHT) < encoderStart)
204
        {
205
            encoderStart = 0;
206
            // Temporary: display an "error message" in case of overflow.
207
            // Using this for debugging, take it out soon!
208
            motor_l_set(FORWARD,0);
209
            motor_r_set(FORWARD,0);
210
            //orb_set_color(WHITE);
211
            delay_ms(2000);
212
        }
213

    
214
        if(encoder_get_x(RIGHT) - encoderStart > 300)
215
        {
216
            encoderReset = 0;
217
            return 0;
218
        }
219
        return 1;
220
}
221

    
222

    
223

    
224
/**
225
 * Turns right at a cross of two lines.  Assumes that we are at lines in a cross
226
 * pattern, and turns until it sets straight on the new line.
227
 * @return 0 if the turn finishes otherwise return 1
228
 */
229
int turnRight()
230
{
231
        motor_r_set(BACKWARD, 200);
232
        motor_l_set(FORWARD, 200);
233
        int colors[5];
234
        updateLine(colors);
235
        int position = lineLocate(colors);
236
        if(position>2 || position<-2)turnDistance++;
237
        if(turnDistance>1) 
238
        {
239
                if(position<3 && position>-3)
240
                {
241
                        turnDistance = 0;
242
                         return 0;
243
                }
244
        }
245
        return 1;
246
}
247

    
248

    
249

    
250
int getBarCode()
251
{
252
        if(barCodePosition[1] != CODESIZE)
253
        return NOBARCODE ;
254
    else
255
    {
256
        int temp = 0;
257
        for(int i=0; i<CODESIZE; i++)
258
            temp += (barCode[1][i] << i);
259
        barCodePosition[1] = 0;
260
        return temp;
261
    }
262
}
263

    
264

    
265

    
266
void updateLine(int* values)
267
{        
268
        for(int i = 0; i<5; i++)
269
                values[i] = (read_line(4-i) < LINE_COLOR ? LWHITE : LBLACK);
270
}
271

    
272

    
273

    
274
int lineLocate(int* colors)
275
{
276
        int i;
277
        int wsum = 0;
278
        int count=0;
279

    
280
        for(i = 0; i<5; i++)
281
        {
282
                count += colors[i]/2;
283
                wsum += (i)*colors[i];
284
        }
285
        if(count==0)
286
                return NOLINE;        
287
        if(count==5)
288
                return FULL_LINE;
289
        return (wsum/count)-4; // Subtract 4 to center the index around the center.
290
}
291

    
292
void addToBuckets(int curColor, int i)
293
{
294
    int oldest = lastReadings[i][lastReadingsPtr[i]];
295
    numLast[i][oldest]--;
296
    lastReadings[i][lastReadingsPtr[i]] = curColor;
297
    lastReadingsPtr[i] = (lastReadingsPtr[i]+1) % NUM_READINGS;
298
    numLast[i][curColor]++;
299

    
300
    /*usb_puts("Totals: ");
301

302
    for(int j=0; j<=2; j++)
303
    {
304
        usb_puts("[");
305
        usb_puti(j);
306
        usb_puts("]: ");
307
        usb_puti(numLast[i][j]);
308
        usb_puts(" ");
309
    }
310
    usb_puts("\n");*/
311
}
312

    
313

    
314
void updateBarCode()
315
{
316
    // USING THESE GLOBAL VARIABLES
317
    // global int duration = 0;
318
    // global int lastColor = 0;
319
    // global int barCodePosition = 0;
320
    // global char isReset = 0;
321

    
322
    // Just uses one sensor for now
323
    for(int i = /*RIGHT*/LEFT_SENSOR; i <= LEFT_SENSOR; i++)
324
    {
325
        // Add 6 to convert left (1) and right (0) to sensor 6 and 7
326
        int curReading = read_line(i + 6);
327
        int curColor;
328

    
329
        if(curReading > BLACK_THRESHOLD)
330
        {
331
            //usb_puts("LBLACK  ");
332
            curColor = LBLACK;
333
        }
334
        else if(curReading < GREY_THRESHOLD)
335
        {
336
            //usb_puts("LWHITE");
337
            curColor = LWHITE;
338
        }
339
        else
340
        {
341
            //usb_puts("LGREY");
342
            curColor = LGREY;
343
        }
344

    
345
        addToBuckets(curColor, i);
346

    
347
        // Just an error check
348
        if(barCodePosition[i] > CODESIZE)
349
        {
350
            barCodePosition[i] = 0;
351
        }
352

    
353
        // We now edit curColor to use the majority of the last buckets.
354
        for(int j = 0; j <= 2; j++)
355
        {
356
            if(numLast[i][1] > NUM_READINGS / 2)
357
            {
358
                curColor = LGREY;
359
            }
360
            else if(numLast[i][2] > NUM_READINGS / 2)
361
            {
362
                curColor = LBLACK;
363
            }
364
            else if(numLast[i][0] > NUM_READINGS / 2)
365
            {
366
                curColor = LWHITE;
367
                duration[i]++;
368
            }
369
            else
370
            {
371
                curColor = NOBARCODE;
372
            }
373
        }
374

    
375
        if(curColor != NOBARCODE)
376
        {
377
            // Now we assume our reading is significant - a bit, or a white space
378

    
379
            if(bitColor[i] == LGREY || bitColor[i] == LWHITE)
380
                bitColor[i] = curColor;
381

    
382
            // Only read a value if we have read 0 first (isReset == 1)
383
            if(isReset[i] && (curColor == LBLACK || curColor == LGREY) )
384
            {
385

    
386
                /*if(barCodePosition[i] == 0)
387
                {
388
                    // testing encoder use
389
                    encoder_rst_dx(LEFT);
390
                    encoder_rst_dx(RIGHT);
391
                    usb_puts("Encoders reset.\n");
392
                }*/
393

    
394
                isReset[i] = 0;
395
                /*if(i==0)
396
                {
397
                    usb_puts("Read barcode bit: ");
398
                    usb_puti(barCodePosition[i]);
399
                    usb_puts(" = ");
400
                    usb_puti(curColor);
401
                    usb_puts(", curReading = ");
402
                    usb_puti(curReading);
403
                    usb_puts(".\n");
404
                }*/
405

    
406
                /*if(curColor == LBLACK)
407
                {
408
                    orb_set_color(RED);
409
                }
410
                else
411
                {
412
                    orb_set_color(BLUE);
413
                }*/
414

    
415
                duration[i] = 0;
416
            }
417
            else if(curColor == LWHITE)
418
            {
419
                if(!isReset[i])
420
                {
421
                    barCode[i][barCodePosition[i]++] = 
422
                        (bitColor[i] == LBLACK) ? 1 : 0;
423
                    usb_puts("Reset. Read bit: ");
424
                    usb_puti(bitColor[i]);
425
                    usb_puts("\n");
426

    
427
                    bitColor[i] = LWHITE;
428
                }
429
                isReset[i] = 1;
430
                orb_set(0, 0, 0);
431
            }
432
        }
433

    
434
        if(curColor == LWHITE && duration[i] > TIMEOUT_DURATION 
435
            && barCodePosition[i] != 0)
436
        {
437
            usb_puts("TIMED OUT. BARCODE READER RESET.\n");
438
            usb_puts("Encoders: ");
439
            usb_puti(encoder_get_dx(LEFT));
440
            usb_puts(", ");
441
            usb_puti(encoder_get_dx(RIGHT));
442
            usb_puts("\n");
443
            barCodePosition[i] = 0;
444
            duration[i] = 0;
445
            isReset[i] = 1;
446
        }
447
    }
448
}
449

    
450

    
451
int min(int x, int y){return x>y ? y : x;}
452
int max(int x, int y){return x<y ? y : x;}
453

    
454
void motorLeft(int speed){
455
        ((speed-=127)>=0)?motor_l_set(FORWARD, 160+speed*95/128):motor_l_set(BACKWARD, 160-speed*95/127);
456
}
457

    
458
void motorRight(int speed){
459
        ((speed-=127)>=0)?motor_r_set(FORWARD, 160+speed*95/128):motor_r_set(BACKWARD, 160-speed*95/127);
460
}