# Coding Guide for Botball ## Start Every File the Same Way Define your ports at the top using `#define`. This way if a wire gets moved, you only change one line instead of hunting through the whole program. ```c #include // --- PORT ASSIGNMENTS --- #define LEFT_MOTOR 0 #define RIGHT_MOTOR 3 #define ARM_SERVO 3 #define CLAW_SERVO 2 #define LINE_SENSOR 0 #define BUMP_SENSOR 1 // --- THRESHOLDS --- #define BLACK_VALUE 3000 #define LINE_THRESHOLD 2000 ``` Then your code reads like plain English: `motor(LEFT_MOTOR, 100)` is much clearer than `motor(0, 100)`. --- ## Break Your Route into Functions Don't write one giant `main()`. Write one function per task. Each function should do one thing and have a name that describes what it does. ```c void drive_to_wall() { ... } void grab_object() { ... } void return_to_start() { ... } int main() { wait_for_light(0); shut_down_in(119); drive_to_wall(); grab_object(); return_to_start(); ao(); return 0; } ``` Benefits: easier to test one section at a time, easier to fix bugs, easier to read. --- ## Always Stop Your Motors Every time you start motors, there needs to be a clear place where they stop. Forgetting `ao()` is one of the most common bugs. ```c // Good: clear start and stop motor(LEFT_MOTOR, 80); motor(RIGHT_MOTOR, 80); msleep(1000); ao(); // <-- don't forget this msleep(200); // brief pause after stopping ``` --- ## Two Ways to Control Distance **Time-based:** Simple, but affected by battery level and surface friction. Good for rough positioning. ```c motor(LEFT_MOTOR, 80); motor(RIGHT_MOTOR, 80); msleep(1500); // go for 1.5 seconds ao(); ``` **Encoder-based:** More reliable for consistent distances. Encoders count wheel "ticks" as the wheel turns — but how many ticks per full rotation depends on your motor and gearing. Common values are around 1440 ticks/rotation for Tetrix motors, but ask your coach before relying on exact numbers. The tick counts in your route code are found by testing, not calculated. ```c cmpc(LEFT_MOTOR); // reset counter to 0 while (gmpc(LEFT_MOTOR) < 5000) { motor(LEFT_MOTOR, 80); motor(RIGHT_MOTOR, 80); msleep(10); // always include a short sleep in loops like this — // without it the loop runs so fast it can crash the Wombat } ao(); ``` When precision matters (like lining up to grab something), use encoders. When you just need to get somewhere approximately, time-based is fine. --- ## Sensor-Based Stopping Using a sensor to stop is more reliable than guessing how long something takes. ```c // Stop when you hit a wall while (digital(BUMP_SENSOR) == 0) { motor(LEFT_MOTOR, 60); motor(RIGHT_MOTOR, 60); msleep(10); } ao(); // Stop when you reach a black line while (analog(LINE_SENSOR) < BLACK_VALUE) { motor(LEFT_MOTOR, 60); motor(RIGHT_MOTOR, 60); msleep(10); } ao(); ``` If a sensor isn't working, a time-based fallback is okay for competition, but plan to fix it. --- ## Debug with printf `printf` is your best debugging tool. Print sensor values while the robot is running to see what it's actually experiencing. ```c // Print once each loop iteration - see what the sensor reads while (1) { printf("line sensor: %d\n", analog(LINE_SENSOR)); msleep(100); } ``` Watch the output in the Wombat's terminal as the robot moves. This will tell you the right threshold values to use. When you find a value that works, set it as a `#define` constant. Remove or comment out excessive `printf` calls before competition — they slow the program down. --- ## Servos: Enable, Move, and Be Patient Always call `enable_servos()` before using servos, and `disable_servos()` when done. After setting a position, give the servo time to physically reach it. ```c enable_servos(); set_servo_position(ARM_SERVO, 1000); // move arm msleep(1000); // wait for it to get there set_servo_position(CLAW_SERVO, 2047); // close claw msleep(500); disable_servos(); ``` Servo positions range from 0 to 2047. You'll need to experiment to find the right positions for your specific arm — there's no universal answer. --- ## Mecanum Wheels: Motor Direction Reference | Movement | Motor 0 (LF) | Motor 1 (RF) | Motor 2 (LB) | Motor 3 (RB) | |---------------|:---:|:---:|:---:|:---:| | Forward | + | + | + | + | | Backward | - | - | - | - | | Strafe Right | + | - | - | + | | Strafe Left | - | + | + | - | | Rotate Right | + | - | + | - | | Rotate Left | - | + | - | + | If something isn't moving the right direction, check whether one or more motors is spinning backwards. The self-test program will help you verify each motor individually. --- ## Common Mistakes **Changing too many things at once.** If the robot isn't working, change one thing and test it before changing anything else. Otherwise you won't know what fixed it. **Hardcoding port numbers.** Use `#define` constants. `motor(0, 100)` is hard to read and hard to fix when something changes. **No pause between movements.** Add a short `ao(); msleep(200);` between sections. It gives the robot time to stop fully before the next movement starts. **Trusting timing over sensors.** If the robot does the same task multiple times and the timing varies, use a sensor instead. **Not testing sections separately.** If you're debugging section 3, comment out sections 1 and 2 so you don't have to wait through them every test run. **One giant `main()`**. If your `main()` is longer than about 30 lines, you probably need more functions. Long `main()` functions are hard to debug and hard to test piece by piece.