ROBOTC
Volume 1, 3rd Edition
Written by George Gillard
Published: 18-July-2016
Introduction
ROBOTC is an application used for programming robots. There are many different
versions of ROBOTC, but I highly recommend using the latest version, and use the same
version across your whole team. That way, different people in your team can program
the same robot without having to download the firmwares every time.
In this guide to ROBOTC, I'm using ROBOTC for VEX Robotics version 4.52, a VEX Cortex
Microcontroller and a VEXnet Joystick. ROBOTC for VEX Robotics is able to program the
VEX Cortex and VEX IQ Brain. If you wish to program the discontinued VEX PIC
Microcontroller, you will need to install ROBOTC 3.X for Cortex & PIC.
There are also many different styles of programming - this guide has been written for
the way that I personally program.
In this guide, I will show you the basics of coding in ROBOTC, from setting up a file for
your robot, to writing code to control your robot via remote control and even basic
autonomous routines with sensors.
Sections
1. Setting Up
2. Driver Control Code
3. Downloading a Program
4. Basic Autonomous Routines
5. Introduction to Sensors
This guide is provided to assist those learning how to program VEX Robots. This is a
free document, but I ask that you ask for my consent before redistributing online, but
please feel free to share a link. This document, along with my others, are available for
free download from http://georgegillard.com.
Check that the platform type in ROBOTC matches the sort of robot which you wish to
program (Robot Platform Type, Figure 1.1.1).
Figure 1.1.1
A new window will open (Figure 1.2.1), where you can enter names for all of your motors
and sensors according to their corresponding port numbers which they are physically
plugged into.
1.2.1 Motors
In the Motors tab, enter appropriate names for each motor, in the boxes that correspond
to the physical ports which they are plugged into. Make sure you do not leave spaces in
the names – e.g. use “leftDrive”, “LeftDrive”, or “left_drive” instead of “left drive”. Select
the type of motor in the dropdown menu (although which type you select generally
doesn’t matter for most cases), and reverse the motor if it spins the wrong way when you
use it later on. Ignore the other options for now.
Tip: Plug in your motors such that they mirror across all of the ports (e.g. if you have two
motors, left and right, consider plugging one into port 1 and one into port 10, or 2 and 9,
etc.). The VEX Cortex has two breakers which each serve half of the ports, so particularly
on intense robots which draw lots of current, by sharing the motors across the breakers,
you are less likely to run into issues. It can also be easier to remember which motors plug
into which ports this way.
Tip: Use reasonably short and concise names, but with enough detail in them that they
make sense. “leftDrive” is much easier to understand than “LD”, but shorter and easier
to use than “leftDriveWheels”.
I2C Sensors such as the Integrated Motor Encoders are a little more complicated.
Navigate to the I2C Sensors tab, and type in appropriate names, in the box that
corresponds to each sensor. I2C_1 is the first sensor in the daisy-chain setup of sensors,
that is, the one closest to the Cortex. Select the sensor type, then go back to the Motors
tab. Find the relevant motor for each Integrated Motor Encoder, and in the Encoder Port
dropdown menu, select the correct I2C sensor number.
Once you have set up all motors and sensors, select “OK”.
1.3 Saving
At this point, it’s a good idea to save your file. Either use the big “Save” button, Ctrl + S,
or use the File menu. By default, your file will autosave when you compile your code
(which you can use F7 to do), this setting is located at View Preferences Auto File
Save Before Compile. It’s wise to regularly save your code, particularly if you do not use
the auto save before compiling option.
motor[name] = speed;
The speed value ranges from -127 to +127, where -127 is full speed in reverse, +127 is full
speed forwards, and 0 is no power.
Note: It is crucial to add the semicolon “;” to the end of the line. The semicolon indicates
the end of the command.
To control the motors from a joystick, we need to be able to get a value from a particular
control on the joystick, and use that to send a value for the speed to the motor. We then
need to keep updating this value, so that the motor speed changes to correspond what
we do with the joystick.
To understand what goes on with the joystick, we split it up into 8 channels, as follows:
Each of these channels outputs a number, which is the value we use to control the motors.
If we were to take one of the thumb-stick channels, it would range from -127 to +127.
Conveniently, this matches the output of the motors, which makes it all very easy to
match them up. If we were to take one of the buttons, each button returns a value of 0
(not pressed), or 1 (pressed). How we get these values in code though, changes a bit.
vexRT[Ch_]
where _ is where we write the channel number. For example, the value of the vertical left
hand joystick would be:
vexRT[Ch3]
vexRT[Btn__]
where __ is where we write the button number. First we write the number (5/6/7/8), and
then the letter (U/D/L/R) which describes the button (Up/Down/Left/Right). For example,
the value of the upper left hand back button would be:
vexRT[Btn5U]
For convenience, these numbers and letters are marked on the joystick.
If we wanted to use a partner joystick (so two remote controls), to access the values on
the second joystick, we add “Xmtr2” to the end. For example:
vexRT[Ch3Xmtr2]
vexRT[Btn5UXmtr2]
Note: For the older 75mHz transmitter that works with the older PIC controllers,
Channels 1-4 are the same as for the VEXnet Joystick that works with the Cortex, however,
the buttons on the back work like thumb-stick channels instead of buttons, called as Ch5
and Ch6, which each range from -127 (bottom button pressed) to +127 (top button
pressed).
So, now, we want to take the values we have got from the joystick, and use them to power
the motors.
motor[leftDrive] = vexRT[Ch3];
motor[rightDrive] = vexRT[Ch2];
When the thumb-stick is pushed to the right hand side, we get a positive value, and when
it is pushed to the left hand side, a negative value. When we push the joystick to the right,
we generally want the robot to rotate clockwise when viewed from the top (the front
would swing to the right). So, in order to achieve that, the wheels on the left hand side
would need to go forwards (positive), and the wheels on the right hand side would need
to go backwards (negative). Hence, we end up with:
To control anything with buttons, we need to be able to use values of 0 and 1 to control a
speed much greater than 0 or 1. There are a few ways of doing this - through a series of
decisions, or elegantly through a bit of math. Let’s just focus on using two buttons to
control something – such as the up and down buttons on channel 5.
We can use if/else statements to do this. An “if” structure is where we have a condition,
and then make some action depending on the result of this condition.
if (condition)
{
action;
}
For the case of using the upper button to make the arm go up, we could write:
Figure 2.2.1.1
Notice how two equal signs are used in the condition. When we are testing if something
is equal to something else, we always use double equal signs. The result of the condition
is always either true or false, that is, 1 or 0. Of course, the output of the button is also 1 or
0, so we can simplify this further:
Figure 2.2.1.2
Now, we need to be able to lower the arm too, and also we need to be able to stop it
(because nothing will stop unless you tell it to!). This is where we can bring in the “else”
case – what happens if the condition in the if statement is not true.
Figure 2.2.1.3
When there is only one command as the action for the if condition, the curly brackets
can be omitted to make your code even more concise if you wanted so:
Figure 2.2.1.4
Figure 2.2.2.1
Or,
Figure 2.2.2.2
If you are using a competition template, your driver control code should all be placed
inside the while loop of the usercontrol() task. Remove the placeholder function.
If you are not using a competition template, ensure your file has a main() task below the
motors and sensors setup #pragma config lines, like shown below:
Figure 2.2.2.3
Once you have this, you will need to have a while loop inside the main() task, so that the
values for the motors continue to update as the control from the joystick changes. The
while loop looks similar to an if statement, as it has a condition at the top, and then curly
brackets below which show the beginning and end of the loop. The condition needs to
always be true so that the driver control code runs for infinity (don’t worry about this in
competition, even if your loop theoretically runs for infinity, the competition control will
stop your robot). Such conditions could be “1 == 1”, or simply just “true”.
Put all of your driver control code within the loop and you’re done!
Note: if you are programming for the PIC microcontroller and not using the competition
template, you need to include the following line at the very beginning of the main() task
before the while loop to tell the microcontroller to operate in a user control mode. This
is unnecessary for the Cortex microcontroller, or if you are using a competition template.
bIfiAutonomousMode = false;
In the case where you need to manually load the firmwares, you can select them through
“Robot Download Firmware Manually Update Firmware”.
Note: The VEXnet 2.0 (white) keys also have their own firmwares. These can be
downloaded through a separate VEXnet Key 2.0 Update Utility, available from the VEX
Robotics website.
If the program fails to download, check that the robot is switched on and plugged into the
computer with the VEX programming cable (USB – USB for Cortex, USB – Serial for PIC).
Also, make sure the programming cable is plugged into the right place on the robot (the
Serial port on the far left for PIC, or the USB port on the top of the Cortex, where the
VEXnet key goes).
If you are using VEXnet, you can download a program wirelessly. This can be done by
plugging the serial cable into the serial (or “Program”) port on the VEXnet Joystick or
VEXnet Upgrade transmitter module (for PIC).
It is a good idea to regularly compile your code as you build it up to check for errors. You
can do this with F7, or by clicking the big “Compile Program” button, or go through the
menu: “Robot Compile Program”.
If you are using a Competition Template in your code, your autonomous routine(s)
should go in the autonomous() task. If not, just code into the main() task.
or
It is important to say what is going to happen after that length of time, for instance in the
following code:
Figure 4.1
This code does not explain what the robot will do after five seconds, so it will continue to
go forwards. If you wanted it to stop after five seconds, you would need to tell it to do so,
like shown below:
Figure 4.2
Figure 4.3
4.1 Commenting
When programming autonomous routines, it is particularly useful to add helpful
comments, so that it is easier to understand for other people, and to help you as you code.
In ROBOTC, you can add comments in your code to help explain what a particular line
does, or to make a note. Comments have no function on the robot – they’re purely for us
humans to read. The two types of comments are as below:
or
/*
area
comment
*/
The difference is, a single line comment can be used to explain what is happening at the
end of a line of code, whereas a multiple line comment can be used to comment out large
areas of text, or temporarily disable an area of code by converting it into a comment.
Sensors can also be used to tell when a robot has hit something, distance between it and
an object and plenty more. Sensors should be setup in the Motors and Sensors Setup
window, as per the instructions in Section 1.
The output from the sensor is given as a numeric value. Different sensors will give a
different range of values. To get the value of a sensor, we use:
sensorValue(name)
nMotorEncoder[motor’s name]
In this example, the robot will drive forwards and stop if the bumper switch is pressed.
Figure 5.1.1
while(!sensorValue(bumper))
Where “!” basically means “not” something – i.e. if the sensor value is not 1.
Note: The “motor[name] = 127;” commands could be placed before the while loop – since
nothing is changing within the loop, it could be placed just before the loop.
The above code will work once – that is, once the button has been pressed, the program
is over. If we wanted the robot to continuously check if the button is pressed, and if pulled
away from the wall such that the button is no longer pressed, drive again until it is
pressed, we would need to write an infinite loop, and within that loop, run a quick check:
Figure 5.1.2
Figure 5.2.1
Note: the less than “<” symbol can be used to determine if one value is less than another.
Similarly, the symbols “>”, “<=” and “>=” can also be used for other purposes. We can also
use “&&” as “and”, or “||” as “or”.
This example uses integrated motor encoders to drive until one side has reached 1000
units:
Figure 5.2.2
Conclusion
I hope that this guide has been of good use to you, and that you now feel more confident
in programming using ROBOTC. When I began programming, I was incredibly nervous
the first time I tried to write code. Thankfully, ROBOTC is very forgiving, and will point
out most issues with your code when you compile it. In the current day and age, learning
to program is an incredibly useful skill, and ROBOTC is a great language to learn in.
I have other guides available on my website, and there are plenty of other fantastic
resources online. For example, ROBOTC have a great wiki/API on their website, which
has more-or-less everything you’d need to know to be able to use the language. ROBOTC
also provide plenty of sample programs, which are useful for learning.
I would like to thank everyone who has helped me with this guide, in particular Michael
Lawton and Richard Paul, who taught me to program at first and have inspired me to
continue.