libnxter  0.1
AlphaRexPlus.nxc
Go to the documentation of this file.
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  AlphaRexPlus.nxc
4  Copyright (C) 2008 Naba Kumar <naba@gnome.org>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
25 /* Power assignments */
26 #define MOTOR_POWER_FAST 100
27 #define MOTOR_POWER_MODERATE 75
28 #define MOTOR_POWER_SLOW 30
29 
30 /* MOTOR PID */
31 #define MOTOR_P 450
32 #define MOTOR_I 0
33 #define MOTOR_D 0
34 
35 /* Motor assignments */
36 #define MOTOR_TILT OUT_C
37 #define MOTOR_STRIDE OUT_B
38 #define MOTOR_NECK OUT_A
39 
40 #define NECK_CYCLE 2160
41 
42 /* Sensor assignments */
43 #define TOUCH_SENSOR IN_1
44 #define SOUND_SENSOR IN_2
45 #define LIGHT_SENSOR IN_3
46 #define RANGE_SENSOR IN_4
47 
48 /* Sensor Offset (in cycle percentage) from Neutral alignment */
49 #define TOUCH_SENSOR_OFFSET -25 /* 1/4 Cycle ahead of neutral */
50 #define LIGHT_SENSOR_OFFSET 12 /* 1/10 Cycle before neutral */
51 
52 /* Sound sensor threshold for detecting claps */
53 #define SOUND_SENSOR_THRESHOLD 60 /* Threshold for sound detection */
54 
55 /* Range sensor threshold for detecting obstacle */
56 #define RANGE_SENSOR_THRESHOLD 50 /* cm */
57 
58 /* Light sensor threshold below which proximity is confirmed */
59 #define LIGHT_SENSOR_PROXIMITY_THRESHOLD 40
60 
61 /* Tolerance degrees for cycle caliberation. Cycle count will be trimmed */
62 #define CALIBERATION_ERROR_TOLERANCE 90
63 
64 /* Move commands */
65 #define MOVE_STOP 0
66 #define MOVE_FORWARD 1
67 #define MOVE_LEFT 2
68 #define MOVE_RIGHT 3
69 #define NUM_COMMANDS 4
70 
71 /* Move States */
72 #define LTRF 0 /* Left tilted, right foot ahead */
73 #define CLF 1 /* Center tilted, left foot ahead */
74 #define REST 2 /* Center tilted, feets centered */
75 #define CRF 3 /* Center tilted, right foot ahead */
76 #define RTLF 4 /* Right tilted, left foot ahead */
77 #define NUM_STATES 5
78 
79 /* Action elements index */
80 #define ACTION_ELEMENT_STRIDE_FIRST 0 /* If true, stride first, else tilt first */
81 #define ACTION_ELEMENT_TILT_AMOUNT 1 /* -100 to +100 percentage */
82 #define ACTION_ELEMENT_STRIDE_AMOUNT 2 /* -100 to +100 percentage */
83 #define NUM_ELEMENTS 3
84 
85 /* Macro to retrieve action elements from above state transition action table */
86 #define GetActionElement(int prevState, int nextState, int element) \
87  stateTransitionAction[prevState * NUM_STATES * NUM_ELEMENTS \
88  + nextState * NUM_ELEMENTS \
89  + element]
90 
91 /* Executed upon entering a state */
92 int stateTransitionAction[] = {
93 /* ---------|-----------------------------------------------------------------*/
94 /* | (nextState) */
95 /* prevState| LTRF CLF REST CRF RTLF */
96 /* ---------|-----------------------------------------------------------------*/
97 /* LTRF |*/ 0, 0, 0, 0,-25, 50, 1,-25, 25, 0,-25, 0, 0,-50, 50,
98 /* CLF |*/ 0, 25,-50, 0, 0, 0, 0, 0,-25, 0, 0,-50, 0,-25, 0,
99 /* REST |*/ 0, 25,-25, 0, 0, 25, 0, 0, 0, 0, 0,-25, 0,-25, 25,
100 /* CRF |*/ 0, 25, 0, 0, 0, 50, 0, 0, 25, 0, 0, 0, 0,-25, 50,
101 /* RTLF |*/ 0, 50,-50, 0, 25, 0, 1, 25,-25, 0, 25,-50, 0, 0, 0,
102 /* ---------|------------------------------------------------------------------*/
103 };
104 
105 /* State transitions table */
106 int stateTransition[] = {
107 /* ---------|-----------------------------------------------------------------*/
108 /* | MOVE_STOP MOVE_FORWARD MOVE_LEFT MOVE_RIGHT */
109 /* ---------|-----------------------------------------------------------------*/
110 /* LTRF |*/ REST, RTLF, CLF, RTLF,
111 /* CLF |*/ REST, LTRF, LTRF, RTLF,
112 /* REST |*/ REST, LTRF, LTRF, RTLF,
113 /* CRF |*/ REST, LTRF, LTRF, RTLF,
114 /* RTLF |*/ REST, LTRF, LTRF, CRF,
115 /* ---------|-----------------------------------------------------------------*/
116 };
117 
118 mutex moveMutex;
119 int moveCommand = MOVE_STOP;
120 int moveState = REST;
121 int tiltCycleCount, strideCycleCount;
122 
123 void startMotor(int motor, int power)
124 {
125  SetOutput(motor, OutputMode, OUT_MODE_MOTORON | OUT_MODE_BRAKE);
126  SetOutput(motor, Power, power);
127  SetOutput(motor, UpdateFlags, UF_UPDATE_MODE | UF_UPDATE_SPEED |
128  UF_UPDATE_RESET_BLOCK_COUNT);
129  SetOutput(motor, RunState, OUT_RUNSTATE_RUNNING);
130 }
131 
132 void stopMotor(int motor)
133 {
134  SetOutput(motor, RunState, OUT_RUNSTATE_IDLE);
135  SetOutput(motor, OutputMode, 0);
136  SetOutput(motor, Power, 0);
137  SetOutput(motor, UpdateFlags, UF_UPDATE_SPEED);
138 }
139 
140 int RotateAngle(int motor, int power, int angle, int PValue, int IValue, int DValue)
141 {
142  int pidScale = 1000;
143  int samplePeriod = 20; /* ms */
144  int dt = 1; /* 1dt == 20 msec */
145  int outputScale = 2;
146  int I = 0;
147  int lastError = 0;
148  int steadyStateCount = 0;
149 
150  /* Speed is evaluated in the loop below */
151  startMotor(motor, 0);
152 
153  while(steadyStateCount < 5)
154  {
155  int absPower = Abs(power);
156  int error = angle - GetOutput(motor, BlockTachoCount);
157 
158  /* If error hasn't changed for last 5 samples, quit */
159  if ((error - lastError) == 0)
160  steadyStateCount++;
161 
162  int P = PValue * error / pidScale;
163  I += IValue * error * dt / pidScale;
164  int D = (DValue / dt) * (error - lastError) / pidScale;
165  int output = outputScale * (P + I + D);
166  if (output > absPower) output = absPower;
167  if (output < -absPower) output = -absPower;
168  SetOutput(motor, Power, output);
169  SetOutput(motor, UpdateFlags, UF_UPDATE_SPEED);
170  lastError = error;
171  Wait(dt * samplePeriod);
172  }
173  stopMotor(motor);
174  return lastError;
175 }
176 
177 int GetSensorProximity (int sensor)
178 {
179  if (sensor == TOUCH_SENSOR)
180  return Sensor(TOUCH_SENSOR);
181  if (Sensor(LIGHT_SENSOR) < LIGHT_SENSOR_PROXIMITY_THRESHOLD)
182  return 1;
183  else
184  return 0;
185 }
186 
187 int CaliberateMotor(int motor, int sensor, int postAlignmentPercentage)
188 {
189  int extremeTachoMin;
190  int extremeTachoMax;
191  int cycleCountMin;
192  int cycleCountMax;
193  int cycleCount;
194  int alignDegrees;
195 
196  /* Start motor and monitor sensor for rythm cycle */
197  startMotor(motor, MOTOR_POWER_FAST);
198 
199  /*vxbxcds21111 First let the sensor get out of active state */
200  while (GetSensorProximity(sensor));
201 
202  /* Wait for sensor to activate */
203  while (!GetSensorProximity(sensor));
204 
205  /* Start both extreme count and cycle count */
206  extremeTachoMin = GetOutput(motor, TachoCount);
207  cycleCountMin = extremeTachoMin;
208 
209  /* Wait for sensor to deactivate */
210  while (GetSensorProximity(sensor));
211 
212  /* end count */
213  extremeTachoMax = GetOutput(motor, TachoCount);
214 
215  /* Wait for sensor to activate again */
216  while (!GetSensorProximity(sensor));
217 
218  /* End cycle count */
219  cycleCountMax = GetOutput(motor, TachoCount);
220 
221  /* Stop the motor */
222  stopMotor(motor);
223 
224  /* Correct any error within cycle count */
225  cycleCount = cycleCountMax - cycleCountMin;
226  int errorCycleCount = cycleCount % CALIBERATION_ERROR_TOLERANCE;
227  if (errorCycleCount < CALIBERATION_ERROR_TOLERANCE/2)
228  cycleCount -= errorCycleCount;
229  else
230  cycleCount += CALIBERATION_ERROR_TOLERANCE - errorCycleCount;
231 
232  /* Align the moter to neutral */
233  /* Move the tacho limit to neutralAlignment + 1/2 extreme sensor period */
234  alignDegrees = (cycleCount * postAlignmentPercentage)/100 +
235  (extremeTachoMax - extremeTachoMin)/2;
236  RotateAngle(motor, MOTOR_POWER_FAST, alignDegrees, MOTOR_P, MOTOR_I, MOTOR_D);
237 
238  return cycleCount;
239 }
240 
241 task Movement()
242 {
243  while(true)
244  {
245  int command = moveCommand;
246  int nextState = stateTransition[moveState * NUM_COMMANDS + command];
247 
248  /* Demultiplex state data */
249  /* Each tilt/stride fraction is 1/8 of cycle */
250  int strideFirst = GetActionElement(moveState, nextState,
251  ACTION_ELEMENT_STRIDE_FIRST);
252  int tiltFraction = GetActionElement(moveState, nextState,
253  ACTION_ELEMENT_TILT_AMOUNT);
254  int strideFraction = GetActionElement(moveState, nextState,
255  ACTION_ELEMENT_STRIDE_AMOUNT);
256 
257  if (tiltFraction && !strideFirst)
258  RotateAngle(MOTOR_TILT, MOTOR_POWER_FAST,
259  (tiltCycleCount * tiltFraction)/100,
260  MOTOR_P, MOTOR_I, MOTOR_D);
261  if (strideFraction)
262  RotateAngle(MOTOR_STRIDE, MOTOR_POWER_FAST,
263  (strideCycleCount * strideFraction)/100,
264  MOTOR_P, MOTOR_I, MOTOR_D);
265  if (tiltFraction && strideFirst)
266  RotateAngle(MOTOR_TILT, MOTOR_POWER_FAST,
267  (tiltCycleCount * tiltFraction)/100,
268  MOTOR_P, MOTOR_I, MOTOR_D);
269  if (moveState == nextState)
270  Wait(1000);
271  moveState = nextState;
272  }
273 }
274 
275 task Navigation()
276 {
277  while(true)
278  {
279  /* Continue turning left as long as there is an obstacle in front */
280  if(SensorUS(RANGE_SENSOR) < RANGE_SENSOR_THRESHOLD)
281  {
282  Acquire(moveMutex);
283  if (moveCommand == MOVE_FORWARD)
284  {
285  moveCommand = MOVE_LEFT;
286  }
287  Release(moveMutex);
288  }
289  else /* Go straight ahead if there is no obstacle any more */
290  {
291  Acquire(moveMutex);
292  if (moveCommand == MOVE_LEFT)
293  {
294  moveCommand = MOVE_FORWARD;
295  }
296  Release(moveMutex);
297  }
298  }
299 }
300 
301 task CommandCenter()
302 {
303  while(true)
304  {
305  while(Sensor(SOUND_SENSOR) < SOUND_SENSOR_THRESHOLD) Wait(20);
306  Acquire(moveMutex);
307  if (moveCommand == MOVE_STOP) /* First clap to move */
308  {
309  moveCommand = MOVE_FORWARD;
310  }
311  else
312  {
313  moveCommand = MOVE_STOP; /* Second clap to stop */
314  }
315  Release(moveMutex);
316  Wait(1000);
317  }
318 }
319 
320 task main ()
321 {
322  SetSensorTouch(TOUCH_SENSOR);
323  SetSensorLight(LIGHT_SENSOR);
324  SetSensorSound(SOUND_SENSOR);
325  SetSensorLowspeed(RANGE_SENSOR);
326 
327  /* Give user time to get out of way */
328  Wait (1000);
329 
330  /* Calibrate robot position and determine tilt and stride cycles */
331  tiltCycleCount = CaliberateMotor(MOTOR_TILT, TOUCH_SENSOR, 0);
332  strideCycleCount = CaliberateMotor(MOTOR_STRIDE, LIGHT_SENSOR, 0);
333 
334  /* Bring to neutral */
335  RotateAngle(MOTOR_STRIDE, MOTOR_POWER_FAST,
336  strideCycleCount * (LIGHT_SENSOR_OFFSET)/100,
337  MOTOR_P, MOTOR_I, MOTOR_D);
338  RotateAngle(MOTOR_TILT, MOTOR_POWER_FAST,
339  tiltCycleCount * (TOUCH_SENSOR_OFFSET)/100,
340  MOTOR_P, MOTOR_I, MOTOR_D);
341 
342  start Navigation;
343  start Movement;
344  start CommandCenter;
345 }
346 
int CaliberateMotor(int motor, int sensor, int postAlignmentPercentage)
Caliberates a rotary motor setup that has a sensor attached to detect a cyclic position.