📄 motor.java
字号:
package lejos.nxt;import lejos.nxt.*;import lejos.util.*;/** * Abstraction for a NXT motor. Three instances of <code>Motor</code> * are available: <code>Motor.A</code>, <code>Motor.B</code> * and <code>Motor.C</code>. To control each motor use * methods <code>forward, backward, reverseDirection, stop</code> * and <code>flt</code>. To set each motor's speed, use * <code>setSpeed. Speed is in degrees per second. </code>.\ * Methods that use the tachometer: regulateSpeed, rotate, rotateTo <br> * Motor has 2 modes : speedRegulation and smoothAcceleration. These are initially enabled. <> * They can be switched off/on by the methods regulateSpeed() and smoothAcceleration(). * The actual maximum speed of the motor depends on battery voltage and load.. * Speed regulation fails if the target speed exceeds the capability of the motor. * * <p> * Example:<p> * <code><pre> * Motor.A.setSpeed(720);// 2 RPM * Motor.C.setSpeed(7200); * Motor.A.forward(); * Motor.C.forward(); * Thread.sleep (1000); * Motor.A.stop(); * Motor.C.stop(); * Motor.A.regulateSpeed(true); * Motor.A.rotateTo( 360); * Motor.A.rotate(-720,true); * while(Motor.A.isRotating(); * int angle = Motor.A.getTachoCount(); // should be -360 * </pre></code> * @author Roger Glassey revised 22 March 2007 */public class Motor extends BasicMotor implements TimerListener{ private TachoMotorPort _port; private int _speed = 360; private int _speed0 = 360; // used for speed regulation private boolean _keepGoing = true;// for regulator /** * Initially true; changed only by regulateSpeed(),<br> * used by Regulator, updteState, reset* */ private boolean _regulate = true; public Regulator regulator = new Regulator(); private Timer timer = new Timer(100,this); // used for control of angle of rotation private int _direction = 1; // +1 is forward ; used by rotate(); private int _limitAngle; private int _stopAngle; private boolean _rotating = false; private boolean _wasRotating = false; private boolean _rampUp = true; private int _lastTacho = 0; private int _actualSpeed; /** initialized to be false(ramping enabled); changed only by smoothAcceleration */ private boolean _noRamp = false; /** * Motor A. */ public static final Motor A = new Motor (MotorPort.A); /** * Motor B. */ public static final Motor B = new Motor (MotorPort.B); /** * Motor C. */ public static final Motor C = new Motor (MotorPort.C); public Motor (MotorPort port) { _port = port; regulator.start(); regulator.setDaemon(true); timer.start(); } public int getStopAngle() { return (int)_stopAngle;} /** *calls controlMotor, startRegating; updates _direction, _rotating, _wasRotating */ void updateState() { synchronized(regulator) { if(_wasRotating)setSpeed(_speed0); _rotating = false; _wasRotating = false; if(_mode>2) // stop or float { _port.controlMotor(0, _mode); return; } _port.controlMotor(_power, _mode); if(_regulate) { regulator.reset(); _rampUp = true; } _direction = 3 - 2*_mode; } } /** * @return true iff the motor is currently in motion. */ public final boolean isMoving() { return (_mode == 1 || _mode == 2 || _rotating); } /** * causes motor to rotate through angle. <br> * @param angle through which the motor will rotate */ public void rotate(int angle) { rotateTo(getTachoCount()+angle); } /** * causes motor to rotate through angle; <br> * iff immediateReturn is true, method returns immediately and the motor stops by itself <br> * When the angle is reached, the method isRotating() returns false; * @param angle through which the motor will rotate * @param immediateReturn iff true, method returns immediately, thus allowing monitoring of sensors in the calling thread. */ public void rotate(int angle, boolean immediateReturn) { int t = getTachoCount(); rotateTo(t+angle,immediateReturn); } /** * causes motor to rotate to limitAngle; <br> * Then getTachoCount should be within +- 2 degrees of the limit angle when the method returns * @param limitAngle to which the motor will rotate */ public void rotateTo(int limitAngle) { rotateTo(limitAngle,false); } /** * causes motor to rotate to limitAngle; <br> * if immediateReturn is true, method returns immediately and the motor stops by itself <br> * Then getTachoCount should be within +- 2 degrees if the limit angle * When the angle is reached, the method isRotating() returns false; * @param limitAngle to which the motor will rotate, and then stop. * @param immediateReturn iff true, method returns immediately, thus allowing monitoring of sensors in the calling thread. */ public void rotateTo(int limitAngle,boolean immediateReturn) { _stopAngle = limitAngle; if(limitAngle > getTachoCount()) _mode = 1; else _mode = 2; _port.controlMotor(_power, _mode); _direction = 3 - 2*_mode; if(_regulate) regulator.reset(); if(!_wasRotating) { _stopAngle -= _direction * overshoot(); _limitAngle = limitAngle; } _rotating = true; // rotating to a limit _rampUp = !_noRamp && Math.abs(_stopAngle-getTachoCount())>40 && _speed>200; //no ramp for small angles if(immediateReturn)return; while(isMoving()) Thread.yield(); }/** *inner class to regulate speed; also stop motor at desired rotation angle **/ private class Regulator extends Thread { /** *tachoCount when regulating started */ int angle0 = 0; /** * set by reset, used to regulate motor speed */ float basePower = 0; /** * time regulating started */ int time0 = 0; /** * helper method - used by reset and setSpeed() */ int calcPower(int speed) { float pwr = 100 - 7.4f*Battery.getVoltage()+0.065f*speed;// no-load motor if(pwr<0) return 0; if(pwr>100)return 100; else return (int)pwr; } /** * called by forward() backward() and reverseDirection() <br> * resets parameters for speed regulation **/ public void reset() { if(!_regulate)return; time0 = (int)System.currentTimeMillis(); angle0 = getTachoCount(); basePower = calcPower(_speed); setPower((int)basePower); } /** * Monitors time and tachoCount to regulate speed and stop motor rotation at limit angle */ public void run() { int limit = 0; float error = 0; float e0 = 0; float accel = 1.5f;// deg/sec/ms was 1.5 int td = 100; float ts = 0; //time to stabilize boolean wasRegulating = true; while(_keepGoing) { synchronized(this) { if(_regulate && isMoving()) //regulate speed { int elapsed = (int)System.currentTimeMillis()-time0; int angle = getTachoCount()-angle0; if(_rampUp) { ts = _speed/accel; if (elapsed +td<ts)// not yet up to speed { elapsed +=td; // target distance = a * t * t/ 2 - maintain constant acceleration error = accel*elapsed * elapsed/2000 - (float)Math.abs(angle); basePower = calcPower((int)Math.max(elapsed*accel,400)); } else // adjust elapsed time for acceleration time - don't try to catch up { error = ((elapsed + td-ts/2)* _speed)/1000f - (float)Math.abs(angle); } } else error = (elapsed*_speed/1000f)- (float)Math.abs(angle); float power = basePower + 2 * error -1 * e0;// magic numbers from experiment if(power<0) power = 0; e0 = error; float smooth = 0.0015f;// another magic number from experiment basePower = basePower + smooth*(power-basePower); setPower((int)power); } // stop at rotation limit angle// int tc = getTachoCount(); if(_rotating && _direction*(getTachoCount() - _stopAngle)>-1) { _mode = 3; // stop motor _port.controlMotor (0, 3); int a = angleAtStop();//returns when motor has stopped int remaining = _limitAngle - a; if(_direction * remaining >0 ) // not yet done { if(!_wasRotating)// initial call to rotate(); save state variables { _speed0 = _speed; setSpeed(150); _wasRotating = true; wasRegulating = _regulate; _regulate = true; limit = _limitAngle; } rotateTo(limit - remaining/3,true); //another try } else //rotation complete; restore state variables { setSpeed(_speed0);//restore speed setting _mode = 3; // stop motor maybe redundant _port.controlMotor (0, _mode); _rotating = false; _wasRotating = false; _regulate = wasRegulating; } } } Thread.yield(); } } /** *helper method for run **/ int angleAtStop() { int a0 = getTachoCount(); boolean turning = true; int a = 0; while(turning) { _port.controlMotor(0,3); // looks redundant, but controlMotor(0,3) fails, rarely. try{Thread.sleep(20);}// was 10 catch(InterruptedException w){} a = getTachoCount(); turning = Math.abs(a - a0)>0; a0 = a; } return a; } } /** *causes run() to exit */ public void shutdown(){_keepGoing = false;} /** * turns speed regulation on/off; <br> * Cumulative speed error is within about 1 degree after initial acceleration. * @param yes is true for speed regulation on */ public void regulateSpeed(boolean yes) { _regulate = yes; } /** * enables smoother acceleration. Motor speed increases gently, and does not <> * overshoot when regulate Speed is used. * */ public void smoothAcceleration(boolean yes) {_noRamp = ! yes;} /** * Sets motor speed , in degrees per second; Up to 900 is posssible with 8 volts. * @param speed value in degrees/sec */ public final void setSpeed (int speed) { _speed = Math.abs(speed); setPower((int)regulator.calcPower(_speed)); regulator.reset(); _rampUp = false; } /** *sets motor power. This method is used by the Regulator thread to control motor speed. *Warning: negative power will cause the motor to run in reverse but without updating the _direction *field which is used by the Regulator thread. If the speed regulation is enabled, the rusults are *unpredictable. */ public synchronized void setPower(int power) { _power = power; _port.controlMotor (_power, _mode); } /** * Returns the current motor speed in degrees per second */ public final int getSpeed() { return _speed; } public int getMode() {return _mode;} public int getPower() { return _power;} private int overshoot() { return (int)( _speed*0.060f); } /** * Return the angle that a Motor is rotating to. * * @return angle in degrees */ public int getLimitAngle() { return _limitAngle; } /** *returns true when motor is rotating towarad a specified angle */ public final boolean isRotating() { return _rotating; } /** * requred by TimerListener interface */ public void timedOut() { int angle = getTachoCount(); _actualSpeed = 10*(angle - _lastTacho); _lastTacho = angle; } /** *returns actualSpeed degrees per second, calculated every 100 ms; negative value means motor is rotating backward */ public int getActualSpeed() { return _actualSpeed;} /** * Returns the tachometer count. * * @return tachometer count in degrees */ public int getTachoCount() { return _port.getTachoCount(); } /** * Resets the tachometer count to zero. */ public void resetTachoCount() { _port.resetTachoCount(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -