NXT Motors and Servos Overview

From ROBOTC API Guide
Revision as of 20:17, 18 April 2012 by Bfeher (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
NXT → Motors and Servos Overview


For ROBOTC NXT Motor and Servo functions, check out Motor Functions and Servo Functions!



Motor Speed / Power Control

Motors are controlled by specifying a power level to apply to the motor. Power levels range from -100 to +100. Negative values indicate reverse direction and positive values indicate forward direction. To move motor ‘A’ forward at 50% of full power, you would use the following statement:
motor[motorA] = 50;  // set motorA to power level 50 (forward, half speed)
motor[] is the ROBOTC array variable that controls the motor power and motorA is an enum variable for motor A.


The default motor operating mode is an “open loop” configuration where the above statement would apply 50% ‘raw’ power to the motor. Open loop control does not result in a consistent speed across all motors; e.g. the speed will become lower as the batteries discharge and different motors will produce different speeds because of minor variations in the motors.


A “closed loop” control algorithm uses feedback from the motor encoder to adjust the raw power to provide consistent speed. Closed loop control continuously adjusts or regulates the motor raw power to maintain (for the above example) a motor speed that is 50% of the maximum regulated speed. Regulated motor control is enabled and disabled with the array variable nMotorPIDSpeedCtrl[].

nMotorPIDSpeedCtrl[motorA] = mtrNoReg;     // disables motor speed regulation
nMotorPIDSpeedCtrl[motorA] = mtrSpeedReg;  // enables motor speed regulation
With brand new alkaline batteries a motor can move at almost 1,000 encoder counts per second. But with a partially discharged motor and a motor that has had some wear and tear the maximum speed may reduce to 750 counts. This has an impact on speed regulation.


With fully charged batteries, the speed regulation software might result in an average to 75% power to achieve a regulated speed of 750 counts per second. But with partially charged batteries, it might be applying power almost all the time!


For speed regulation to function properly there needs to be “room” for the closed loop control firmware to adjust the raw power. If the batteries are partially discharged, you shouldn’t try to achieve a regulated speed above 750 counts per second.


The default maximum speed level is 1,000 counts per second. This value was chosen because it is the same value used by the standard NXT-G firmware. But, as explained above, with partially discharged batteries, perhaps only 750 counts can be achieved. This means that if you want to achieve consistent speeds across battery level you must either not specify speeds above the 75% level or reduce the maximum speed level. The maximum speed can be set with the following variable:

nMaxRegulatedSpeed = 750;  // max regulated speed level in degrees per second


Encoder Value

nMotorEncoder[] is an array that provides access to the current value of the motor encoder. To wait until the motor moves to a specific encoder position, you might use the following:
while (nMotorEncoder[motorA] < 1000)  // wait for motor to reach a specific location
{
  motor[motorA] = 50;  /* Run the motors forward at a power level of 50 
                          until 1000 encoder counts have been reached.  */
}
nMotorEncoder[] is a 16-bit variable. The maximum value before it overflows is 32,767 which allows for about 95 motor rotations. In long running applications, you may want to periodically reset the value in your application program to avoid overflow situations.


Moving to a Specific Encoder Value

You can move a motor a specific amount with the variable nMotorEncoderTarget[]. This indicates the number of encoder ticks to move. If you specify a positive value the motor will slow to a stop at this position. A negative value will leave the motor in coast / float mode when the encoder position is reached.


nMotorEncoderTarget[] does not turn on the motor. It only sets the target “stop” position. You have to start the motor moving with an assignment to motor[] variable.

nMotorEncoder[motorB] = 0;                // reset the Motor Encoder of Motor B
nMotorEncoderTarget[motorB] = 360;        // set the  target for Motor Encoder of Motor B to 360
motor[motorB] = 75;                       // motor B is run at a power level of 75
motor[motorC] = 75;                       // motor C is run at a power level of 75
 
while(nMotorRunState[motorB] != runStateIdle)  // while Motor B is still running:
{
  // do not continue
}
motor[motorB] = 0;                       // motor B is stopped at a power level of 0
motor[motorC] = 0;                       // motor C is stopped at a power level of 0


Synchronizing Two Motors

A very common application is two motors used to power the ‘left’ and ‘right’ motors on a robot. The robot will travel a straight line if both motors are rotating an exactly the same speed. The variable nSyncedMotors is used to synchronize two motors so that the second motor’s speed is slaved to the first motor.
nSyncedMotors = synchNone;  // no motor synchronization
nSyncedMotors = synchBC;    // motor ‘C’ is slaved to motor ‘B’
The synchronization “mode” is specified with the variable nSyncedTurnRatio. This ranges in value from -100% to +100%. The magnitude (0 to 100) represents the ratio of the slave speed to the primary motor speed. The sign indicates same (positive) or opposite (negative) direction of travel for the slave vs. the primary. A value of less than 100 will cause the robot to turn.
The following example will drive robot in a straight line and then turn the robot:
nSyncedMotors = synchBC;              // motor ‘C’ is slaved to motor ‘B’
// Drive in a straight line 
nSyncedTurnRatio = +100;              // move in a straight line
nMotorEncoder[motorB] = 0;
nMotorEncoderTarget[motorB] = -1000;  // move 1000 encoder counts and stop
motor[motorB] = 100;
 
while (nMotorEncoder[motorB] < 1000)  // wait until movement is complete
{}
 
// Rotate in place to turn robot
nSyncedTurnRatio = -100;              // rotate in place
nMotorEncoderTarget[motorB] = 200;    // move 200 encoder counts and stop
motor[motorB] = 50;
wait1Msec(3000);
A value of 100 indicates that the slave will travel in the same direction and at exactly the same speed as the primary motor. Sync ratio -100 indicates that slave will travel at same speed but in opposite direction.


Brake vs. Coast/Float Mode

Motor speed is controlled via a technique called pulse width modulation (PWM). PWM applies “pulses” of power to the motor thousands of times a second. Each pulse is a square wave containing a period of on or powered time followed by a period of off time. The ratio of on-time to off-time adjusts the power applied to the motor. Full battery voltage is applied during the on-time; this is a better technique for speed adjustment than systems that applies partial battery voltage to regulate the speed.

During the “off” time, power is not applied to the motors. During off-time the motors can be either “open-circuited” ore “short-circuited”. Open circuit results in a “floating” voltage where the motor is coasted. Short circuit results in a braking action. ROBOTC has a variable that controls which mode is used.

bFloatDuringInactiveMotorPWM = false;  // brake
bFloatDuringInactiveMotorPWM = true;   // coast or float
Brake mode works best for the NXT motors. This is the default mode. You can change the default mode within the ROBOTC “preferences” setup when under the "Expert" menu level. The ROBOTC compiler will automatically generate code at the start of your program to setup the brake or float mode.


Reflected or Mirrored Motors

Forward and reverse direction for a motor can be somewhat arbitrary. You may build a Lego model where the forward / reverse direction of the motor is the opposite of what seems logical. This can be easily handled in ROBOTC with the bMotorReflected[] variable which flips or mirrors the motor direction.
bMotorReflected[motorA] = true;  // flips/reflects the logical motor direction