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!
Quick Check
Let's review quick our basic positions:
Programmed Position
Degrees
0
-135°
0.5
0°
1
135°
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?
Click to reveal the answers
Breaking it down we can see that -67.5° would be half of our movement between 0° and -135° . Therefore, we will set our position to halfway between 0 and 0.5 equaling 0.25.
This second question requires a little more math. Let's think about how far our servo would move for each 0.1 of a position. Our total movement is 270° so if divided by 10 we know 0.1 = 27°. Going from there we can do the math starting from the 0° we know position 0.5 brings us to. Therefore, moving to position 0.7 should be 54°.
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.
Let's get Programming!
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.
Add the line test_servo.setPosition(1);to the OpMode while loop.
Select Build Everything to build the code.
Quick Check!
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?
Running our program a second time
Likely, on a second run our servo did not move since it is already at the correct position. Now check what happens if you first manually rotate the servo while the robot is disabled. Once the code is activated again by pressing play we should see it move again!
Note: Servos are designed to maintain their position so long as the robot's program is enabled. Trying to forcibly move the servo while ON may damage it and is not recommended.
If your servo did not move as expected, double check your wiring and port are correct compared to your configuration.
Resetting Back to Zero
The intent of thetest_servo.setPosition();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 the line test_servo.setPosition(0).
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 add this line?
Recall when we discussed the different sections of our OpMode during Programming Essentials. 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.
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!
Programming Servo Telemetry
What is Telemetry?
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.
For OnBot Java we can use the following to request the servo's position:
test_servo.getPosition();
We already have a couple lines of telemetry within our code to let us know what state our program is in: "Initialized" or "Running". Below our if/else if statement we can add another telemetry.addData();.
First, we need to add a "string" or the text that we want to appear on our Driver Hub. For now we will enter this as "Servo Position". After our comma, we will add the data we want outputted to the Driver Hub, which is test_servo.getPosition(); .
@TeleOp
public class HelloRobot_TeleOp extends LinearOpMode {
private Blinker control_Hub;
private DcMotor test_motor;
private Servo test_servo;
private TouchSensor test_touch;
@Override
public void runOpMode() {
control_Hub = hardwareMap.get(Blinker.class, "Control Hub");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(TouchSensor.class, "test_touch");
test_servo.setPosition(0);
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
if (gamepad1.y){
//move to position 0
test_servo.setPosition(0);
} else if (gamepad1.x || gamepad1.b) {
//move to position 0.5
test_servo.setPosition(0.5);
} else if (gamepad1.a) {
//move to position 1
test_servo.setPosition(1);
}
telemetry.addData("Servo Position", test_servo.getPosition());
telemetry.addData("Status", "Running");
telemetry.update();
}
}
while (opModeIsActive()) {
test_servo.setPosition(1);
telemetry.addData("Status", "Running");
telemetry.update();
}
public void runOpMode() {
control_Hub = hardwareMap.get(Blinker.class, "Control Hub");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(TouchSensor.class, "test_touch");
test_servo.setPosition(0);
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
test_servo.setPosition(1);
telemetry.addData("Status", "Running");
telemetry.update();
}
}
}
while (opModeIsActive()) {
if (gamepad1.y){
//move to position 0
test_servo.setPosition(0);
} else if (gamepad1.x || gamepad1.b) {
//move to position 0.5
test_servo.setPosition(0.5);
} else if (gamepad1.a) {
//move to position 1
test_servo.setPosition(1);
telemetry.addData("Servo Position", test_servo.getPosition());
telemetry.addData("Status", "Running");
telemetry.update();
}
Using a Gamepad with a Servo
Programming a Servo with a Gamepad
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)
Button
Degree Position
One of the most common logic statements used in programming is an if/else statement, also known as an if/then statement. 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)?
An if/else if statement takes in multiple different conditional statements. If the first conditional statement is found to be false then the second conditional state is analyzed.
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?
We've previously added our ability to move to position 0 and 1, but what about 0.5?
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.
In OnBot Java, || means "or" allowing the robot to check if one of two buttons things are true. In this case, it will check if the x OR b button are pressed on the gamepad.
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.
Code Position
Y/Triangle
-135
0
X/Square
0
0.5
B/Circle
0
0.5
A/Cross
135
1
Introducing If/Else Statements
Quick Check!
What will happen when the answer is FALSE?
At the moment, we have not asked our robot to do anything specific when our statement is false. This means for now our servo will not move or change while our Y button is not pressed.
If/Else If Statements:
Quick Check!
Reveal the answer!
Programming our servo to move to position 1 when A is pressed will look very similar to our existing code:
Now our statement reads: "If the Y button is pressed then move the servo to position 0, else if the A button is pressed then move the servo to position 1."
If you have not already, test the code we have written thus far! The previous test_servo.setPosition(1);should be removed if it has not already.
What happens when both buttons are pressed at the same time?
Adding Logic Operators:
Click to Build Everything and give your program a try!
Full Program:
if (gamepad1.y){
test_servo.setPosition(0);
}
if (gamepad1.y){
test_servo.setPosition(0);
} else if () {
}
if (gamepad1.y){
//move to position 0
test_servo.setPosition(0);
} else if (gamepad1.x || gamepad1.b) {
//move to position 0.5
test_servo.setPosition(0.5);
} else if (gamepad1.a) {
//move to position 1
test_servo.setPosition(1);
}
public void runOpMode() {
control_Hub = hardwareMap.get(Blinker.class, "Control Hub");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(TouchSensor.class, "test_touch");
test_servo.setPosition(0);
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
if (gamepad1.y){
//move to position 0
test_servo.setPosition(0);
} else if (gamepad1.x || gamepad1.b) {
//move to position 0.5
test_servo.setPosition(0.5);
} else if (gamepad1.a) {
//move to position 1
test_servo.setPosition(1);
}
telemetry.addData("Status", "Running");
telemetry.update();
}
}
}
if (gamepad1.y){
test_servo.setPosition(0);
} else if (gamepad1.a) {
test_servo.setPosition(1);
}