-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTachoNav.nxc
179 lines (161 loc) · 5.58 KB
/
TachoNav.nxc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#ifndef ____TachoNavLoad____
#define ____TachoNavLoad____
#include "Lib/LibV2.c"
#include "Lib/LineLib.c"
struct tnFlags
{
float WheelBaseWidth;
float WheelDiameter;
float heading;
char leftMotor;
char rightMotor;
Vector2f position;
long tacL;
long tacR;
};
tnFlags tnFlagsReadOnly;
void tnSetFlags(float wheelbaseWidth, float wheelDiameter,
char outLeft, char outRight)
{
tnFlagsReadOnly.leftMotor = outLeft;
tnFlagsReadOnly.rightMotor = outRight;
tnFlagsReadOnly.WheelBaseWidth = wheelbaseWidth;
tnFlagsReadOnly.WheelDiameter = wheelDiameter;
tnFlagsReadOnly.heading = 90.0;
tnFlagsReadOnly.position = v2New(0,0);
}
void tnSetDefaults()
{
tnFlagsReadOnly.WheelBaseWidth = 0.135 * PI;
tnFlagsReadOnly.WheelDiameter = 0.057 * PI;
tnFlagsReadOnly.leftMotor = OUT_A;
tnFlagsReadOnly.rightMotor = OUT_C;
tnFlagsReadOnly.heading = 90.0;
tnFlagsReadOnly.position = v2New(0,0);
}
tnFlags __updateHeadingPosition(tnFlags __flags__)
{
//calculate positions and distances in local coordinates
float degL =
(MotorTachoCount(__flags__.leftMotor) -
__flags__.tacL);
float degR =
(MotorTachoCount(__flags__.rightMotor) -
__flags__.tacR);
float distL = PI * __flags__.WheelDiameter * degL / 360.0;
float distR = PI * __flags__.WheelDiameter * degR / 360.0;
//determine the current wheel position in local coors
Vector2f TCur, TPrev, L0, L1, R0, R1, C0;
L0 = v2New(__flags__.WheelBaseWidth / -2.0, 0);
R0 = v2New(__flags__.WheelBaseWidth / 2.0, 0);
L1 = v2New(L0.X, distL);
R1 = v2New(R0.X, distR);
C0 = __flags__.position;
//In the special case where wheels barely move,
//or the wheels move in sync so there is minimal turning,
//we're simply going to add the distance and convert back to globals
bool leftNearZero = abs(degL) <= 2.0;
bool rightNearZero = abs(degR) <= 2.0;
bool isTurning = (distL - distR) > (distL + distR) / 256.0;
if((leftNearZero && rightNearZero) || !isTurning)
{
Vector2f C1 = v2Midpoint(L1,R1);
__flags__.heading += v2AngleBetween(
v2Dif(L1,R1),
v2Dif(L0,R0));
__flags__.position += v2Mult(
v2FromAngle(__flags__.heading),
v2Length(C1));
__flags__.tacL = MotorTachoCount(__flags__.leftMotor);
__flags__.tacR = MotorTachoCount(__flags__.rightMotor);
return __flags__;
}
//special case where one wheel is stationary
//we only need one itteration, with the stationary wheel as pivot
if(leftNearZero || rightNearZero)
{
if(leftNearZero)
{
TCur = L0;
L1 = L0;
float RadR = v2Dist(R0, TCur);
R1 = v2Mult(v2FromAngle(360.0 * distR / RadR), RadR);
if(TCur.X >= R0.X)
R1 = v2ReflectY(R1);
R1 = v2Dif(TCur, R1);
}
if(rightNearZero)
{
TCur = R0;
R1 = R0;
float RadL = v2Dist(L0, TCur);
L1 = v2Mult(v2FromAngle(360.0 * distL / RadL), RadL);
if(TCur.X >= L0.X)
L1 = v2ReflectY(L1);
L1 = v2Dif(TCur, L1);
}
Vector2f C1 = v2Midpoint(L1,R1);
__flags__.position += v2RotateAbout(v2Zero,
C1, __flags__.heading);
__flags__.heading += v2AngleBetween(
v2Dif(L1,R1),
v2Dif(L0,R0));
__flags__.tacL = MotorTachoCount(__flags__.leftMotor);
__flags__.tacR = MotorTachoCount(__flags__.rightMotor);
return __flags__;
}
//Primary case where both wheels move a different non-zero amount
//T is the turn pivot
TCur = l2Intercept(l2NewPtPt(L0,R0), l2NewPtPt(L1,R1));
TPrev = v2New(0,100);
//Itterate until our turn point is accurate to within a small margin
while(v2Dist(TCur,TPrev) > 0.1)
{
TPrev = TCur;
//circle radius to project distance onto
float RadL = v2Dist(L0, TCur);
float RadR = v2Dist(R0, TCur);
//new endpoints from distance over arc,
//rather than straight line
L1 = v2Mult(v2FromAngle(360.0 * distL / RadL), RadL);
R1 = v2Mult(v2FromAngle(360.0 * distR / RadR), RadR);
if(TCur.X >= L0.X)
L1 = v2ReflectY(L1);
L1 = v2Dif(TCur, L1);
if(TCur.X >= R0.X)
R1 = v2ReflectY(R1);
R1 = v2Dif(TCur, R1);
TCur = l2Intercept(l2NewPtPt(L0,R0), l2NewPtPt(L1,R1));
}
//take the last itteration's end points as final
//and update our flags
Vector2f C1 = v2Midpoint(L1,R1);
__flags__.position += v2RotateAbout(v2Zero,
C1, __flags__.heading);
__flags__.heading += v2AngleBetween(
v2Dif(L1,R1), v2Dif(L0,R0));
__flags__.tacL = MotorTachoCount(__flags__.leftMotor);
__flags__.tacR = MotorTachoCount(__flags__.rightMotor);
return __flags__;
}
task NavigateByTachometer()
{
tnFlags flags = tnFlagsReadOnly;
unsigned int time;
unsigned int delta;
while(true)
{
time = CurrentTick();
flags = __updateHeadingPosition(flags);
delta = CurrentTick() - time;
if(delta < 10)
Wait(10 - delta);
else
PlayTone(4000, 50);
}
}
void tnStop()
{
StopTask(NavigateByTachometer);
}
#endif