Servos

Though a lot of a Botball match is spent driving around the board, the key to any successful robot is the manipulators it uses to score points. Though creative use of a sled can score many kinds of points in Botball matches, the highest scoring objectives almost always require the use of claws or other more sophisticated manipulators. In this article, I'll be covering the software side of these kind of appendages by controlling servos.

Servos

(TODO: Pics of servos?)

As you probably already know, servos are often used to power manipulators like claws and sweepers because of their strength and precision. Though a servo can only rotate approximately 270 degrees (TODO: hardware confirmation?), they can simply and easily be commanded to move to extremely precise and repeatable positions, and are very good at holding those positions. Once set, a servo will "fight" any attempts to move it from its set position, which is what gives claws their grasp and lift arms the ability to hold a mechanism in the air. Better yet, servos are extremely simple to use in your program! Lets start with a simple example:

  1. int main() {
  2. printf("Powering servo to its center position\n");
  3. set_servo_position(3, 1000);
  4. enable_servos();
  5.  
  6. sleep(4);
  7.  
  8. printf("Sending servo to position 200\n");
  9. set_servo_position(3, 200);
  10.  
  11. sleep(4);
  12.  
  13. printf("Sending servo to position 1800\n");
  14. set_servo_position(3, 1800);
  15.  
  16. sleep(4);
  17.  
  18. printf("Turning servos off\n");
  19. disable_servos();
  20. }

To try this program out, you'll need to attach a servo to port 3. To attach the servos, look for the pins labeled "S3". The servo will only connect in one direction, so be sure the yellow wire goes into the pin marked 'S', and the black wire in the pin marked '-'. When you run the program, you should see the servo spring to life and move to the center, then counterclockwise and clockwise. (TODO: I don't actually remember if lower numbers = clockwise or counterclockwise :/)

Servo Positions

Looking closely at the program, we can see that servos are really quite simple! There's really only one function to move them around, and thats set_servo_position. Let's take a closer look:

  1. set_servo_position(1, 400); // move servo 1 to 400
  2. set_servo_position(3, 0); // move servo 3 to position 0, the lowest you can go (TODO: make sure this doesn't go beyond servo's internal stops)
  3. set_servo_position(4, 2047); // move servo 4 to position 2047, the highest you can go

Are you seeing the pattern yet? set_servo_position takes two arguments, or numbers in parenthesis. The first number is always the number on the servo port that we want to move. 1 means "S1", 2 means "S2", etc. Since their are only 4 servo ports, this number should always be between 1 and 4.

The second argument is the servo's position. Before we type the second number however, we must always put a comma to separate them. Otherwise, our code won't compile. After the comma, we can put any number from 0 to 2047. This number represents where the servo should travel to. Picture the servo as the needle on a speedometer, with the number 0 on the left and 2047 on the right (TODO, double check), and all the numbers in between representing intermediate positions. The number we specify is where the "needle" will travel to.

(TODO: somebody who whip up the picture described above?)

As you're running the program, try out the other interesting property of servos: They have some "fight" to them! Try to hold the servo back as it is moving, or push it to a different place while it is stationary. It can put out a surprising amount of force, though the amount of kick it has is highly dependent on battery level. This has some extremely useful applications to Botball that will be addressed in the "Tips and Tricks" section.

Enabling and Disabling Servos

If you look closely at the program, there's actually two more functions that we haven't covered yet: enable_servos and disable_servos. Though they may seem small and inconsequential, they are actually very important to a good servo-using program.

When you first plugged in the servos, you probably noticed that nothing happened. They were completely slack, and easy to move around. This is because when you first boot the CBC up, the servos are disabled. To enable them, your program must use enable_servos. This turns on the power to all four servo ports, causing the servos to travel to and hold their set positions. At the end of program, disable_servos is used to put servos back to their disabled state, where they are loose and easy to move about.

Lets talk a bit more about the proper way to enable servos. If you look at the example program, I set the servo's position before I enabled it. This initially doesn't make much sense, so lets think about it. When servos are disabled, they have no power, so the set position has no effect. But when we enable power, the servos all begin to travel to their set positions. In this case, the servo goes directly to the position set previously. So what? Well, consider if we enabled the servos without setting a position. At least initially, they would all begin to travel to random positions. When the servo travels too far and starts ripping your robot apart trying to lower the claw into the ground, you won't be very popular among your team's builders, so always be sure to set your servos before enabling!

Disabling servos at the end of your program is equally important. It isn't safe to remove servos while they're enabled, for instance, so disabling is important so your builders can perform quick fixes without fully powering off the CBC. It also saves battery life. Enabling servos represents a small performance drain that quickly becomes a large power drain if one of the servos is under load, or being forced to exert itself holding something up. Disabling servos lets your robot relax and hold on to battery life in between runs of your program.

Finding Servo Positions

Finding useful servo positions that cause your robots claw to move correctly can be tricky. Here's a simple program you can use to calibrate a single servo. Don't worry if you don't understand it yet, it uses some more advanced programming elements which will be covered later in the guide.

  1. #define TEST_SERVO 2
  2.  
  3. int main() {
  4. int pos=1000;
  5. set_servo_position(TEST_SERVO, pos);
  6. enable_servos();
  7.  
  8. printf("Simple servo calibration program.\n");
  9. printf("Use the left and right buttons to move\n");
  10. printf("the servo. Press B when finished.\n");
  11.  
  12. while (1) {
  13. while (1) {
  14. if (left_button() && pos > 0) {
  15. while (left_button()) { }
  16. pos -= 100;
  17. break;
  18. }
  19. if (right_button() && pos < 2000) {
  20. while (right_button()) { }
  21. pos += 100;
  22. break;
  23. }
  24. if (b_button()) {
  25. disable_servos();
  26. return 0;
  27. }
  28. }
  29. set_servo_position(TEST_SERVO, pos);
  30. printf("Current position: %d\n", pos);
  31. }
  32. }

To use it, just use the arrows to move the servo to the correct spot, then use the current position that the program prints in your program. It only moves servos in increments of 100, so if you want a finer adjustment than that you can either modify the program, or resort to a bit of trial and error.

At the top of the program, you can see that I used #define to name one of the servo's TEST_SERVO. To change the program to test the correct servo, just change the number 2 to another servo port. This is also a very good technique to try to use in your own program.

Tips and Tricks

Here's some useful tips. Even if you've programmed botball robots for a while, some of these may still be helpful! These are probably a bit beyond someone who is just learning to program, so don't worry if you don't follow these parts. Focus on experimenting with the above programs instead.

Torque your servos

You can push your servos past where they can physically go to create a strong grip, which at least my team calls "torquing" the servo. If your claw is dropping things, particularly the more squishy scoring items, try telling the servo to move beyond the position that shuts the claw. It will never get there, but it will apply more force on the object your holding, giving your claw a greater ability to hold on. Don't do this for too long though, as it will drain your batteries rapidly!

Control your servo's speed

Though set_servo_position doesn't have an argument for servo speed, you can emulate speed by moving the servo in small increments with delays. If you're familiar with loops and variables, you can easily move the servo to a position using 100 small adjustments or more with a few milliseconds of delay between each. The servo will follow your commands, so the more time your code spends "guiding" it to intermediate positions the slower the servo will move.

Never forget to disable servos again

The following command will automatically disable servos when your program ends. Unfortunately, if you press the Stop button on the CBC, the program is terminated in such a way that the servos won't get turned off. Still, its a nice trick.

  1. int main() {
  2. atexit(disable_servos); // just put this at the top of your program!
  3.  
  4. // ...
  5. }

Wrapping it up

And with that, you have everything you need to know to program servos, in three easy steps. Set an initial position and enable them, then move them around using set_servo_position. Be sure to disable your servos some time before the program ends, and you're ready to lift and grab your way to victory!