Virus Robotics Programming Help

Hi,
We are nearing the time for Uk nationals again, as a result im switching our code from easy to robotc (I feel more comfortable using robotc with sensors.)

I would like to attempt to do some more complicated things than I have attempted in the past, but I envisage I will need some help!

To begin with I would like to programme an arcade style drive. I though this would be a fairly simple task, but I seem to be only able to use my motors up to half their possible power levels (due to the /2 bit)? I have searched the internet but lots of different sites say different things.

Help will be much appreciated!

There are a few variations on arcade drive, mostly the differences are about how to handle the clipping when control values are added and go over the maximum.

Here is probably the simplest version, no clipping, we let ROBOTC handle motor control values that are over 127.

task main()
{
    int forward, turn;
    int drive_l_motor;
    int drive_r_motor;
    
    while(1)
        {
        // get joystick
        forward = vexRT Ch3 ];
        turn    = vexRT Ch4 ];
        
        // Set drive
        drive_l_motor = forward + turn;
        drive_r_motor = forward - turn;

        // set motors
        motor port1  ] = drive_l_motor;
        motor port10 ] = drive_r_motor;
        
        // Don't hog the cpu
        wait1Msec(25);
        }
}

I’ve written that in a verbose fashion so you can see what each part means and does. Others may write as follows.

task main()
{    
    while(1)
        {
        // set motors
        motor port1  ] = vexRT Ch3 ] + vexRT Ch4 ];
        motor port10 ] = vexRT Ch3 ] - vexRT Ch4 ];
        
        // Don't hog the cpu
        wait1Msec(25);
        }
}

The format of the code I generally use is like this.

void
DriveSystemArcadeDrive( int forward, int turn )
{
    long drive_l_motor;
    long drive_r_motor;

    // Set drive
    drive_l_motor = forward + turn;
    drive_r_motor = forward - turn;

    // normalize drive so max is 127 if any drive is over 127
    int max = abs(drive_l_motor);
    if (abs(drive_r_motor)  > max)
        max = abs(drive_r_motor);
    if (max>127) {
        drive_l_motor = 127 * drive_l_motor / max;
        drive_r_motor = 127 * drive_r_motor / max;
    }

    // set motors
    motor port1  ] = drive_l_motor;
    motor port10 ] = drive_r_motor;
}

task main()
{
    int forward, turn;

    while(1)
        {
        // get joystick
        forward = vexRT Ch3 ];
        turn    = vexRT Ch4 ];
        
        // Arcade drive
        DriveSystemArcadeDrive( forward, turn );
        
        // Don;t hog cpu
        wait1Msec(25);
        }
}

I’m using a function to implement the arcade drive, the function also has some control value limiting. The advantage with using a function is that when creating your autonomous code you can also call this with fixed values, for example, to drive forwards.

DriveSystemArcadeDrive( 127, 0 );

To Stop

DriveSystemArcadeDrive( 0, 0 );

To rotate right

DriveSystemArcadeDrive( 0, 127 );

Ok thanks for the help, it’s really useful and the first set of code helps me to understand the second (unfortunately your third bit went over my head sorry.) Just out of interest what is this whole idea of variable ‘clipping’, is it something to do with the 127 limit and having to be reduced or am I confused?

Yes. Normally if you try to set a motor to value 400 (for example), the motor will just be set at 127. Imagine you try to set two motors at 800 and 400. The first motor should go twice the speed of the second, but if you try to set each motor independently of each other (i.e. the first way), both motors will be cut off at 127. If the third way is used, the motors will be set at 127 and 64. The idea of scaling is to make sure that all motors go the same relative speed, scaled down to between -127 and 127.

Thanks to your help I managed to get the arcade drive working (although we have now switched to mecanums.) I have now moved on to autonomous and have managed to use two encoders to make the robot drive forwards in a straight line. However, I am finding it impossible to move on to the next stage of the program (the lift going up.) If I include a set all motors to 0 function the robot drive jerkily and never stops and if not it won’t move on either!

I am guessing I am missing something very obvious… I have attached a copy of the code .
Thanks again!
test autonmous.c (1.92 KB)

You have to look closely at where you have “while” loops and what code will execute in them. The drive code is like this in your file.

while(SensorValue[encoderleft]> -1150)
{
    if(SensorValue[encoderright] == SensorValue[encoderleft]) // If rightEncoder has counted the same amount as leftEncoder:
        {
        // Move Forward
        }
    else if(SensorValue[encoderright] > SensorValue[encoderleft])   // If rightEncoder has counted more encoder counts
        {
        // Turn slightly right
        }
    else    // Only runs if leftEncoder has counted more encoder counts
        {
        // Turn slightly left
        }

        {
        // Stop
        }

    while(SensorValue[pot]<170)
        {
        motor[lift]= 127;
        }
        {
        motor[lift]=0;
        }
}

It will run one of the three if-then-else conditions, then stop the drive, then try and raise the lift. All this is happening in one loop so the drive will be starting then stopping very quickly. The arm may also be slightly moving depending on the potentiometer value. You need to have a while loop for the drive forward section, followed by stopping the drive and then movement of the arm, something like this.

task main()
{
    wait1Msec(10);

    // Clear encoders
    SensorValue[encoderright] = 0;
    SensorValue[encoderleft] = 0;


    // This while loop runs until the robot has moved
    // forward to 1150 encoder counts
    while(SensorValue[encoderleft]> -1150)
        {
        if(SensorValue[encoderright] == SensorValue[encoderleft]) // If rightEncoder has counted the same amount as leftEncoder:
            {
            // Move Forward
            motor[frontleft] = 127;
            motor[backleft] = 127;
            motor[frontright] = 127;
            motor[backright] = 127;
            }
        else if(SensorValue[encoderright] > SensorValue[encoderleft])   // If rightEncoder has counted more encoder counts
            {
            // Turn slightly right
            motor[frontleft] = 127;
            motor[backleft] = 127;
            motor[frontright] = 102;
            motor[backright] = 102;
            }
        else    // Only runs if leftEncoder has counted more encoder counts
            {
            // Turn slightly left
            motor[frontleft] = 102;
            motor[backleft] = 102;
            motor[frontright] = 127;
            motor[backright] = 127;
            }
        
        // It's good to have a small delay in every while loop
        wait1Msec(10);
        } // this is the extent of the while loop to drive forward

    // Now stop the drive, we have arrived
    motor[frontleft] = 0;
    motor[backleft] = 0;
    motor[frontright] = 0;
    motor[backright] = 0;

    // Now lift the arm
    // start the arm motor
    motor[lift]= 127;
    // A value of 170 seems very small, logic may be backwards here
    while(SensorValue[pot]<170)
        wait1Msec(10);
    // stop the arm motor
    motor[lift]=0;

        
    // Auton finished
}

You may want to consider move some of your code into functions so that as the autonomous gets more complicated then it will be easier to read and use, the drive forward section is a good candidate here.

Ah ok, i see what you mean! sorry that was a pretty stupid mistake. As for adding functions I may try too but I have never done it before so depends on time.

I have one other question currently. Our pneumatics (single acting) are firing incessantly while the robot is connected turned on or off or basically for any reason when the button to fire them is not pressed. Is there anything I can do to solve this? At the moment we seem to have wasted all our air before we begin practicing!

When using ROBOTC, the pneumatics will fire when the cortex is first turned on, but should not fire when your program is running unless you tell them to. Usual procedure is to turn on the robot with the air turned off, after VEXnet has connected then turn the air on. If you have problems after VEXnet is connected then post the code and I will have a look.

See this thread for a long complicated explanation on why ROBOTC fires the pneumatics on startup.

Thank you again a very useful reply. By turning the air on once connected you mean we shouldn’t plug the pnemautics cable in until after the robot is connected? (I’m pretty sure that’s what you mean!)

You may have an on/off switch that looks something like this. If not, then you could a) not pump up pnuematics until you’re ready, b) unplug the solenoid (as you suggested), or c) use the pressure regulator to act as an on/off switch, not recommended if you’ve fine tuned the pressure.

Ok, we have managed to get around the firing problem by not connecting our pneumatics until after the robot is connected. However, I have developed a new problem with the robot not driving straight despite my attempts at using two encoders together.

I have enclosed a full copy of the code(sorry about the hideous lack of functions :frowning: ) if anyone has any ideas I will try them out tomorrow!

P.S. I may try adding functions I just have no idea where to begin

Thanks
virusrobotics nationals code (front left).c (8.27 KB)

I assume that setting all drive motors to 127 does not make them drive straight. The best way to fix this issue is to make sure motor speeds are fairly close when at full speed and to reduce friction. The week before competition isn’t exactly the best time for these kinds of repairs, so programming is the next best option. Might I introduce you to the P controller?

A P controller will let you make gradual changes to driving straight, I’ve edited one block of your code below:


#define P_straight 0.5 // *This should be put with the other preprocessor statements (#pragma and #include)*
	int error;
	while (SensorValue[encoderleft] > -1100)
	{
		// *If error is positive, Right > Left  - slow down right*
		// *If error is negative, Left > Right - slow down left*
		error = SensorValue[encoderright] - SensorValue[encoderleft];
		error *= P_straight;

		motor[frontleft] = 127 + error;
		motor[backleft] = 127 + error;
		motor[frontright] = 127 - error;
		motor[backright] = 127 - error;

		// *Don't be a hog*
		wait10Msec(1);
	}
	motor[frontleft] = 0;
	motor[backleft] = 0;
	motor[frontright] = 0;
	motor[backright] = 0;

The P_straight value will need to be adjusted until the desired effect is reached. Ideally, you would also use a PID controller for controlling the overall speed of the motors. But as you’ve already got values plugged in that I assume work at the moment, using a PID controller will only make you have to readjust everything.

Also, is there any particular reason why you’ve surrounded portions of code in brackets, like here (ln 72-78):

	{

		motor[frontleft] = 0;
		motor[backleft] = 0;
		motor[frontright] = 0;
		motor[backright] = 0;
	}

Hope this helps!