1 package lejos.navigation;
2 //import lejos.navigation.*;
4 import lejos.navigation.*;
8 * The TachoNavigator class can keep track of the robot position and the direction angle it faces; It uses a _pilot object to control NXT robot movements.<br>
9 * The position and direction angle values are updated automatically when the movement command returns after the movement is complete and and after stop() command is issued.
10 * However, some commands optionally return immediately, to permit sensor monitoring in the main thread. It is then the programmers responsibility to
11 * call updatePosition() when the robot motion is completed. All angles are in degrees, distances in the units used to specify robot dimensions.
12 * As with pilot, the robot must be have two independently controlled drive wheels.
13 * The assumed initial position of the robot is at (0,0) and initial angle 0 i.e. pointing in the +X direction.
16 public class TachoNavigator implements Navigator
18 // orientation and co-ordinate data
19 protected float _heading = 0;
22 protected int _left0 = 0;
23 protected int _right0 = 0;
25 // The essential component
26 protected Pilot _pilot;
29 * set false whenever the robot moves, set to true by updatePosition();
31 private boolean _updated = false;
34 * Allocates a Navigator object and initializes it with the proper motors.
35 * The x and y values and the direction angle are all initialized to 0, so if the first move is forward() the robot will run along
37 * @param wheelDiameter The diameter of the wheel, usually printed right on the
38 * wheel, in centimeters (e.g. 49.6 mm = 4.96 cm = 1.95 in)
39 * @param trackWidth The distance from the center of the left tire to the center
40 * of the right tire, in units of your choice
41 * @param rightMotor The motor used to drive the right wheel e.g. Motor.C.
42 * @param leftMotor The motor used to drive the left wheel e.g. Motor.A.
43 * @param reverse If motor.forward() dives the robot backwars, set this parameter true.
45 public TachoNavigator(float wheelDiameter, float trackWidth, Motor leftMotor, Motor rightMotor, boolean reverse)
47 _pilot = new Pilot(wheelDiameter,trackWidth,leftMotor, rightMotor,reverse);
50 public TachoNavigator(float wheelDiameter, float trackWidth, Motor leftMotor, Motor rightMotor)
52 _pilot = new Pilot(wheelDiameter,trackWidth,leftMotor, rightMotor);
56 public TachoNavigator(Pilot pilot) {
61 * Overloaded TachoNavigator constructor that assumes the following:<BR>
62 * Left motor = Motor.A Right motor = Motor.C <BR>
63 * @param wheelDiameter The diameter of the wheel, usually printed right on the
64 * wheel, in centimeters (e.g. 49.6 mm = 4.96 cm)
65 * @param driveLength The distance from the center of the left tire to the center
68 public TachoNavigator(float wheelDiameter, float driveLength)
70 this(wheelDiameter, driveLength, Motor.A, Motor.C);
73 public Pilot getPilot(){ return _pilot;}
75 * Returns the current x coordinate of the NXT.
76 * @return float Present x coordinate.
84 * Returns the current y coordinate of the NXT.
85 * Note: At present it will only give an updated reading when the NXT is stopped.
86 * @return float Present y coordinate.
88 public float getY() { return _y;}
91 * Returns the current angle the NXT robot is facing, relative to the +X axis direction; the +Y direction is 90 degrees.
92 * Note: At present it will only give an updated reading when the NXT is stopped.
93 * @return float Angle in degrees.
95 public float getAngle() { return _heading;}
98 *sets robot location (x,y) and direction angle
99 *@param x the x coordinate of the robot
100 *@param y the y coordinate of the robot
101 *@param directionAngle the angle the robot is heading, measured from the x axis. 90 degrees is the +Y direction
103 public void setPosition(float x, float y, float directionAngle)
107 _heading = directionAngle;
110 *sets the motor speed of the robot, in degrees/second.
112 public void setSpeed(int speed)
114 _pilot.setSpeed(speed);
118 * Moves the NXT robot forward until stop() is called.
119 * @see Navigator#stop().
121 public void forward()
124 _pilot.resetTachoCount();
131 * Moves the NXT robot backward until stop() is called.
133 public void backward()
136 _pilot.resetTachoCount();
143 * Halts the NXT robot and calculates new x, y coordinates.
152 *returns true iff the robot is moving under power
154 public boolean isMoving()
156 return _pilot.isMoving();
160 * Moves the NXT robot a specific distance. A positive value moves it forwards and
161 * a negative value moves it backwards.
162 * The robot position is updated atomatically when the method returns.
163 * @param distance The positive or negative distance to move the robot, same units as _wheelDiameter
165 public void travel(float distance)
167 travel(distance,false);
171 * Moves the NXT robot a specific distance. A positive value moves it forwards and
172 * a negative value moves it backwards.
173 * If immediateReturnis true, method returns immidiately and your code MUST call updatePostion()
174 * when the robot has stopped. Otherwise, the robot position is lost.
175 * @param distance The positive or negative distance to move the robot, same units as _wheelDiameter
176 * @param immediateReturn iff true, the method returns immediately, in which case the programmer <br>
177 * is responsible for calling updatePosition() before the robot moves again.
179 public void travel(float distance,boolean immediateReturn)
182 _pilot.resetTachoCount();
185 _pilot.travel(distance,immediateReturn);
186 if(!immediateReturn) updatePosition();
190 *Rotates the NXT to the left (increasing angle) until stop() is called;
192 public void rotateLeft()
195 _pilot.resetTachoCount();
202 *Rotates the NXT to the right (decreasing angle) until stop() is called;
204 public void rotateRight()
207 _pilot.resetTachoCount();
214 * Rotates the NXT robot a specific number of degrees in a direction (+ or -).
215 * @param angle Angle to rotate in degrees. A positive value rotates left, a negative value right.
217 public void rotate(float angle)
223 * Rotates the NXT robot a specific number of degrees in a direction (+ or -).
224 * If immediateReturn is true, method returns immidiately and your code MUST call updatePostion()
225 * when the robot has stopped. Otherwise, the robot position is lost.
226 * @param angle Angle to rotate in degrees. A positive value rotates left, a negative value right.
227 * @param immediateReturn iff true, the method returns immediately, in which case the programmer <br>
228 * is responsible for calling updatePosition() before the robot moves again.
230 public void rotate(float angle,boolean immediateReturn)
233 int turnAngle = Math.round(normalize(angle));
234 _pilot.resetTachoCount();
237 _pilot.rotate(turnAngle,immediateReturn);
238 if(!immediateReturn) updatePosition();
242 * Rotates the NXT robot to point in a specific direction. It will take the shortest
243 * path necessary to point to the desired angle.
244 * @param angle The angle to rotate to, in degrees.
246 public void rotateTo(float angle)
248 rotateTo(angle,false);
252 * Rotates the NXT robot to point in a specific direction. It will take the shortest
253 * path necessary to point to the desired angle.
254 * If immediateReturnis true, method returns immidiately and your code MUST call updatePostion()
255 * when the robot has stopped. Otherwise, the robot position is lost.
256 * @param angle The angle to rotate to, in degrees.
257 * @param immediateReturn iff true, method returns immediately and the programmer is responsible for calling
258 * updatePosition() before the robot moves again.
260 public void rotateTo(float angle,boolean immediateReturn)
262 float turnAngle = normalize( angle - _heading);
263 rotate(turnAngle,immediateReturn);
267 * Rotates the NXT robot towards the target point (x,y) and moves the required distance.
268 * Method returns when target point is reached, and the robot position is updated;
269 * @param x The x coordinate to move to.
270 * @param y The y coordinate to move to.
272 public void goTo(float x, float y)
274 rotateTo(angleTo(x,y));
275 travel(distanceTo(x,y));
279 * Rotates the NXT robot towards the target point (x,y) and moves the required distance.
280 * Method returns when target point is reached, and the robot position is updated;
281 * @param x The x coordinate to move to.
282 * @param y The y coordinate to move to.
283 * @param immediateReturn iff true, method returns immediately
285 public void goTo(float x, float y, boolean immediateReturn)
287 rotateTo(angleTo(x,y));
288 travel(distanceTo(x,y), immediateReturn);
292 * distance from robot to the point with coordinates (x,y) .
293 * @param x coordinate of the point
294 * @param y coordinate of the point
295 * @return the distance from the robot current location to the point
297 public float distanceTo( float x, float y)
301 //use hypotenuse formula
302 return (float)Math.sqrt(dx*dx+dy*dy);
306 * returns the direction angle (degrees) to point with coordinates (x,y)
307 * @param x coordinate of the point
308 * @param y coordinate of the point
309 * @return the direction angle to the point (x,y) from the NXT. Rotate to this angle to head toward it.
311 public float angleTo(float x, float y)
315 return(float)Math.toDegrees(Math.atan2(dy,dx));
319 * Updates robot location (x,y) and direction angle. Called by stop, and movement commands that terminate when complete.
320 * If you use a movement command that returns immediately, you MUST call this method when the movement is complete.
321 * It may also be called while movement is on progress.
323 public void updatePosition()
326 int left = _pilot.getLeftCount();//left wheel rotation angle
327 int right = _pilot.getRightCount();
334 if(left == 0 && right == 0)return; // no movement
340 if(Math.abs(left)<Math.abs(right))
350 direction = -1; // turn to right
353 float turnAngle = direction*(outside-inside)*_pilot._wheelDiameter/(2*_pilot._trackWidth);
355 boolean approx = false;
356 if(1.0f*inside/outside > .98) // probably movement was intended to be straight
358 float distance = 0.5f*(inside+outside)/_pilot._degPerDistance;
359 float projection = (float)Math.toRadians(_heading+turnAngle/2);
360 dx = distance*(float)Math.cos(projection);
361 dy = distance*(float)Math.sin(projection);
366 float turnRadius = _pilot._trackWidth*(outside+inside)/(2*(outside - inside));
367 double headingRad = (Math.toRadians(_heading));
368 if(direction == -1)headingRad +=Math.PI;
369 double turnRad = Math.toRadians(turnAngle);
370 dx = turnRadius*(float)(Math.sin(headingRad + turnRad) - Math.sin(headingRad));
371 dy = turnRadius*(float)(Math.cos(headingRad)- Math.cos(headingRad+turnRad));
373 _heading = normalize(_heading + turnAngle); // keep angle between -180 and 180
376 if(approx) _heading -= turnAngle/2; // correct approximation
381 * Moves the NXT robot in a circular path with a specified radius. <br>
382 * The center of the turning circle is on the right side of the robot iff parameter radius is negative; <br>
383 * Postcondition: motor speed is NOT restored to previous value;
384 * @param radius is the radius of the circular path. If positive, the left wheel is on the inside of the turn. If negative, the left wheel is on the outside.
386 public void turn(float radius)
389 _pilot.resetTachoCount();
392 _pilot.steer(turnRate(radius));
396 * Moves the NXT robot in a circular path through a specific angle; If waitForCompletion is true, returns when angle is reached. <br>
397 * The center of the turning circle is on the right side of the robot iff parameter radius is negative.
398 * Robot will stop when total rotation equals angle. If angle is negative, robot will move travel backwards.
399 * @param radius radius of the turning circle
400 * @param angle the angle by which the robot heading changes, + or -
402 public void turn(float radius, int angle)
404 turn(radius,angle,false);
408 * Moves the NXT robot in a circular path through a specific angle; If waitForCompletion is true, returns when angle is reached. <br>
409 * The center of the turning circle is on the right side of the robot iff parameter radius is negative.
410 * Robot will stop when total rotation equals angle. If angle is negative, robot will travel backwards.
411 * @param radius see turn(turnRage, angle)
412 * @param immediateReturn iff true, the method returns immediately, in which case the programmer <br>
413 * is responsible for calling updatePosition() before the robot moves again.
415 public void turn(float radius, int angle, boolean immediateReturn)
418 _pilot.resetTachoCount();
421 _pilot.steer(turnRate(radius),angle,immediateReturn);
422 if(!immediateReturn) updatePosition();
426 * returns equivalent angle between -180 and +180
428 private float normalize(float angle)
431 while(a > 180) a -= 360;
432 while(a < -180) a += 360;
436 private int turnRate(float radius)
444 float ratio = (2*radius - _pilot._trackWidth)/(2*radius+_pilot._trackWidth);
445 return Math.round(direction * 100*(1 - ratio));