diff --git a/.gitmodules b/.gitmodules index 802b9ef..0ac4131 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/ryanplusplus/stm8s-header [submodule "lib/stm8-tiny"] path = lib/stm8-tiny - url = https://github/com/ryanplusplus/stm8-tiny + url = https://github.com/ryanplusplus/stm8-tiny diff --git a/.vscode/launch.json b/.vscode/launch.json index aea11e7..5cf34d9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,7 @@ "name": "Test", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/zumo_tests", + "program": "${workspaceFolder}/build/test/zumo_tests", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -44,4 +44,4 @@ "preLaunchTask": "debug-deps-test" } ] -} +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index e973ddb..951c19e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,10 @@ "editor.tabSize": 2, "editor.insertSpaces": true }, - "editor.formatOnSave": true + "editor.formatOnSave": true, + "files.associations": { + "tuning.h": "c", + "tiny_utils.h": "c", + "cstdio": "c" + } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index c12de91..c53d87b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -19,7 +19,7 @@ { "label": "debug-deps-test", "type": "shell", - "command": "make -j8 -f test.mk debug-deps", + "command": "", "presentation": { "echo": true, "reveal": "silent", @@ -30,4 +30,4 @@ } } ] -} +} \ No newline at end of file diff --git a/README.md b/README.md index 2de74e4..7130b45 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ make -f test.mk ## Pinout | STM8 Pin | Zumo Pin | Peripheral | Function | -|----------|----------|------------|------------------------| +| -------- | -------- | ---------- | ---------------------- | | PA3 | N/A | GPIO | Heartbeat LED | | PE1 | SCL | I2C SCL | I2C SCL | | PE2 | SDA | I2C SDA | I2C SDA | @@ -58,6 +58,7 @@ make -f test.mk | PB3 | ? | AN2 | Left distance sensor | | N/A | N/A | AN4 | Center distance sensor | | PB2 | ? | AN3 | Right distance sensor | +| PC7 | 12 | GPIO | Configuration pin | ## Resources - [STM8S/STM8AF Reference Manual](https://www.st.com/resource/en/reference_manual/cd00190271.pdf) diff --git a/src/application/application.c b/src/application/application.c index fa06b75..3b2b81f 100644 --- a/src/application/application.c +++ b/src/application/application.c @@ -13,7 +13,7 @@ void application_init(application_t* self, tiny_timer_group_t* timer_group) { motors_plugin_init(&self->motors_plugin, store); line_sensors_plugin_init(&self->line_sensors_plugin, store, timer_group); - distance_sensors_plugin_init(&self->distance_sensors_plugin, store, timer_group); + // distance_sensors_plugin_init(&self->distance_sensors_plugin, store, timer_group); accelerometer_plugin_init(&self->accelerometer_plugin, store, timer_group); buzzer_plugin_init(&self->buzzer_plugin, store); strategy_plugin_init(&self->strategy_plugin, store, timer_group); diff --git a/src/application/data_model.h b/src/application/data_model.h index e2c4750..2e07852 100644 --- a/src/application/data_model.h +++ b/src/application/data_model.h @@ -17,6 +17,7 @@ #include "direction.h" #include "distance_in_cm.h" #include "buzzer_frequency.h" +#include "i_tiny_adc.h" // clang-format off #define data_model_key_value_pairs(pair) \ @@ -37,6 +38,7 @@ pair(key_center_sensor_distance, distance_in_cm_t) \ pair(key_right_sensor_distance, distance_in_cm_t) \ pair(key_buzzer_frequency, buzzer_frequency_t) \ + pair(key_knob_counts, tiny_adc_counts_t) \ // clang-format on enumerate_ram_key_value_pairs(data_model_key_value_pairs); diff --git a/src/application/meta-sensing/tactic.h b/src/application/meta-sensing/tactic.h index ccd9eca..ecc24c0 100644 --- a/src/application/meta-sensing/tactic.h +++ b/src/application/meta-sensing/tactic.h @@ -10,6 +10,7 @@ enum { tactic_idle, + tactic_init, tactic_seek_clockwise, tactic_seek_counterclockwise, tactic_charge, diff --git a/src/application/plugin/strategy_plugin.c b/src/application/plugin/strategy_plugin.c index 729744a..480a436 100644 --- a/src/application/plugin/strategy_plugin.c +++ b/src/application/plugin/strategy_plugin.c @@ -5,6 +5,7 @@ #include "strategy_plugin.h" #include "data_model.h" +#include "tuning.h" static const strategist_keys_t strategist_keys = { .key_tactic = key_current_tactic, @@ -24,13 +25,6 @@ static const line_detected_keys_t line_detected_keys = { .key_tactic_stopped = key_tactic_stopped }; -static const line_detected_config_t line_detected_config = { - .near_wheel_power = 30, - .far_wheel_power = 100, - .back_up_time = 200, - .turn_time = 300 -}; - static const charge_keys_t charge_keys = { .left_motor = key_left_motor, .right_motor = key_right_motor, @@ -44,14 +38,27 @@ static const seeking_keys_t seeking_keys = { .tactic = key_current_tactic }; +static const spin_on_init_keys_t spin_on_init_keys = { + .left_motor = key_left_motor, + .right_motor = key_right_motor, + .knob_counts = key_knob_counts, + .tactic = key_current_tactic, + .tactic_stopped = key_tactic_stopped +}; + void strategy_plugin_init(strategy_plugin_t* self, i_tiny_key_value_store_t* key_value_store, tiny_timer_group_t* timer_group) { strategist_init(&self->strategist, key_value_store, &strategist_keys); + spin_on_init_init( + &self->spin_on_init, + key_value_store, + &spin_on_init_keys, + timer_group); + line_detected_init( &self->line_detected, key_value_store, &line_detected_keys, - &line_detected_config, timer_group); charge_init(&self->charge, key_value_store, &charge_keys); diff --git a/src/application/plugin/strategy_plugin.h b/src/application/plugin/strategy_plugin.h index d7bf83c..c9e43be 100644 --- a/src/application/plugin/strategy_plugin.h +++ b/src/application/plugin/strategy_plugin.h @@ -9,12 +9,14 @@ #include "line_detected.h" #include "charge.h" #include "seeking.h" +#include "spin_on_init.h" typedef struct { strategist_t strategist; line_detected_t line_detected; charge_t charge; seeking_t seeking; + spin_on_init_t spin_on_init; } strategy_plugin_t; void strategy_plugin_init( diff --git a/src/application/tactics/charge.c b/src/application/tactics/charge.c index a55ee06..b9f3407 100644 --- a/src/application/tactics/charge.c +++ b/src/application/tactics/charge.c @@ -7,13 +7,12 @@ #include "enemy_location.h" #include "tactic.h" #include "tiny_utils.h" +#include "tuning.h" #include "motor_power.h" enum { - near_wheel_power = 30, - far_wheel_power = 100, - reduced_charge = 80, - charge = 100, + reduced_charge = charge_reduced_power, + charge = charge_full_power, toward_the_left = enemy_location_front_left, toward_the_right = enemy_location_front_right }; diff --git a/src/application/tactics/line_detected.c b/src/application/tactics/line_detected.c index 84142ef..6cc210b 100644 --- a/src/application/tactics/line_detected.c +++ b/src/application/tactics/line_detected.c @@ -6,6 +6,7 @@ #include "line_detected.h" #include "tactic.h" #include "tiny_utils.h" +#include "tuning.h" static void stop_running_timer_expired(tiny_timer_group_t* group, void* context) { reinterpret(self, context, line_detected_t*); @@ -39,13 +40,13 @@ static void back_up_timer_expired(tiny_timer_group_t* group, void* context) { motor_power_t left_power; motor_power_t right_power; - if(the_left_line_was_detected(self)) { - left_power = 100; - right_power = -30; + if(self->left_line_was_detected) { + left_power = line_detection_near_wheel_power; + right_power = line_detection_far_wheel_power; } else { - left_power = -30; - right_power = 100; + left_power = line_detection_far_wheel_power; + right_power = line_detection_near_wheel_power; } tiny_key_value_store_write( @@ -61,7 +62,7 @@ static void back_up_timer_expired(tiny_timer_group_t* group, void* context) { tiny_timer_start( self->timer_group, &self->stop_running_timer, - self->config->turn_time, + line_detection_turn_time, stop_running_timer_expired, self); } @@ -75,6 +76,7 @@ static void data_changed(void* context, const void* _args) { if(*tactic == tactic_avoid_line) { motor_power_t power = motor_power_min; + self->left_line_was_detected = the_left_line_was_detected(self); tiny_key_value_store_write( self->key_value_store, self->keys->key_left_motor, @@ -87,7 +89,7 @@ static void data_changed(void* context, const void* _args) { tiny_timer_start( self->timer_group, &self->back_up_timer, - self->config->back_up_time, + line_detection_back_up_time, back_up_timer_expired, self); } @@ -98,12 +100,10 @@ void line_detected_init( line_detected_t* self, i_tiny_key_value_store_t* key_value_store, const line_detected_keys_t* keys, - const line_detected_config_t* config, tiny_timer_group_t* timer_group) { self->key_value_store = key_value_store; self->keys = keys; self->timer_group = timer_group; - self->config = config; tiny_event_subscription_init(&self->on_change_subscription, self, data_changed); tiny_event_subscribe(tiny_key_value_store_on_change(key_value_store), &self->on_change_subscription); diff --git a/src/application/tactics/line_detected.h b/src/application/tactics/line_detected.h index f374902..7d1dce6 100644 --- a/src/application/tactics/line_detected.h +++ b/src/application/tactics/line_detected.h @@ -22,28 +22,20 @@ typedef struct { tiny_key_value_store_key_t key_tactic_stopped; } line_detected_keys_t; -typedef struct { - motor_power_t near_wheel_power; - motor_power_t far_wheel_power; - tiny_timer_ticks_t back_up_time; - tiny_timer_ticks_t turn_time; -} line_detected_config_t; - typedef struct { tiny_event_subscription_t on_change_subscription; i_tiny_key_value_store_t* key_value_store; const line_detected_keys_t* keys; - const line_detected_config_t* config; tiny_timer_t back_up_timer; tiny_timer_t stop_running_timer; tiny_timer_group_t* timer_group; + bool left_line_was_detected; } line_detected_t; void line_detected_init( line_detected_t* self, i_tiny_key_value_store_t* key_value_store, const line_detected_keys_t* keys, - const line_detected_config_t* config, tiny_timer_group_t* timer_group); #endif diff --git a/src/application/tactics/seeking.c b/src/application/tactics/seeking.c index 3ba23f3..528c0e7 100644 --- a/src/application/tactics/seeking.c +++ b/src/application/tactics/seeking.c @@ -6,11 +6,12 @@ #include "seeking.h" #include "tactic.h" #include "tiny_utils.h" +#include "tuning.h" #include "motor_power.h" enum { - near_wheel_power = 30, - far_wheel_power = 100 + near_wheel_power = seeking_near_wheel_power, + far_wheel_power = seeking_far_wheel_power }; static void set_right_motor_to(seeking_t* self, motor_power_t power) { diff --git a/src/application/tactics/spin_on_init.c b/src/application/tactics/spin_on_init.c new file mode 100644 index 0000000..1aa5b6a --- /dev/null +++ b/src/application/tactics/spin_on_init.c @@ -0,0 +1,93 @@ +/*! + * @file + * @brief + */ + +#include "spin_on_init.h" +#include "tactic.h" +#include "tiny_utils.h" +#include "tuning.h" +#include "i_tiny_adc.h" +#include + +enum { + max_counts = 0xFFFF +}; + +static void stop_running_timer_expired(tiny_timer_group_t* group, void* context) { + reinterpret(self, context, spin_on_init_t*); + (void)group; + uint8_t stopped; + tiny_key_value_store_read( + self->key_value_store, + self->keys->tactic_stopped, + &stopped); + + stopped++; + + tiny_key_value_store_write( + self->key_value_store, + self->keys->tactic_stopped, + &stopped); +} + +static tiny_adc_counts_t potentiometer_counts(spin_on_init_t* self) { + tiny_adc_counts_t counts; + tiny_key_value_store_read( + self->key_value_store, + self->keys->knob_counts, + &counts); + return counts; +} + +static void spin(spin_on_init_t* self, bool spin_right) { + motor_power_t left_power = spin_right ? spin_on_init_near_wheel_power : spin_on_init_far_wheel_power; + motor_power_t right_power = spin_right ? spin_on_init_far_wheel_power : spin_on_init_near_wheel_power; + tiny_key_value_store_write( + self->key_value_store, + self->keys->left_motor, + &left_power); + tiny_key_value_store_write( + self->key_value_store, + self->keys->right_motor, + &right_power); +} + +// static tiny_timer_ticks_t counts_to_ticks(tiny_adc_counts_t counts) { +// return (((uint64_t)counts) * (uint64_t)turn_time_360_degree) / (uint64_t)max_counts; +// } + +static void data_changed(void* context, const void* _args) { + reinterpret(self, context, spin_on_init_t*); + reinterpret(args, _args, const tiny_key_value_store_on_change_args_t*); + + if(args->key == self->keys->tactic) { + reinterpret(tactic, args->value, const tactic_t*); + + if(*tactic == tactic_init) { + tiny_adc_counts_t counts = potentiometer_counts(self); + bool spin_right = counts < (0xFFFF / 2); + spin(self, spin_right); + + tiny_timer_start( + self->timer_group, + &self->back_up_timer, + turn_time_360_degree / 3, + stop_running_timer_expired, + self); + } + } +} + +void spin_on_init_init( + spin_on_init_t* self, + i_tiny_key_value_store_t* key_value_store, + const spin_on_init_keys_t* keys, + tiny_timer_group_t* timer_group) { + self->key_value_store = key_value_store; + self->keys = keys; + self->timer_group = timer_group; + + tiny_event_subscription_init(&self->on_change_subscription, self, data_changed); + tiny_event_subscribe(tiny_key_value_store_on_change(key_value_store), &self->on_change_subscription); +} diff --git a/src/application/tactics/spin_on_init.h b/src/application/tactics/spin_on_init.h new file mode 100644 index 0000000..8aedb08 --- /dev/null +++ b/src/application/tactics/spin_on_init.h @@ -0,0 +1,39 @@ +/*! + * @file + * @brief + */ + +#ifndef spin_on_init_h +#define spin_on_init_h + +#include "enemy_location.h" +#include "i_tiny_key_value_store.h" +#include "tiny_event_subscription.h" +#include "tiny_fsm.h" +#include "tiny_timer.h" +#include "motor_power.h" + +typedef struct { + tiny_key_value_store_key_t left_motor; + tiny_key_value_store_key_t right_motor; + tiny_key_value_store_key_t knob_counts; + tiny_key_value_store_key_t tactic; + tiny_key_value_store_key_t tactic_stopped; +} spin_on_init_keys_t; + +typedef struct { + tiny_event_subscription_t on_change_subscription; + i_tiny_key_value_store_t* key_value_store; + const spin_on_init_keys_t* keys; + tiny_timer_t back_up_timer; + tiny_timer_t stop_running_timer; + tiny_timer_group_t* timer_group; +} spin_on_init_t; + +void spin_on_init_init( + spin_on_init_t* self, + i_tiny_key_value_store_t* key_value_store, + const spin_on_init_keys_t* keys, + tiny_timer_group_t* timer_group); + +#endif diff --git a/src/application/tactics/strategist.c b/src/application/tactics/strategist.c index af4cccf..b09fac3 100644 --- a/src/application/tactics/strategist.c +++ b/src/application/tactics/strategist.c @@ -16,15 +16,7 @@ static void change_tactic_to(strategist_t* self, tactic_t tactic) { } static void choose_initial_tactic(strategist_t* self) { - direction_t initial_direction; - tactic_t tactic; - tiny_key_value_store_read( - self->key_value_store, - self->keys->key_initial_direction, - &initial_direction); - - tactic = initial_direction == direction_clockwise ? tactic_seek_clockwise : tactic_seek_counterclockwise; - change_tactic_to(self, tactic); + change_tactic_to(self, tactic_init); } static void choose_seeking_tactic(strategist_t* self) { @@ -42,6 +34,15 @@ static bool the_enemy_is_visible(strategist_t* self) { return location != enemy_location_unknown; } +static bool the_current_tactic_is(strategist_t* self, tactic_t expected) { + tactic_t actual; + tiny_key_value_store_read( + self->key_value_store, + self->keys->key_tactic, + &actual); + return expected == actual; +} + static void data_changed(void* context, const void* _args) { reinterpret(self, context, strategist_t*); reinterpret(args, _args, const tiny_key_value_store_on_change_args_t*); @@ -49,12 +50,14 @@ static void data_changed(void* context, const void* _args) { if(args->key == self->keys->key_enemy_location) { reinterpret(location, args->value, const enemy_location_t*); - if(*location == enemy_location_unknown) { - choose_seeking_tactic(self); - } - else { - change_tactic_to(self, tactic_charge); - self->previous_location = *location; + if(!the_current_tactic_is(self, tactic_avoid_line)) { + if(*location == enemy_location_unknown) { + choose_seeking_tactic(self); + } + else { + change_tactic_to(self, tactic_charge); + self->previous_location = *location; + } } } else if(args->key == self->keys->key_robot_running) { @@ -64,12 +67,21 @@ static void data_changed(void* context, const void* _args) { change_tactic_to(self, tactic_avoid_line); } else if(args->key == self->keys->key_tactic_stopped) { - if(the_enemy_is_visible(self)) { - change_tactic_to(self, tactic_charge); - } - else { - choose_seeking_tactic(self); - } + int8_t power = 0; + // tiny_key_value_store_write( + // self->key_value_store, + // 0, + // &power); + // tiny_key_value_store_write( + // self->key_value_store, + // 1, + // &power); + if(the_enemy_is_visible(self)) { + change_tactic_to(self, tactic_charge); + } + else { + choose_seeking_tactic(self); + } } } diff --git a/src/application/tactics/tuning.h b/src/application/tactics/tuning.h new file mode 100644 index 0000000..5f8787d --- /dev/null +++ b/src/application/tactics/tuning.h @@ -0,0 +1,30 @@ +#ifndef tuning_h +#define tuning_h + +enum { + turn_time_360_degree = 630 +}; + +enum { + line_detection_near_wheel_power = 100, + line_detection_far_wheel_power = -100, + line_detection_back_up_time = 150, + line_detection_turn_time = turn_time_360_degree / 3 +}; + +enum { + spin_on_init_near_wheel_power = 100, + spin_on_init_far_wheel_power = -100, +}; + +enum { + charge_full_power = 100, + charge_reduced_power = 50 +}; + +enum { + seeking_near_wheel_power = 40, + seeking_far_wheel_power = 100 +}; + +#endif \ No newline at end of file diff --git a/src/hardware/plugin/distance_sensors_plugin.c b/src/hardware/plugin/distance_sensors_plugin.c index 694c808..f740da0 100644 --- a/src/hardware/plugin/distance_sensors_plugin.c +++ b/src/hardware/plugin/distance_sensors_plugin.c @@ -27,6 +27,7 @@ static const detect_enemy_keys_t detect_right_keys = { .enemy_detected = key_right_sensor_enemy_detected }; +static volatile tiny_adc_counts_t c; static void read_sensor( distance_sensors_plugin_t* self, tiny_adc_channel_t channel, @@ -34,6 +35,10 @@ static void read_sensor( tiny_adc_counts_t counts = tiny_adc_group_read(self->adc_group, channel); distance_in_cm_t distance = gp2y0a21yk0f_counts_to_distance(counts); tiny_key_value_store_write(self->key_value_store, key, &distance); + if(channel == left_channel) { + tiny_key_value_store_write(self->key_value_store, key_knob_counts, &counts); + c = counts; + } } static void poll(tiny_timer_group_t* timer_group, void* context) { diff --git a/src/hardware/plugin/line_sensors_plugin.c b/src/hardware/plugin/line_sensors_plugin.c index 97ca3cf..4e01d18 100644 --- a/src/hardware/plugin/line_sensors_plugin.c +++ b/src/hardware/plugin/line_sensors_plugin.c @@ -53,19 +53,31 @@ static void end_capture(void) { TIM1->CR1 &= ~TIM1_CR1_CEN; } -static volatile uint16_t a; -static volatile uint16_t b; +static volatile uint8_t left_number_detected; +static volatile uint8_t right_number_detected; static void measure(line_sensors_plugin_t* self) { uint16_t left_count = (TIM1->CCR3H << 8) + TIM1->CCR3L; bool left_line_detected = left_count < line_threshold; + if(left_line_detected) { + left_number_detected++; + left_line_detected = left_number_detected > 2; + } + else { + left_number_detected = 0; + } tiny_key_value_store_write(self->key_value_store, key_left_line_detected, &left_line_detected); uint16_t right_count = (TIM1->CCR4H << 8) + TIM1->CCR4L; bool right_line_detected = right_count < line_threshold; + if(right_line_detected) { + right_number_detected++; + right_line_detected = right_number_detected > 2; + } + else { + right_number_detected = 0; + } tiny_key_value_store_write(self->key_value_store, key_right_line_detected, &right_line_detected); - a = left_count; - b = right_count; bool line_detected = left_line_detected || right_line_detected; tiny_key_value_store_write(self->key_value_store, key_line_detected, &line_detected); } diff --git a/src/hardware/plugin/motors_plugin.c b/src/hardware/plugin/motors_plugin.c index 14cea82..b3f6dd1 100644 --- a/src/hardware/plugin/motors_plugin.c +++ b/src/hardware/plugin/motors_plugin.c @@ -28,7 +28,10 @@ static void update_output(motor_power_t power, reg_t* direction, uint8_t directi power = -power; } - uint16_t compare = (period * power) / motor_power_max; + uint16_t compare = ((uint64_t)period * power) / motor_power_max; + (void)compare; + (void)ccrh; + (void)ccrl; *ccrh = compare >> 8; *ccrl = compare & 0xFF; } diff --git a/test/application/application_test.cpp b/test/application/application_test.cpp index 5d05dac..299cbff 100644 --- a/test/application/application_test.cpp +++ b/test/application/application_test.cpp @@ -7,6 +7,7 @@ extern "C" { #include "application.h" #include "tiny_utils.h" #include "tactic.h" +#include "tuning.h" #include "data_model.h" } @@ -16,7 +17,7 @@ extern "C" { enum { startup_delay = 5 * 1000, - line_avoidance_maneuver_time = 500 + 1 // why? no one knows... or cares + line_avoidance_maneuver_time = line_detection_back_up_time + line_detection_turn_time + 1 // why? no one knows... or cares }; TEST_GROUP(application) { diff --git a/test/application/tactics/charge_test.cpp b/test/application/tactics/charge_test.cpp index 6219ee6..19112f6 100644 --- a/test/application/tactics/charge_test.cpp +++ b/test/application/tactics/charge_test.cpp @@ -10,6 +10,7 @@ extern "C" { #include "tiny_ram_key_value_store.h" #include "tiny_utils.h" #include "tactic.h" +#include "tuning.h" #include "enemy_location.h" } @@ -19,8 +20,8 @@ extern "C" { enum { near_wheel_power = 30, far_wheel_power = 100, - charge = 100, - a_reduced_charge = 80, + charge = charge_full_power, + a_reduced_charge = charge_reduced_power, some_power = 77, some_other_power = -22, some_other_tactic = tactic_avoid_line, diff --git a/test/application/tactics/line_detected_test.cpp b/test/application/tactics/line_detected_test.cpp index e5e6672..033b3a7 100644 --- a/test/application/tactics/line_detected_test.cpp +++ b/test/application/tactics/line_detected_test.cpp @@ -8,6 +8,7 @@ extern "C" { #include "line_detected.h" #include "motor_power.h" #include "tactic.h" +#include "tuning.h" #include "enemy_location.h" #include "tiny_utils.h" #include "tiny_ram_key_value_store.h" @@ -25,13 +26,13 @@ enum { some_power = 70, some_other_power = -55, back_up = motor_power_min, - back_up_time = 70, - turn_time = 30, + back_up_time = line_detection_back_up_time, + turn_time = line_detection_turn_time, some_time_has_passed = 17, is_running = 0, has_stopped, - near_wheel_power = -30, - far_wheel_power = 100, + near_wheel_power = line_detection_near_wheel_power, + far_wheel_power = line_detection_far_wheel_power, a_long_time = 200 }; @@ -71,13 +72,6 @@ static const line_detected_keys_t keys = { .key_tactic_stopped = key_tactic_stopped }; -static const line_detected_config_t config = { - .near_wheel_power = near_wheel_power, - .far_wheel_power = far_wheel_power, - .back_up_time = back_up_time, - .turn_time = turn_time, -}; - TEST_GROUP(line_detected) { line_detected_t self; @@ -99,7 +93,7 @@ TEST_GROUP(line_detected) { } void when_it_is_initialized() { - line_detected_init(&self, i_key_value_store, &keys, &config, &timer_group); + line_detected_init(&self, i_key_value_store, &keys, &timer_group); } void given_it_has_been_initialized() { @@ -164,13 +158,13 @@ TEST_GROUP(line_detected) { void the_motors_should_be_turning(uint8_t direction) { if (direction == right) { - the_left_motor_should_be_set_to(far_wheel_power); - the_right_motor_should_be_set_to(near_wheel_power); - } - else { the_left_motor_should_be_set_to(near_wheel_power); the_right_motor_should_be_set_to(far_wheel_power); } + else { + the_left_motor_should_be_set_to(far_wheel_power); + the_right_motor_should_be_set_to(near_wheel_power); + } } void after(tiny_time_source_ticks_t ticks) { @@ -227,7 +221,11 @@ TEST(line_detected, should_turn_right_after_it_has_backed_up_when_the_left_line_ given_the_left_line_has_been(detected); given_this_tactic_is_active(); + the_left_motor_should_be_set_to(back_up); + the_right_motor_should_be_set_to(back_up); + after(back_up_time - 1); + given_the_left_line_has_been(not_detected); the_left_motor_should_be_set_to(back_up); the_right_motor_should_be_set_to(back_up); @@ -257,7 +255,11 @@ TEST(line_detected, should_turn_left_after_it_has_backed_up_when_the_right_line_ given_the_right_line_has_been(detected); given_this_tactic_is_active(); + the_left_motor_should_be_set_to(back_up); + the_right_motor_should_be_set_to(back_up); + after(back_up_time - 1); + given_the_right_line_has_been(not_detected); the_left_motor_should_be_set_to(back_up); the_right_motor_should_be_set_to(back_up); diff --git a/test/application/tactics/seeking_test.cpp b/test/application/tactics/seeking_test.cpp index 4a09bf6..74706cf 100644 --- a/test/application/tactics/seeking_test.cpp +++ b/test/application/tactics/seeking_test.cpp @@ -10,14 +10,15 @@ extern "C" { #include "tiny_ram_key_value_store.h" #include "tiny_utils.h" #include "tactic.h" +#include "tuning.h" } #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" enum { - near_wheel_power = 30, - far_wheel_power = 100, + near_wheel_power = seeking_near_wheel_power, + far_wheel_power = seeking_far_wheel_power, some_power = 77, some_other_power = -22, some_other_tactic = tactic_charge diff --git a/test/application/tactics/spin_on_init_test.cpp b/test/application/tactics/spin_on_init_test.cpp new file mode 100644 index 0000000..4602536 --- /dev/null +++ b/test/application/tactics/spin_on_init_test.cpp @@ -0,0 +1,208 @@ +/*! + * @file + * @brief + */ + +extern "C" { +#include +#include "spin_on_init.h" +#include "motor_power.h" +#include "tactic.h" +#include "tuning.h" +#include "enemy_location.h" +#include "tiny_utils.h" +#include "tiny_ram_key_value_store.h" +#include "i_tiny_adc.h" +} + +#include "CppUTest/TestHarness.h" +#include "CppUTestExt/MockSupport.h" +#include "tiny_time_source_double.h" + +#define degrees + +enum { + right, + left, + detected = true, + not_detected = false, + some_power = 70, + some_other_power = -55, + back_up = motor_power_min, + back_up_time = line_detection_back_up_time, + turn_time = line_detection_turn_time, + some_time_has_passed = 17, + is_running = 0, + has_stopped, + near_wheel_power = line_detection_near_wheel_power, + far_wheel_power = line_detection_far_wheel_power, + a_long_time = 200, + max_counts = 0xFFFF +}; + +// clang-format off +#define data_model_key_value_pairs(pair) \ + pair(key_tactic, tactic_t) \ + pair(key_knob_counts, tiny_adc_counts_t) \ + pair(key_left_motor, motor_power_t) \ + pair(key_right_motor, motor_power_t) \ + pair(key_tactic_stopped, uint8_t) \ +// clang-format on + +enumerate_ram_key_value_pairs(data_model_key_value_pairs); + +#define _storage_type_name data_model_storage_t + +generate_storage_type_for_ram_key_value_pairs(data_model_key_value_pairs); + +static const tiny_ram_key_value_store_key_value_pair_t key_value_pairs[] = { + generate_configuration_pairs_from_ram_key_value_pairs(data_model_key_value_pairs) +}; + +static data_model_storage_t storage; + +static const tiny_ram_key_value_store_configuration_t store_config = { + key_value_pairs, + element_count(key_value_pairs) +}; + +static const spin_on_init_keys_t keys = { + .left_motor = key_left_motor, + .right_motor = key_right_motor, + .knob_counts = key_knob_counts, + .tactic = key_tactic, + .tactic_stopped = key_tactic_stopped +}; + +TEST_GROUP(spin_on_init) { + spin_on_init_t self; + + tiny_ram_key_value_store_t ram_key_value_store; + i_tiny_key_value_store_t* i_key_value_store; + + tiny_time_source_double_t time_source; + tiny_timer_group_t timer_group; + + void setup() { + tiny_ram_key_value_store_init( + &ram_key_value_store, + &store_config, + &storage); + i_key_value_store = &ram_key_value_store.interface; + + tiny_time_source_double_init(&time_source); + tiny_timer_group_init(&timer_group, &time_source.interface); + } + + void when_it_is_initialized_and_the_knob_is_set_to(uint64_t degree) { + tiny_adc_counts_t counts = ((uint64_t)max_counts * degree) / 360; + spin_on_init_init(&self, i_key_value_store, &keys, &timer_group); + tiny_key_value_store_write(i_key_value_store, key_knob_counts, &counts); + } + + void given_it_has_been_initialized_and_the_knob_is_set_to(uint64_t degree) { + when_it_is_initialized_and_the_knob_is_set_to(degree); + } + + void when_another_tactic_is_selected() { + tactic_t tactic = tactic_charge; + tiny_key_value_store_write(i_key_value_store, key_tactic, &tactic); + } + + void when_this_tactic_is_selected() { + tactic_t tactic = tactic_init; + tiny_key_value_store_write(i_key_value_store, key_tactic, &tactic); + } + + void given_this_tactic_is_active() { + when_this_tactic_is_selected(); + } + + void given_the_left_motor_has_been_set_to(motor_power_t value) { + tiny_key_value_store_write(i_key_value_store, key_left_motor, &value); + } + + void given_the_right_motor_has_been_set_to(motor_power_t value) { + tiny_key_value_store_write(i_key_value_store, key_right_motor, &value); + } + + void the_left_motor_should_be_set_to(motor_power_t expected) { + motor_power_t actual; + tiny_key_value_store_read(i_key_value_store, key_left_motor, &actual); + CHECK_EQUAL(expected, actual); + } + + void the_right_motor_should_be_set_to(motor_power_t expected) { + motor_power_t actual; + tiny_key_value_store_read(i_key_value_store, key_right_motor, &actual); + CHECK_EQUAL(expected, actual); + } + + void the_tactic_should_indicate_that_it(uint8_t expected) { + uint8_t actual; + tiny_key_value_store_read(i_key_value_store, key_tactic_stopped, &actual); + CHECK_EQUAL(expected, actual); + } + + void the_motors_should_be_turning(uint8_t direction) { + if (direction == right) { + the_left_motor_should_be_set_to(near_wheel_power); + the_right_motor_should_be_set_to(far_wheel_power); + } + else { + the_left_motor_should_be_set_to(far_wheel_power); + the_right_motor_should_be_set_to(near_wheel_power); + } + } + + void after(tiny_time_source_ticks_t ticks) { + tiny_time_source_double_tick(&time_source, ticks); + tiny_timer_group_run(&timer_group); + } + + void the_robot_should_spin(uint8_t direction, uint64_t degree) { + tiny_timer_ticks_t ticks = (degree * turn_time_360_degree) / 360; + the_motors_should_be_turning(direction); + the_tactic_should_indicate_that_it(is_running); + + after(ticks - 1); + the_motors_should_be_turning(direction); + the_tactic_should_indicate_that_it(is_running); + + after(1); + the_tactic_should_indicate_that_it(has_stopped); + } +}; + +TEST(spin_on_init, should_do_nothing_on_init) { + given_the_left_motor_has_been_set_to(some_power); + given_the_right_motor_has_been_set_to(some_other_power); + + when_it_is_initialized_and_the_knob_is_set_to(90); + the_left_motor_should_be_set_to(some_power); + the_right_motor_should_be_set_to(some_other_power); +} + +TEST(spin_on_init, should_spin_right_when_the_tactic_is_selected) { + given_it_has_been_initialized_and_the_knob_is_set_to(90 degrees); + when_this_tactic_is_selected(); + the_robot_should_spin(right, 90 degrees); +} + +TEST(spin_on_init, should_spin_right_at_another_angle) { + given_it_has_been_initialized_and_the_knob_is_set_to(110 degrees); + when_this_tactic_is_selected(); + the_robot_should_spin(right, 110 degrees); +} + +TEST(spin_on_init, should_spin_left_when_the_tactic_is_selected) { + given_it_has_been_initialized_and_the_knob_is_set_to(270 degrees); + when_this_tactic_is_selected(); + the_robot_should_spin(left, 270 degrees); +} + +TEST(spin_on_init, should_spin_left_at_another_angle) { + given_it_has_been_initialized_and_the_knob_is_set_to(181 degrees); + when_this_tactic_is_selected(); + the_robot_should_spin(left, 181 degrees); +} diff --git a/test/application/tactics/strategist_test.cpp b/test/application/tactics/strategist_test.cpp index cd8e2d5..a687648 100644 --- a/test/application/tactics/strategist_test.cpp +++ b/test/application/tactics/strategist_test.cpp @@ -123,22 +123,12 @@ TEST(strategist, should_idle_on_init) { the_selected_tactic_should_be(tactic_idle); } -TEST(strategist, should_seek_clockwise_when_the_robot_is_running_and_clockwise_is_selected) { +TEST(strategist, should_start_the_init_tactic_when_the_robot_is_running) { given_it_has_been_initialized(); - given_the_initial_seeking_direction_is(direction_clockwise); the_selected_tactic_should_be(tactic_idle); when_the_robot_starts_running(); - the_selected_tactic_should_become(tactic_seek_clockwise); -} - -TEST(strategist, should_seek_counterclockwise_when_the_robot_is_running_and_counterclockwise_is_selected) { - given_it_has_been_initialized(); - given_the_initial_seeking_direction_is(direction_counterclockwise); - the_selected_tactic_should_be(tactic_idle); - - when_the_robot_starts_running(); - the_selected_tactic_should_become(tactic_seek_counterclockwise); + the_selected_tactic_should_become(tactic_init); } TEST(strategist, should_charge_when_the_enemy_moves_detected) { @@ -153,6 +143,19 @@ TEST(strategist, should_charge_when_the_enemy_moves_detected) { the_selected_tactic_should_become(tactic_charge); } +TEST(strategist, should_not_charge_when_the_enemy_is_detected_during_line_avoidance) { + given_it_has_been_initialized(); + given_a_line_has(been_detected); + when_the_enemy_moves(in_front); + the_selected_tactic_should_be(tactic_avoid_line); + + when_the_enemy_moves(in_front_left); + the_selected_tactic_should_be(tactic_avoid_line); + + when_the_enemy_moves(in_front_right); + the_selected_tactic_should_be(tactic_avoid_line); +} + TEST(strategist, should_seek_clockwise_when_the_enemy_was_last_seen_to_the_right) { given_it_has_been_initialized(); given_the_enemy_was(in_front_right);