Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The time has come to create our first OpMode. We want to make sure to choose a clear and unique name each time we make a program. This will help us to find it again later or to communicate with teammates who may also be driving the robot.
In the programming world, there are common naming conventions that have been established to denote variables, classes, functions, etc. OpModes share some similarities to classes, a program-code-template. Thus the naming convention for OpModes tends to follow the naming convention for classes, which has the first letter of every word is capitalized.
While there are standardized naming conventions in programming, at the end of the day you will want to pick something that makes sense to YOU or your team. This might include having your name, team name, a school class period, or similar in your name.
Your OpMode name should not be the same as a created variable name.
To start, in the REV Hardware Client, select the "Program and Manage" menu tab. In the upper left-hand corner of there is a "Create New OpMode" button, click it:
Clicking the "Create New OpMode" button will open a new window to name and, if applicable, select a sample template for a program. For this guide use the default "BasicOpMode" sample and name the OpMode HelloRobot_TeleOp as shown in the image below.
Once the OpMode has been named click 'OK' to proceed forward.
Creating an OpMode will open up the main Blocks programming page. Before moving on to programming, take some time to learn and understand the following key components of Blocks featured in the image below:
Save OpMode - Click this button to save an OpMode to the robot. It is important to save the OpMode any time you stop working on a code, so that progress is not lost. Blocks does not have an autosave feature!
TeleOp/Autonomous - This section of blocks allows users to change between the two types of OpMode: teleop and autonomous.
Categorized Blocks - This section of the screen is where the programming blocks are categorized and accessible. For instance, clicking Logic will open access to programming blocks like if/else statements.
Programming Space - This space is where blocks are added to build programs. Blocks not currently in the use may be dragged off to the side to be clicked back in later or deleted.
Greeting Message - This intro information message may appear when creating a new, empty OpMode. Clicking the ? icon will close this message.
Remember a configuration needs to be completed first before programming! Some blocks or dropdown menus may be hidden from the side menu until a configuration is made active.
Blocks includes a nifty tool to view how our code would appear if converted to Java. You can click the button on the far right side to open or close this viewer.
While this feature is designed to aid in the transition between programming platforms, some edits may be required for the Java code to properly compiled if added to an OnBot Java OpMode.
Now that we have our Control System all set up and ready to program it's time to get a full robot running, right?
While we will be getting motors moving and sensors sensing during this section, it's important that we first start small. In this section, we'll be working with a simple test bed as we breakdown how to program some of the components that can be connected to the Control Hub.
By tackling these components individually we'll be able to explore more of their capabilities, common uses, and discuss errors that may occur while working with a full robot.
During Hello Robot you will encounter sections called "Quick Check!" These pauses are intend to be moments to think deeper on a topic or to self-check your understanding as you progress. It's is expected that the completion of Hello Robot may take multiple days, meetings, or classes.
As mentioned, during this section we will be focus first on the concept of testing. Why do you think testing might be important in robotics?
One of the best practices to get into the routine of is testing all your components individually when they are first received. That's where out test bed comes into play. For our test bed we will be sticking to the basics with our components connected directly to our Control Hub rather than something like a Servo Power Module or Expansion Hub. If desired, we could add some mechanical parts, such as a servo horn or wheel, to aid with visualizing our testing, but this is not required.
in this tutorial we'll be using our test bed to learn about programming basics, however it is highly encourage to maintain a test bed for future testing.
Remember when testing a component there may be multiple points of failure such as the port, wire, program, or device itself. Utilizing a test bed helps to narrow down those failure points by making it easier to test and compare in a system's simplest state.
To create our test bed for this tutorial you will need the following. The names we used in our configuration are included:
The design of a test bed depends on the use case and available resources. For instance, one of the design requirements for the test bed featured here was accessibility. Notice that the placement of the hardware components on the Extrusion allows for the actuators, sensors, and Control Hub to be removed or swapped out with ease.
Be sure to complete your configuration on the Driver Hub once you have assembled your test bed.
There are other minor, but important, design considerations to make for a test bed. For example, when adding an actuator to a test bed consider the following questions:
What level of constraint does the actuator need? One of the benefits of creating a test bed for motors, or other actuators, is that the motors can be properly constrained during the testing process. In this case providing basic motion support and constraint is valuable.
How will you be able to tell the behavior of the actuator? The example test bed uses a wheel with a zip tie to help users visualize the behavior of the motor. Tape or other markers can be used, as well.
Well a test bed is recommended, in the case of time restrictions, space, or other limitations, individual components may be added or removed during each section of Hello Robot. Make sure moving components, such as motors or servos are ALWAYS secured while running, even at low speeds.
During the process of creating an OpMode the Blocks tool prompted the selection of a sample code. In Blocks these samples act as templates; providing the blocks and logical structure for different robotics use cases. In the previous section the sample code BasicOpMode was selected. This sample code, seen in the image below, is the structural shell needed in order to have a working OpMode.
An OpMode can often be considered a set of instructions for a robot to follow in order to understand the world around it. The BasicOpMode provides the initial set of instructions that are needed in order for an OpMode to properly function.
Though this sample is given to users to reduce some of the complexities of programming as they learn; it introduces some of the most important code blocks. Let's take a closer look at some of them!
Comments are blocks of code intended to help you the programmer.
They can be used to explain the function of a section of code. This is especially helpful in collaborative programming environments. If code is handed from one programmer to another, comments communicate the intent of the code to the other programmer.
When using the BasicOpMode template we can see there are three comments already clicked into place:
"Put loop blocks here" is similar to our last comment, but is for anything that needs to be repeated the entire time our program is running and will be halted when pressing the stop button.
A variable is a storage location with an associated symbolic name, which contains some known or unknown quantity of information referred to as a value. Variables can be numbers, characters, or even motors and servos.
Take a moment to think where else comment blocks may be useful in a program or to communicate with others.
If-then (if-else) statements are similar to the concept of cause and effect. If cause (or condition) happens, then perform effect.
In this case it could be read as "If the OpMode is active (or running) then do the following code."
Component | Configuration Name | |
---|---|---|
Quick Jump Back to a Section |
---|
Pre-added blocks like are comments written by the FIRST Tech Team to help with getting started using the provided template.
shows us where we will be establishing variables, resetting encoders, setting motor directions, and anything else that needs to happen when the code is first activated.
is where anything that will be used when hitting the play button on our Driver Hub should be added.
When the Robot Controller reaches the block it will stop and wait until it receives a Start command from the Driver Hub. Any code after this block will get executed only after the Start button has been pressed.
After the , there is a conditional if block that only gets executed if the OpMode is still active (i.e., a stop command hasn't been received).
You may notice there are two insistences of "opModeIsActive". This allows us to have two options at the start of our program becoming active. The first option has anything that needs to be run only ONCE to be added before our repeat. Then the that follows these blocks is an iterative or looping control structure.
As long as is true those blocks within our loop will remain active when applicable. This is where we will add a majority of our code!
Once the you press the Stop button, the clause is no longer true and the loop will exit.
1
Control Hub
2
Core Hex Motor
test_motor
3
Smart Robot Servo
test_servo
4
REV Touch Sensor
test_touch
5
Color Sensor V3
test_color
6
Battery
This section is considering the Smart Robot Servo in its default mode. If your servo has been changed to function in continuous mode or with angular limits it will not behave the same using the code examples below. You can learn more about the Smart Robot Servo or changing the Servo's mode via the SRS Programmer by clicking the hyperlinks.
A servo is a form of actuator, or a device designed for moving. With a typical servo, you can specify a target position. The servo will turn its motor shaft to move to the target position, and then maintain that position, even if moderate forces are applied to try and disturb its position.
For Hello Robot we will be using the Smart Robot Servo, which is able to switch between a continuous and angular mode.
Continuous mode allows for the servo to rotate a full 360°, either direction, indefinitely similar to a standard motor.
Angular mode sets the servo to move to specified positions within a 270° range of motion.
Let's take a look at how to program our servo while it is on angular mode:
While most common servos have a range of 180° for motion, the Smart Robot Servo has a range of 270° due to its ability to switch between modes. When programming this means our 0 and 1 position might be a little different than what you'd expect.
Looking at the image above we can see that on default when asking our servo to move to its position 0 it will be at -135° . On the opposite end, moving to its position 1 takes our servo to +135° . Therefore if we wanted to return to 0° we would need to program it to move to its position 0.5.
A servo horn attachment connected to your Smart Robot Servo may effect where 0° appears. We recommend using a SRS programmer to set the servo to zero before adding attachments. This may also be done using the code learned in this section!
Let's review quick our basic positions:
Based on what we've learned so far, think about the follow two questions:
If we wanted our servo to move to -67.5° what position would we program it move to?
If we have programmed our servo to move to position 0.7, what would that equal in degrees?
For Hello Robot we will only be programming using positions. Understanding their translation to degrees is still important, however, to help think through designing a mechanism. Degrees may also be preferred when using a direct pulse input to program the servo.
In the next few sections, we will be learning to program our servo to first move automatically to different requested positions then in response to our gamepad's input.
Below is a sneak peek of our final full code:
Let's start by reviewing how to access servos within Blocks. At the top of the Categorize Blocks section there is a drop down menu for Actuators. When the menu is selected it will drop down two choices: DcMotor or Servo. Selecting Servo will open a side window filled with various servo related blocks.
The block above will change names depending on the name of the servo in a configuration file. If there are multiple servos in a configuration file the arrow next to test_servo will drop down a menu of all the servos in a configuration.
Different block options will appear when using a continuous rotation servo.
Let's start by programming our servo to rotate to the default 1 position!
Select Save OpMode in the upper lefthand corner in the programming interface.
Let's give our program a try. Take a moment to observe what happens.
When running our program for the first time, we should have seen our servo move itself to position 1 and maintain that position. But what happens if we run it again? Does the servo move?
If your servo did not move as expected, double check your wiring and port are correct compared to your configuration.
Try running this op mode on the test bed and consider the following question:
What is different from the previous run?
In many applications starting the servo in a known state, like at position zero, is beneficial to the operation of a mechanism. Setting the servo to the known state in the initialization ensures it is in the correct position when the OpMode runs.
Take a moment to think about where setting the servo to a known state during initialization may be helpful before moving to the next section!
Programmed Position | Degrees |
---|---|
From the Servo menu, we will primarily be using the block
Add this block to the op mode code within the .
Click on the number block to change from to .
The intent of the is to set the position of the servo. If the servo is already in the set position when a code is run, it will not change positions. Lets try adding another block and see what changes.
In this case, we do not want our servo to reset to 0 every time our code repeats. Because of this where do you think we would snap in our block?
Recall when we discussed the section marked by the comment during . Since we only want our servo to reset ONCE we will request it do so during the initialization process when the code is first activated, but before play is pressed.
Go ahead and click a block into place to match the code below:
0
-135°
0.5
0°
1
135°
Having our robot able to rotate the servo automatically can be incredibly useful, especially when writing an autonomous program, but what if I want to control the positions with my gamepad?
Let's take a look at how we can add input commands to our code!
For this example the known state will stay at position 0, so that after initialization the servo will be a the -135 degree position of the servo range. The following list shows what buttons correspond with which servo position:
If you are using a PS4 Controller, selecting the appropriate button from the dropdown in Blocks may be easier to follow when looking back at your code. The buttons are also interchangeable when programming in Blocks. (ex: Y in code = Triangle pressed on controller)
Blocks for adding controller inputs can be found in the "Gamepad" menu:
One of the most common logic statements used in programming is an if/else statement, also known as an if/then statement. This block can be found under the "Logic" menu in Blocks:
In its most simple format we will be asking our robot to check IF something is happening and if the answer is yes, or true in our robot's mind, THEN it will DO what has been asked.
During this section we are going to be asking "If the Y button is pressed on our controller then move our servo to position 0."
If our servo will move to position 0 when the previous statement is TRUE, what do expect to happen when the answer is FALSE (or the Y button is not pressed)?
Now our statement is checking first if Y is being pressed to move to position 0, but has added now the option to look for something else, such as another button being pressed.
Let's add to our existing logic statement the ability to move our servo to position 1 when A is pressed on our controller. Give it a try first before revealing the answer below!
How would our full logic statement be read once our new blocks are added?
What happens when both buttons are pressed at the same time?
To add all of our gamepad inputs we need to further extend our if/else if statement:
Now there are three different paths in our if/else if block that our robot may follow based on each input request. We've previously added our ability to move to position 0 and 1, but what about 0.5?
The logical operator or considers two operands if either (or both) are true the or statement is true. If both operands are false the or statement is false.
Similar the logical operator and considers two operands requiring both to be true for the whole statement to be true.
Our previously added blocks for A and Y inputs can be temporarily moved to the side in the workspace to be readded as applicable.
Add each button block to the if/else if block as seen in the image below.
Click Save OpMode and give your program a try!
There are three different paths in this if/else if statement. If the first conditional statement is true (the Y button is pressed) the servo moves to code position 0 and the other conditional statements are ignored.
If the first condition is false (the Y button is not pressed) the second condition is analyzed. This means the order we add our pathways DOES matter. If X and A are pressed at the same time, the robot will will try to prioritize the X button first.
Give it a try!
Our if/else statement can come in many forms that includes multiple different conditional statements. Blocks allows for our base block to be easily added to add as many conditional statements as we need by clicking the blue gear on our block.
Adding an block by clicking and dragging to our existing if statement converts it into becoming an if/else if statement. Using our previous example we can see how this may look in Blocks:
If you have not already, test the code we have written thus far! Our logic statement should be add to our and previous removed.
You may have noticed in our gamepad chart at the beginning of this section that we are going to have two buttons able to move our servo to position 0.5. This is so we can practice using a logical operator like the block in our program!
From the Logic Menu in Blocks select the block.
Add this block to the if/else if block, as shown in the image below. Use the dropdown menu on the block to change it from an block to an block.
Now to finish by adding our blocks to each section of the If/else if block. Set the servo position to correspond with the assigned gamepad button.
Button
Degree Position
Code Position
Y/Triangle
-135
0
X/Square
0
0.5
B/Circle
0
0.5
A/Cross
135
1
Telemetry is the process of collecting and transmitting data. In robotics ,telemetry is used to output internal data from the actuators and sensors to the Driver Hub. It is a way for the robot to communicate back to you the programmer what the robot thinks its doing or seeing. This information can then be used to improve your code, make adjustments to a mechanism, or to strategize when driving around the field if competing.
Telemetry blocks in Blocks can be found under the Utilities dropdown menu:
The most useful telemetry from the servo is the position of the servo along its 270° range.
Only certain blocks can be added to the second parameter based on what is being requested. In this case the parameter number means the data must be a numeric value.
Change the key parameter to "Servo Position"
Give your program a go!
From the telemetry menu, select the block.
Drag the block and place it beneath the if/else if block set. In this scenario, we want our telemetry to be constantly providing output rather than waiting for a designated check.
From the Servo menu pullout the block Drag the Block and attach it to the number parameter on the telemetry blocks.
For the block "key" is a text box we are able to change to help define what the value is being read out to the Driver Hub's screen. Think of it like an answer key or one used on a map to identify symbols.
Modify your OpMode to add the motor related code. For now your completed servo code can be dragged to the side of your work space. You may alternatively choose to create a second program.
Just like servos, a motor is a form of actuator. You may picture a dozen different things when you think of a motor, from those used to spin the wheels of a car to the large turbines that allow a plane to fly. For our robots, we will be focusing on DC motors. These are a type of electrical motor that use direct current, or DC, to rotate and produce the mechanical force needed to move an attached mechanism.
For this tutorial, either a Core Hex Motor or HD Hex Motor may be used as long as they have been properly configured on the Driver Hub.
Most standard motors are able to continuously rotate in either direction with an adjustable speed or power. Some motors may also include a built in encoder, which allows them to move to a specified position, similar to a servo, or to collect data like the number of completed rotations!
To access the motor snippets in Blocks we need to look under the Actuators dropdown menu:
You may notice there are several options for blocks under the DcMotor menu. For Hello Robot we will be using those found in the DcMotor menu itself and under Dual.
As the name suggests, the blocks found under Dual are intended for the use of two motors. We will learn more about them in Part 2!
If you do not see the DcMotor menu under Actuators double check your configuration includes a motor and is currently active on the Driver Hub!
In the next few sections, we will be learning to program our motor to first move automatically in different directions then in response to our gamepad inputs. In our final section we will take a look at using telemetry with our motor's built in encoder.
Below is a sneak peek of our final full code:
Let's start by getting a motor spinning automatically when we hit play on our program!
Not seeing your motor listed? Be sure the correct configuration has been activated!
The block above will change names depending on the name of the motor in a configuration file. If there are multiple motors in a configuration file the arrow next to test_motor will drop down a menu of all the motors in a configuration.
Add this block to the OpMode within the while loop. In this scenario we want our motor to continually run so long as our OpMode is active:
Select Save OpMode in the upper lefthand corner of the programming interface.
Try running this OpMode on the test bed and consider the following questions:
How fast is the motor running?
What happens if you change the power from 1 to 5? What about 100?
What happens if you change the power from 1 to 0.3?
This is a good time to experiment with different values to see how our motor reacts. You might notice that setting our power to 5 or even 100 does not make the motor spin any fast than when set to 1. But setting our power to 0.3 significantly slows our motor's speed, right?
Now what happens if you change the power from 1 to -1?
From our perspective, a power level of 1 probably doesn't sound very strong. However, to our robot the power being set to 1 translates to the motor running at 100%. That would mean setting the power to 0.3 requests the motor to spin at 30% of power.
When we set our power to a negative power, the motor is told to reverse direction while maintaining that power. So if we set our power to -1 then our motor will still run at 100%, but in the opposite direction than when set to 1.
The direction a motor spins may be determined by the power OR may be designated during the initialization process.
In the previous section you learned how to set the motor to run at a specific power level in a specific direction. However, in most applications, it will be necessary to control the motor with a gamepad, to easily change the direction or power level of a mechanism.
We are able to use a button to set the motor to a specific power or we can program it so it changes based on the direction of one of the gamepad's joysticks!
When using Blocks we are able to snap some blocks together.
This set of blocks will now continually loop and read the value of gamepad #1’s left joystick (the y position) and set the motor power to the Y value of the left joystick.
Save your OpMode and test it out with your gamepad! Think about the following questions while testing:
What happens when you move the left joystick up a small amount versus a large amount?
What happens if you move the joystick to the left or right along the X-axis?
What happens if you move the joystick at a diagonal or rotate it 360 degrees?
You may notice that when moving along the X-axis nothing happens at the moment. However, once the joystick hits an angle near the Y-axis vertices the motor may start to jitter and spin.
When you tested your program, did the motor spin the expected direction while moving the joystick up or down?
In the FTC SDK for most controllers the Y value of a joystick ranges from -1 when a joystick is in its topmost position, to +1 when a joystick is in its bottommost position.
That may be a little confusing to control, but we can add a negative symbol, or negation operator, to the line of code to change the direction of the motor in relation to the gamepad.
From the DcMotor menu in Blocks select the block .
From the Gamepad Menu in Blocks select the Block.
Looking at the block you might notice it is the perfect shape to snap into the end of block, over the 1, like a puzzle piece!
From the Math Menu in Blocks select the block in the image below.
Drag the negative symbol block so it snaps in place between the and blocks:
Recall that telemetry is the process of collecting and transmitting data. There is a lot of useful information our motors could send back to us, but to start let's have it output the power based on the joystick's movement.
Change the key parameter to "Motor Power"
When the OpMode is run the telemetry block will display the current power based on the joysticks movement. Give it a try!
Similar to what we did for our servo program, let's add a block from the telemetry menu to the end of our loop:
From the DcMotor menu pullout the block . Drag the block and attach it to the number parameter on the telemetry blocks.
This section applies to the use of the REV Touch Sensor or Limit Switch. Requirements may vary when using other 3rd party touch sensors.
The REV Touch Sensor must be configured to digital port 1, 3, 5, or 7.
It is recommended to create a new OpMode while following this tutorial. Ours is named HelloRobot_TouchSensor!
The touch sensor block is now found under the "Sensors" dropdown as seen below:
Let's start by breaking down how a touch sensor works at its core!
Remember what sensors and motors are available in your program are determined by your configuration! Double check the correct configuration is active if you do not see a device list.
The information collected by a touch sensor comes in two states, also known as binary states. This information is perfect to use with a conditional statement like an if/else
statement.
Take a moment to think what this code is asking the robot to do. We could read this line of code as "If the touch sensor is pressed do ____, else if the touch sensor is not pressed do _____."
It's always helpful for us to be able to see what the robot thinks its doing on our Driver Hub's screen. To do this, let's request the robot shares some telemetry data while our program is active.
What happens if you run the program right now?
When on the default "Telemetry" block the information provided is not helpful for the robot to communicate with us. Therefore we need to change "key" and "text" to match the desired information.
The "key" should be something related to which sensor, motor, or other device we are receiving information from. Meanwhile "text" will tell us what is happening based on the state of our touch sensor and our if/else statement.
Let's give our code another try to see what happens on the Driver Hub's Screen. Did you see something like the following?
Remember its up to us to decide what our telemetry readout says. With that in mind we could change it so our robot says "Hello World" when the button is pressed:
Take a moment to think about how else telemetry data could be used with your robot before moving on to the next section!
At the moment, our robot does not have any senses to help navigate the world around it like you might. However, that's the key advantage to adding sensors to our design.
For the touch sensor, one of the most common uses is for it to act as a limit switch. This will help the robot know when it needs to halt the movement of a mechanism, like an arm or lift, that's at its limit similar to how your nerves help to tell your brain to do the same.
In the above example the if/else is checking first for if the touch sensor is pressed. The full statement could be read as "If the touch sensor is pressed set the motor's power to 0 else, if it is not pressed, set the power to 0.3".
Give it a try!
The block collects the binary TRUE/FALSE
state from the touch sensor and acts as the condition for the if/else
statement.
Let's take a look at our touch sensor block paired with our block:
We can access the "Telemetry" blocks under our "Utilities" dropdown on the menu. Look for the block to be added in each section of the if/else statement.
We can test this idea by adding on to our existing if/else statement. This time we are going to ask our motor to move until our sensor is pressed using the block:
There may be situations where we want our program to read if the touch is NOT pressed first. Let's take a quick look at how that would function using the block from the "Logic" menu.