There are three motors on the NXT labeled A, B and C. Each motor is equipped with an integrated encoder that can be used to determine the current position of the motor. The encoders have 360 counts per single revolution of the motor. A count of 180 indicates that the motor has traveled half a rotation.
motor[]
Sets the speed (-100 to +100) for a motor
nMotorPIDSpeedCtrl[]
Enables or disables speed regulation on a motor. Regulation provides precise control over motor speed using feedback from the motor encoders.
nSyncedMotors
Specifies the pair of motors to synchronize movement of a slave motor with the primary. The ‘’slaved’ motor will follow the speed and movement of the ‘primary’ motor.
nSyncedTurnRatio
Specifies the movement for the slaved motor for a pair of synchronized motors.
nMotorEncoder[]
Read / write the current position of a motor encoder.
nMotorEncoderTarget[]
Sets the targeted incremental movement for a motor.
nMotorRunState[]
Contains the state (idle, ramping up or down, steady state, holding encoder position while stopped) of a motor. This variable provides a convenient method of checking when a motor has reached a targeted encoder count – the motor state will change to “idle” when position is reached and motor has been stopped.
Additional variables used for advanced motor control
bFloatDuringInactiveMotorPWM
Indiciates whether float (coast0 or brake mode should be used during unpowered periods of motor movement.
nPidUpdateInterval[]
Specifies the update period, in milliseconds, for the motor speed regulation.
bMotorReflected[]
Boolean flag to indicate whether motor direction should be ‘flipped’ or ‘reflected’ from the normal.
nMaxRegulatedSpeed
Specifies the maximum speed, in encoder counts per second, to use for speed regulation.
nMaxRegulatedSpeed
Specifies the maximum speed, in encoder counts per second, to use for speed regulation.
bRobolab
A Boolean flag that indicates the NXT motor control should emulate the legacy RCX implementation. In the legacy implementation setting a value to ‘motor’ does not start the motor moving. There are additional function calls to turn the motor.on and off; these function calls are not exposed in RobotC. This variable is for compatibility with Robolab for the NXT.
Moors 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;
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 later can be set with the following variable
nMaxRegulatedSpeed = 750; // max regulated speed level
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
{}
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.
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.
nMotorEncoderTarget[motorA] = 1000; // move 1000 encoder counts and stop
motor[motorA] = 50; // move at half speed
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 = synchAC; // Motor ‘C’ is slaved to motor ‘A’
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 = synchAC; // Motor ‘C’ is slaved to motor ‘A’
//
// Drive in a straight line
//
nSyncedTurnRatio = +100; // Move in a straight line
nMotorEncoder[motorA] = 0;
nMotorEncoderTarget[motorA] = -1000; // move 1000 encoder counts and stop
motor[motorA] = 100;
while (nMotorEncoder[motorA] < 1000) // wait til movement is complete
{}
//
// Rotate in place to turn robot
//
nSyncedTurnRatio = -100; // Rotate in place
nMotorEncoderTarget[motorA] = 200; // move 200 encoder counts and stop
motor[motorA] = 50;
A value of 100 indicates that the slave will travel in the same direction and at exactly the same speed as the primary motor. -100 indicates that slave will travel at same speed but in opposite direction.
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. The RobotC compiler will automatically generate code at the start of your program to setup the brake or float mode.
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