In this instructable, you will learn the basics of programming a VEX Cortex, in the RobotC software. Before reading this instructable, you should have a basic understanding of programming, and how to use the RobotC software.
*Click images to enlarge*
Starting right at the beginning, the first thing that you have to do, in order to program the robot, is have a programming software and compiler! This is made simple with RobotC - www.robotc.net
In the pictures, you can see the steps required to install RobotC, but just in case, they are also listed below:
1. Go to www.robotc.net
2. Select Download, and in the drop-down, select the version you want, for this demonstration I will be using "RobotC for Vex Cortex & PIC"
3. Click the Blue download button
4. Wait for the download to complete. Once it has, click and open the .exe file
1. Follow on-screen instructions to successfully install RobotC
2. Let's get to work! Open the new icon on your desktop!
*Click image to enlarge*
Purchasing a license is very simple, you go to the robotc website and select "Purchase", after, find the version of RobotC and pay for it - www.robotc.net/purchase
Once you have purchased a license, it is not difficult at all to register your software:
1. Click on the "Help" tab, and then click "Manage Licenses"
2. Click "Add License", select your version, and fill out the necessary fields. If everything was entered correctly, your license should be ready and working right away!
*Click images to enlarge*
The first thing we need to do, after activating the license, is to make sure that the proper platform is selected. To do so, go to "Robot > Platform Type > VEX Robotics > VEX 2.0 Cortex". Once this has been selected, we are ready to start programming a competition template!
To open your first competition template, where we will do all of the programming, go to "File > New > Competition Template".
IMPORTANT NOTE: When first opening the Competition Template, do not change ANY values, unless you know EXACTLY what you are doing. If these values are changed incorrectly, your program WILL NOT work!
The first thing you should do with any RobotC code, is setup your motors and sensors, so that we can begin to program a drive. If you do not setup these motors, it will be a pain to change all of your motor names in your entire code once that is done. Essentially, make sure your robot has at least a chassis with motors on it before you start programming!
To setup your motors:
1. Go to "Robot > Motors and Sensors Setup"
2. You will have many tabs to choose from, to setup the motor ports, navigate to the "Motors" tab, for Analog Sensors, navigate to the "VEX 2.0 Analog Sensors 1-8" tab, etc...
3. Enter a name for the motor and/or sensor beside the correct port number. In the "Type" drop-down, select what type of motor or sensor you are using. IMPORTANT NOTE: You may have to reverse a motor, depending on how it is positioned on the robot.
4. An example of a completed Motor setup can be found in the gallery above.
Once you have successfully completed the Motor and Sensor setup, you should now have several lines of new code at the very top of your Competition Template. Do not try to change these values directly in the code while you are still learning, stay with the graphical Motor Setup!
*Click images to enlarge*
Competition includes:
Competition includes, load all the files and values that the program uses to make it work in a competition. DO NOT edit any of these, unless you know EXACTLY what you are doing.
The Pre-Autonomous is the field where you tell the robot what to do, before the competition match starts. This means that if you need a Gyro sensor to be reset to 0, so the autonomous turns to the correct degree, this is where you do it!
This section of the Competition Template, is where you put your program-controlled drive, for the beginning of every match, otherwise known as the "Autonomous". In this code, everything that you want the robot to do MUST be controlled by your program, as trying to implement a drive program WILL NOT work in the Autonomous section of a competition.
Within the "while" loop, this is where you program your driver control. If you want a joystick to move the robot forward, while the other joystick turns it, this is where you would program it! In this mode, if you try to program an Autonomous to be triggered when you push a button, it can be done, however it is more advanced and can be quite difficult to operate.
At the very top of your program, after the motor setup but before the Pre-Autonomous, you have the option to write and/or include functions. Functions are programmed only once at the top, but you can call it within your Autonomous whenever you need to, this makes programming A LOT easier, and cleaner!
*Click image to enlarge*
When programming an autonomous, you want it to be as accurate as possible, and to do so, adding a couple sensors will help A LOT! Programming these sensors can be difficult, but setting them up, is extremely simple! Once you have setup your sensor in the Motor and Sensor Setup, there is not much you have to do to configure them:
Setting up a gyroscope:
1. Make sure what you are going to type is in the Pre-Autonomous loop
3. Type the following:
SensorValue[] = SensorNone;
Add the name of your gyroscope between the "[]". Do not forget the semicolon!
4. Type the following:
SensorValue[] = SensorGyro;
Add the name of your gyroscope between the "[]". Do not forget the semicolon!
5. Type the following:
SensorValue[] = 0;
Add the name of your gyroscope between the "[]". Do not forget the semicolon!
In these 3 lines of code, "SensorValue", is the way of telling the sensor what you want the value to be. Setting the sensor as "sensorNone" tells the cortex that the sensor is non-existent, then telling it that the sensor is "sensorGyro", tells the cortex that the sensor is actually a gyroscope. This has just reset the gyroscope! When you are setting the sensor as "0", you are telling the gyroscope that the current degree is "0", so when you want it to turn 90 degrees, the value is exact.
Setting up other sensors:
Setting up other sensors is the same thing as setting up a gyro, however, instead of "sensorGyro", it will be the sensor that you chose. Here are some sensor reset commands for the following:
Ultrasonic (Inch):
SensorValue[] = sensorNone; SensorValue[] = sensorSONAR_Ping_inch; //Replace "inch" with cm or mm, depending on the measurements you want. SensorValue[] = 0;
Potentiometer:
SensorValue[] = sensorNone; SensorValue[] = sensorPotentiometer; SensorValue[] = 0;
I2C QuadEncoder:
SensorValue[] = sensorNone; SensorValue[] = sensorQuadEncoderOnI2CPort; SensorValue[] = 0;
Pneumatics:
SensorValue[] = sensorNone; SensorValue[pneuOut1] = sensorDigitalOut; SensorValue[] = 0; // 0 is neutral or closed state, change to 1 if starting should be open
If there are any sensors that I missed that you need, the RobotC forums are an excellent source, but this is pretty self explanatory.
*Click image to enlarge*
When writing a driver control, you have a few options, depending on what chassis you have setup. If you are running a standard 4 motor drive, with regular rubber wheels, you have two options, a tank type drive, or an arcade style drive.
A tank type drive uses both joysticks, the left to control your two left wheels, and the right to control your two right wheels. This is probably the most simple drive program to write, however it is not very good when it comes to competitions, because you may need a joystick for something else. To turn the robot towards the left, you would move the left joystick back, and the right joystick forward. This would do a spot-turn to wherever you need it to. To turn right you would do the opposite. Driving forward has both joysticks forward, and backwards has both joysticks backwards.
Here is an example code of a tank type drive, keep in mind that values would have to be changed to suit your robot.
motor[FrontL] = vexRT[Ch3]; motor[BackL] = vexRT[Ch3]; motor[FrontR] = vexRT[Ch2]; motor[BackR] = vexRT[Ch2];
In this code, we are assigning the "motor[]" to a joystick on the controller. "vexRT[];" is simply the command for the controller, "Ch2" assigns which controller channel to use, "Ch2" is the Y axis on the right joystick of the controller. An image is provided in the gallery that shows the controller with the joystick channels. If you are using this code, make sure you replace what's in between the "[]", with the name of your own motors, but make sure that both left motors are on the same channel, and that the right motors are both on their channel.
An arcade style drive can be more complicated to program, as you are only using one joystick to control the entire motion of the robot's chassis. Below is an arcade style code, with explanations.
motor[FrontL] = vexRT[Ch2] + vexRT[Ch1]; motor[BackL] = vexRT[Ch2] + vexRT[Ch1]; motor[FrontR] = vexRT[Ch2] - vexRT[Ch1]; motor[BackR] = vexRT[Ch2] - vexRT[Ch1];
In this code, we are still assigning the motor to the correct channel, but now we are adding or subtracting another channel, to allow the robot to turn as you move the joystick to the side. This has been made and tested to only use one joystick, and this particular code uses the right joystick, which leaves the left one open for a lift!
When programming a motor powered lift, you are essentially writing the same thing as a chassis drive. Here is an example of a simple lift program, for a six-bar design:
motor[BackL] = vexRT[Ch3]; motor[TopR] = vexRT[Ch3]; motor[BackR] = vexRT[Ch3]; motor[TopL] = vexRT[Ch3];
In this code, all motors are being controlled by channel 3, otherwise known as the Y axis of the left joystick. Now with this code, and an arcade style drive, you can control both the lift and the drive at the same time!
Pneumatics are a little different when it comes to programming, remember when we were setting up the sensors in the Pre-Autonomous? We are essentially doing the same thing, however now we are only providing a value of "0", or "1", and it is within an if / else if / else loop!
If / else if / else loops:
If / else if / else loops do exactly what they sound like they would do, "IF" this is done, then do something, if it isn't done, then do something "ELSE". Here is a sample code:
if (x = 2) { //If x is equal to 2... print("x is equal to 2!"); } else if (x = 3) { //If x is equal to 3... print("x is equal to 3!"); } else { //If x is not equal to either of those print("I don't know what x is!"); }
This code is a simple way of demonstrating an if / else if / else loop. Now, here is the code for the pneumatics, keep in mind that we are implementing the pneumatics command, and the controller command in the same if / else if / else loop.
if (vexRT[Btn6U] == 1) { //If the controller button "6 UP" is pressed, extend the pneumatics SensorValue[Pneumatics] = 1; } else if (vexRT[Btn6D] == 1) { //If the controller button "6 DOWN" is pressed, retract the pneumatics SensorValue[Pneumatics] = 0; } else { // If nothing is pressed // Do nothing at all }
In this loop above, it is saying IF the controller button "6 UP" is pressed, extend the pneumatics, but IF the controller button "6 DOWN" is pressed, retract the pneumatics, and if nothing is pressed, then do nothing!
When you're working with buttons, it is almost the same code as the joystick, however instead of just assigning the joystick to a motor, we have to tell the cortex that when the button is pressed, do something. The button state of "1" means that the button is being pressed, while the button state of "0", means that the button is not being pressed. When programming the buttons, make sure you include two equal signs (==).
Autonomous functions, are a nice and simple way to keep your code neat and tidy. When it comes to programming them, they are placed before the pre-autonomous, but after the competition includes (see gallery). A lot of function examples can be found in the RobotC files.
Below is a code for a standard move, explanations are commented in the code.
void standardMove(int time, int power) { // void is a type of loop, we are creating a motor[BackL] = power; // function called "standardMove", in this motor[FrontL] = power; // function, an int of time, and power is motor[BackR] = power; // created, and called within the loop. motor[FrontR] = power; // If you wanted the robot to move forward wait1Msec(time); // for 1 second, at the power of 80, you motor[BackL] = 0; // would write "standardMove(1000, 80);". motor[FrontL] = 0; // This works because the "1000" is replacing motor[BackR] = 0; // the "time", and 80 is replacing the "power". motor[FrontR] = 0; // Stop motors once done. }
Programming a standard lift is essentially the same thing as a drive, all you really have to do is change the motor names, and rename the actual function. Therefore, an explanation is not needed.
void standardLift(int time, int power) { motor[BackL] = power; motor[TopL] = power; motor[BackR] = power; motor[TopR] = power; wait1Msec(time); motor[BackL] = 0; motor[TopL] = 0; motor[BackR] = 0; motor[TopR] = 0; }
Now we have come to the more tricky part, programming a gyro turn. There are several ways of doing this, some very simple yet not as reliable, and some more complicated with drift corrections, that are more reliable. Luckily for us, RobotC has already provided a drift correction program, so it's all copy and paste into our own function!
#define TURN_SLOWDOWN 100 int degrees = 0; int error = 5; void gyroTurn(int bearing) { int currentBearing = SensorValue[Gyro]; int targetBearing = bearing + currentBearing; if (bearing > 0) { // Left turn while (SensorValue[Gyro] < targetBearing - TURN_SLOWDOWN) { motor[BackL] = -50; motor[FrontL] = -50; motor[BackR] = 50; motor[FrontR] = 50; } while (SensorValue[Gyro] < targetBearing) { motor[BackL] = -20; motor[FrontL] = -20; motor[BackR] = 20; motor[FrontR] = 20; } motor[BackL] = 0; motor[FrontL] = 0; motor[BackR] = 0; motor[FrontR] = 0; } else { // Right turn while (SensorValue[Gyro] > targetBearing + TURN_SLOWDOWN) { motor[BackL] = 50; motor[FrontL] = 50; motor[BackR] = -50; motor[FrontR] = -50; } while (SensorValue[Gyro] > targetBearing) { motor[BackL] = 20; motor[FrontL] = 20; motor[BackR] = -20; motor[FrontR] = -20; } motor[BackL] = 0; motor[FrontL] = 0; motor[BackR] = 0; motor[FrontR] = 0; } }
Make sure you copy the whole code, including the "#define" and integers.
You have made it to one of the most difficult parts in this Instructable, writing the autonomous. Before even starting an autonomous, be sure that all of your motors and sensors are connected, and setup properly in the code. If you are writing an autonomous for a competition, I would highly recommend taking a birds-eye view picture of the field, and sketching out the path that you want the robot to take.
For this autonomous, we are going to stick with a very simple code, however everything you learn here can be used to a make very complex and high-scoring autonomous!
Let's say that I want the robot to drive forward, turn 90 degrees clockwise, lift up the lift, and then drive backwards, this can be easily done with the functions you have made!
standardMove(200, 80); // Call the move function, forward for 2 milliseconds at speed 80 standardTurn(900); // Call the turn function, turn 900, or 90 degrees. If you wanted to turn 45 degrees, you would enter 450 standardLift(500, 127); // Lift the lift at full power, for 5 milliseconds standardMove(300, -80); // Move backwards for 3 milliseconds, at speed 80, or -80 in this case
That's it, see how useful those functions can be, it turns several dozen lines of code into only four! Without autonomous functions, that code would look something more like this....
motor[BackL] = 80; // Move forward motor[FrontL] = 80; motor[BackR] = 80; motor[FrontR] = 80; wait1Msec(200); motor[BackL] = 0; motor[FrontL] = 0; motor[BackR] = 0; motor[FrontR] = 0; SensorValue[Gyro] = 0; if (SensorValue[Gyro] < 900) { //Turn 90 degrees motor[BackL] = 50; motor[FrontL] = 50; motor[BackR] = -50; motor[FrontR] = -50 wait1Msec(100); motor[BackL] = 0; motor[FrontL] = 0; motor[BackR] = 0; motor[FrontR] = 0; } else if (SensorValue[Gyro] > 900) { motor[BackL] = -50; motor[FrontL] = -50; motor[BackR] = 50; motor[FrontR] = 50; wait1Msec(100); motor[BackL] = 0; motor[FrontL] = 0; motor[BackR] = 0; motor[FrontR] = 0; } else if (SensorValue[Gyro] == 900) { motor[BackL] = 0; motor[FrontL] = 0; motor[BackR] = 0; motor[FrontR] = 0; } else { // Do nothing } motor[BackL] = 127; // Lift up the lift motor[BackR] = 127; motor[TopL] = 127; motor[TopR] = 127; wait1Msec(500); motor[BackL] = 0; motor[BackR] = 0; motor[TopL] = 0; motor[TopR] = 0; motor[BackL] = -80; // Move backwards motor[FrontL] = -80; motor[BackR] = -80; motor[FrontR] = -80; wait1Msec(300); motor[BackL] = 0; motor[FrontL] = 0; motor[BackR] = 0; motor[FrontR] = 0;
Yeah... use functions, it makes your task a whole lot easier.
With everything that you learned, and all the code examples that were provided, you should now be all set to start programming in RobotC! All the pre-autonomous and autonomous functions can be changed, and new ones can be made, to completely change what your autonomous will do! If you have any questions, please let me know in the comments below!