Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / mapping / odometry / odometry.c @ 947

History | View | Annotate | Download (3.83 KB)

1
#include "odometry.h"
2
#include <encoders.h>
3
#include <math.h>
4
#include <avr/interrupt.h>
5
#include <dragonfly_lib.h>
6

    
7
int encoder_ltm1, encoder_rtm1;
8

    
9
//Measures mm displacement in x and y from starting position. (+x:theta=0 +y:theta=M_PI/2)
10
long diff_x,diff_y;
11

    
12
//Measures radian angle displacement from starting position. (initially 0)
13
double angle;
14

    
15

    
16
long odometry_dx(void){
17
        return diff_x;
18
}
19

    
20
long odometry_dy(void){
21
        return diff_y;
22
}
23

    
24
double odometry_angle(void){
25
        return angle;
26
}
27

    
28
void odometry_init(void){
29
        
30
        encoders_init();
31
        
32
        delay_ms(100);
33

    
34
        odometry_reset();
35

    
36
        
37
        //CTC Mode. CLK / 1024
38
        TCCR2 = 0; // (Fully disconnected)
39
        TCCR2 = _BV(WGM21) | _BV(CS22) | _BV(CS20); //CLK/1024 , CTC Mode.
40

    
41
        TIMSK |= _BV(OCIE2);
42

    
43
        OCR2 = ODOMETRY_CLK;
44
}
45

    
46
void odometry_reset(void){
47
        diff_x = 0;
48
        diff_y = 0;
49
        encoder_ltm1 = encoder_read(LEFT);
50
        encoder_rtm1 = encoder_read(RIGHT);
51
        angle = 0.0;
52
}
53

    
54
/*Currently assumes robot only goes forward (neither wheel goes backward).
55
void odometry_run(void){
56
        double theta;
57
        int encoder_left, encoder_right,dl,dr; 
58
        long distance_um;
59
        char buf[100];        
60
        //Relative to the inner wheel, the radius of its turn.
61
        double turning_radius;
62

63
        encoder_left = encoder_read(LEFT);        
64
        encoder_right = encoder_read(RIGHT);        
65
        
66
        dl = encoder_left - encoder_ltm1;
67
        dr = encoder_right - encoder_rtm1;
68

69
        dl = dl > 512 ? dl - 1024 :dl;
70
        dl = dl < -512 ? dl + 1024 :dl;
71
        dr = dr > 512 ? dr - 1024 :dr;
72
        dr = dr < -512 ? dr + 1024 :dr;
73

74
        //idle?
75
        if(dl < 2 && dr < 2) return;
76

77
        if(dl == dr){
78
                distance_um = dl*CLICK_DISTANCE_UM;
79
                diff_x += distance_um*cos(angle)/1000; 
80
                diff_y += distance_um*sin(angle)/1000; 
81
                //sprintf(buf,"Distance in um: %d\n\r",distance_um);
82
                //usb_puts(buf);
83
                return;
84
        }
85
        
86
        if(dr > dl){ //CCW positive.
87
                turning_radius = ROBOT_WIDTH_UM * dl / (dr - dl); //um
88
                theta = ((double)(dr-dl)*CLICK_DISTANCE_UM) / ((double)ROBOT_WIDTH_UM);
89
                distance_um = theta*((double)(turning_radius + ROBOT_WIDTH_UM/2)); 
90
        }
91
        else{ //CW negative.
92
                turning_radius = ROBOT_WIDTH_UM * dr / (dl - dr); //um
93
                theta = -((double)(dl-dr)*CLICK_DISTANCE_UM) / ((double)ROBOT_WIDTH_UM);
94
                distance_um = -theta*((double)(turning_radius + ROBOT_WIDTH_UM/2)); 
95
                
96
        }
97
        
98
        //sprintf(buf,"Distance in um: %d\n\r",distance_um);
99
        //usb_puts(buf);
100

101
        diff_x += distance_um * cos(angle)/1000;
102
        diff_y += distance_um * sin(angle)/1000;
103
        
104
        angle += theta;
105

106
        encoder_ltm1 = encoder_left;
107
        encoder_rtm1 = encoder_right;
108
}*/
109

    
110

    
111
/*Generalized version of odometry.*/
112
void odometry_run(void){
113
        //Angle swept through in a time step CCW-
114
        double theta, rl, dc;
115
        long dr,dl;
116
        
117
        //Get the change in wheel positions
118
        {        
119
                int encoder_right = encoder_read(RIGHT);        
120
                int encoder_left = encoder_read(LEFT);        
121
        
122
                dl = encoder_left - encoder_ltm1;
123
                dr = encoder_right - encoder_rtm1;
124
                
125
                //No motion.
126
                if(dl == 0 && dr == 0) return;
127

    
128
                encoder_ltm1 = encoder_left;
129
                encoder_rtm1 = encoder_right;
130
        
131
                // Try to avoid over/underflow.
132
                dl = dl > 512 ? dl - 1024 :dl;
133
                dl = dl < -512 ? dl + 1024 :dl;
134
                dr = dr > 512 ? dr - 1024 :dr;
135
                dr = dr < -512 ? dr + 1024 :dr;
136
        
137
                //Convert "clicks" to um
138
                dl *= CLICK_DISTANCE_UM; //um
139
                dr *= CLICK_DISTANCE_UM;
140
        }
141
        
142

    
143
        if(dl == dr){
144
                diff_x += lround(dl*cos(angle)/1000.0); //mm
145
                diff_y += lround(dl*sin(angle)/1000.0); //mm
146
                return;
147
        }
148
        
149
        //Call the left wheel 0, clockwise positive.
150
        rl = ((double)(ROBOT_WIDTH_UM*dl))/((double)(dl - dr)); //um
151
        theta = ((double)(dl - dr))/((double)ROBOT_WIDTH_UM);   //rad
152
        
153
        //Distance the center has traveled.
154
        dc = lround( (theta * (rl - ROBOT_WIDTH_UM)) / 2.0 ); //um
155
        
156
        //angle is necessarily CCW+, so subtract.
157
        angle -= ANGLE_SCALE * theta; 
158
        
159
        //Change state variables.        
160
        diff_x += lround((DISTANCE_SCALE * dc * cos(angle))/1000.0); //mm
161
        diff_y += lround((DISTANCE_SCALE * dc * sin(angle))/1000.0); //mm
162
}
163

    
164
ISR(TIMER2_COMP_vect){
165
        odometry_run(); 
166
}
167

    
168
long lround(double d){
169
        double f = floor(d);
170
        return (long)(d - f > 0.5 ? f + 1 : f);
171
}
172

    
173