Now that we have an estimate for our target position let's see if we can refine it to be more precise using similar methods to what we covered during the Drivetrain Encoders section.
Recall, that ticks per revolution of the encoder shaft is different than the ticks per revolution of the shaft that is controlling a mechanism, such as what we determined on our Drivetrain.
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:
Ticks per revolution
288 ticks
Total gear reduction
2.777778
Now that we have this information lets create two constant variables:
COUNTS_PER_MOTOR_REV
GEAR_REDUCTION
Add the variables COUNTS_PER_MOTOR_REV
and GEAR_REDUCTION
variables to the initialization section of the program.
Our COUNTS_PER_MOTOR_REV
and GEAR_REDUCTION
variables will be set to a value that will then be used to calculate our other two variables COUNTS_PER_DEGREE
and COUNTS_PER_GEAR_REV
.
Let's go ahead and add these variables to our OpMode.
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 we used for COUNTS_PER_WHEEL_REV
variable on our drivetrain, so to get this variable we can multiple COUNTS_PER_MOTOR_REV
by GEAR_REDUCTION
.
To calculate the number of COUNTS_PER_DEGREE
divide the COUNTS_PER_GEAR_REV
variable by 360.
All together our variables will look like below:
We need to create one more non-constant variable that will act as our position. This will be called armPosition
.
To get to the 90 degree position, the arm needs to move roughly 45 degrees therefore set arm position equal to COUNTS_PER_DEGREE
times 45.
Save your OpMode and give it a test!
Once the variables are created and in place, use the blocks to set the first 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.
This section is written with the Class Bot V2 in mind, but can be followed with appropriate adjustments, such as mechanism angles, on other robot designs!
We've covered using encoders for a drivetrain, but what about for a different mechanism, such as an arm? Unlike the drivetrain, the arm does not follow a linear path. This means rather than converting 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 Class Bot arm. One of the positions (blue) is the position where the arm meets the limit of the touch sensor. Due to the limit, this position will be our default 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 tutorial 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. For example, an estimation can be done by moving the arm to the desired position and recording the telemetry feedback from the Driver Station. Alternatively, we can do the math calculations to find the amount of encoder ticks that occur per degree moved.
Follow through this tutorial to walk through both options and determine which is the best for your team!
For this tutorial, our OpMode is named HelloRobot_ArmEncoder!
Let's start by creating a simple program for moving our robot's arm. The one below will look very similar to the code created during Part 2: Robot Control!
Save the OpMode 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 Hub to determine the encoder count relative to the position of the arm.
Remember 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.
Lastly, we can remove the final "else" of our statement for now since we are now using RUN_TO_POSITION
mode.
Despite our power being a positive value for both directions, the arm will move up or down based on the set position!
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.
Recall 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, or ways to have the program exit once the position is reached, 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.
In Part 2: Robot Control the idea of creating a limit switch was introduced using a physical sensor, like a touch sensor. We can make use of our motor's built-in encoder to do something similar. While a physical sensor would be described as a hard limit, using the built-in encoder is called a soft limit.
To set the soft limits we will build off the program created in the last sections (HelloRobot_ArmEncoder)!
To start, we need to create our upper and lower limits. Create two new variables one called minPosition
and one called maxPosition
to be added to initialization.
To start, our If/Else Statement will be changed back to a simplified format like we had at the beginning of estimating the position of the arm.
To set the limit we need to edit our if/else
statement to include our limits:
If up on the Dpad is pressed and the position of the arm is less than the maxPosition
, then the arm will move to the maxPosition
.
If down on the Dpad is pressed and the position of the arm is greater than the minPosition
then the arm will move towards the minPosition
.
One of the benefits of having a soft limit is being able to exceed that limit.
Remember that the encoders zero tick position is determined by the position of the arm when the Control Hub powers on! So if we aren't careful to reset the arm before powering on our robot this will effect the arm's range of motion. For instance, if we have to reset the Control Hub while the arm is in the 90 degree position, the 90 degree position will become equal to 0 encoder ticks.
As a back up, we can create an override for the range of motion. There are a few different ways an override can be created, but 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.
Next, when the arm reaches and presses the touch sensor we want to STOP_AND_RESET_ENCODER
.
Save your OpMode and try testing it!
Within the loop we'll 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.
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 . The block previously used for armPosition
can be moved to our maxPosition
.
Start by editing the to add another condition. Use the block as the condition. Add a block to the do portion of the block and set the power to -0.5.
We can create an additional statement that focuses on performing this stop and reset when the touch sensor is pressed. Check out Programming Touch Sensors from Part 1: Tackling the Basics for review if needed!