Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Right now our robot should move forward 3 seconds then stop. What if we wanted our robot to do something else after those 3 seconds? How do we request our program to continue?
To start let's duplicate our existing loop. We can right click on a block to duplicate it. In this case, since our block is a loop, it will duplicate everything within the loop.
Notice our second loop also has a call for telemetry data, however the name is the same! Let's edit it to be "Number of Seconds in Phase 2". Keep the names in mind if you duplicate additional loops.
Give your program a test to see what happens. Think about the following while testing:
How long does the robot move?
Could you tell when the robot switched between Phase 1 and 2?
What happens if we change the power in the second loop?
Having multiple loops with different amounts of time can give us a lot of power to help our robot navigate an area. For now let's have our robot complete it's first movement forward for 3 seconds, then reverse back to the start.
This simply requires changing our power in the second loop to -1 !
Before getting started, let's quickly identify where we will find our ElapsedTime blocks. This menu can be found under the Utilities dropdown on our side toolbar.
For this section, let's start by creating a new OpMode named HelloRobot_ElapsedTime using the BasicOpMode sample.
Recall when we created variables while programming our drivetrain. We will be using them again during this part to help with calculations! To start create a variable called runtime.
Since speed an directionality impacts how a robot turns, target position and velocity need to be edited to get the robot to turn. Consider the following code:
The rightTarget
has been changed to be a negative target position. Assuming that the encoder starts at zero due to STOP_AND_RESET_ENCODER
this causes the robot to turn to the right. Velocity is the same for both motors. If you try running this code, you may notice that the robot pivots along its center of rotation. To get a wider turn changing the velocity so that the right motor is running at a lower velocity than the left motor. Adjust the velocity and target position as needed to get the turn you need.
Hello Robot Part 3: Autonomous and Encoders is currently under construction. Please stay tuned for future updates!
We've tackled the basics. We have a robot able to drive around. What could be next?
Right now our robot is largely dependent on inputs from us as the driver from the gamepad. We've helped it learn to sense a little bit using the touch sensor, but there is still more we can do.
During Part 3 we will be learning how to help our robot navigate the world around it autonomously in different ways. To start we will look at how to use a timer for the robot to keep track of how long it should do something. From there, we will move on to using the built in encoders of the HD Hex and Core Hex Motors.
Encoders are a form of sensor that help collect data for the motor. Some encoders count the number of completed rotations. Others are able to track the exact position of a motor, similar to a servo. The use of encoders brings the need for more math and complex programming, however it will allow your robot to navigate more efficiently.
Rather than attempt to measure, or estimate, the distance the robot moves, the encoder ticks can be converted from amount of ticks per revolution of the encoder to how many encoder ticks it takes to move the robot a unit of distance, like a millimeter or inch. Knowing the amount of ticks per a unit of measure allows you to set a specific distance. For instance, if you work through the conversion process and find out that a drivetrain takes 700 ticks to move an inch, this can be used to find the total number of ticks need to move the robot 24 inches.
Reminder that the basis for this guide is the Class Bot V2. The REV DUO Build System is a metric system. Since part of the conversion process references the diameter of the wheels, this section will convert to ticks per mm.
When using encoders built into motors, converting from ticks per revolution to ticks per unit of measure moved requires the following information:
Ticks per revolution of the encoder shaft
Total gear reduction on the motor
Including gearboxes and motion transmission components like gears, sprockets and chain, or belts and pulleys
Circumference of the driven wheels
The amount of ticks per revolution of the encoder shaft is dependent on the motor and encoder. Manufacturers of motors with built-in encoders will have information on the amount of ticks per revolution. For HD Hex Motors the encoder counts 28 ticks per revolution of the motor shaft.
Visit the manufacturers website for your motor or encoders for more information on encoder counts. For HD Hex Motors or Core Hex Motors visit the Motor documentation.
Since ticks per revolution of the encoder shaft is before any gear reduction calculating the total gear reduction is needed. This includes the gearbox and any addition reduction from motion transmission components. To find the total gear reduction use the Compound Gearing formula.
For the Class Bot V2 there are two UltraPlanetary Cartridges, 4:1 and 5:1, and an additional gear reduction from the UltraPlanetary Output to the wheels, 72T:45T ratio.
The UltraPlanetary Cartridges use the nominal gear ratio as a descriptor. The actual gear ratios can be found in the UltraPlanetary Users Manual's Cartridge Details.
Using the compound gearing formula for the Class Bot V2 the total gear reduction is:
Unlike the the spur gears used to transfer motion to the wheels, the UltraPlanetary Gearbox Cartridges are planetary gear systems. To make calculations easier the gear ratios for the Cartridges are already reduced.
The Class Bot V2 uses the 90mm Traction Wheels. 90mm is the diameter of the wheel. To get the appropriate circumference use the following formula
You can calculate this by hand, but for the purpose of this guide, this can be calculated within the code.
Due to wear and manufacturing tolerances, the diameter of some wheels may be nominally different. For the most accurate results consider measuring your wheel to confirm that the diameter is accurate.
To summarize, for the Class Bot V2 the following information is true:
Each of these pieces of information will be used to find the number of encoder ticks (or counts) per mm that the wheel moves. Rather than worry about calculating this information by hand, these values can be added to the code as constant variables. To do this create three variables:
COUNTS_PER_MOTOR_REV
DRIVE_GEAR_REDUCTION
WHEEL_CIRCUMFERENCE_MM
The common naming convention for constant variables is known as CONSTANT_CASE, where the variable name is in all caps and words are separated by and underscore.
Add the variables to the initialization section of the op mode.
Now that these three variables have been defined, we can use them to calculate two other variables: the amount of encoder counts per rotation of the wheel and the number of counts per mm that the wheel moves.
To calculate counts per wheel revolution multipleCOUNTS_PER_MOTOR_REV
by DRIVE_GEAR_REDUCTION
Use the following formula:
Where,
Once COUNTS_PER_WHEEL_REV
is calculated, use it to calculate the counts per mm that the wheel moves. To do this divide theCOUNTS_PER_WHEEL_REV
by the WHEEL_CIRCUMFERENCE_MM
. Use the following formula.
Where,
COUNTS_PER_WHEEL_REV
will be created as a separate variable fromCOUNTS_PER_MM
as it is used in calculating a target velocity.
Create these variables in Blocks and add then to the op mode under the other constant variables.
OnceCOUNTS_PER_WHEEL_MM
is set, this completes the conversion process, and all constant variables are set.
For now our goal will be to have the motors move forward for 3 seconds. To accomplish this we need to edit our main While Loop so that it triggers when the OpMode is active AND the ElapsedTime timer is less than or equal to 3 seconds.
With our time condition ready, we can set it aside for a moment.
Now let's set up our logic to modify our While Loop.
Let's give our OpMode a try and test the following scenarios:
What happens when hitting play quickly after the initialization button is pressed?
What happens when hitting play 2 seconds after the initialization button is pressed?
What happens when hitting play 10 seconds after the initialization button is pressed?
Not being able to pause between initialization and pressing Play is probably not ideal in most situations. It certainly makes tracking how far the robot will travel more challenging, the opposite of what we'd like ElapsedTime to help us do.
Since this is before our loop our robot will complete it once when Play is pressed. Then will complete the check for our while loop.
Test your program again with this change!
Consider marking different goals on the floor with tape to practice determining how much time the robot needs to reach it.
In previous parts, we've looked at adding telemetry as a way for the robot to communicate with us. In this situation, it would be helpful for the robot to be able to tell us how much time it has counted so we can make adjustments to our program!
Recall we can find our telemetry block under the utilities menu:
For our key let's call it "Number of Seconds in Phase 1" for now. This will be useful for distinguishing where in our program our robot is during the next section.
Save your OpMode and give it a try!
In the Drivetrain Encoders section the concept of moving the motor to a specific position based on encoder ticks was introduced. The process highlighted in Encoder Navigation focused on how to convert from encoder ticks to rotations to a linear distance. A similar procedure can be utilized to move the arm to a particular position. However, unlike the drivetrain, the arm does not follow a linear path. Rather than convert to a linear distance it makes more sense to convert the encoder ticks into an angle measured in degrees.
In the image below two potential positions are showcased for the ClassBot arm. One of the positions - highlighted in blue below - is the position where the arm meets the limit of the touch sensor. Due to the limit, this position will be our default or starting position. From the Class Bot build guide, it is known that the Extrusion supporting the battery sits a 45 degree angle. Since the arm is roughly parallel to these extrusion when it is in the starting position, we can estimate that the default angle of the arm is roughly 45 degrees.
The goal of this section is to determine the amount of encoder ticks it will take to move the arm from its starting position to a position around 90 degrees. There are a few different ways this can be accomplished. An estimation can be done by moving the arm to the desired position and recording the telemetry feedback from the Driver Station. Another option is to do to the math calculations to find the amount of encoder ticks occur per degree moved. Follow through this section to walk through both options and determine which is the best for your team.
Now that you have created the constant variables needed to calculate the amount of ticks per mm moved, you can use this to set a target distance. For instance, if you would like to have the robot move forward two feet, converting from feet to millimeters and multiplying by the COUNTS_PER_MM
will give you the amount of counts (or ticks) needed to reach that distance.
Right now the main distance factor is COUNTS_PER_MM
, however you may want to go a distance that is in the imperial system, such as 2 feet (or 24 inches). The target distance in this case will need to be converted to mm. To convert from feet to millimeters use the following formula:
If you convert 2 feet to millimeters, it comes out the be 609.6 millimeters. For the purpose of this guide, lets go ahead an round this to be 610 millimeters. Multiply 610 millimeters by theCOUNTS_PER_MM
variable to get the number of ticks needed to move the robot 2 feet. Since the intent is to have the robot move in a straight line, set both the leftTarget
and rightTarget
, to be equal to 610 * COUNTS_PER_MM
In the previous sections you worked on some of the building blocks for restricting an arms range of motion. From those sections you should have the foundation you need to perform basic arm control. However, there are some other creative ways you can use encoder positions and limits to expand the control you have over your arm.
This section will cover two additional types of control. The first type of control we will explore is the idea of soft limits. In the Adding a Limit Switch section we discuss the concept of physical limits of a mechanism however, there may be times you need to limit the range of motion of an arm without installing a physical limit. To do this a position based code can be used to create a range for the arm.
Once you have a basic idea of how to create soft limits, we will explore how to use a limit switch (like a touch sensor) to reset the range of motion. This type of control reduces the risk of getting stuck outside of your intended range of motion, which can affect the expected behavior of your robot.
To set the soft limits we will use some of the basic logic we established in previous sections, with some edited changes. Start with a Basic Op Mode
and add the constant variables from the Calculating Target Position section to the op mode.
Next we need to create our upper and lower limits. Create two new variables one called minPosition
and one called maxPosition
. Add both of these to the initialization section of the op mode.
An if/else if
statement needs to be added to control the arm, for this we can use the same basic logic we use in the Basics of Programming an Arm section.
To set the limit we need to edit our if/else if
statement so that the limits are built in. If DpadUp
is selected and the position of the arm is less than the maxPosition
then the arm will move to the maxPosition
. If DpadDown
is selected and the position of the is greater that the minPosition
then the arm will move towards the minPosition
.
The current code configuration will stop the motor at any point that the conditions to power the motor are not met. Depending to factors like the weight of the mechanism and any load that it is bearing, when the motor stops the arm may drop below the maxPosition
. Take time to test out the code and confirm that it behaves in the way you expect it to.
One of the benefits of having a soft limit is being able to exceed that limit. Since encoders zero tick position is determined by the position of the arm when the Control Hub powers on; if attention is not payed to what position the arm is on power up the range of motion of the arm is affected. For instance, if we have to reset the Control Hub while the arm is in the 90 degree position, the 90 degree position is equal to 0 encoder ticks. One way around this is to create an override for the range of motion.
There are a few different ways an override of sorts can be created, in our case we are going to use the a button and touch sensor to help reset our range.
Now that we have this change in place, when the a
button is pressed the arm will move toward the starting position. When the arm reaches and presses the touch sensor we want toSTOP_AND_RESET_ENCODER
.
So, if the touch sensor returns false
(or is pressed) the motor run mode STOP_AND_RESET_ENCODER
will be activated causing the motor encoder to reset to 0 ticks.
Now that this code is done, try testing it!
We're updating this documentation!
During 2024 Summer, "Hello Robot" will be getting a refreshed look to reflect changes to the latest versions of the REV Hardware Client and Robot Controller App.
While this guide is still generally relevant, you may see differences in the naming of devices or commands along with visual updates to the guide.
In the previous section you learned about how to use Elapsed Time to allow your robot to navigate the world around it autonomously. When starting out many of the robot actions can be accomplished by turning on a motor for a specific amount of time. Eventually, these time-based actions may not be accurate or repeatable enough. Environmental factors, such as the state of battery charge during operation and mechanisms wearing in through use, can all affect time-based actions. Fortunately, there is a way to give feedback to the robot about how it is operating by using sensors; devices that are used to collect information about the robot and the environment around it.
With Elapsed Time, in order to get the robot to move to a specific distance, you had to estimate the amount of time and the percentage of duty cycle needed to get from point a to point b. However, the REV motors come with built in encoders, which provide feedback in the form of ticks ( or counts) per revolution of the motor. The information provided by the encoders can be used to move the motor to a target position, or a target distance.
Moving the motors to a specific position, using the encoders, removes any potential inaccuracies or inconsistencies from using Elapsed Time. The focus of this section is to move the robot to a target position using encoders.
There are two articles in that go through the basics of Encoders. Using Encoders goes through the basics of the different types of motor modes, as well as a few application examples of using these modes in code. In this section we will focus on using RUN_TO_POSITION
.
The other article, Encoders, focuses on the general functionality of an encoder.
It is recommended that you review both articles before moving on with this guide.
Start by creating a basic op mode called HelloRobot_EncoderAuton.
When creating an op mode a decision needs to be made on whether or not to set it to autonomous mode. For applications under 30 seconds, typically required for competitive game play changing the op mode type to autonomous is recommended. For applications over 30 seconds, setting the code to the autonomous op mode type will limit your autonomous code to 30 seconds of run time. If you plan on exceeding the 30 seconds built into the SDK, keeping the code as a teleoperated op mode type is recommended.
For information on how op modes work please visit the Introduction to Programming section.
For more information on how to change the op mode type check out the Test Bed - Blocks section.
For more information on the directionality of motor check out the Basics of Programming Drivetrains section.
Save and run the op mode two times in a row. Does the robot move as expected the second time?
Try turning the Control Hub off and then back on. How does the robot move?
For more information on the motor mode STOP_AND_RESET_ENCODERS
check out the STOP_AND_RESET_ENCODERS section of the Using Encoders guide.
Velocity is a closed loop control within the SDK that uses the encoder counts to determine the approximate power/speed the motors need to go in order to meet the set velocity. When working with encoder setting a velocity is recommended over setting a power level, as it offers a higher level of control.
To set a velocity, its important to understand the maximum velocity in RPM your motor is capable of. For the Class Bot V2 the motors are capable of a maximum RPM of 300. With a drivetrain, you are likely to get better control by setting velocity lower than the maximum. In this case, lets set the velocity to 175 RPM
Recall that setVelocity
is measure in ticks per second.
Since RPM is the amount of revolutions per minute a conversion needs to be made from RPM to ticks per second. To do this divide the RPM by 60, to get the amount of rotations per second. Rotations per second can the be multiplied by COUNTS_PER_WHEEL_REV
, to get the amount of ticks per second.
With the velocity set, this is the final thing needed to complete the objective of driving in a straight line. Consider adding telemetry and other hardware components as you begin fleshing out your full autonomous code.
To estimate the position of the arm using telemetry and testing, lets start with the initial code we created at the start of the Basics of Programming an Arm, section.
For now you can move the limit switch related blocks to the side of your project.
Save the op mode and run it. Use the gamepad commands to move the arm to the 90 degree position. Once you have the arm properly positioned read the telemetry off the Driver Station to determine the encoder count relative to the position of the arm.
Recall from the Basic Encoder Concepts section that the encoder position is set to 0 each time the Control Hub is turned on. This means that if your arm is in a position other than the starting position when the Control Hub is turned on, that position becomes zero instead of the starting position.
The number given in the image above is not necessarily an accurate encoder count for the 90 degree position. To get the most accurate encoder reading for your robot make sure that your starting position reads as 0 encoder counts. To further increase accuracy consider doing several testing runs before deciding on the number of counts.
If you try running this code you may notice that the arm oscillates around the 90 degree position. When this behavior is present you should also notice the telemetry output for the encoder counts fluctuating. RUN_TO_POSITION
is a Closed Loop Control, which means that if the arm does not perfectly reach the target position, the motor will continue to fluctuate until it does. When motors continue to oscillate and never quite reach the target position this may be a sign that the factors determining tolerances and other aspects of the closed loop are not tuned to this particular motor or mechanism. There are ways to tune the motor, but for now we want to focus on working with the arm and expanding on how limits and positions work with regards to the mechanism.
We're updating this documentation!
During 2024 Summer, "Hello Robot" will be getting a refreshed look to reflect changes to the latest versions of the REV Hardware Client and Robot Controller App.
While this guide is still generally relevant, you may see differences in the naming of devices or commands along with visual updates to the guide.
Each motor designed by REV has an encoder built into it that keeps track of its rotation. To use it, you must have a 4-pin JST PH cable connecting the motor to the Control Hub (REV-31-1595) or Expansion Hub (REV-31-1153), next to the 2-pin JST VH cable used to provide power to the motor.
Encoder values are measured in “ticks.” Different motors have different numbers of ticks per rotation of the output shaft based on the gear ratio of the motor. When the Control Hub is turned on, all of its encoder ports are at 0 ticks. As a motor moves forward, its encoder value increases. As a motor moves backwards, its encoder value decreases.
For more information see the section on encoders.
Your programs can always access the encoder values directly, but you can also direct the Control Hub to use the encoder values to maintain a motor’s speed, or maintain a particular position. You do this by changing the motor’s mode.
It is recommended to use the latest Control Hub and Expansion Hub firmware before using RUN_USING_ENCODER mode or RUN_TO_POSITION mode.
Place a motor in this mode when you want to set its encoder position back to 0. The motor will stop. To start it again, you need to place the motor into one of the other three modes. It is recommended to place each motor you will be using encoders with into this mode at the start of each program, so that you know what position the motor is starting out in.
Use this mode when you don’t want the Control Hub to attempt to use the encoders to maintain a constant speed. You can still access the encoder values, but your actual motor speed will vary more based on external factors such as battery life and friction. In this mode, you provide a power level in the -1 to 1 range, where -1 is full speed backwards, 0 is stopped, and 1 is full speed forwards. Reducing the power reduces both torque and speed.
This mode is a good choice for drivetrain motors driven by joysticks on the gamepad.
In this mode, the Control Hub will use the encoder to take an active role in managing the motor’s speed. Rather than directly applying a percentage of the available power, RUN_USING_ENCODER mode targets a specific velocity (speed). This allows the motor to account for friction, battery voltage, and other factors.
This mode is a good choice for operations, like a flywheel, that require a specific speed and can use buttons on a gamepad for control.
In this mode, the Control Hub will target a specific position, rather than a specific velocity. You still set a velocity, but it is only used as the maximum velocity. The motor will continue to hold its position even after it has reached its target.
This mode is a good choice for operations, like an arm, that require a specific position and can use buttons on a gamepad for control.
In Blocks, you access the current encoder value by using the DcMotor CurrentPosition block.
In Java, you access the current encoder value by calling getCurrentPosition()
on a DcMotor or DcMotorEx object. This sample program prints the encoder value for a motor configured with the name “Motor” to telemetry:
In Blocks, you set the motor’s mode with this block. You can select different modes from its dropdown menu.
Here is a snippet of code that demonstrates how to do the same thing in Java. You can skip the first line if you already have retrieved the motor object from hardwareMap. Change RUN_WITHOUT_ENCODER to the desired motor mode (STOP_AND_RESET_ENCODER, RUN_WITHOUT_ENCODER, RUN_USING_ENCODER, or RUN_TO_POSITION).
The RUN_WITHOUT_ENCODER motor mode is very straightforward, you simply set a power in the range of -1.0 to 1.0. However, if you try to set a velocity (which will be covered later on), the motor will automatically be switched into RUN_USING_ENCODER mode.
The power level is set in Blocks mode using this block:
The power level is set in Java by calling setPower()
on a DcMotor or DcMotorEx object, as is shown in this snippet. You can skip the first two lines if you already have retrieved the motor object from hardwareMap and set the mode to RUN_WITHOUT_ENCODER.
In RUN_USING_ENCODER mode, you should set a velocity (measured in ticks per second), rather than a power level. You can still provide a power level in RUN_USING_ENCODER mode, but this is not recommended, as it will limit your target speed significantly. Setting a velocity from RUN_WITHOUT_ENCODER mode will automatically switch the motor to RUN_USING_ENCODER mode. You should pick a velocity that the motor will be capable of reaching even with a full load and a low battery.
Providing a velocity is an extended motor feature, which means that the block for it is located under DcMotor > Extended. You can see it here:
The velocity is set in Java by calling setVelocity()
on a DcMotorEx object, as is shown in this snippet. You can skip the first two lines if you have already retrieved the motor object as a DcMotorEx from hardwareMap and set the mode to RUN_USING_ENCODER.
To use RUN_TO_POSITION mode, you need to do the following things in this order:
Set a target position (in ticks)
Switch to RUN_TO_POSITION mode
Set the maximum velocity
You should reset the encoders (switch to STOP_AND_RESET_ENCODER mode) during initialization when you use RUN_TO_POSITION mode. If you are using it with a mechanism such as a lift, you have to be careful to make sure that you always have the motor in the same physical location when you reset the encoders, or else your target position won’t mean the same thing between runs.
The motor will continue to hold its position even after it has reached its target, unless you set the velocity or power to zero, or switch to a different motor mode.
The following examples assume that the motor used is a Core Hex Motor. If it is a motor that has a more precise encoder, such as an HD Hex Motor, higher velocity and target position values will be more appropriate.
Here is a complete Blocks program that uses RUN_TO_POSITION.
If you want to wait for the motor to reach its target position before continuing in your program, you can use a while loop that checks if the motor is busy (not yet at its target):
If you want to wait for the motor to reach its target position before continuing in your program, you can use a while loop that checks if the motor is busy (not yet at its target):
In the initial introduction to run to position, you worked through the calculations needed to convert the ticks per rotation of a motor into ticks per mm moved. Now we want to focus on how to convert ticks per rotation of the motor to ticks per degree moved. From the previous section you should have a rough estimate of the amount of ticks you need to get to the 90 degree position. The goal of this section is to work through how to get a more exact position.
To start you will need some of the same variables we used in Encoder Navigation:
Recall, that ticks per revolution of the encoder shaft is different than the ticks per revolution of the shaft that is controlling a mechanism. We saw this in the Encoder Navigation section when the ticks per revolution at the motor was different from the ticks per revolution of the wheel. As motion is transmitted from a motor to a mechanism, the resolution of the encoder ticks changes.
For more information on the effect of motion transmission across a mechanism check out the Compound Gearing section.
The amount of ticks per revolution of the encoder shaft is dependent on the motor and encoder. Manufacturers of motors with built-in encoders will have information on the amount of ticks per revolution.
Visit the manufacturers website for your motor or encoders for more information on encoder counts. For HD Hex Motors or Core Hex Motors visit the Motor documentation.
In the Core Hex Motor specifications there are two different Encoder Counts per Revolution numbers:
At the motor - 4 counts/revolution
At the output - 288 counts/revolution
At the motor is the number of encoder counts on the shaft that encoder is on. This number is equivalent to the 28 counts per revolution we used for the HD Hex Motor. The 288 counts "at the output" accounts for the change in resolution after the motion is transmitted from the motor to the built in 72:1 gearbox. Lets use the 288 as ticks per revolution so that we do not have to account for the gearbox in our total gear reduction variable.
Since we built the the gear reduction from the motor gearbox into the ticks per revolution the main focus of this section is calculating the gear reduction of the arm joint. The motor shaft drives a 45 tooth gear that transmits motion to a 125 tooth gear. The total gear ratio is 125T:45T. To calculate the gear reduction for this gear train, we can simply divide 125 by 45.
To summarize, for the Class Bot V2 the following information is true:
Now that we have this information lets create two constant variables:
COUNTS_PER_MOTOR_REV
GEAR_REDUCTION
The common naming convention for constant variables is known as CONSTANT_CASE, where the variable name is in all caps and words are separated by and underscore.
Add the variablesCOUNTS_PER_MOTOR_REV
and GEAR_REDUCTION
variables to the initialization section of the op mode.
Now that these two variables have been defined, we can use them to calculate two other variables: the amount of encoder counts per rotation of the 125T driven gear and the number of counts per degree moved.
Calculating counts per revolution of the 125T gear (or COUNTS_PER_GEAR_REV
)is the same formula used in Encoder Navigation for ourCOUNTS_PER_WHEEL_REV
variable. So to get this variable we can multipleCOUNTS_PER_MOTOR_REV
by GEAR_REDUCTION
.
To calculate the number of counts per degree or moved or COUNTS_PER_DEGREE
divide the COUNTS_PER_GEAR_REV
variable by 360.
Add both these variables to the op mode in the initialization section of the op mode.
Finally we need to create a non-constant variable that will act as our position. Create a variable called arm position.
To get to the 90 degree position, the arm needs to move roughly 45 degrees. Set arm position equal to COUNTS_PER_DEGREE
times 45.
When using our gamepad, we can actively communicate with our robot while our program runs. Our robot waits for our input and acts accordingly until a different command is issued. However, this may not always be the case, such as during the autonomous period of a FTC competition.
Our robot is smart enough to navigate some on its own, however we need to help it along to know what to look for. Eventually, you could work up to your robot being able to navigate using a camera and machine learning or its IMU to sense direction, but for now let's start with one of the built in features of the SDK: ElapsedTime
What do you think of when you think of a timer? A stopwatch? Your phone? Maybe the timer on a microwave or oven? Timers commonly consist of two main categories: count up and count down. You can think about the differences of these two by a comparison like keeping track of how fast a runner did a 100m dash vs. needing to know how much longer our food should cook.
ElapsedTime is a count up timer. Registering the amount of time elapsed from the start of a set event, like the starting of a stopwatch. In this situation, it is the amount of time passed from when the timer is created or reset within the code.
We can snap our second loop below the original, however something is still missing. If we want our second loop to start we need our timer to first reset! We can add a block between our two loops.
From the variable menu, add the block to the OpMode below the comment block.
In order to utilize elements of the ElapsedTime, runtime will act as the ElapsedTime variable. Add the block to the block.
Before moving on to the rest of the ElapsedTime structure lets go ahead and add the motor related blocks. Add to the op mode to the while loop.
Remember that on a drivetrain one of our motors will need to be set to run in reverse to prevent the robot from spinning in place! Add the block under the the block set.
In the Programming Drivetrain Motors - Blocks section, the mechanism of was discussed. dictates what direction and speed a motor moves in. On a drivetrain the combined direction and speed of the motors dictates whether the robot moves in forward, backwards, or turns.
In RUN_TO_POSITION
mode the encoder counts are used instead of to dictate directionality of the motor. If a target position value is greater than the current position of the encoder, the motor moves forward. If the target position value is less than the current position of the encoder, the motor moves backwards
For more information on how direction and speed impact the movement of a robot please refer to the explanation of in the Programming Drivetrain Motors section.
ElapsedTime | Drivetrain Encoders | Arm Encoders |
---|---|---|
In the previous section, the basic structure needed to use RUN_TO_POSITION
was created. The placement ofwithin the code, set the target position to 1000 ticks. What is the distance from the starting point of the robot and the point the robot moves to after running this code?
Once the variables are created and added to the op mode, use the blocks to set the variables to the respective values. For WHEEL_CIRCUMFERENCE_MM
a combination of the , , and blocks to get the circumference of the wheel. The
= COUNTS_PER_MOTOR_REV
= DRIVE_GEAR_REDUCTION
= COUNTS_PER_WHEEL_REV
= COUNTS_PER_MOTOR_REV
= DRIVE_GEAR_REDUCTION
= WHEEL_CIRCUMFERENCE_MM
= COUNTS_PER_WHEEL_REV
= COUNTS_PER_MM
Again math blocks need to be used to define these variables. Lets start with the COUNTS_PER_WHEEL_REV
variable. Add a to the block. Add the and blocks to either side of the block.
Since COUNTS_PER_WHEEL_REV
has been calculated it can be used to calculate COUNTS_PER_MM
add the to the . On the left side of the add the block. On the right side of the add the .
Lets start by creating our less than or equal to condition. Grab the from the Logic menu.
Next select the block from the ElapsedTime menu. Snap the block into the left side of the block. Using the dropdown menu, change the generic to the variable we established earlier.
On the other side of our equation, we need to add a block from the Math menu. Change the number block to 3.
Right now the is equal to three. Use the arrow next to the equal sign to choose the less than or equal to sign from the dropdown menu.
First, grab an block from the Logic menu. The block we currently have as part of our loop will be moved to the lefthand side.
On the other side, add the block:
This block set will connect where the block originally was. Now the while loop will now activate when both conditions of the AND block are true.
To keep this from happening the timer should be reset once the OpMode is active. Grab the call block from the ElapsedTime menu and switch it to our runtime variable.
This will be added to our program BELOW the comment and ABOVE the while loop.
Now let's explore what happens when we change our time limit to different amounts. You can adjust your time limit by changing the 3 in our block to a different number.
Our block will snap into our number slot.
Create two more variables called leftTarget
andrightTarget
. Add the and blocks to the op mode above the block.
Edit the so that both motors are set to the appropriate target position. To do this add the and blocks to their respective motor.
For now we want the minPosition
set as our starting position and the maxPosition
set to our 90 degree position. Set minPosition
equal to and set maxPosition
equal to .
Start by editing the to add another condition. Use the block as the condition. Add a block to the do portion of the block.
We can create an statement that focuses on performing this stop and reset when the touch sensor is pressed. Since the touch sensor reports true
when its not pressed and false
when it is, we will need to use the block.
The not operator can be used in conditional binary statements when you need inverse whether something is true
of false
. For instance, an if
statement activates when something is true, but when the Touch Sensor reports true
it is not pressed. In our case we want this if statement to activate when the touch sensor is pressed thus we need to use the not operator.
Add the block to the op mode under the .This will change the direction of the rotation of the right motor to be the same direction as the left motor.
Recall from Using Encoders that using RUN_TO_POSITION
mode requires a three step process. The first step is setting target position. To set target position, grab the block and add it to the op mode under the comment. To get a target position that equates to a target distance requires so calculations, which will be covered later. For now, set target position to 1000 ticks.
When there are multiple of the same type of variable (such as multiple Dc Motor variables) the variable specific blocks will choose a default variable based on alphabetical order. For this example Op Mode Dc Motor blocks will default to the arm variable. Click the arrow next to the motor name to change the arm motor variable to the rightmotor variable. Use the variable drop down menu on the block to change from arm to rightmotor.
The next step is to set both motors to the RUN_TO_POSITION
mode. Place the block beneath the block.
The main focus of the three step process is to set a target, tell the robot to move to that target, and at what speed (or velocity) the robot should get to that target. Normally, the recommended next step is to calculate velocity and set a target velocity based on ticks. However, this requires quite a bit of math to find the appropriate velocity. For testing purposes, its more important to make sure that the main part of the code is working before getting too deep into the creation of the code. Since the function was covered in previous sections and will communicate to the system what relative speed (or in this case duty cycle) is needed to get to the target, this can be used in the place of velocity for now.
Add the block to the op mode beneath the block. Change the duty cycle (or power) of both motors to 0.8, instead of 1.
Now that all three RUN_TO_POSITION
steps have been added to the code the code can be tested. However, if you want to wait for the motor to reach its target position before continuing in your program, you can use a while loop that checks if the motor is busy (not yet at its target). For this program lets edit the block.
Recall that, within a linear op mode, a while loop must always have the Boolean as a condition. This condition ensures that the while loop will terminate when the stop button is pressed.
Grab an block from the logic menu and add it to the while loop. On the left side of the block add the block. On the right side add the block.
Embed the in another block. Place the on the right side of the block. On the left side add the block.
Right now the while loop is waiting for the right and left motors to reach their respective targets. There may be occasions when you want to wait for both motors to reach their target position, in this case the can be used.
In the Basic Encoder Concepts section, it is clarified that ell encoder ports start at 0 ticks when the Control Hub is turned on. Since you did not turn off the Control Hub in between runs, the second time you ran the op mode the motors were already at, or around, the target position. When you run a code, you want to ensure that certain variables start in a known state. For the encoder ticks, this can be achieved by setting the mode to . Add this block to the op mode in the initialization section. Each time the op mode is initialized, the encoder ticks will be reset to zero.
Create a new variable called TPS. Add the to the op mode under the comment block.
Add a block to the block. On the right side of the block add the . One the left side of the add the block. Add the chosen RPM to the left side of the block and 60 to the right side.
Now that the target ticks per second has been set, swap the block for a block. Add the to both motors.
Within the loop add a block. Add the to the number portion of the block. Change the key string from the default "key"
to "Arm Test."
To add the RUN_TO_POSITION
code the if/else
statement must first be edited back into an block, as shown in the code below.
When DpadUp
is pressed, the arm should move to the the 90 degree position. When DpadDown
is pressed the arm should move back to the starting position. To do this set the first equal to the number of ticks it took your arm to get to 90 degrees, for this example we will use 83 ticks.
Since we want DpadDown
to return the arm to the starting position, keeping the block set to 0 will allow us to accomplish this. Set both blocks equal to 0.5.
Recall that the target position dictates which direction the motor moves, taking over the directionality control from the block, so both blocks can be set to a positive value since they will control the speed.
Once the variables are created and added to the op mode, use the blocks to set the variables to the respective values
Add this variable to the section of the statement, as this section dictates the 90 degree position. Add the block to the block.
We could set equal to . However, it is a good practice to create a variable in situations like this. If we want to add another position later, we can easily edit the variable to fit our needs.
Coming Soon
Coming Soon
Ticks per revolution
28 ticks
Total gear reduction
30.21
Circumference of the wheel
Ticks per revolution
288 ticks
Total gear reduction
2.777778