diff options
-rw-r--r-- | .clang-format | 5 | ||||
-rw-r--r-- | readme.md | 24 | ||||
-rw-r--r-- | robot/calibration.c | 1 | ||||
-rw-r--r-- | robot/calibration.h | 9 | ||||
-rw-r--r-- | robot/consts.h | 33 | ||||
-rw-r--r-- | robot/errcatch.c | 7 | ||||
-rw-r--r-- | robot/errcatch.h | 14 | ||||
-rw-r--r-- | robot/grid.c | 1 | ||||
-rw-r--r-- | robot/grid.h | 8 | ||||
-rw-r--r-- | robot/halt.c | 5 | ||||
-rw-r--r-- | robot/halt.h | 8 | ||||
-rw-r--r-- | robot/hypervisor.c | 19 | ||||
-rw-r--r-- | robot/hypervisor.h | 8 | ||||
-rw-r--r-- | robot/io.c | 3 | ||||
-rw-r--r-- | robot/io.h | 4 | ||||
-rw-r--r-- | robot/main.c | 34 | ||||
-rw-r--r-- | robot/main.h | 4 | ||||
-rw-r--r-- | robot/makefile | 6 | ||||
-rw-r--r-- | robot/maze.c | 1 | ||||
-rw-r--r-- | robot/maze.h | 8 | ||||
-rw-r--r-- | robot/modes.c | 6 | ||||
-rw-r--r-- | robot/modes.h | 10 | ||||
-rw-r--r-- | robot/readme.md | 223 | ||||
-rw-r--r-- | robot/sercomm.c | 3 | ||||
-rw-r--r-- | robot/sercomm.h | 9 | ||||
-rw-r--r-- | robot/setup.c | 21 | ||||
-rw-r--r-- | robot/setup.h | 11 |
27 files changed, 431 insertions, 54 deletions
diff --git a/.clang-format b/.clang-format index c7d6b0a..2f7e218 100644 --- a/.clang-format +++ b/.clang-format @@ -1,14 +1,17 @@ --- AccessModifierOffset: 0 +AlignConsecutiveAssignments: true +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true BasedOnStyle: LLVM BreakBeforeBraces: Attach ColumnLimit: 100 +IndentCaseLabels: true IndentWidth: '4' Language: Cpp Standard: Cpp11 TabWidth: '4' UseTab: Always -IndentCaseLabels: true ... # vim: ft=yaml @@ -16,7 +16,9 @@ gebruikte externe libraries: ## samenvatting werking -Globaal gezien draait de robot altijd in een van twee 'standen'. De eerste +hoop onder constructie + +~Globaal gezien draait de robot altijd in een van twee 'standen'. De eerste stand is voor het doolhof-gedeelte van de kaart, en de tweede is voor het warenhuis-gedeelte. Tijdens de assessment kan het zijn dat de robot opgetild wordt en ergens anders wordt neergezet in het doolhof gedeelte, en hier moet de @@ -25,9 +27,9 @@ de linkerhandregel gebruikt, zodat de robot altijd een uitgang van het doolhof kan vinden, zonder dat de robot zijn eigen positie binnen het doolhof hoeft te weten, of überhaupt bewust hoeft te zijn van de lay-out van het doolhof zelf. De overgang tussen het doolhof en het warenhuis wordt aangegeven met een soort -zebrapad die dezelfde breedte als de rest van de lijnen heeft. Vooraf wordt via -de client aangegeven aan de robot hoe groot het warenhuis is, en waar de in- en -uitgangen van het warenhuis zitten, zodat de robot zelfstandig naar het +zebrapad die dezelfde breedte als de rest van de lijnen heeft.~ Vooraf wordt +via de client aangegeven aan de robot hoe groot het warenhuis is, en waar de +in- en uitgangen van het warenhuis zitten, zodat de robot zelfstandig naar het afleverpunt en het oplaadstation kan rijden zodra alle bestellingen opgehaald zijn. De volgende specificaties moeten nog exact afgesproken worden voordat er een kaart gemaakt kan worden: @@ -42,20 +44,6 @@ warenhuis-gedeelte. ## te bespreken -- Consequent snake case gebruiken inplaats van camel case -- Hoe wordt de controle over de robot 'overhandigd' tussen verschillende - standen? -- Hoe weet de robot via welke in-/uitgang hij het warenhuis in/uit rijdt? - (barcode-scanner implementeren?) -- Globale status met alle sensor data en andere diagnostische info in een - struct zetten en toeganklijk maken vanuit aansturingsstanden? -- Middleware maken zodat er een soort pseudo-supervisor draait die het - overschakelen tussen standen kan beheren, en alle sensordata update in de - globale status struct? -- Misschien een globaal software diagram maken? -- Is het slim om de test stand voor de natte vloer (spinnen) ook een losse - 'stand' te maken? - - Noodstop ook een stand maken? - Welke software wordt er gebruikt om de kaart te maken? (moet met exacte afstanden kunnen werken, lieft in centimeters; als het kan ook fijn om in samen te werken) diff --git a/robot/calibration.c b/robot/calibration.c new file mode 100644 index 0000000..7788532 --- /dev/null +++ b/robot/calibration.c @@ -0,0 +1 @@ +#include "calibration.h" diff --git a/robot/calibration.h b/robot/calibration.h new file mode 100644 index 0000000..5c1af38 --- /dev/null +++ b/robot/calibration.h @@ -0,0 +1,9 @@ +#pragma once + +/** + * calibration mode + * + * turns robot on its own axis 360 degress, and aligns the front sensors with + * the line if found, else triggers halt mode (emergency) + */ +void w2_mode_calb(); diff --git a/robot/consts.h b/robot/consts.h new file mode 100644 index 0000000..6530528 --- /dev/null +++ b/robot/consts.h @@ -0,0 +1,33 @@ +#pragma once + +#ifndef BUILD_STR +// should be defined with -DBUILD_STR in makefile +#define BUILD_STR ("????????") +#endif + +#define W2_MAX_MODULE_CYCLE_MS (20) +#define W2_SERIAL_BAUD (9600) + +#define W2_ERR_TYPE_CRIT (0b00 << 6) +#define W2_ERR_TYPE_WARN (0b01 << 6) +#define W2_ERR_TYPE_INFO (0b10 << 6) +#define W2_ERR_TYPE_VERB (0b11 << 6) + +/** + * enum storing all error codes + * + * error codes are between 0-63 because the two most significant bits are + * reserved for error type checking + */ +enum w2_e_errorcodes { + // critical error codes + W2_ERR_CONN_LOST = 0x00 | W2_ERR_TYPE_CRIT, + W2_ERR_COM_UNAVAILABLE = 0x01 | W2_ERR_TYPE_CRIT, // client-only + W2_ERR_LINE_LOST = 0x02 | W2_ERR_TYPE_CRIT, + W2_ERR_OBSTACLE_STUCK = 0x03 | W2_ERR_TYPE_CRIT, + + // warnings + W2_ERR_BATTERY_LOW = 0x00 | W2_ERR_TYPE_WARN, + W2_ERR_OBSTACLE_DETECTED = 0x01 | W2_ERR_TYPE_WARN, + W2_ERR_CYCLE_EXPIRED = 0x02 | W2_ERR_TYPE_WARN, +}; diff --git a/robot/errcatch.c b/robot/errcatch.c new file mode 100644 index 0000000..5b42bb4 --- /dev/null +++ b/robot/errcatch.c @@ -0,0 +1,7 @@ +#include "errcatch.h" + +void w2_errcatch_main() {} + +void w2_errcatch_throw_msg(enum w2_e_errorcodes code, uint16_t length, const char *message) {} + +void w2_errcatch_throw(enum w2_e_errorcodes code) { w2_errcatch_throw_msg(code, 0, ""); } diff --git a/robot/errcatch.h b/robot/errcatch.h new file mode 100644 index 0000000..48e2a75 --- /dev/null +++ b/robot/errcatch.h @@ -0,0 +1,14 @@ +#pragma once + +#include <stdint.h> + +#include "consts.h" + +/** error-handler module main */ +void w2_errcatch_main(); + +/** append error to error buffer */ +void w2_errcatch_throw(enum w2_e_errorcodes code); + +/** append error to error buffer (with debug message) */ +void w2_errcatch_throw_msg(enum w2_e_errorcodes code, uint16_t length, const char *message); diff --git a/robot/grid.c b/robot/grid.c new file mode 100644 index 0000000..0c83272 --- /dev/null +++ b/robot/grid.c @@ -0,0 +1 @@ +#include "grid.h" diff --git a/robot/grid.h b/robot/grid.h new file mode 100644 index 0000000..fcf9100 --- /dev/null +++ b/robot/grid.h @@ -0,0 +1,8 @@ +#pragma once + +/** + * warehouse mode + * + * processes orders from the order buffer + */ +void w2_mode_grid(); diff --git a/robot/halt.c b/robot/halt.c new file mode 100644 index 0000000..2f159f0 --- /dev/null +++ b/robot/halt.c @@ -0,0 +1,5 @@ +#include <stdbool.h> + +#include "halt.h" + +void w2_mode_halt() { return; } diff --git a/robot/halt.h b/robot/halt.h new file mode 100644 index 0000000..d92905e --- /dev/null +++ b/robot/halt.h @@ -0,0 +1,8 @@ +#pragma once + +/** + * halt (emergency) mode + * + * stops all execution until emergency status is manually cleared by the user + */ +void w2_mode_halt(); diff --git a/robot/hypervisor.c b/robot/hypervisor.c new file mode 100644 index 0000000..381d9af --- /dev/null +++ b/robot/hypervisor.c @@ -0,0 +1,19 @@ +#include <pololu/orangutan.h> + +#include "consts.h" +#include "errcatch.h" +#include "hypervisor.h" +#include "io.h" +#include "modes.h" +#include "sercomm.h" + +void w2_hypervisor_main() { + w2_sercomm_main(); + w2_errcatch_main(); + w2_io_main(); + + time_reset(); + w2_modes_main(); + unsigned long elapsed_ms = get_ms(); + if (elapsed_ms > W2_MAX_MODULE_CYCLE_MS) w2_errcatch_throw(W2_ERR_CYCLE_EXPIRED); +} diff --git a/robot/hypervisor.h b/robot/hypervisor.h new file mode 100644 index 0000000..0e73259 --- /dev/null +++ b/robot/hypervisor.h @@ -0,0 +1,8 @@ +#pragma once + +/** + * backbone of all other modules + * + * stores global variables and controls when other modules run + */ +void w2_hypervisor_main(); diff --git a/robot/io.c b/robot/io.c new file mode 100644 index 0000000..4a85458 --- /dev/null +++ b/robot/io.c @@ -0,0 +1,3 @@ +#include "io.h" + +void w2_io_main() {} diff --git a/robot/io.h b/robot/io.h new file mode 100644 index 0000000..14fe0af --- /dev/null +++ b/robot/io.h @@ -0,0 +1,4 @@ +#pragma once + +/** i/o module main */ +void w2_io_main(); diff --git a/robot/main.c b/robot/main.c index 21d0e5c..fbfd38b 100644 --- a/robot/main.c +++ b/robot/main.c @@ -1,34 +1,12 @@ -#include <pololu/orangutan.h> -#include <stdlib.h> +#include "main.h" +#include "hypervisor.h" +#include "setup.h" int main() { - play("L50 c>c"); - serial_set_baud_rate(9600); + w2_setup_main(); - char *buf = malloc(20); - unsigned int counter = 0; - - while (1) { - serial_receive_blocking(buf, 1, 65e3); - - switch (buf[0]) { - case 0x7f: { - counter--; - lcd_goto_xy(counter, 0); - print(" "); - lcd_goto_xy(counter, 0); - break; - } - default: { - print(&buf[0]); - counter++; - if (counter > 20) { - counter = 0; - lcd_goto_xy(0, 0); - } - } - } - } + for (;;) w2_hypervisor_main(); + // satisfy compiler return 0; } diff --git a/robot/main.h b/robot/main.h new file mode 100644 index 0000000..5b0a1b2 --- /dev/null +++ b/robot/main.h @@ -0,0 +1,4 @@ +#pragma once + +/** program entrypoint */ +int main(); diff --git a/robot/makefile b/robot/makefile index d01ad30..8ddcb28 100644 --- a/robot/makefile +++ b/robot/makefile @@ -8,7 +8,7 @@ AVRDUDE_DEVICE ?= m168 CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) $(DEVICE_SPECIFIC_CFLAGS) -Os LDFLAGS=-Wl,-gc-sections -lpololu_$(DEVICE) -Wl,-relax -PORT ?= /dev/ttyACM1 +PORT ?= /dev/ttyACM0 SOURCES := $(wildcard *.c) HEADERS := $(wildcard *.h) @@ -18,6 +18,9 @@ AVRDUDE=avrdude CC=avr-gcc OBJ2HEX=avr-objcopy +BUILD_STR=$(shell git update-index -q --refresh; git describe --tags --dirty='*' --broken='x' | cut -c1-20) +CFLAGS += -DBUILD_STR="$(BUILD_STR)" + all: out.hex clean: @@ -31,6 +34,7 @@ a.out: $(OBJECTS) out.hex: a.out $(OBJ2HEX) -R .eeprom -O ihex $< $@ + $(info build $(BUILD_STR) complete) flash: out.hex $(AVRDUDE) -p $(AVRDUDE_DEVICE) -c avrisp2 -P $(PORT) -U flash:w:out.hex diff --git a/robot/maze.c b/robot/maze.c new file mode 100644 index 0000000..a27414f --- /dev/null +++ b/robot/maze.c @@ -0,0 +1 @@ +#include "maze.h" diff --git a/robot/maze.h b/robot/maze.h new file mode 100644 index 0000000..9fbeb8c --- /dev/null +++ b/robot/maze.h @@ -0,0 +1,8 @@ +#pragma once + +/** + * maze mode + * + * finds route out of maze + */ +void w2_mode_maze(); diff --git a/robot/modes.c b/robot/modes.c new file mode 100644 index 0000000..c22875c --- /dev/null +++ b/robot/modes.c @@ -0,0 +1,6 @@ +#include "modes.h" +#include "halt.h" + +void (*g_w2_current_mode)() = &w2_mode_halt; + +void w2_modes_main() { (*g_w2_current_mode)(); } diff --git a/robot/modes.h b/robot/modes.h new file mode 100644 index 0000000..dd34690 --- /dev/null +++ b/robot/modes.h @@ -0,0 +1,10 @@ +#pragma once + +extern void (*g_w2_current_mode)(); + +/** + * mode logic + * + * executes mode in g_w2_current_mode + */ +void w2_modes_main(); diff --git a/robot/readme.md b/robot/readme.md index 5e7efb6..fa5774c 100644 --- a/robot/readme.md +++ b/robot/readme.md @@ -1,10 +1,221 @@ # robot code -dit is de submap voor alle code die op de robot zelf draait +this is the subdirectory for all code that runs on the 3pi robot -## make gedoe +## make + +the makefile in this directory works the same as a regular makefile, with the +exception of the `make flash` command. + +to upload the compiled robot executable, you need to change the com port +specified in the makefile in this directory (line that says `PORT ?= +/dev/ttyACMx`). for windows this should be changed to `PORT ?= COMx`, where x +is the number of the 'programming' com port on the programmer. this will +probably change every time you re-plug the programmer, so you should try every +com port until it uploads successfully. you can find available com ports in +device manager on windows, or by running `ls /dev/ttyACM*` on linux. once the +com port is configured, run `make flash` to upload the executable and +automatically reboot the robot. + +## module hierarchy + +the software is divided into seperate 'modules' for organizational, +maintenance, testing and debugging purposes. the sizes of the blocks in the +following diagram are a bit misleading, as some of these blocks are mostly +organizational and form more of a software 'skeleton', while the 'maze' and +'warehouse' modules provide the majority of the actual control logic. + +``` +┌──────────────────────────────────────────────────────────────────────┐ +│ "Hypervisor" │ +└────────┬──────────────────┬──────────────────┬────────────────┬──────┘ +┌────────┴───────┐┌─────────┴────────┐┌────────┴─────────┐┌─────┴──────┐ +│ Error handling ││ I/O Read & Write ││ PC communication ││ Mode logic │ +└────────────────┘└──────────────────┘└──────────────────┘└─────┬──────┘ + ┌──────────┬──────────────┬───────────────┤ + ┌───┴──┐┌──────┴────┐┌────────┴───────┐┌──────┴──────┐ + *modes* -> │ Maze ││ Warehouse ││ Emergency stop ││ Calibration │ + └──────┘└───────────┘└────────────────┘└─────────────┘ +``` + +this diagram roughly describes how different parts of the robot software are +called. most of these modules can talk to each other using functions exposed by +the modules themselves (e.g. the maze module sending an error code to the error +handling module, which then both handles the error and forwards it to pc +communication for logging purposes). here's a quick run-down of all modules and +what they're supposed to do: + +|module |internal name|purpose| +|----------------|-------------|-| +|hypervisor |`hypervisor `|backbone of all other modules; stores global variables; controls when other modules run| +|pc communication|`sercomm `|reads and parses incoming serial data; sends all data in the message buffer| +|error handling |`errcatch `|receives error codes; controls how errors are handled| +|i/o read & write|`io `|reads all inputs to global state; writes all outputs| +|mode logic |`modes `|executes the appropriate module for current mode| +|maze |`mode_maze `|controls robot during maze portion of map; hands off control to warehouse module| +|warehouse |`mode_grid `|controls robot during warehouse portion of map; hands off control to maze module| +|emergency stop |`mode_halt `|stops all execution until emergency mode is reset by software or user| +|calibration |`mode_calb `|find line by turning on own axis if lost| + +## some standards + +this list will probably get updated from time to time: + +- modules shouldn't create any global state variables, they should use `static` + variables instead. +- modules are run cyclically, so they shouldn't take more than + `W2_MAX_MODULE_CYCLE_MS` to execute (this is an arbitrary number, and may be + changed). +- documentation comments should follow the [javadoc-style doxygen + format](https://wiki.scilab.org/Doxygen%20documentation%20Examples) and be + placed in header (.h) files if possible. this only applies to public members + (e.g. no local variables or module-internal code). +- code style is mostly handled by `clang-format` and `clang-tidy`, but you + should still follow these naming conventions (`<angle brackets>` indicate + placeholders): + |symbol type|name|example| + |-|-|-| + |function|`w2_<module>_<name>`|`w2_errcatch_pushcode`; `w2_sercomm_sendraw`| + |variable|`g_w2_<name>`|`g_w2_inputs`; `g_w2_current_mode`| + |constant|`W2_<NAME>`|`W2_MAX_MODULE_CYCLE_MS`; `W2_SERIAL_BAUD`| + |struct|`w2_s_<name>`|`w2_s_input_data`; `w2_s_output_data`| + |enum|`w2_e_<name>`|`w2_e_errorcodes`; `w2_e_serial_commands`| + + this again only applies to public members. local variables should still have + short descriptive names, but shouldn't be prefixed with `w2_*`. +- arbitrary numbers should be aliased to `#define` statements or `enum`s if + part of a series. +- general constants should be placed in `consts.h` + +## todo + +global todo: + +- [ ] add test/simulation mode for wet floor (spinning) +- [ ] add a manual control mode +- [ ] start robot in calibration mode +- [ ] assume robot starts in maze +- [ ] maze-grid transition detection in seperate file (used by grid and maze + mode) +- [ ] clear global timer at start of cycle instead of just for mode selection + module (for last ping time measurement) +- [ ] calibrate (line-detecting) light sensors in setup.c, or manually by + placing the robot and pressing a button + +### hypervisor + +the hypervisor executes all other modules, and measures execution time. it also +provides all other modules with a central place for defining global variables. + +### pc communication + +> this mode can't be implemented until the pc-communication protocol spec is +> finished + +the pc communication module sends messages in a binary format over the serial +connection provided by the wixel modules. this module should also send a 'ping' +command each cycle to check if the connection is still intact. the pc will also +periodically send ping, and various other commands which this module will have +to act on accordingly. + +### error handling + +the error handling module (a) provides functions for other modules to report +errors, and (b) handles errors accordingly. + +- [ ] create an error `struct` that holds: + - [ ] error code + - [ ] message length + - [ ] message contents +- [ ] create a global error ring buffer with an appropriate size that holds + error messages +- [ ] handle errors in the error buffer, referencing the functional + specification for details on what the robot should do to resolve each kind of + error +- [ ] forward error codes to the pc-communication module + +empty function declarations are in place for providing other modules an error +reporting function. + +### i/o read & write + +the i/o module reads all inputs once and writes all outputs once. this keeps +cycle time constant, and makes sure no time is wasted re-reading inputs, or +writing outputs more than once. + +- [ ] create `struct`s for each type of input: + - [ ] button + - [ ] infrared light sensor + - [ ] time-of-flight distance sensor +- [ ] create a single `struct` that holds all input data +- [ ] create a single `struct` that holds output data values for: + - [ ] left motor speed + - [ ] right motor speed + - [ ] red led + - [ ] green led + +extra (requires external interrupt setup): +- [ ] add a `pressed` property to the button struct that turns on if the button + was pressed outside the i/o module execution span +- [ ] add a `press_duration` property to the button struct that measures button + press duration, and that works when the button is pressed outside the i/o + module execution span + +technically the wixel serial channel, programmer debug serial channel, lcd +contents and speaker tones are also considered outputs, but these all take +significant time or memory to update, so these will not be updated using the +cyclic i/o module. + +### modes + +modes is a shim module that forwards execution to the currently selected mode. +the global variable `g_w2_current_mode` holds a pointer to the current mode. +this makes sure only a single mode handler gets ran on every execution cycle. + +### maze + +the maze mode controls the robot when it's in the maze, and sets execution to +grid mode when it detects the maze-grid transition. the solving algorithm will +constantly keep either left or right until (a) the maze-grid transition is +detected, (b) the charging pad is detected, or (c) the starting point is +detected. depending on which location is desired, the robot may continue to +venture through the maze when it finds any of these. exact implementation +details for this mode are yet to be determined. + +### warehouse + +the warehouse mode controls the robot when it's in the warehouse, and sets +execution to maze mode when it detects the maze-grid transition. exact +implementation details for this mode are yet to be determined. + +### emergency stop + +> this mode can't be implemented until the pc-communication protocol spec is +> finished + +the emergency stop mode stops the robot from doing anything until the user +determines it is safe to resume execution. + +- [ ] create a global variable that holds the previous mode +- [ ] create a global variable that holds a 'safe' state (startup/default + value = false) +- [ ] add a condition in the supervisor that switches to the emergency mode if + the 'safe' state variable is false +- [ ] add a condition in the emergency mode handler that switches to the + previous mode if the 'safe' state returns to false + +### calibration + +the calibration sequence is used during the maze mode for re-finding the line +when the robot gets lost. the robot will first try to find the line by itself +when it gets lost. when it does this it will send a warning to the error +buffer. in case it can't find the line anymore, it will go into emergency mode +and send a critical warning. + +- [ ] implement line-finding sequence + - turn 360 degrees (about robot's own axis) + - if a line is found at any point during this rotation, stop turning + - if a full rotation is completed without a found line, enter emergency + mode +- [ ] add a warning for line lost -om de code te uploaden naar de robot moet je de juiste com-poort instellen in -de makefile in deze map (regel waar `PORT ?= /dev/ttyACM0` staat). deze kun je -waarschijnlijk vinden in apparaatbeheer op windows (bijv. `PORT ?= COM4`). -daarna kun je `make flash` uitvoeren om de code te uploaden diff --git a/robot/sercomm.c b/robot/sercomm.c new file mode 100644 index 0000000..a0eed3a --- /dev/null +++ b/robot/sercomm.c @@ -0,0 +1,3 @@ +#include "sercomm.h" + +void w2_sercomm_main() {} diff --git a/robot/sercomm.h b/robot/sercomm.h new file mode 100644 index 0000000..58c79b9 --- /dev/null +++ b/robot/sercomm.h @@ -0,0 +1,9 @@ +#pragma once + +/** + * serial pc-robot communication module + * + * - reads and parses incoming serial data + * - sends all data in the message buffer + */ +void w2_sercomm_main(); diff --git a/robot/setup.c b/robot/setup.c new file mode 100644 index 0000000..10001c7 --- /dev/null +++ b/robot/setup.c @@ -0,0 +1,21 @@ +#include <pololu/orangutan.h> +#include <stdlib.h> + +#include "consts.h" +#include "halt.h" +#include "modes.h" +#include "setup.h" + +void w2_setup_main() { + serial_set_baud_rate(W2_SERIAL_BAUD); + + // reset underside leds + red_led(0); + green_led(0); + + // clear lcd + clear(); + + // indicate startup done + play("L50 c>c"); +} diff --git a/robot/setup.h b/robot/setup.h new file mode 100644 index 0000000..17ac78d --- /dev/null +++ b/robot/setup.h @@ -0,0 +1,11 @@ +#pragma once + +/** + * runs once at startup, plays beep when setup finishes + * + * configures: + * - serial connection (wixel) + * - lcd display + * - underside leds + */ +void w2_setup_main(); |