beginnersguidetorobotcvol1ed3

advertisement
The Beginners Guide to
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.
Page 2
Published: 18-July-2016
© George Gillard
1 Setting Up
1.1 New Files
Once you have opened ROBOTC, open a new file (the big “New File” button, File  New…
 File, or Ctrl + N). If this is for a robot that will be competing in the VEX Robotics
Competition, open a new competition template (File  New…  Competition Template).
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
1.2 Setting Up Motors and Sensors
In your new file, use the toolbar to go to the Motors and Sensors Setup window (the big
“Motors and Sensors Setup” button, Robot  Motors and Sensors Setup, or in an existing
file just double click the “#pragma config” lines at the top).
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.
Page 3
Published: 18-July-2016
© George Gillard
Figure 1.2.1
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”.
Page 4
Published: 18-July-2016
© George Gillard
1.2.2 Sensors
There are three sensors tabs for the three categories of sensors. For analog and digital
sensors, navigate to the relevant tab, put an appropriate name in the correct box, and
select the type of sensor from the dropdown menu. Note that for Quadrature Encoders
and Ultrasonic Rangefinders (SONAR), you will need to use two ports, but you only need
to name the first port. For Ultrasonic Rangefinders (SONAR), there are different options
for the resolution – choose an option that will give you enough detail for what you require.
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.
1.2.3 LCD Displays
If you have an LCD display on your robot, go to the Serial Ports tab, and for whichever
UART port you use, select the VEX 2x16 LCD option.
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.
Page 5
Published: 18-July-2016
© George Gillard
2 Driver Control Code
In this section, we’ll go over how to control a robot from a joystick.
When we want to control the speed of a motor, we write:
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:
Channel 1, the sideways channel on the right thumb-stick
Channel 2, the vertical channel on the right thumb-stick
Channel 3, the vertical channel on the left thumb-stick
Channel 4, the sideways channel on the left thumb-stick
Channel 5, the back buttons on the left (looking from the front)
Channel 6, the back buttons on the right (looking from the front)
Channel 7, the 4 buttons on the left of the joystick, on the top
Channel 8, the 4 buttons on the right of the joystick, on the top
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.
For a thumb-stick, we write:
vexRT[Ch_]
where _ is where we write the channel number. For example, the value of the vertical left
hand joystick would be:
vexRT[Ch3]
Page 6
Published: 18-July-2016
© George Gillard
For a button, we write:
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.
2.1 Controlling Wheels
The two main styles of driving are tank and arcade control. Tank control is where we use
the two vertical channels on the two thumb-sticks to control each side of the drive-train.
Arcade control is where we use one vertical channel to control forwards/backwards
movement, and one horizontal channel to control the turning of the robot.
2.1.1 Tank Control
This is perhaps the easiest control of all to code. All we need to do is write the output
value from the joystick thumb-sticks directly to the motors, as follows:
motor[leftDrive] = vexRT[Ch3];
motor[rightDrive] = vexRT[Ch2];
Page 7
Published: 18-July-2016
© George Gillard
2.1.2 Arcade Control
Slightly more complicated, this is where we first meet mathematical operators in
ROBOTC. We either add or subtract the horizontal (turn) channel to the vertical
(forwards/backwards) channel. To determine to which one we add or subtract, we just
need to think a little about what happens in each case.
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:
motor[leftDrive] = vertical + horizontal;
motor[rightDrive] = vertical – horizontal;
2.2 Controlling Other Mechanisms
If we’d wish to control a mechanism with a thumb-stick, we’d generally be able to control
it much like tank control on a drive-train.
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.
2.2.1 Controlling with Buttons via Decisions
To do this, we need to be able to say if the up button is pressed, to go at a speed in one
direction, and if the bottom button is pressed, to go at a speed in the other direction. Say
we want to use the buttons to lift an arm, up and down, where up is positive.
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:
if (upper button is pressed)
{
motor[arm] = 127;
}
Page 8
Published: 18-July-2016
© George Gillard
Which in proper code is:
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
Page 9
Published: 18-July-2016
© George Gillard
2.2.2 Controlling with Buttons via Mathematical Operators
We can combine the output buttons, and scale them up by multiplying (*), to produce a
value which ranges from -127 to +127. We can then feed this straight into our motor from
this point, making an elegant solution out of the multiple inputs.
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;
Page 10
Published: 18-July-2016
© George Gillard
3 Downloading a Program
3.1 Firmware
If the robot that you are using has been programmed using a different version of
ROBOTC, or has never been programmed before, you will need to download the
firmwares. If you are using Cortex, by clicking “Robot  Download Firmware 
Automatically Update VEX Cortex” ROBOTC will update all the firmwares required. If
you are using a VEXnet Joystick, you will need to also download the firmwares onto that,
too. For the Joystick firmware, plug in the USB – USB cable into the underside of the
Joystick, where the VEXnet key would go. Just like the Cortex microcontroller, you can
easily download the firmware by clicking “Robot  Download Firmware 
Automatically Update VEXnet Joystick”.
In the case where you need to manually load the firmwares, you can select them through
“Robot  Download Firmware  Manually Update Firmware”.
For the Cortex Microcontroller (Manually):
Select “Master CPU Firmware  Standard File” Once downloaded successfully, go
through the menu again, except choose “ROBOTC Firmware  Standard File”.
For the VEXnet Joystick (Manually):
Select “VEXnet Joystick Firmware  Standard File”.
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.
3.2 Downloading the Program
To download a program, hit F5 on your keyboard (you may need to press a function
button to use F5). Alternatively, press the big “Download to Robot” button, or go through
the menu: “Robot  Compile and Download Program”.
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”.
Page 11
Published: 18-July-2016
© George Gillard
4 Basic Autonomous Routines
Autonomous routines are essentially a series of commands that the robot executes by
itself – with no human driver input. Whilst the robot may be programmed to make some
decisions that alter it’s routine, the routines for the VEX Robotics Competition tend to be
fully planned step-by-step.
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.
The easiest autonomous to make is a timed autonomous. This is basically something
along the lines of “Go forward for 5 seconds at full speed then turn left for 1 second and
go forwards at half speed”.
To do something for a specific length of time, we use:
wait1Msec(length of time here);
or
wait10Msec(length of time here);
The difference is counting in either milliseconds or 10s of milliseconds. The main
difference between counting in milliseconds or 10s of milliseconds is that the command
“wait1Msec” can count up to a maximum of 32.768 seconds, whereas the command
“wait10Msec” can count a maximum of 327.68 seconds.
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
Page 12
Published: 18-July-2016
© George Gillard
So say if we wanted the robot to go forwards for 5 seconds, then turn left for one second,
and then go forwards for another 2 and a half seconds, the code would look like this:
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:
// single line comment
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.
Comments show up green in ROBOTC, for easy spotting.
Page 13
Published: 18-July-2016
© George Gillard
5 Introduction to Sensors
Sensors are used for more accurate and precise programming. For instance, instead of
saying, go forward for 5 seconds, you can say go forward 5 rotations. For this, we would
use an encoder. Instead of saying lift the arm for 2 seconds, we could replace that with
lift the arm to a certain angle. A good example of why sensors can make your
programming more accurate, is that the arm may have already been slightly raised,
therefore timing how long to raise the arm would not get to the right position.
Generally, you would use a potentiometer on an arm, as it is a rotation sensor, like an
encoder. The difference between a potentiometer and an encoder is that a
potentiometer can't spin numerous times, and unlike an encoder, cannot be reset.
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)
Or, for an integrated motor encoder:
nMotorEncoder[motor’s name]
5.1 Bumper and Limit Switches
The first sensor we will use is a Bumper Switch. They are little buttons generally used for
hitting into walls. Limit switches are programmed exactly the same way; the only major
difference is that a limit switch has a thin metal tab that often snaps off. These switches,
known as touch sensors, have 2 different values. They are 1, or 0 – pressed and released,
respectively.
In this example, the robot will drive forwards and stop if the bumper switch is pressed.
Figure 5.1.1
Page 14
Published: 18-July-2016
© George Gillard
Note: The condition could also be rewritten as:
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
5.2 Potentiometers and Encoders
Potentiometers and encoders are very simple rotational sensors to use. As explained
before, the main difference between the two is that potentiometers can only be rotated
within a limited range, whereas encoders can be spun continuously. This makes
potentiometers more useful on an arm, since they are more compact the larger
quadrature encoders, only use one wire due to being an analog sensor, and have a
greater resolution than encoders. For a drive train, you’d need to use encoders should
you wish to measure rotation of the wheels. It is also quite common however to use an
integrated motor encoder on the motor powering an arm, however you’d need a way of
resetting the position at some point – such as by having a button at the bottom to detect
when the arm is down, and using this to reset the encoder(s) to zero.
Page 15
Published: 18-July-2016
© George Gillard
In this example, we use a potentiometer to raise an arm to a “height” of 2000.
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.
Page 16
Published: 18-July-2016
© George Gillard