Last active 1 month ago

Coaching guide, student coding reference, troubleshooting guide, and self-test programs (standard + mecanum) for middle school Botball teams.

jesse's Avatar jesse revised this gist 1 month ago. Go to revision

5 files changed, 920 insertions

coach_guide.md(file created)

@@ -0,0 +1,86 @@
1 + # Botball Coach Guide
2 +
3 + ## Your Job Isn't to Write the Code
4 +
5 + The goal is for the students to understand what their robot is doing and why. When they're stuck, your instinct will be to fix it for them — resist that. Ask questions instead. "What do you think is happening?" is more valuable than pointing at the bug.
6 +
7 + That said, don't let them spin indefinitely. A good rule: if students have tried **three different ideas** and nothing has changed, step in and suggest a new direction. Three attempts is enough to learn from; more than that without progress is just frustrating.
8 +
9 + ---
10 +
11 + ## How to Coach a Troubleshooting Session
12 +
13 + When something goes wrong, walk them through the same process every time. They'll internalize it.
14 +
15 + **1. Observe before touching anything.**
16 + Watch the robot fail. Ask: "What did you expect to happen? What actually happened?" If they can't articulate the difference, they're not ready to fix it.
17 +
18 + **2. Isolate the problem.**
19 + Is it mechanical (motor, servo, wiring), sensor-related, or code logic? Have them run the self-test program first if they're unsure. "Let's rule things out one at a time."
20 +
21 + **3. Form a hypothesis.**
22 + "What do you think is causing it?" Make them guess. Wrong guesses are fine — they're learning. Then test the guess.
23 +
24 + **4. Change one thing at a time.**
25 + Students will often change three things at once and then not know what worked. Slow them down. One change, one test, record what happened.
26 +
27 + **5. Use `printf`.**
28 + If they can't see what the robot is thinking, have them print sensor values and motor states. "What does the sensor actually read when the robot is in that position?"
29 +
30 + ---
31 +
32 + ## When They're Stuck on Code
33 +
34 + **They don't know where to start:** Help them break it down. "What's the very first thing the robot needs to do in this section?" Get them writing one function at a time.
35 +
36 + **The code doesn't compile:** Read the error with them, out loud. Compiler errors are intimidating but usually specific. Most common issues: missing semicolons, mismatched braces, calling a function before it's defined.
37 +
38 + **The robot does something unexpected:** Ask them to walk you through the code line by line, out loud, and describe what each line should do. They'll often find the bug themselves mid-explanation. (This is called rubber duck debugging — it works.)
39 +
40 + **Timing is off (robot stops too early or too late):** Remind them that `msleep` timings depend on battery level and surface conditions. If they're relying heavily on time-based movement, encourage them to add encoder or sensor checks.
41 +
42 + **The sensor threshold seems wrong:** Have them print the sensor value in a loop while moving the robot to the exact position where the behavior should change. Then set the threshold to that value, with a small buffer.
43 +
44 + ---
45 +
46 + ## Coaching Mecanum Bots Specifically
47 +
48 + Mecanum robots are powerful but have a higher coordination cost. A few things to watch for:
49 +
50 + - **Motor directions matter more.** Each wheel needs to spin the right way for strafing and diagonal moves to work. If the bot is spinning instead of strafing, at least one motor direction is flipped. Run the self-test to check each motor in isolation.
51 + - **"Squaring up" is tricky.** Mecanum bots can strafe into walls to align, but students often just use time-based strafing. Encourage them to think about whether a sensor could give them a more reliable stop condition.
52 + - **Inconsistent strafing.** Friction and floor surface variation affect mecanum movement more than regular drive. If a strafe distance is inconsistent, use encoder ticks (`cmpc`/`gmpc`) instead of `msleep`.
53 +
54 + ---
55 +
56 + ## Pre-Practice Habits Worth Building
57 +
58 + - **Always run the self-test first.** Before writing new code or debugging a route, verify the hardware is working. A loose motor wire will look like a code bug.
59 + - **Charge batteries before practice, not during.** Nothing kills debugging momentum like stopping to swap batteries mid-session.
60 + - **Back up code before making changes.** Encourage them to copy working code to a commented-out block or a separate file before experimenting. They'll thank you when they break something.
61 + - **Write port assignments as `#define` constants at the top of the file.** If a wire gets moved to a different port, changing one line is far better than hunting through code.
62 +
63 + ---
64 +
65 + ## Pre-Competition Checklist
66 +
67 + Run through this with the team the day before and the morning of competition.
68 +
69 + - [ ] Self-test passes on competition robot (all motors and servos respond correctly)
70 + - [ ] Sensor thresholds verified on the actual competition surface and lighting
71 + - [ ] `wait_for_light()` is the first call in `main()`, not buried in a section function
72 + - [ ] `shut_down_in(119)` is called early in `main()` as a safety net
73 + - [ ] All `#define` port constants match the physical wiring
74 + - [ ] Robot starts from the correct position and orientation
75 + - [ ] Team knows what to do if the robot fails mid-run (stay calm, note what happened for next run)
76 + - [ ] Battery is fully charged
77 +
78 + ---
79 +
80 + ## Managing the Team Dynamic
81 +
82 + Middle schoolers will disagree about the code. That's good — let them argue it out to a point, then have them *test* the disagreement rather than just debate it. "Both ideas sound reasonable. Let's try yours first and see what happens."
83 +
84 + If one student is dominating the keyboard, rotate. Even if they're the strongest coder, the others need hands-on time.
85 +
86 + Celebrate working things. A section that runs correctly in practice is worth noting, even if the full route isn't done yet.

self_test_mecanum.c(file created)

@@ -0,0 +1,286 @@
1 + // ============================================================
2 + // SELF-TEST: Mecanum Robot
3 + // Run this before every practice and competition to verify
4 + // all hardware is working correctly.
5 + //
6 + // HOW TO USE:
7 + // 1. Update the port #defines below to match your robot
8 + // 2. Set TEST_MOTORS / TEST_SERVOS / TEST_SENSORS to 0
9 + // if you want to skip that section
10 + // 3. Set any unused port to -1 to skip it
11 + // 4. Run the program — press the A button to advance
12 + // between tests so you can watch each component
13 + //
14 + // OUTPUT: Open the Console window in the Wombat software
15 + // to see all printed messages.
16 + //
17 + // MECANUM MOTOR LAYOUT (top view):
18 + //
19 + // FRONT
20 + //
21 + // LF (0) RF (1)
22 + //
23 + // LB (2) RB (3)
24 + //
25 + // BACK
26 + //
27 + // ============================================================
28 +
29 + #include <kipr/wombat.h>
30 +
31 + // ============================================================
32 + // --- WHAT TO TEST (set to 0 to skip a whole section) ---
33 + // ============================================================
34 + #define TEST_MOTORS 1
35 + #define TEST_SERVOS 1
36 + #define TEST_SENSORS 1
37 +
38 + // ============================================================
39 + // --- PORT ASSIGNMENTS ---
40 + // Use -1 if you DON'T have something plugged in.
41 + // ============================================================
42 +
43 + // Drive motors — update these if yours are wired differently
44 + #define MOTOR_LF 0 // Left Front
45 + #define MOTOR_RF 1 // Right Front
46 + #define MOTOR_LB 2 // Left Back
47 + #define MOTOR_RB 3 // Right Back
48 +
49 + // Extra motors (set to -1 to skip)
50 + #define EXTRA_MOTOR_A -1
51 + #define EXTRA_MOTOR_B -1
52 +
53 + // Servos (set to -1 to skip)
54 + #define SERVO_0 0
55 + #define SERVO_1 1
56 + #define SERVO_2 2
57 + #define SERVO_3 3
58 +
59 + // Analog sensors (set to -1 to skip)
60 + #define ANALOG_0 0
61 + #define ANALOG_1 1
62 + #define ANALOG_2 2
63 + #define ANALOG_3 -1
64 +
65 + // Digital sensors (set to -1 to skip)
66 + #define DIGITAL_0 0
67 + #define DIGITAL_1 1
68 + #define DIGITAL_2 -1
69 + #define DIGITAL_3 -1
70 +
71 + // Speed for motor tests — keep low so robot doesn't travel far
72 + #define TEST_SPEED 60
73 + #define TEST_TIME 1200 // ms per direction
74 +
75 + // ============================================================
76 + // --- HELPERS ---
77 + // ============================================================
78 +
79 + void wait_for_a() {
80 + printf(" [ Press A button to continue ]\n");
81 + while (!a_button()) { msleep(50); }
82 + msleep(400);
83 + }
84 +
85 + void section_header(const char* title) {
86 + printf("\n=========================\n");
87 + printf(" %s\n", title);
88 + printf("=========================\n");
89 + }
90 +
91 + void set_drive(int lf, int rf, int lb, int rb) {
92 + motor(MOTOR_LF, lf);
93 + motor(MOTOR_RF, rf);
94 + motor(MOTOR_LB, lb);
95 + motor(MOTOR_RB, rb);
96 + }
97 +
98 + // ============================================================
99 + // --- TEST FUNCTIONS ---
100 + // ============================================================
101 +
102 + void test_single_motor(int port, const char* name) {
103 + if (port < 0) return;
104 +
105 + printf("\nMotor: %s (port %d)\n", name, port);
106 + printf(" EXPECTED: Only this wheel spins.\n");
107 + wait_for_a();
108 +
109 + printf(" Forward (%d)...\n", TEST_SPEED);
110 + printf(" EXPECTED: Wheel spins forward.\n");
111 + motor(port, TEST_SPEED);
112 + msleep(TEST_TIME);
113 + ao();
114 + msleep(300);
115 +
116 + printf(" Backward (-%d)...\n", TEST_SPEED);
117 + printf(" EXPECTED: Wheel spins backward.\n");
118 + motor(port, -TEST_SPEED);
119 + msleep(TEST_TIME);
120 + ao();
121 + msleep(300);
122 +
123 + printf(" Done with %s.\n", name);
124 + }
125 +
126 + void test_drive_directions() {
127 + int s = TEST_SPEED;
128 +
129 + printf("\nForward\n");
130 + printf(" EXPECTED: Robot moves straight forward.\n");
131 + wait_for_a();
132 + set_drive(s, s, s, s);
133 + msleep(TEST_TIME);
134 + ao(); msleep(500);
135 +
136 + printf("\nBackward\n");
137 + printf(" EXPECTED: Robot moves straight backward.\n");
138 + wait_for_a();
139 + set_drive(-s, -s, -s, -s);
140 + msleep(TEST_TIME);
141 + ao(); msleep(500);
142 +
143 + printf("\nStrafe Right\n");
144 + printf(" EXPECTED: Robot slides right with NO rotation.\n");
145 + printf(" If it spins, a motor direction is wrong - note which ones.\n");
146 + wait_for_a();
147 + set_drive(s, -s, -s, s);
148 + msleep(TEST_TIME);
149 + ao(); msleep(500);
150 +
151 + printf("\nStrafe Left\n");
152 + printf(" EXPECTED: Robot slides left with NO rotation.\n");
153 + wait_for_a();
154 + set_drive(-s, s, s, -s);
155 + msleep(TEST_TIME);
156 + ao(); msleep(500);
157 +
158 + printf("\nRotate Right\n");
159 + printf(" EXPECTED: Robot spins clockwise in place.\n");
160 + wait_for_a();
161 + set_drive(s, -s, s, -s);
162 + msleep(TEST_TIME);
163 + ao(); msleep(500);
164 +
165 + printf("\nRotate Left\n");
166 + printf(" EXPECTED: Robot spins counter-clockwise in place.\n");
167 + wait_for_a();
168 + set_drive(-s, s, -s, s);
169 + msleep(TEST_TIME);
170 + ao(); msleep(500);
171 + }
172 +
173 + void test_servo(int port, const char* name) {
174 + if (port < 0) return;
175 +
176 + printf("\nServo: %s (port %d)\n", name, port);
177 + printf(" EXPECTED: Servo sweeps from one end to the other and back to center.\n");
178 + wait_for_a();
179 +
180 + enable_servo(port);
181 +
182 + printf(" Moving to 0...\n");
183 + set_servo_position(port, 0);
184 + msleep(1500);
185 +
186 + printf(" Moving to 2047...\n");
187 + set_servo_position(port, 2047);
188 + msleep(1500);
189 +
190 + printf(" Moving to center (1024)...\n");
191 + set_servo_position(port, 1024);
192 + msleep(1000);
193 +
194 + disable_servo(port);
195 + printf(" Done with %s.\n", name);
196 + }
197 +
198 + void test_sensors() {
199 + printf("\nAnalog sensor readings (range 0-4095):\n");
200 + printf(" EXPECTED: Values change when you cover or move the sensor.\n");
201 + if (ANALOG_0 >= 0) printf(" Analog port %d: %4d\n", ANALOG_0, analog(ANALOG_0));
202 + if (ANALOG_1 >= 0) printf(" Analog port %d: %4d\n", ANALOG_1, analog(ANALOG_1));
203 + if (ANALOG_2 >= 0) printf(" Analog port %d: %4d\n", ANALOG_2, analog(ANALOG_2));
204 + if (ANALOG_3 >= 0) printf(" Analog port %d: %4d\n", ANALOG_3, analog(ANALOG_3));
205 +
206 + printf("\nDigital sensor readings (0 or 1):\n");
207 + printf(" EXPECTED: Value flips when you press/activate the sensor.\n");
208 + if (DIGITAL_0 >= 0) printf(" Digital port %d: %d\n", DIGITAL_0, digital(DIGITAL_0));
209 + if (DIGITAL_1 >= 0) printf(" Digital port %d: %d\n", DIGITAL_1, digital(DIGITAL_1));
210 + if (DIGITAL_2 >= 0) printf(" Digital port %d: %d\n", DIGITAL_2, digital(DIGITAL_2));
211 + if (DIGITAL_3 >= 0) printf(" Digital port %d: %d\n", DIGITAL_3, digital(DIGITAL_3));
212 +
213 + printf("\nWatching digital sensors for 5 seconds - press them now!\n");
214 + int i;
215 + for (i = 0; i < 50; i++) {
216 + if (DIGITAL_0 >= 0 && digital(DIGITAL_0)) printf(" >> Digital port %d TRIGGERED\n", DIGITAL_0);
217 + if (DIGITAL_1 >= 0 && digital(DIGITAL_1)) printf(" >> Digital port %d TRIGGERED\n", DIGITAL_1);
218 + if (DIGITAL_2 >= 0 && digital(DIGITAL_2)) printf(" >> Digital port %d TRIGGERED\n", DIGITAL_2);
219 + if (DIGITAL_3 >= 0 && digital(DIGITAL_3)) printf(" >> Digital port %d TRIGGERED\n", DIGITAL_3);
220 + msleep(100);
221 + }
222 + }
223 +
224 + // ============================================================
225 + // --- MAIN ---
226 + // ============================================================
227 +
228 + int main() {
229 + enable_servos();
230 +
231 + printf("========================================\n");
232 + printf(" BOTBALL SELF-TEST: Mecanum Robot\n");
233 + printf("========================================\n");
234 + printf("Put the robot on the floor with room\n");
235 + printf("to move in all directions.\n");
236 + printf("Press A button to step through each test.\n");
237 + printf("Check the Console window for output.\n");
238 +
239 + msleep(1000);
240 +
241 + #if TEST_MOTORS
242 + section_header("INDIVIDUAL MOTOR TESTS");
243 + printf("Each wheel tested alone.\n");
244 + printf("Watch which wheel spins - it should match the label.\n");
245 + test_single_motor(MOTOR_LF, "Left Front (port 0)");
246 + test_single_motor(MOTOR_RF, "Right Front (port 1)");
247 + test_single_motor(MOTOR_LB, "Left Back (port 2)");
248 + test_single_motor(MOTOR_RB, "Right Back (port 3)");
249 + if (EXTRA_MOTOR_A >= 0) test_single_motor(EXTRA_MOTOR_A, "Extra Motor A");
250 + if (EXTRA_MOTOR_B >= 0) test_single_motor(EXTRA_MOTOR_B, "Extra Motor B");
251 +
252 + section_header("DRIVE DIRECTION TESTS");
253 + printf("If strafe produces spinning, a motor direction is wrong.\n");
254 + printf("Use the individual tests above to find which motor.\n");
255 + test_drive_directions();
256 + #endif
257 +
258 + #if TEST_SERVOS
259 + section_header("SERVO TESTS");
260 + test_servo(SERVO_0, "Servo 0");
261 + test_servo(SERVO_1, "Servo 1");
262 + test_servo(SERVO_2, "Servo 2");
263 + test_servo(SERVO_3, "Servo 3");
264 + #endif
265 +
266 + #if TEST_SENSORS
267 + section_header("SENSOR TESTS");
268 + test_sensors();
269 + #endif
270 +
271 + disable_servos();
272 +
273 + printf("\n========================================\n");
274 + printf(" SELF-TEST COMPLETE\n");
275 + printf("\n");
276 + printf(" If everything moved correctly,\n");
277 + printf(" your hardware is ready.\n");
278 + printf("\n");
279 + printf(" Strafe wrong? Check motor directions\n");
280 + printf(" in the student coding guide.\n");
281 + printf(" Fix wiring before fixing in code.\n");
282 + printf("========================================\n");
283 +
284 + ao();
285 + return 0;
286 + }

self_test_standard.c(file created)

@@ -0,0 +1,211 @@
1 + // ============================================================
2 + // SELF-TEST: Standard (Non-Mecanum) Robot
3 + // Run this before every practice and competition to verify
4 + // all hardware is working correctly.
5 + //
6 + // HOW TO USE:
7 + // 1. Update the port #defines below to match your robot
8 + // 2. Set TEST_MOTORS / TEST_SERVOS / TEST_SENSORS to 0
9 + // if you want to skip that section
10 + // 3. Set any unused port to -1 to skip it
11 + // 4. Run the program — press the A button to advance
12 + // between tests so you can watch each component
13 + //
14 + // OUTPUT: Open the Console window in the Wombat software
15 + // to see all printed messages.
16 + // ============================================================
17 +
18 + #include <kipr/wombat.h>
19 +
20 + // ============================================================
21 + // --- WHAT TO TEST (set to 0 to skip a whole section) ---
22 + // ============================================================
23 + #define TEST_MOTORS 1
24 + #define TEST_SERVOS 1
25 + #define TEST_SENSORS 1
26 +
27 + // ============================================================
28 + // --- PORT ASSIGNMENTS ---
29 + // Use -1 if you DON'T have something plugged in.
30 + // Example: only one extra motor? Set EXTRA_MOTOR_B to -1.
31 + // ============================================================
32 +
33 + // Drive motors
34 + #define LEFT_MOTOR 3
35 + #define RIGHT_MOTOR 0
36 +
37 + // Extra motors, e.g. arm motor, pulley (set to -1 to skip)
38 + #define EXTRA_MOTOR_A 1
39 + #define EXTRA_MOTOR_B -1
40 +
41 + // Servos (set to -1 to skip)
42 + #define SERVO_0 0
43 + #define SERVO_1 1
44 + #define SERVO_2 -1
45 + #define SERVO_3 -1
46 +
47 + // Analog sensors (set to -1 to skip)
48 + #define ANALOG_0 0
49 + #define ANALOG_1 1
50 + #define ANALOG_2 2
51 + #define ANALOG_3 -1
52 +
53 + // Digital sensors (set to -1 to skip)
54 + #define DIGITAL_0 0
55 + #define DIGITAL_1 1
56 + #define DIGITAL_2 -1
57 + #define DIGITAL_3 -1
58 +
59 + // Speed for motor tests — keep low so robot doesn't travel far
60 + #define TEST_SPEED 60
61 + #define TEST_TIME 1500 // ms per direction
62 +
63 + // ============================================================
64 + // --- HELPERS ---
65 + // ============================================================
66 +
67 + void wait_for_a() {
68 + printf(" [ Press A button to continue ]\n");
69 + while (!a_button()) { msleep(50); }
70 + msleep(400);
71 + }
72 +
73 + void section_header(const char* title) {
74 + printf("\n=========================\n");
75 + printf(" %s\n", title);
76 + printf("=========================\n");
77 + }
78 +
79 + // ============================================================
80 + // --- TEST FUNCTIONS ---
81 + // ============================================================
82 +
83 + void test_motor(int port, const char* name) {
84 + if (port < 0) return;
85 +
86 + printf("\nMotor: %s (port %d)\n", name, port);
87 + printf(" EXPECTED: Only this motor spins, not the whole robot.\n");
88 + wait_for_a();
89 +
90 + printf(" Forward (%d)...\n", TEST_SPEED);
91 + printf(" EXPECTED: Motor spins forward.\n");
92 + motor(port, TEST_SPEED);
93 + msleep(TEST_TIME);
94 + ao();
95 + msleep(300);
96 +
97 + printf(" Backward (-%d)...\n", TEST_SPEED);
98 + printf(" EXPECTED: Motor spins backward.\n");
99 + motor(port, -TEST_SPEED);
100 + msleep(TEST_TIME);
101 + ao();
102 + msleep(300);
103 +
104 + printf(" Done with %s.\n", name);
105 + }
106 +
107 + void test_servo(int port, const char* name) {
108 + if (port < 0) return;
109 +
110 + printf("\nServo: %s (port %d)\n", name, port);
111 + printf(" EXPECTED: Servo sweeps from one end to the other and back to center.\n");
112 + wait_for_a();
113 +
114 + enable_servo(port);
115 +
116 + printf(" Moving to 0...\n");
117 + set_servo_position(port, 0);
118 + msleep(1500);
119 +
120 + printf(" Moving to 2047...\n");
121 + set_servo_position(port, 2047);
122 + msleep(1500);
123 +
124 + printf(" Moving to center (1024)...\n");
125 + set_servo_position(port, 1024);
126 + msleep(1000);
127 +
128 + disable_servo(port);
129 + printf(" Done with %s.\n", name);
130 + }
131 +
132 + void test_sensors() {
133 + printf("\nAnalog sensor readings (range 0-4095):\n");
134 + printf(" EXPECTED: Values change when you cover or move the sensor.\n");
135 + if (ANALOG_0 >= 0) printf(" Analog port %d: %4d\n", ANALOG_0, analog(ANALOG_0));
136 + if (ANALOG_1 >= 0) printf(" Analog port %d: %4d\n", ANALOG_1, analog(ANALOG_1));
137 + if (ANALOG_2 >= 0) printf(" Analog port %d: %4d\n", ANALOG_2, analog(ANALOG_2));
138 + if (ANALOG_3 >= 0) printf(" Analog port %d: %4d\n", ANALOG_3, analog(ANALOG_3));
139 +
140 + printf("\nDigital sensor readings (0 or 1):\n");
141 + printf(" EXPECTED: Value flips when you press/activate the sensor.\n");
142 + if (DIGITAL_0 >= 0) printf(" Digital port %d: %d\n", DIGITAL_0, digital(DIGITAL_0));
143 + if (DIGITAL_1 >= 0) printf(" Digital port %d: %d\n", DIGITAL_1, digital(DIGITAL_1));
144 + if (DIGITAL_2 >= 0) printf(" Digital port %d: %d\n", DIGITAL_2, digital(DIGITAL_2));
145 + if (DIGITAL_3 >= 0) printf(" Digital port %d: %d\n", DIGITAL_3, digital(DIGITAL_3));
146 +
147 + printf("\nWatching digital sensors for 5 seconds - press them now!\n");
148 + int i;
149 + for (i = 0; i < 50; i++) {
150 + if (DIGITAL_0 >= 0 && digital(DIGITAL_0)) printf(" >> Digital port %d TRIGGERED\n", DIGITAL_0);
151 + if (DIGITAL_1 >= 0 && digital(DIGITAL_1)) printf(" >> Digital port %d TRIGGERED\n", DIGITAL_1);
152 + if (DIGITAL_2 >= 0 && digital(DIGITAL_2)) printf(" >> Digital port %d TRIGGERED\n", DIGITAL_2);
153 + if (DIGITAL_3 >= 0 && digital(DIGITAL_3)) printf(" >> Digital port %d TRIGGERED\n", DIGITAL_3);
154 + msleep(100);
155 + }
156 + }
157 +
158 + // ============================================================
159 + // --- MAIN ---
160 + // ============================================================
161 +
162 + int main() {
163 + enable_servos();
164 +
165 + printf("========================================\n");
166 + printf(" BOTBALL SELF-TEST: Standard Robot\n");
167 + printf("========================================\n");
168 + printf("Keep the robot clear of obstacles.\n");
169 + printf("Watch each component as it's tested.\n");
170 + printf("Press A button to step through each test.\n");
171 + printf("Check the Console window for output.\n");
172 +
173 + msleep(1000);
174 +
175 + #if TEST_MOTORS
176 + section_header("MOTOR TESTS");
177 + printf("Each motor tested individually.\n");
178 + test_motor(LEFT_MOTOR, "Left Motor");
179 + test_motor(RIGHT_MOTOR, "Right Motor");
180 + test_motor(EXTRA_MOTOR_A, "Extra Motor A");
181 + test_motor(EXTRA_MOTOR_B, "Extra Motor B");
182 + #endif
183 +
184 + #if TEST_SERVOS
185 + section_header("SERVO TESTS");
186 + test_servo(SERVO_0, "Servo 0");
187 + test_servo(SERVO_1, "Servo 1");
188 + test_servo(SERVO_2, "Servo 2");
189 + test_servo(SERVO_3, "Servo 3");
190 + #endif
191 +
192 + #if TEST_SENSORS
193 + section_header("SENSOR TESTS");
194 + test_sensors();
195 + #endif
196 +
197 + disable_servos();
198 +
199 + printf("\n========================================\n");
200 + printf(" SELF-TEST COMPLETE\n");
201 + printf("\n");
202 + printf(" If everything moved correctly,\n");
203 + printf(" your hardware is ready.\n");
204 + printf("\n");
205 + printf(" Something wrong? Check the cable\n");
206 + printf(" and port number for that component.\n");
207 + printf("========================================\n");
208 +
209 + ao();
210 + return 0;
211 + }

student_coding_guide.md(file created)

@@ -0,0 +1,186 @@
1 + # Coding Guide for Botball
2 +
3 + ## Start Every File the Same Way
4 +
5 + 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.
6 +
7 + ```c
8 + #include <kipr/wombat.h>
9 +
10 + // --- PORT ASSIGNMENTS ---
11 + #define LEFT_MOTOR 0
12 + #define RIGHT_MOTOR 3
13 + #define ARM_SERVO 3
14 + #define CLAW_SERVO 2
15 + #define LINE_SENSOR 0
16 + #define BUMP_SENSOR 1
17 +
18 + // --- THRESHOLDS ---
19 + #define BLACK_VALUE 3000
20 + #define LINE_THRESHOLD 2000
21 + ```
22 +
23 + Then your code reads like plain English: `motor(LEFT_MOTOR, 100)` is much clearer than `motor(0, 100)`.
24 +
25 + ---
26 +
27 + ## Break Your Route into Functions
28 +
29 + 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.
30 +
31 + ```c
32 + void drive_to_wall() { ... }
33 + void grab_object() { ... }
34 + void return_to_start() { ... }
35 +
36 + int main() {
37 + wait_for_light(0);
38 + shut_down_in(119);
39 +
40 + drive_to_wall();
41 + grab_object();
42 + return_to_start();
43 +
44 + ao();
45 + return 0;
46 + }
47 + ```
48 +
49 + Benefits: easier to test one section at a time, easier to fix bugs, easier to read.
50 +
51 + ---
52 +
53 + ## Always Stop Your Motors
54 +
55 + Every time you start motors, there needs to be a clear place where they stop. Forgetting `ao()` is one of the most common bugs.
56 +
57 + ```c
58 + // Good: clear start and stop
59 + motor(LEFT_MOTOR, 80);
60 + motor(RIGHT_MOTOR, 80);
61 + msleep(1000);
62 + ao(); // <-- don't forget this
63 + msleep(200); // brief pause after stopping
64 + ```
65 +
66 + ---
67 +
68 + ## Two Ways to Control Distance
69 +
70 + **Time-based:** Simple, but affected by battery level and surface friction. Good for rough positioning.
71 + ```c
72 + motor(LEFT_MOTOR, 80);
73 + motor(RIGHT_MOTOR, 80);
74 + msleep(1500); // go for 1.5 seconds
75 + ao();
76 + ```
77 +
78 + **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.
79 +
80 + ```c
81 + cmpc(LEFT_MOTOR); // reset counter to 0
82 + while (gmpc(LEFT_MOTOR) < 5000) {
83 + motor(LEFT_MOTOR, 80);
84 + motor(RIGHT_MOTOR, 80);
85 + msleep(10); // always include a short sleep in loops like this —
86 + // without it the loop runs so fast it can crash the Wombat
87 + }
88 + ao();
89 + ```
90 +
91 + When precision matters (like lining up to grab something), use encoders. When you just need to get somewhere approximately, time-based is fine.
92 +
93 + ---
94 +
95 + ## Sensor-Based Stopping
96 +
97 + Using a sensor to stop is more reliable than guessing how long something takes.
98 +
99 + ```c
100 + // Stop when you hit a wall
101 + while (digital(BUMP_SENSOR) == 0) {
102 + motor(LEFT_MOTOR, 60);
103 + motor(RIGHT_MOTOR, 60);
104 + msleep(10);
105 + }
106 + ao();
107 +
108 + // Stop when you reach a black line
109 + while (analog(LINE_SENSOR) < BLACK_VALUE) {
110 + motor(LEFT_MOTOR, 60);
111 + motor(RIGHT_MOTOR, 60);
112 + msleep(10);
113 + }
114 + ao();
115 + ```
116 +
117 + If a sensor isn't working, a time-based fallback is okay for competition, but plan to fix it.
118 +
119 + ---
120 +
121 + ## Debug with printf
122 +
123 + `printf` is your best debugging tool. Print sensor values while the robot is running to see what it's actually experiencing.
124 +
125 + ```c
126 + // Print once each loop iteration - see what the sensor reads
127 + while (1) {
128 + printf("line sensor: %d\n", analog(LINE_SENSOR));
129 + msleep(100);
130 + }
131 + ```
132 +
133 + 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.
134 +
135 + Remove or comment out excessive `printf` calls before competition — they slow the program down.
136 +
137 + ---
138 +
139 + ## Servos: Enable, Move, and Be Patient
140 +
141 + Always call `enable_servos()` before using servos, and `disable_servos()` when done. After setting a position, give the servo time to physically reach it.
142 +
143 + ```c
144 + enable_servos();
145 +
146 + set_servo_position(ARM_SERVO, 1000); // move arm
147 + msleep(1000); // wait for it to get there
148 +
149 + set_servo_position(CLAW_SERVO, 2047); // close claw
150 + msleep(500);
151 +
152 + disable_servos();
153 + ```
154 +
155 + 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.
156 +
157 + ---
158 +
159 + ## Mecanum Wheels: Motor Direction Reference
160 +
161 + | Movement | Motor 0 (LF) | Motor 1 (RF) | Motor 2 (LB) | Motor 3 (RB) |
162 + |---------------|:---:|:---:|:---:|:---:|
163 + | Forward | + | + | + | + |
164 + | Backward | - | - | - | - |
165 + | Strafe Right | + | - | - | + |
166 + | Strafe Left | - | + | + | - |
167 + | Rotate Right | + | - | + | - |
168 + | Rotate Left | - | + | - | + |
169 +
170 + 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.
171 +
172 + ---
173 +
174 + ## Common Mistakes
175 +
176 + **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.
177 +
178 + **Hardcoding port numbers.** Use `#define` constants. `motor(0, 100)` is hard to read and hard to fix when something changes.
179 +
180 + **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.
181 +
182 + **Trusting timing over sensors.** If the robot does the same task multiple times and the timing varies, use a sensor instead.
183 +
184 + **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.
185 +
186 + **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.

student_troubleshooting_guide.md(file created)

@@ -0,0 +1,151 @@
1 + # Troubleshooting Guide
2 +
3 + When something isn't working, don't just start changing code. Observe first, then figure out what's actually wrong.
4 +
5 + ---
6 +
7 + ## Step 1: Run the Self-Test
8 +
9 + Before assuming it's a code problem, run `self_test.c`. It will test each motor and servo one at a time. This rules out hardware problems quickly.
10 +
11 + If a motor or servo fails the self-test:
12 + - Check the cable connection at both ends
13 + - Try swapping the cable
14 + - Check the port number in the test file matches where it's plugged in
15 +
16 + ---
17 +
18 + ## Fix Hardware Before Code
19 +
20 + If something moves the wrong direction, fix the wiring first before changing code. Hardware fixes work everywhere. Code fixes only work in one program, and future code becomes confusing to write.
21 +
22 + ---
23 +
24 + ## My Robot Won't Move At All
25 +
26 + Work through this in order:
27 +
28 + 1. **Are the motors getting power?** Check that the Wombat is on and the battery has charge.
29 + 2. **Does the self-test work?** If a motor works in the self-test but not in your code, the bug is in your code.
30 + 3. **Are you calling `ao()` before you move?** If there's an `ao()` right before your motor call, that's fine. But if you have `ao()` *inside* a loop where you want movement, that's stopping the motor every iteration.
31 + 4. **Are you using the right port number?** Compare your `#define` constants to the physical port labels on the Wombat.
32 +
33 + ---
34 +
35 + ## Robot Curves Instead of Driving Straight
36 +
37 + If your robot drives forward but slowly curves left or right, this is very common and almost never a wiring problem.
38 +
39 + Possible causes: one motor is slightly stronger than the other (very common), uneven wheel friction, low battery, or uneven weight distribution.
40 +
41 + Fix it by adjusting motor speeds slightly until the robot tracks straight:
42 +
43 + ```c
44 + motor(LEFT_MOTOR, 80);
45 + motor(RIGHT_MOTOR, 75); // reduce the faster side in small steps (3-10 points)
46 + ```
47 +
48 + Test, watch, adjust, repeat. Once it drives straight, write down the values.
49 +
50 + ## Robot Spins in Place Instead of Moving Forward
51 +
52 + If the robot spins rather than driving forward, one motor is running backwards. This is a direction problem, not a speed problem.
53 +
54 + **Fix this by swapping the two wires on that motor** — don't fix it in code if you can avoid it. Code fixes for direction make future programs confusing.
55 +
56 + If wiring can't be changed, you can negate the speed in code:
57 + ```c
58 + // If LEFT_MOTOR spins wrong, negate its value:
59 + motor(LEFT_MOTOR, -80); // was 80
60 + motor(RIGHT_MOTOR, 80);
61 + ```
62 +
63 + ## Mecanum Bot Spins Instead of Strafing
64 +
65 + One or more wheels is going the wrong direction. Run the self-test to check each motor individually, then compare against the motor direction table in the coding guide. Fix in wiring if possible.
66 +
67 + ---
68 +
69 + ## Robot Drifts to One Side
70 +
71 + This is almost always a hardware issue, not a code issue. Check:
72 +
73 + - **Are both drive wheels touching the ground equally?** An uneven chassis will cause drift.
74 + - **Are the wheels on tight?** A loose wheel slips.
75 + - **Is one motor slightly slower than the other?** You can compensate in code by lowering the faster motor's speed slightly (e.g., `motor(LEFT_MOTOR, 95)` instead of 100) until it drives straight. Use `printf` to print encoder values of both motors while driving — they should be roughly equal.
76 +
77 + ---
78 +
79 + ## Debug with printf — Where Does the Output Go?
80 +
81 + Open the Console window in the Wombat software. That's where `printf` messages appear. If you don't see the console, look for a "Console" or "Output" tab in the interface.
82 +
83 + ---
84 +
85 + ## Sensor Isn't Reading What I Expect
86 +
87 + **First: print the actual value.** Don't guess. Put this in a loop and watch the output:
88 + ```c
89 + while(1) {
90 + printf("sensor value: %d\n", analog(0));
91 + msleep(100);
92 + }
93 + ```
94 +
95 + Move the robot/sensor to different positions and see what values you get. Set your threshold based on actual readings, not guesses.
96 +
97 + **Digital sensor always reads 0 or always reads 1:**
98 + - Check the cable connection
99 + - Make sure you're reading the right port number
100 + - Check that the sensor isn't physically stuck
101 +
102 + **Analog sensor reads 0:**
103 + - Usually a disconnected or broken cable
104 + - Try a different port and update the `#define`
105 +
106 + **Line sensor doesn't detect black:**
107 + - The sensor may be too far from the surface. It should be close but not dragging.
108 + - Check what value it reads on white vs. black. Your `#define BLACK_VALUE` threshold should be somewhere between the two.
109 + - Lighting in the competition venue may be different from where you practiced. Re-check thresholds on the day of competition if possible.
110 +
111 + ---
112 +
113 + ## Robot Stops Too Early or Too Late
114 +
115 + **Time-based movement:** `msleep` timing depends on battery charge and floor friction. A lower battery makes the robot slower, so it travels less distance in the same time. If you're using time-based movement for anything precise, consider switching to encoder-based.
116 +
117 + **Encoder-based movement:** Print the encoder value at the moment it stops to make sure it's reaching the target. If it stops too soon, the target tick count is too low. Add `printf("ticks: %d\n", gmpc(0))` inside your loop.
118 +
119 + **Sensor-based stopping:** If the robot doesn't stop at a line, the threshold is probably wrong. Print sensor values and adjust. If the robot stops immediately, the sensor is already reading above the threshold before it starts moving — check your starting position.
120 +
121 + ---
122 +
123 + ## Arm / Claw Isn't Moving
124 +
125 + 1. Did you call `enable_servos()` before `set_servo_position()`?
126 + 2. Is the port number correct?
127 + 3. Are you giving it enough time to move? `set_servo_position` tells the servo where to go, but `msleep(1000)` gives it time to actually get there.
128 + 4. Run the self-test — does the servo work at all? If not, check the cable.
129 + 5. Is the servo stalled against something mechanical? A servo fighting against a physical obstruction will hum, get hot, and eventually stop working.
130 +
131 + ---
132 +
133 + ## Code Compiles But Crashes or Freezes
134 +
135 + **Infinite loop:** You probably have a `while` loop with a condition that never becomes false. Add a `printf` inside the loop to confirm it's actually running. Ask: what would need to change for the loop to end? Is that thing actually changing?
136 +
137 + **Robot freezes partway through the route:** Add `printf("section X starting\n")` at the beginning of each function. This tells you exactly where execution stopped.
138 +
139 + **Timing out:** If your route takes more than 119 seconds, `shut_down_in(119)` will cut power to the motors. If the robot stops unexpectedly near the end of a long run, this might be why.
140 +
141 + ---
142 +
143 + ## Competition Day Problems
144 +
145 + **The route worked in practice but fails at competition:**
146 + - Different lighting → re-check sensor thresholds
147 + - Different floor surface → re-check line sensor sensitivity and timing
148 + - Battery not fully charged → movements will be slower than expected
149 +
150 + **Robot starts before the light:**
151 + - `wait_for_light()` can be triggered by ambient light changes. If the venue is bright, it may fire early. Test `wait_for_light()` in the actual competition lighting before your run.
Newer Older