Around four years ago I started a thread called “RobotC programming tips”. I’ve decided to start another called “RobotC - Bad programming habits” as I’ve recently seen multiple examples of the same bad programming techniques being used and it seems that we (the forum) should try and address these so that everyone can improve and learn.
(Many of these will also apply to EasyC, PROS or ConVEX)
**Using double negatives
**
Imaging you have just created a new robot drive, very simple, four wheels and four direct drive motors. You decide (as you have been doing VEX for six weeks now and are an expert ) to add some sensors to this skyrise dominating robot and have read on the forum that using encoders on the wheels will allow super accurate autonomous code. So you add an IME to each of the two front wheels and start to write your program. First of all you create this code.
#pragma config(Motor, port2, DriveWheel_LF, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port3, DriveWheel_LB, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port8, DriveWheel_RB, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port9, DriveWheel_RF, tmotorVex393_MC29, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
task main()
{
while( 1 )
{
motor DriveWheel_LF ] = vexRT Ch3 ];
motor DriveWheel_LB ] = vexRT Ch3 ];
motor DriveWheel_RF ] = vexRT Ch2 ];
motor DriveWheel_RB ] = vexRT Ch2 ];
wait1Msec(10);
}
}
It’s just a simple tank drive control.
But you find that the robot spins, obvious, you need to reverse the direction of the wheels on one side. So you modify the code and send negative values to the right side motors.
#pragma config(Motor, port2, DriveWheel_LF, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port3, DriveWheel_LB, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port8, DriveWheel_RB, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port9, DriveWheel_RF, tmotorVex393_MC29, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
task main()
{
while( 1 )
{
motor DriveWheel_LF ] = vexRT Ch3 ];
motor DriveWheel_LB ] = vexRT Ch3 ];
motor DriveWheel_RF ] = -vexRT Ch2 ];
motor DriveWheel_RB ] = -vexRT Ch2 ];
wait1Msec(10);
}
}
Great, now the robot drives correctly. Time to start on the autonomous code. You write the following.
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, I2C_1, , sensorQuadEncoderOnI2CPort, , AutoAssign)
#pragma config(Sensor, I2C_2, , sensorQuadEncoderOnI2CPort, , AutoAssign)
#pragma config(Motor, port2, DriveWheel_LF, tmotorVex393_MC29, openLoop, encoderPort, I2C_1)
#pragma config(Motor, port3, DriveWheel_LB, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port8, DriveWheel_RB, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port9, DriveWheel_RF, tmotorVex393_MC29, openLoop, encoderPort, I2C_2)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
#include "Vex_Competition_Includes.c" //Main competition background code...do not modify!
void pre_auton()
{
bStopTasksBetweenModes = true;
}
task autonomous()
{
nMotorEncoder DriveWheel_LF ] = 0;
nMotorEncoder DriveWheel_RF ] = 0;
// Go forwards
motor DriveWheel_LF ] = 127;
motor DriveWheel_LB ] = 127;
motor DriveWheel_RF ] = -127;
motor DriveWheel_RB ] = -127;
// Wait until encoder has changed by 1000 counts
while( ( nMotorEncoder DriveWheel_LF ] < 1000 ) && ( nMotorEncoder DriveWheel_RF ] < 1000 ) )
wait1Msec(10);
// Stop
motor DriveWheel_LF ] = 0;
motor DriveWheel_LB ] = 0;
motor DriveWheel_RF ] = 0;
motor DriveWheel_RB ] = 0;
}
task usercontrol()
{
// add my driver code later
while(1) wait1Msec(10);
}
Easy, drive forwards 1000 counts. But the code doesn’t work, the robot keeps driving. You break out the ROBOTC debugger and look at what the motors and sensors are doing and see the problem, the IME on the right wheel is counting backwards, you change the code.
// Wait until encoder has changed by 1000 counts
while( ( nMotorEncoder DriveWheel_LF ] < 1000 ) && ( nMotorEncoder DriveWheel_RF ] > -1000 ) )
wait1Msec(10);
and the robot drives forward and stops.
What you have done here is create a double negative, sending negative control values to the motor has caused the encoder to count backwards and now you have to either negate that number or reverse the logical tests to account for it. Very soon the code gets complicated as more steps to the autonomous code are added.
What you should do
Use the motor reverse flag in motors&sensors setup.
You want to always try and have the following setup.
**Send positive control values to motors to make the robot go forwards.
When the robot goes forward (by sending those positive control values) the encoders you have should increment.
**
Here is the correct version of the autonomous code.
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, I2C_1, , sensorQuadEncoderOnI2CPort, , AutoAssign)
#pragma config(Sensor, I2C_2, , sensorQuadEncoderOnI2CPort, , AutoAssign)
#pragma config(Motor, port2, DriveWheel_LF, tmotorVex393_MC29, openLoop, encoderPort, I2C_1)
#pragma config(Motor, port3, DriveWheel_LB, tmotorVex393_MC29, openLoop)
#pragma config(Motor, port8, DriveWheel_RB, tmotorVex393_MC29, openLoop, reversed)
#pragma config(Motor, port9, DriveWheel_RF, tmotorVex393_MC29, openLoop, reversed, encoderPort, I2C_2)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
#include "Vex_Competition_Includes.c" //Main competition background code...do not modify!
void pre_auton()
{
bStopTasksBetweenModes = true;
}
task autonomous()
{
nMotorEncoder DriveWheel_LF ] = 0;
nMotorEncoder DriveWheel_RF ] = 0;
// Go forwards
motor DriveWheel_LF ] = 127;
motor DriveWheel_LB ] = 127;
motor DriveWheel_RF ] = 127;
motor DriveWheel_RB ] = 127;
// Wait until encoder has changed by 1000 counts
while( ( nMotorEncoder DriveWheel_LF ] < 1000 ) && ( nMotorEncoder DriveWheel_RF ] < 1000 ) )
wait1Msec(10);
// Stop
motor DriveWheel_LF ] = 0;
motor DriveWheel_LB ] = 0;
motor DriveWheel_RF ] = 0;
motor DriveWheel_RB ] = 0;
}
task usercontrol()
{
// add my driver code later
while(1) wait1Msec(10);
}
If gearing is such that the left hand side need reversing then so be it but always try and achieve.
Positive motor values => forwards => incrementing encoders.
The same applies to lift systems, try and achieve the following
Positive motor values => lift going up => incrementing encoders.
Trust me, creating autonomous (or PID) code gets easier if you do this.