Package lejos.robotics.proposal

Source Code of lejos.robotics.proposal.DifferentialPilot$Monitor

package lejos.robotics.proposal;

import java.util.ArrayList;
import lejos.nxt.Battery;
import lejos.robotics.MoveListener;
import lejos.robotics.Movement;
import lejos.robotics.TachoMotor;

/*
* WARNING: THIS CLASS IS SHARED BETWEEN THE classes AND pccomms PROJECTS.
* DO NOT EDIT THE VERSION IN pccomms AS IT WILL BE OVERWRITTEN WHEN THE PROJECT IS BUILT.
*/

/**
* The DifferentialPilot class is a software abstraction of the Pilot mechanism of a
* NXT robot. It contains methods to control robot movements: travel forward or
* backward in a straight line or a circular path or rotate to a new direction.<br>
* Note: this class will only work with two independently controlled motors to
* steer differentially, so it can rotate within its own footprint (i.e. turn on
* one spot).<br>
* It can be used with robots that have reversed motor design: the robot moves
* in the direction opposite to the the direction of motor rotation. Uses the
* TachoMotor class, which regulates motor speed using the NXT motor's built in
* tachometer.<br>
* It automatically updates the Pose of a robot if the Pose calls the
* addMoveListener() method on this class.
* Some methods optionally return immediately so the thread that called the
* method can monitor sensors, get current pose, and call stop() if necessary.<br>
*  Example:
* <p>
* <code><pre>
* PdifferentialPilot pilot = new DifferentialPilot(2.1f, 4.4f, Motor.A, Motor.C, true);  // parameters in inches
* pilot.setRobotSpeed(10);                                           // inches per second
* pilot.travel(12);                                                  // inches
* pilot.rotate(-90);                                                 // degree clockwise
* pilot.travel(-12,true);
* while(pilot.isMoving())Thread.yield();
* pilot.rotate(-90);
* pilot.rotateTo(270);
* pilot.steer(-50,180,true);
* while(pilot.isMoving())Thread.yield();
* pilot.steer(100);
* try{Thread.sleep(1000);}
* catch(InterruptedException e){}
* pilot.stop();
* </pre></code>
* </p>
*
**/
public class DifferentialPilot implements ArcRotatePilot
{

  /**
   * Allocates a TachoPilot object, and sets the physical parameters of the
   * NXT robot.<br>
   * Assumes Motor.forward() causes the robot to move forward.
   *
   * @param wheelDiameter
   *            Diameter of the tire, in any convenient units (diameter in mm
   *            is usually printed on the tire).
   * @param trackWidth
   *            Distance between center of right tire and center of left tire,
   *            in same units as wheelDiameter.
   * @param leftMotor
   *            The left Motor (e.g., Motor.C).
   * @param rightMotor
   *            The right Motor (e.g., Motor.A).
   */
  public DifferentialPilot(final float wheelDiameter, final float trackWidth,
          final TachoMotor leftMotor, final TachoMotor rightMotor)
  {
    this(wheelDiameter, trackWidth, leftMotor, rightMotor, false);
  }

  /**
   * Allocates a TachoPilot object, and sets the physical parameters of the
   * NXT robot.<br>
   *
   * @param wheelDiameter
   *            Diameter of the tire, in any convenient units (diameter in mm
   *            is usually printed on the tire).
   * @param trackWidth
   *            Distance between center of right tire and center of left tire,
   *            in same units as wheelDiameter.
   * @param leftMotor
   *            The left Motor (e.g., Motor.C).
   * @param rightMotor
   *            The right Motor (e.g., Motor.A).
   * @param reverse
   *            If true, the NXT robot moves forward when the motors are
   *            running backward.
   */
  public DifferentialPilot(final float wheelDiameter, final float trackWidth,
          final TachoMotor leftMotor, final TachoMotor rightMotor,
          final boolean reverse)
  {
    this(wheelDiameter, wheelDiameter, trackWidth, leftMotor, rightMotor,
            reverse);
  }

  /**
   * Allocates a TachoPilot object, and sets the physical parameters of the
   * NXT robot.<br>
   *
   * @param leftWheelDiameter
   *            Diameter of the left wheel, in any convenient units (diameter
   *            in mm is usually printed on the tire).
   * @param rightWheelDiameter
   *            Diameter of the right wheel. You can actually fit
   *            intentionally wheels with different size to your robot. If you
   *            fitted wheels with the same size, but your robot is not going
   *            straight, try swapping the wheels and see if it deviates into
   *            the other direction. That would indicate a small difference in
   *            wheel size. Adjust wheel size accordingly. The minimum change
   *            in wheel size which will actually have an effect is given by
   *            minChange = A*wheelDiameter*wheelDiameter/(1-(A*wheelDiameter)
   *            where A = PI/(moveSpeed*360). Thus for a moveSpeed of 25
   *            cm/second and a wheelDiameter of 5,5 cm the minChange is about
   *            0,01058 cm. The reason for this is, that different while sizes
   *            will result in different motor speed. And that is given as an
   *            integer in degree per second.
   * @param trackWidth
   *            Distance between center of right tire and center of left tire,
   *            in same units as wheelDiameter.
   * @param leftMotor
   *            The left Motor (e.g., Motor.C).
   * @param rightMotor
   *            The right Motor (e.g., Motor.A).
   * @param reverse
   *            If true, the NXT robot moves forward when the motors are
   *            running backward.
   */
  public DifferentialPilot(final float leftWheelDiameter,
          final float rightWheelDiameter, final float trackWidth,
          final TachoMotor leftMotor, final TachoMotor rightMotor,
          final boolean reverse)
  {
    _left = leftMotor;
    _leftWheelDiameter = leftWheelDiameter;
    _leftTurnRatio = trackWidth / leftWheelDiameter;
    _leftDegPerDistance = 360 / ((float) Math.PI * leftWheelDiameter);
    // right
    _right = rightMotor;
    _rightWheelDiameter = rightWheelDiameter;
    _rightTurnRatio = trackWidth / rightWheelDiameter;
    _rightDegPerDistance = 360 / ((float) Math.PI * rightWheelDiameter);
    // both
    _trackWidth = trackWidth;
    _parity = (byte) (reverse ? -1 : 1);
    setSpeed(360);
    monitor.setDaemon(true);
    monitor.start();
  }

  public void addMoveListener(MoveListener aListener)
  {
    listeners.add(aListener);
  }

  /**
   * @return left motor.
   */
  public TachoMotor getLeft()
  {
    return _left;
  }

  /**
   * @return right motor.
   */
  public TachoMotor getRight()
  {
    return _right;
  }

  /**
   * @return tachoCount of left motor. Positive value means motor has moved
   *         the robot forward.
   */
  public int getLeftCount()
  {
    return _parity * _left.getTachoCount();
  }

  /**
   * @return tachoCount of the right motor. Positive value means motor has
   *         moved the robot forward.
   */
  public int getRightCount()
  {
    return _parity * _right.getTachoCount();
  }

  /**
   * @return actual speed of left motor in degrees per second. A negative
   *         value if motor is rotating backwards. Updated every 100 ms.
   **/
  public int getLeftActualSpeed()
  {
    return _left.getRotationSpeed();
  }

  /**
   * @return actual speed of right motor in degrees per second. A negative
   *         value if motor is rotating backwards. Updated every 100 ms.
   **/
  public int getRightActualSpeed()
  {
    return _right.getRotationSpeed();
  }

  /**
   * @return ratio of motor revolutions per 360 degree rotation of the robot.
   *         If your robot has wheels with different size, it is the average.
   */
  public float getTurnRatio()
  {
    return (_leftTurnRatio + _rightTurnRatio) / 2.0f;
  }

  /**
   * Sets speed of both motors, as well as moveSpeed and turnSpeed. Only use
   * if your wheels have the same size.
   *
   * @param speed
   *            The wanted speed in degrees per second.
   */
  public void setSpeed(final int speed)
  {
    _motorSpeed = speed;
    _robotMoveSpeed = speed / Math.max(_leftDegPerDistance, _rightDegPerDistance);
    _robotTurnSpeed = speed / Math.max(_leftTurnRatio, _rightTurnRatio);
    setSpeed(speed, speed);
  }

  protected void setSpeed(final int leftSpeed, final int rightSpeed)
  {
    _left.regulateSpeed(_regulating);
    _left.smoothAcceleration(!isMoving());
    _right.regulateSpeed(_regulating);
    _right.smoothAcceleration(!isMoving());
    _left.setSpeed(leftSpeed);
    _right.setSpeed(rightSpeed);
  }

  /**
   * also sets _motorSpeed
   *
   * @see lejos.robotics.navigation.Pilot#setMoveSpeed(float)
   */
  public void setMoveSpeed(float speed)
  {
    _robotMoveSpeed = speed;
    _motorSpeed = Math.round(0.5f * speed * (_leftDegPerDistance + _rightDegPerDistance));
    setSpeed(Math.round(speed * _leftDegPerDistance), Math.round(speed * _rightDegPerDistance));
  }

  /**
   * @see lejos.robotics.navigation.Pilot#getMoveSpeed()
   */
  public float getMoveSpeed()
  {
    return _robotMoveSpeed;
  }

  /**
   * @see lejos.robotics.navigation.Pilot#getMoveMaxSpeed()
   */
  public float getMoveMaxSpeed()
  {
    // it is generally assumed, that the maximum accurate speed of Motor is
    // 100 degree/second * Voltage
    return Battery.getVoltage() * 100.0f / Math.max(_leftDegPerDistance, _rightDegPerDistance);
  // max degree/second divided by degree/unit = unit/second
  }

  /**
   * @see lejos.robotics.navigation.Pilot#setTurnSpeed(float)
   */
  public void setTurnSpeed(float speed)
  {
    _robotTurnSpeed = speed;
    setSpeed(Math.round(speed * _leftTurnRatio), Math.round(speed * _rightTurnRatio));
  }

  /**
   * @see lejos.robotics.navigation.Pilot#getTurnSpeed()
   */
  public float getTurnSpeed()
  {
    return _robotTurnSpeed;
  }

  /**
   * @see lejos.robotics.navigation.Pilot#getTurnMaxSpeed()
   */
  public float getTurnMaxSpeed()
  {
    // it is generally assumed, that the maximum accurate speed of Motor is
    // 100 degree/second * Voltage
    return Battery.getVoltage() * 100.0f / Math.max(_leftTurnRatio, _rightTurnRatio);
  // max degree/second divided by degree/unit = unit/second
  }

  /**
   * @return true if the NXT robot is moving.
   **/
  public boolean isMoving()
  {
    return _left.isMoving() || _right.isMoving();
//                ||_left.isRotating()||_right.isRotating();//ensure that motor.rotate() is complete
  }

  /**
   * @return distance traveled since last movement started.
   **/
  public float getTravelDistance()
  {
    float left = _left.getTachoCount() / _leftDegPerDistance;
    float right = _right.getTachoCount() / _rightDegPerDistance;
    return _parity * (left + right) / 2.0f;
  }

  /**
   * @return the angle of rotation of the robot since last started
   *         tacho count;
   */
  public float getAngle()
  {
    float angle = _parity * ((_right.getTachoCount() / _rightTurnRatio) - (_left.getTachoCount() / _leftTurnRatio)) / 2.0f;
    return angle;
  }

  /**
   * Resets tacho count for both motors.
   **/
  public void reset()
  {
    _left.resetTachoCount();
    _right.resetTachoCount();

  }

  /**
   * Moves the NXT robot forward until stop() is called.
   */
  public void forward()
  {
    if(isMoving())stop();
    _moveType = Movement.MovementType.TRAVEL;
    movementStart();
    reset();
    setSpeed(Math.round(_robotMoveSpeed * _leftDegPerDistance), Math.round(_robotMoveSpeed * _rightDegPerDistance));
   
    if (_parity == 1) fwd();
    else bak();
  }

  /**
   * Moves the NXT robot backward until stop() is called.
   */
  public void backward()
  {
    if (isMoving()) stop();
    _moveType = Movement.MovementType.TRAVEL;
    movementStart();
    reset();
    setSpeed(Math.round(_robotMoveSpeed * _leftDegPerDistance), Math.round(_robotMoveSpeed * _rightDegPerDistance));

    if (_parity == 1) bak();
    else fwd();
  }

  /**
   * Motors forward. This is called by forward() and backward().
   */
  private void fwd()
  {
    _left.forward();
    _right.forward();
  }

  /**
   * Motors backward. This is called by forward() and backward().
   */
  private void bak()
  {
    _left.backward();
    _right.backward();
  }

  /**
   * Rotates the NXT robot through a specific angle. Returns when angle is
   * reached. Wheels turn in opposite directions producing a zero radius turn.<br>
   * Note: Requires correct values for wheel diameter and track width.
   *
   * @param angle
   *            The wanted angle of rotation in degrees. Positive angle rotate
   *            left (clockwise), negative right.
   */
  public Movement rotate(final float angle)
  {
    return rotate(angle, false);
  }

  /**
   * Rotates the NXT robot through a specific angle. Returns when angle is
   * reached. Wheels turn in opposite directions producing a zero radius turn.<br>
   * Note: Requires correct values for wheel diameter and track width.
   *
   * @param angle
   *            The wanted angle of rotation in degrees. Positive angle rotate
   *            left (clockwise), negative right.
   * @param immediateReturn
   *            If true this method returns immediately.
   */
  public Movement rotate(final float angle, final boolean immediateReturn)
  {
    if(isMoving())stop();
    _moveType = Movement.MovementType.ROTATE;
    reset();
    movementStart();
    _alert = immediateReturn;
    setSpeed(Math.round(_robotTurnSpeed * _leftTurnRatio), Math.round(_robotTurnSpeed * _rightTurnRatio));
    int rotateAngleLeft = _parity * (int) (angle * _leftTurnRatio);
    int rotateAngleRight = _parity * (int) (angle * _rightTurnRatio);
    _left.rotate(-rotateAngleLeft, true);
    _right.rotate(rotateAngleRight, immediateReturn);
   
    if (!immediateReturn)
    {
      while (isMoving()) Thread.yield();
      stop();
    }
    return getMovement();
  }


  /**
   * This method can be overridden by subclasses to stop the robot if a hazard
   * is detected
   *
   * @return true iff no hazard is detected
   */
  protected boolean continueMoving() {
  return true;
}

/**
   * Stops the NXT robot.
   */
  public Movement  stop()
  {
    _alert = false;
    _left.stop();
    _right.stop();
    while (isMoving()) Thread.yield();
    movementStop();
    return getMovement();
  }

  /**
   * Moves the NXT robot a specific distance in an (hopefully) straight line.<br>
   * A positive distance causes forward motion, a negative distance moves
   * backward. If a drift correction has been specified in the constructor it
   * will be applied to the left motor.
   *
   * @param distance
   *            The distance to move. Unit of measure for distance must be
   *            same as wheelDiameter and trackWidth.
   **/
  public Movement travel(final float distance)
  {
    return travel(distance, false);
  }

  /**
   * Moves the NXT robot a specific distance in an (hopefully) straight line.<br>
   * A positive distance causes forward motion, a negative distance moves
   * backward. If a drift correction has been specified in the constructor it
   * will be applied to the left motor.
   *
   * @param distance
   *            The distance to move. Unit of measure for distance must be
   *            same as wheelDiameter and trackWidth.
   * @param immediateReturn
   *            If true this method returns immediately.
   */
  public Movement travel(final float distance, final boolean immediateReturn)
  {
    if(isMoving())stop();
    _moveType = Movement.MovementType.TRAVEL;
    reset();
    movementStart();
      _alert = immediateReturn;
    setSpeed(Math.round(_robotMoveSpeed * _leftDegPerDistance), Math.round(_robotMoveSpeed * _rightDegPerDistance));
    _left.rotate((int) (_parity * distance * _leftDegPerDistance), true);
    _right.rotate((int) (_parity * distance * _rightDegPerDistance),
            true);  _alert = immediateReturn;
    if (!immediateReturn)
    {
      while (isMoving() && continueMoving()) Thread.yield();
      stop();
    }
    return getMovement();
  }

  public void steer(final float turnRate)
  {
    steer(turnRate, Float.POSITIVE_INFINITY, true);

  }

  public Movement steer(final float turnRate, float angle)
  {
    return steer(turnRate, angle, false);
  }

  public Movement steer(final float turnRate, final float angle,
          final boolean immediateReturn)
  {
    if(isMoving())stop();
    _moveType = Movement.MovementType.ARC;
 
    reset();
    movementStart();
   
       _alert = immediateReturn;
    // TODO: make this work with wheels of different size
    TachoMotor inside;
    TachoMotor outside;
    float rate = turnRate;
    if (rate < -200) rate = -200;
    else if (rate > 200)rate = 200;
    else if (rate == 0)
    {
      if (angle < 0) backward();
       else forward();
      return getMovement();
    }
    if (turnRate < 0)
    {
      inside = _right;
      outside = _left;
      rate = -rate;
    } else
    {
      inside = _left;
      outside = _right;
    }
    outside.setSpeed(_motorSpeed);
    float steerRatio = 1 - rate / 100.0f;
    inside.setSpeed((int) (_motorSpeed * steerRatio));
    if (angle == Float.POSITIVE_INFINITY) // no limit angle for turn
    {
      if (_parity == 1) outside.forward();
       else outside.backward();
      if (_parity * steerRatio > 0)
      {
        inside.forward();
      } else
      {
        inside.backward();
      }
      return getMovement();
    // end no turn limit
    float rotAngle = angle * _trackWidth * 2 / (_leftWheelDiameter * (1 - steerRatio));
    inside.rotate(_parity * (int) (rotAngle * steerRatio), true);
    outside.rotate(_parity * (int) rotAngle, true);
    if (!immediateReturn)
    {
      while (isMoving() && continueMoving()) Thread.yield();
      stop();
    }
    return getMovement();
  }


  public void arc(final float radius)
  {
    steer(turnRate(radius));
  }

  public Movement arc(final float radius, final float angle)
  {
    return steer(turnRate(radius), angle);
  }

  public Movement arc(final float radius, final float angle,
          final boolean immediateReturn)
  {
    return steer(turnRate(radius), angle, immediateReturn);
  }

  public Movement travelArc(float radius, float distance)
  {
    return travelArc(radius, distance, false);
  }

  public Movement travelArc(float radius, float distance, boolean immediateReturn)
  {
    double angle = (distance * 180) / (Math.PI * radius);
    return arc(radius, (float) angle, immediateReturn);
  }

  /**
   * Calculates the turn rate corresponding to the turn radius; <br>
   * use as the parameter for steer() negative argument means center of turn
   * is on right, so angle of turn is negative
   *
   * @param radius
   * @return steer()
   */
  protected int turnRate(final float radius)
  {
    int direction;
    float radiusToUse;
    if (radius < 0)
    {
      direction = -1;
      radiusToUse = -radius;
    } else
    {
      direction = 1;
      radiusToUse = radius;
    }
    float ratio = (2 * radiusToUse - _trackWidth) / (2 * radiusToUse + _trackWidth);
    return Math.round(direction * 100 * (1 - ratio));
  }

  protected void movementStart()
  {
    for (MoveListener p : listeners)
    {
      p.movementStarted(new Movement(_moveType, 0, 0, true ), this);
    }
  }

  protected void movementStop()
  {
    for (MoveListener p : listeners)
    {
      Movement move = new Movement(_moveType, getTravelDistance(), getAngle(), false);
      p.movementStopped(move, this);
    }
  }
 
public void setMinRadius(float radius){
   _minRadius = radius;
}
public float getMinRadius(){return _minRadius;}
  public Movement getMovement()
  {
    return new Movement(_moveType, getTravelDistance(), getAngle(), isMoving());
  }

  /**
   * The only purpose of this inner class is to detect when an immediate return
   * method exits  because the distance or angle has been reached.
   */
  private class Monitor extends Thread
  {

    public void run()
    {
      while (true)
      {
        // note:  the pilot may stop or  _alert may be cancelled by the main
        // thread at any time. Do not call stopNow if either happens
        while (!_alert)
        {
          Thread.yield();//no movement in progress
        }
        while (!isMoving())
        {
          Thread.yield();
        }

        while (isMoving())
        {
          Thread.yield();
        }
        synchronized (monitor)
        {
          if (_alert)
          {
            _alert = false;
            movementStop(); // updates listeners
          }
        }//end synchronized
      }
    }
  }
  /**
   * should be true if an immediate return movement is in progress.
   * used by monitor
   */
  protected boolean _alert = false;
  /**
   * the pilot listeners
   */
  protected ArrayList<MoveListener> listeners = new ArrayList<MoveListener>();
  /**
   * type of the current movement
   */
  protected Movement.MovementType _moveType;
  private Monitor monitor = new Monitor();
  /**
   * Left motor.
   */
  protected final TachoMotor _left;
  /**
   * Right motor.
   */
  protected final TachoMotor _right;
  /**
   * Left motor degrees per unit of travel.
   */
  protected final float _leftDegPerDistance;
  /**
   * Right motor degrees per unit of travel.
   */
  protected final float _rightDegPerDistance;
  /**
   * Left motor revolutions for 360 degree rotation of robot (motors running
   * in opposite directions). Calculated from wheel diameter and track width.
   * Used by rotate() and steer() methods.
   **/
  protected final float _leftTurnRatio;
  /**
   * Right motor revolutions for 360 degree rotation of robot (motors running
   * in opposite directions). Calculated from wheel diameter and track width.
   * Used by rotate() and steer() methods.
   **/
  protected final float _rightTurnRatio;
  /**
   * Speed of robot for moving in wheel diameter units per seconds. Set by
   * setSpeed(), setMoveSpeed()
   */
  protected float _robotMoveSpeed;
  /**
   * Speed of robot for turning in degree per seconds.
   */
  protected float _robotTurnSpeed;
  /**
   * Motor speed degrees per second. Used by forward(),backward() and steer().
   */
  protected int _motorSpeed;
  /**
   * Motor rotation forward makes robot move forward if parity == 1.
   */
  protected byte _parity;
  /**
   * If true, motor speed regulation is turned on. Default = true.
   */
  protected boolean _regulating = true;
  /**
   * Distance between wheels. Used in steer() and rotate().
   */
  protected final float _trackWidth;
  /**
   * Diameter of left wheel.
   */
  protected final float _leftWheelDiameter;
  /**
   * Diameter of right wheel.
   */
  protected final float _rightWheelDiameter;
 
  protected float _minRadius = 0;
 
public float getMovementIncrement() {
  // TODO Auto-generated method stub
  return 0;
}

public float getAngleIncrement() {
  // TODO Auto-generated method stub
  return 0;
}
}
TOP

Related Classes of lejos.robotics.proposal.DifferentialPilot$Monitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.