From d8b4421c73bce5ea7fe3bc451592cd940928b4d8 Mon Sep 17 00:00:00 2001 From: Ernesto Voltaggio Date: Wed, 27 Apr 2022 19:57:12 +0200 Subject: [PATCH 01/24] added the enter button as click input --- .../Braccio_Learn_and_Repeat.ino | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index f9b5564..8c78516 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -5,6 +5,9 @@ #define COLOR_LIGHT_TEAL 0x62AEB2 #define COLOR_ORANGE 0xE47128 +// ENTER button +#define BUTTON_ENTER 6 + enum states { RECORD, REPLAY, @@ -28,12 +31,8 @@ static void eventHandlerMenu(lv_event_t * e) { lv_event_code_t code = lv_event_get_code(e); lv_obj_t * obj = lv_event_get_target(e); - if (code == LV_EVENT_KEY && lv_indev_get_key(lv_indev_get_act()) == LV_KEY_HOME) { - state = ZERO_POSITION; - return; - } - if (code == LV_EVENT_CLICKED) { + if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) { uint32_t id = lv_btnmatrix_get_selected_btn(obj); const char * txt = lv_btnmatrix_get_btn_text(obj, id); From d7368cc522c8b74d8eeedc16baa2a8ceca7cd65d Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 27 Apr 2022 11:38:14 +0200 Subject: [PATCH 02/24] Fix: Prevent sample array (values) from overflowing. --- .../Braccio_Learn_and_Repeat.ino | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 8c78516..5b8bd30 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -16,9 +16,12 @@ enum states { int state = ZERO_POSITION; -float values[10000]; +static int const MAX_SAMPLES = 6*1000*2; /* 20 seconds. */ + +float values[MAX_SAMPLES]; float* idx = values; float* final_idx = 0; +int sample_cnt = 0; float homePos[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; static lv_obj_t * counter; @@ -41,6 +44,7 @@ static void eventHandlerMenu(lv_event_t * e) { } idx = values; + sample_cnt = 0; switch (id) { case 0: // if the button pressed is the first one @@ -140,12 +144,23 @@ void setup() { void loop() { if (state == RECORD) { + + /* Check if we still have space for samples. */ + if (sample_cnt >= MAX_SAMPLES) { + state = ZERO_POSITION; + Serial.println("ZERO_POSITION"); + btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); + } + /* Capture those samples. */ Braccio.positions(idx); idx += 6; + sample_cnt += 6; } if (state == REPLAY) { Braccio.moveTo(idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); idx += 6; + sample_cnt += 6; if (idx >= final_idx) { Serial.println("REPLAY done"); state = ZERO_POSITION; @@ -153,12 +168,8 @@ void loop() { lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); } } - if (idx - values >= sizeof(values)) { - Serial.println("ZERO_POSITION"); - state = ZERO_POSITION; - } delay(100); if (state != ZERO_POSITION) { - lv_label_set_text_fmt(counter, "Counter: %d" , idx - values); + lv_label_set_text_fmt(counter, "Counter: %d" , sample_cnt); } } From 250343dc39e99ee8ff5f528570cb22a0a3972357 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 27 Apr 2022 11:41:41 +0200 Subject: [PATCH 03/24] Show a count of captured joint states instead of individual sample cnt (which is not so meaningful). --- examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 5b8bd30..64d586c 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -170,6 +170,6 @@ void loop() { } delay(100); if (state != ZERO_POSITION) { - lv_label_set_text_fmt(counter, "Counter: %d" , sample_cnt); + lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); } } From f6931cf3c28a0a8a17e1aa66c4e2692e683521aa Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 28 Apr 2022 06:39:43 +0200 Subject: [PATCH 04/24] Prevent race conditions due to multi-threaded LVGL access. --- .../Braccio_Learn_and_Repeat.ino | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 64d586c..1e8cd6e 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -31,10 +31,10 @@ static const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITIO static void eventHandlerMenu(lv_event_t * e) { + Braccio.lvgl_lock(); lv_event_code_t code = lv_event_get_code(e); lv_obj_t * obj = lv_event_get_target(e); - if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) { uint32_t id = lv_btnmatrix_get_selected_btn(obj); const char * txt = lv_btnmatrix_get_btn_text(obj, id); @@ -93,9 +93,12 @@ static void eventHandlerMenu(lv_event_t * e) { break; } } + Braccio.lvgl_unlock(); } -void mainMenu() { +void mainMenu() +{ + Braccio.lvgl_lock(); static lv_style_t style_focus; lv_style_init(&style_focus); lv_style_set_outline_color(&style_focus, lv_color_hex(COLOR_ORANGE)); @@ -127,6 +130,7 @@ void mainMenu() { lv_obj_align(counter, LV_ALIGN_CENTER, 0, 80); lv_obj_add_event_cb(btnm, eventHandlerMenu, LV_EVENT_ALL, NULL); + Braccio.lvgl_unlock(); Braccio.connectJoystickTo(btnm); } @@ -149,8 +153,10 @@ void loop() { if (sample_cnt >= MAX_SAMPLES) { state = ZERO_POSITION; Serial.println("ZERO_POSITION"); + Braccio.lvgl_lock(); btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); + Braccio.lvgl_unlock(); } /* Capture those samples. */ Braccio.positions(idx); @@ -164,12 +170,16 @@ void loop() { if (idx >= final_idx) { Serial.println("REPLAY done"); state = ZERO_POSITION; + Braccio.lvgl_lock(); btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); + Braccio.lvgl_unlock(); } } delay(100); if (state != ZERO_POSITION) { + Braccio.lvgl_lock(); lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); + Braccio.lvgl_unlock(); } } From 671909cd8436b64dc139534f7ed2651576c382bb Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 07:04:04 +0200 Subject: [PATCH 05/24] Fix: Do not perform a last capture when the sample cnt has been exceeded already. --- .../Braccio_Learn_and_Repeat.ino | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 1e8cd6e..82690a1 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -146,9 +146,10 @@ void setup() { Serial.println("Replicate a movement"); } -void loop() { - if (state == RECORD) { - +void loop() +{ + if (state == RECORD) + { /* Check if we still have space for samples. */ if (sample_cnt >= MAX_SAMPLES) { state = ZERO_POSITION; @@ -158,12 +159,17 @@ void loop() { lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); Braccio.lvgl_unlock(); } - /* Capture those samples. */ - Braccio.positions(idx); - idx += 6; - sample_cnt += 6; + else + { + /* Capture those samples. */ + Braccio.positions(idx); + idx += 6; + sample_cnt += 6; + } } - if (state == REPLAY) { + + if (state == REPLAY) + { Braccio.moveTo(idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); idx += 6; sample_cnt += 6; @@ -176,8 +182,11 @@ void loop() { Braccio.lvgl_unlock(); } } + delay(100); - if (state != ZERO_POSITION) { + + if (state != ZERO_POSITION) + { Braccio.lvgl_lock(); lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); Braccio.lvgl_unlock(); From e7d0fac629a2b06b9405a205619053b9f1359ff5 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 07:11:28 +0200 Subject: [PATCH 06/24] Fix: Execute state code every 100 ms, instead of a 100 ms delay, which delays by 100 ms PLUS code execution time. --- .../Braccio_Learn_and_Repeat.ino | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 82690a1..a58b082 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -148,47 +148,53 @@ void setup() { void loop() { - if (state == RECORD) + /* Every 100 ms, which is the system sample rate, do ... */ + static auto prev = millis(); + auto const now = millis(); + if ((now - prev) >= 100) { - /* Check if we still have space for samples. */ - if (sample_cnt >= MAX_SAMPLES) { - state = ZERO_POSITION; - Serial.println("ZERO_POSITION"); - Braccio.lvgl_lock(); - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); - Braccio.lvgl_unlock(); + prev = now; + + if (state == RECORD) + { + /* Check if we still have space for samples. */ + if (sample_cnt >= MAX_SAMPLES) { + state = ZERO_POSITION; + Serial.println("ZERO_POSITION"); + Braccio.lvgl_lock(); + btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); + Braccio.lvgl_unlock(); + } + else + { + /* Capture those samples. */ + Braccio.positions(idx); + idx += 6; + sample_cnt += 6; + } } - else + + if (state == REPLAY) { - /* Capture those samples. */ - Braccio.positions(idx); + Braccio.moveTo(idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); idx += 6; sample_cnt += 6; + if (idx >= final_idx) { + Serial.println("REPLAY done"); + state = ZERO_POSITION; + Braccio.lvgl_lock(); + btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); + Braccio.lvgl_unlock(); + } } - } - if (state == REPLAY) - { - Braccio.moveTo(idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); - idx += 6; - sample_cnt += 6; - if (idx >= final_idx) { - Serial.println("REPLAY done"); - state = ZERO_POSITION; + if (state != ZERO_POSITION) + { Braccio.lvgl_lock(); - btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); + lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); Braccio.lvgl_unlock(); } } - - delay(100); - - if (state != ZERO_POSITION) - { - Braccio.lvgl_lock(); - lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); - Braccio.lvgl_unlock(); - } } From 34ea2ba704ce2d9430c119445a4cda8216c140d9 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 07:38:57 +0200 Subject: [PATCH 07/24] Fix: Real sample time was in fact 200 seconds, not 20 (comment/reality mismatch). Real sampletime is now 20 seconds. --- examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index a58b082..c8b46d6 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -16,7 +16,7 @@ enum states { int state = ZERO_POSITION; -static int const MAX_SAMPLES = 6*1000*2; /* 20 seconds. */ +static int const MAX_SAMPLES = 6*100*2; /* 20 seconds. */ float values[MAX_SAMPLES]; float* idx = values; From 9016b55a3e27f6376c0e5ec2d6a19931a26a7eac Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 07:59:03 +0200 Subject: [PATCH 08/24] Simplify state transition logic. --- .../Braccio_Learn_and_Repeat.ino | 76 ++++++++++--------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index c8b46d6..4d2a7ca 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -19,9 +19,8 @@ int state = ZERO_POSITION; static int const MAX_SAMPLES = 6*100*2; /* 20 seconds. */ float values[MAX_SAMPLES]; -float* idx = values; -float* final_idx = 0; int sample_cnt = 0; +int replay_cnt = 0; float homePos[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; static lv_obj_t * counter; @@ -30,33 +29,32 @@ static lv_obj_t * btnm; static const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" }; -static void eventHandlerMenu(lv_event_t * e) { +static void eventHandlerMenu(lv_event_t * e) +{ Braccio.lvgl_lock(); lv_event_code_t code = lv_event_get_code(e); lv_obj_t * obj = lv_event_get_target(e); - if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) { + if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) + { uint32_t id = lv_btnmatrix_get_selected_btn(obj); const char * txt = lv_btnmatrix_get_btn_text(obj, id); - if (state == RECORD) { - final_idx = idx; - } - - idx = values; - sample_cnt = 0; - - switch (id) { + switch (id) + { case 0: // if the button pressed is the first one - if (txt == "RECORD") { + if (txt == "RECORD") + { state = RECORD; + sample_cnt = 0; Braccio.disengage(); // allow the user to freely move the braccio lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); Serial.println("RECORD"); lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); // remove disabled state of the replay button btnm_map[0] = "STOP"; // change the label of the first button to "STOP" } - else if (txt == "STOP") { + else if (txt == "STOP") + { state = ZERO_POSITION; Braccio.engage(); // enable the steppers so that the braccio stands still lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); @@ -65,14 +63,16 @@ static void eventHandlerMenu(lv_event_t * e) { break; case 1: btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - if (txt == "REPLAY"){ - state = REPLAY; - btnm_map[2] = "STOP"; // change the label of the second button to "STOP" - Braccio.engage(); - lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); - Serial.println("REPLAY"); + if (txt == "REPLAY") + { + state = REPLAY; + replay_cnt = 0; + btnm_map[2] = "STOP"; // change the label of the second button to "STOP" + Braccio.engage(); + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); } - else if (txt=="STOP"){ + else if (txt=="STOP") + { state = ZERO_POSITION; Braccio.engage(); // enable the steppers so that the braccio stands still lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); @@ -89,7 +89,6 @@ static void eventHandlerMenu(lv_event_t * e) { delay(500); Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - Serial.println("ZERO_POSITION"); break; } } @@ -158,9 +157,10 @@ void loop() if (state == RECORD) { /* Check if we still have space for samples. */ - if (sample_cnt >= MAX_SAMPLES) { + if (sample_cnt >= MAX_SAMPLES) + { state = ZERO_POSITION; - Serial.println("ZERO_POSITION"); + replay_cnt = 0; Braccio.lvgl_lock(); btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); @@ -169,32 +169,38 @@ void loop() else { /* Capture those samples. */ - Braccio.positions(idx); - idx += 6; + Braccio.positions(values + sample_cnt); sample_cnt += 6; } + + Braccio.lvgl_lock(); + lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); + Braccio.lvgl_unlock(); } if (state == REPLAY) { - Braccio.moveTo(idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); - idx += 6; - sample_cnt += 6; - if (idx >= final_idx) { - Serial.println("REPLAY done"); + Braccio.moveTo(values[replay_cnt + 0], values[replay_cnt + 1], values[replay_cnt + 2], values[replay_cnt + 3], values[replay_cnt + 4], values[replay_cnt + 5]); + replay_cnt += 6; + + if (replay_cnt >= sample_cnt) + { state = ZERO_POSITION; Braccio.lvgl_lock(); btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); Braccio.lvgl_unlock(); } - } - if (state != ZERO_POSITION) - { Braccio.lvgl_lock(); - lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); + lv_label_set_text_fmt(counter, "Counter: %d" , (replay_cnt / 6)); Braccio.lvgl_unlock(); } + + if (state == ZERO_POSITION) + { + Braccio.engage(); + Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); + } } } From 6f22436366d8fd532b819ebe8c08a52e29667663 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 08:03:43 +0200 Subject: [PATCH 09/24] Use enum classes for increased type safety. --- .../Braccio_Learn_and_Repeat.ino | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 4d2a7ca..b50060a 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -8,13 +8,14 @@ // ENTER button #define BUTTON_ENTER 6 -enum states { +enum class State +{ RECORD, REPLAY, ZERO_POSITION }; -int state = ZERO_POSITION; +State state = State::ZERO_POSITION; static int const MAX_SAMPLES = 6*100*2; /* 20 seconds. */ @@ -45,7 +46,7 @@ static void eventHandlerMenu(lv_event_t * e) case 0: // if the button pressed is the first one if (txt == "RECORD") { - state = RECORD; + state = State::RECORD; sample_cnt = 0; Braccio.disengage(); // allow the user to freely move the braccio lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); @@ -55,7 +56,7 @@ static void eventHandlerMenu(lv_event_t * e) } else if (txt == "STOP") { - state = ZERO_POSITION; + state = State::ZERO_POSITION; Braccio.engage(); // enable the steppers so that the braccio stands still lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" @@ -65,7 +66,7 @@ static void eventHandlerMenu(lv_event_t * e) btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" if (txt == "REPLAY") { - state = REPLAY; + state = State::REPLAY; replay_cnt = 0; btnm_map[2] = "STOP"; // change the label of the second button to "STOP" Braccio.engage(); @@ -73,7 +74,7 @@ static void eventHandlerMenu(lv_event_t * e) } else if (txt=="STOP") { - state = ZERO_POSITION; + state = State::ZERO_POSITION; Braccio.engage(); // enable the steppers so that the braccio stands still lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" @@ -82,7 +83,7 @@ static void eventHandlerMenu(lv_event_t * e) break; default: - state = ZERO_POSITION; + state = State::ZERO_POSITION; btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" Braccio.engage(); @@ -154,12 +155,12 @@ void loop() { prev = now; - if (state == RECORD) + if (state == State::RECORD) { /* Check if we still have space for samples. */ if (sample_cnt >= MAX_SAMPLES) { - state = ZERO_POSITION; + state = State::ZERO_POSITION; replay_cnt = 0; Braccio.lvgl_lock(); btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" @@ -178,14 +179,14 @@ void loop() Braccio.lvgl_unlock(); } - if (state == REPLAY) + if (state == State::REPLAY) { Braccio.moveTo(values[replay_cnt + 0], values[replay_cnt + 1], values[replay_cnt + 2], values[replay_cnt + 3], values[replay_cnt + 4], values[replay_cnt + 5]); replay_cnt += 6; if (replay_cnt >= sample_cnt) { - state = ZERO_POSITION; + state = State::ZERO_POSITION; Braccio.lvgl_lock(); btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); @@ -197,7 +198,7 @@ void loop() Braccio.lvgl_unlock(); } - if (state == ZERO_POSITION) + if (state == State::ZERO_POSITION) { Braccio.engage(); Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); From 295955edc8bf7ea3fd82b93edc7748b82b51c887 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 08:05:34 +0200 Subject: [PATCH 10/24] Adding separators for better readability. --- .../Braccio_Learn_and_Repeat.ino | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index b50060a..807dbcc 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -1,13 +1,23 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + #include -// Colors +/************************************************************************************** + * DEFINE + **************************************************************************************/ + #define COLOR_TEAL 0x00878F #define COLOR_LIGHT_TEAL 0x62AEB2 #define COLOR_ORANGE 0xE47128 -// ENTER button #define BUTTON_ENTER 6 +/************************************************************************************** + * TYPEDEF + **************************************************************************************/ + enum class State { RECORD, @@ -15,6 +25,10 @@ enum class State ZERO_POSITION }; +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + State state = State::ZERO_POSITION; static int const MAX_SAMPLES = 6*100*2; /* 20 seconds. */ @@ -29,6 +43,9 @@ static lv_obj_t * btnm; static const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" }; +/************************************************************************************** + * FUNCTIONS + **************************************************************************************/ static void eventHandlerMenu(lv_event_t * e) { @@ -135,6 +152,10 @@ void mainMenu() Braccio.connectJoystickTo(btnm); } +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + void setup() { Braccio.begin(mainMenu); delay(500); From 7324dc30ce6c038b2e5c0ec8f00d14ddab9eaa7f Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 08:08:42 +0200 Subject: [PATCH 11/24] Extract code for RECORD state into separate function. --- .../Braccio_Learn_and_Repeat.ino | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 807dbcc..cbac9d8 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -178,26 +178,7 @@ void loop() if (state == State::RECORD) { - /* Check if we still have space for samples. */ - if (sample_cnt >= MAX_SAMPLES) - { - state = State::ZERO_POSITION; - replay_cnt = 0; - Braccio.lvgl_lock(); - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); - Braccio.lvgl_unlock(); - } - else - { - /* Capture those samples. */ - Braccio.positions(values + sample_cnt); - sample_cnt += 6; - } - - Braccio.lvgl_lock(); - lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); - Braccio.lvgl_unlock(); + state = handle_RECORD(); } if (state == State::REPLAY) @@ -226,3 +207,36 @@ void loop() } } } + +/************************************************************************************** + * FUNCTION DEFINITIONS + **************************************************************************************/ + +State handle_RECORD() +{ + /* Check if we still have space for samples. */ + if (sample_cnt >= MAX_SAMPLES) + { + replay_cnt = 0; + + Braccio.lvgl_lock(); + btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); + Braccio.lvgl_unlock(); + + return State::ZERO_POSITION; + } + else + { + /* Capture those samples. */ + Braccio.positions(values + sample_cnt); + sample_cnt += 6; + + /* Update sample counter. */ + Braccio.lvgl_lock(); + lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); + Braccio.lvgl_unlock(); + + return State::RECORD; + } +} \ No newline at end of file From b1bcbf102836cadead891e8c9681d19ac4588d3f Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 08:11:11 +0200 Subject: [PATCH 12/24] Extract code for REPLAY state into separate function. --- .../Braccio_Learn_and_Repeat.ino | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index cbac9d8..750042c 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -183,21 +183,7 @@ void loop() if (state == State::REPLAY) { - Braccio.moveTo(values[replay_cnt + 0], values[replay_cnt + 1], values[replay_cnt + 2], values[replay_cnt + 3], values[replay_cnt + 4], values[replay_cnt + 5]); - replay_cnt += 6; - - if (replay_cnt >= sample_cnt) - { - state = State::ZERO_POSITION; - Braccio.lvgl_lock(); - btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - Braccio.lvgl_unlock(); - } - - Braccio.lvgl_lock(); - lv_label_set_text_fmt(counter, "Counter: %d" , (replay_cnt / 6)); - Braccio.lvgl_unlock(); + state = handle_REPLAY(); } if (state == State::ZERO_POSITION) @@ -220,23 +206,43 @@ State handle_RECORD() replay_cnt = 0; Braccio.lvgl_lock(); - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" + btnm_map[0] = "RECORD"; lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); Braccio.lvgl_unlock(); return State::ZERO_POSITION; } - else - { - /* Capture those samples. */ - Braccio.positions(values + sample_cnt); - sample_cnt += 6; - /* Update sample counter. */ + /* Capture those samples. */ + Braccio.positions(values + sample_cnt); + sample_cnt += 6; + + /* Update sample counter. */ + Braccio.lvgl_lock(); + lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); + Braccio.lvgl_unlock(); + + return State::RECORD; +} + +State handle_REPLAY() +{ + if (replay_cnt >= sample_cnt) + { Braccio.lvgl_lock(); - lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); + btnm_map[2] = "REPLAY"; + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); Braccio.lvgl_unlock(); - return State::RECORD; + return State::ZERO_POSITION; } -} \ No newline at end of file + + Braccio.moveTo(values[replay_cnt + 0], values[replay_cnt + 1], values[replay_cnt + 2], values[replay_cnt + 3], values[replay_cnt + 4], values[replay_cnt + 5]); + replay_cnt += 6; + + Braccio.lvgl_lock(); + lv_label_set_text_fmt(counter, "Counter: %d" , (replay_cnt / 6)); + Braccio.lvgl_unlock(); + + return State::REPLAY; +} From c883902b6165766a944e72998262095796821bd6 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 08:15:57 +0200 Subject: [PATCH 13/24] Extract code for ZERO_POSITION state into separate function. --- .../Braccio_Learn_and_Repeat.ino | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 750042c..b631db6 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -188,8 +188,7 @@ void loop() if (state == State::ZERO_POSITION) { - Braccio.engage(); - Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); + state = handle_ZERO_POSITION(); } } } @@ -208,8 +207,12 @@ State handle_RECORD() Braccio.lvgl_lock(); btnm_map[0] = "RECORD"; lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); + lv_label_set_text_fmt(counter, "Counter: %d" , 0); Braccio.lvgl_unlock(); + Braccio.engage(); + Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); + return State::ZERO_POSITION; } @@ -232,8 +235,11 @@ State handle_REPLAY() Braccio.lvgl_lock(); btnm_map[2] = "REPLAY"; lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); + lv_label_set_text_fmt(counter, "Counter: %d" , 0); Braccio.lvgl_unlock(); + Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); + return State::ZERO_POSITION; } @@ -246,3 +252,8 @@ State handle_REPLAY() return State::REPLAY; } + +State handle_ZERO_POSITION() +{ + return State::ZERO_POSITION; +} From 1813c997991ca85b7ce8290d4b2a7c23cb131b9a Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Mon, 2 May 2022 08:18:15 +0200 Subject: [PATCH 14/24] Replace if state selection with switch/case. --- .../Braccio_Learn_and_Repeat.ino | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index b631db6..c23946b 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -175,20 +175,11 @@ void loop() if ((now - prev) >= 100) { prev = now; - - if (state == State::RECORD) - { - state = handle_RECORD(); - } - - if (state == State::REPLAY) - { - state = handle_REPLAY(); - } - - if (state == State::ZERO_POSITION) + switch (state) { - state = handle_ZERO_POSITION(); + case State::RECORD: state = handle_RECORD(); break; + case State::REPLAY: state = handle_REPLAY(); break; + case State::ZERO_POSITION: state = handle_ZERO_POSITION(); break; } } } From 8bcacfd6e493068ab6732e6088d8797636087724 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 3 May 2022 12:55:50 +0200 Subject: [PATCH 15/24] Reimplementing application flow using the State Design Pattern. --- .../Braccio_Learn_and_Repeat/AppState.cpp | 179 +++++++++++++++++ examples/Braccio_Learn_and_Repeat/AppState.h | 148 ++++++++++++++ .../Braccio_Learn_and_Repeat.ino | 184 +++--------------- 3 files changed, 355 insertions(+), 156 deletions(-) create mode 100644 examples/Braccio_Learn_and_Repeat/AppState.cpp create mode 100644 examples/Braccio_Learn_and_Repeat/AppState.h diff --git a/examples/Braccio_Learn_and_Repeat/AppState.cpp b/examples/Braccio_Learn_and_Repeat/AppState.cpp new file mode 100644 index 0000000..5c32f7a --- /dev/null +++ b/examples/Braccio_Learn_and_Repeat/AppState.cpp @@ -0,0 +1,179 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "AppState.h" + +/************************************************************************************** + * CONSTANT + **************************************************************************************/ + +static int const SAMPLE_BUF_SIZE = 6*100*2; /* 20 seconds. */ +static float const HOME_POS[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; + + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +extern const char * btnm_map[]; +extern lv_obj_t * counter; +extern lv_obj_t * btnm; + +static float sample_buf[SAMPLE_BUF_SIZE]; +static int sample_cnt; + +IdleState LearnAndRepeatApp::_idle_state; +RecordState LearnAndRepeatApp::_record_state; +ReplayState LearnAndRepeatApp::_replay_state; +ZeroState LearnAndRepeatApp::_zero_state; + +/************************************************************************************** + * State + **************************************************************************************/ + +State * State::handle_OnZeroPosition() +{ + return &LearnAndRepeatApp::_zero_state; +} + +/************************************************************************************** + * IdleState + **************************************************************************************/ + +void IdleState::onEnter() +{ + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); +} + +void IdleState::onExit() +{ + lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); +} + +State * IdleState::handle_OnRecord() +{ + return &LearnAndRepeatApp::_record_state; +} + +State * IdleState::handle_OnReplay() +{ + return &LearnAndRepeatApp::_replay_state; +} + +/************************************************************************************** + * RecordState + **************************************************************************************/ + +void RecordState::onEnter() +{ + btnm_map[0] = "STOP"; + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); + + Braccio.disengage(); + sample_cnt = 0; +} + +void RecordState::onExit() +{ + btnm_map[0] = "RECORD"; + lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); + lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); + lv_label_set_text_fmt(counter, "Counter: %d" , 0); + + Braccio.engage(); +} + +State * RecordState::handle_OnRecord() +{ + return &LearnAndRepeatApp::_idle_state; +} + +State * RecordState::handle_OnTimerTick() +{ + /* The sample buffer is full. */ + if (sample_cnt >= SAMPLE_BUF_SIZE) { + return &LearnAndRepeatApp::_idle_state; + } + + /* We still have space, let's sample some data. */ + Braccio.positions(sample_buf + sample_cnt); + sample_cnt += 6; + + /* Update sample counter. */ + lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); + + return this; +} + +/************************************************************************************** + * ReplayState + **************************************************************************************/ + +void ReplayState::onEnter() +{ + _replay_cnt = 0; + + btnm_map[2] = "STOP"; + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); +} + +void ReplayState::onExit() +{ + btnm_map[2] = "REPLAY"; + lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); + lv_label_set_text_fmt(counter, "Counter: %d" , 0); +} + +State * ReplayState::handle_OnReplay() +{ + return &LearnAndRepeatApp::_idle_state; +} + +State * ReplayState::handle_OnTimerTick() +{ + /* All samples have been replayed. */ + if (_replay_cnt >= sample_cnt) { + return &LearnAndRepeatApp::_idle_state; + } + + /* Replay recorded movements. */ + Braccio.moveTo(sample_buf[_replay_cnt + 0], + sample_buf[_replay_cnt + 1], + sample_buf[_replay_cnt + 2], + sample_buf[_replay_cnt + 3], + sample_buf[_replay_cnt + 4], + sample_buf[_replay_cnt + 5]); + _replay_cnt += 6; + + lv_label_set_text_fmt(counter, "Counter: %d" , (_replay_cnt / 6)); + + return this; +} + +/************************************************************************************** + * ReplayState + **************************************************************************************/ + +State * ZeroState::handle_OnTimerTick() +{ + return &LearnAndRepeatApp::_idle_state; +} + +void ZeroState::onEnter() +{ + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); + + Braccio.engage(); + delay(100); + Braccio.moveTo(HOME_POS[0], HOME_POS[1], HOME_POS[2], HOME_POS[3], HOME_POS[4], HOME_POS[5]); + delay(500); +} + +void ZeroState::onExit() +{ + lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); +} diff --git a/examples/Braccio_Learn_and_Repeat/AppState.h b/examples/Braccio_Learn_and_Repeat/AppState.h new file mode 100644 index 0000000..fcc7686 --- /dev/null +++ b/examples/Braccio_Learn_and_Repeat/AppState.h @@ -0,0 +1,148 @@ +#ifndef LEARN_AND_REPEAT_APP_STATE_H_ +#define LEARN_AND_REPEAT_APP_STATE_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * TYPEDEF + **************************************************************************************/ + +enum class EventSource +{ + Button_Record, Button_Replay, Button_ZeroPosition, TimerTick +}; + +enum class StateName +{ + Record, Replay, Idle, Zero +}; + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class State +{ +public: + virtual ~State() { } + virtual void onEnter() { Serial.println("State::onEnter"); } + virtual void onExit() { Serial.println("State::onExit"); } + virtual StateName name() = 0; + State * update(EventSource const evt_src) + { + State * next_state = this; + switch (evt_src) + { + case EventSource::Button_Record: next_state = handle_OnRecord(); break; + case EventSource::Button_Replay: next_state = handle_OnReplay(); break; + case EventSource::Button_ZeroPosition: next_state = handle_OnZeroPosition(); break; + case EventSource::TimerTick: next_state = handle_OnTimerTick(); break; + } + return next_state; + } + +protected: + virtual State * handle_OnRecord() { return this; } + virtual State * handle_OnReplay() { return this; } + virtual State * handle_OnZeroPosition(); + virtual State * handle_OnTimerTick() { return this; } +}; + +class IdleState : public State +{ +public: + virtual ~IdleState() { } + virtual StateName name() override { return StateName::Idle; } + virtual void onEnter() override; + virtual void onExit() override; + +protected: + virtual State * handle_OnRecord() override; + virtual State * handle_OnReplay() override; +}; + +class RecordState : public State +{ +public: + virtual ~RecordState() { } + virtual StateName name() override { return StateName::Record; } + virtual void onEnter() override; + virtual void onExit() override; + +protected: + virtual State * handle_OnRecord() override; + virtual State * handle_OnTimerTick() override; +}; + +class ReplayState : public State +{ +public: + virtual ~ReplayState() { } + virtual StateName name() override { return StateName::Replay; } + virtual void onEnter() override; + virtual void onExit() override; + +protected: + virtual State * handle_OnReplay() override; + virtual State * handle_OnTimerTick() override; + +private: + int _replay_cnt; +}; + +class ZeroState : public State +{ +public: + virtual ~ZeroState() { } + virtual StateName name() override { return StateName::Zero; } + virtual void onEnter() override; + virtual void onExit() override; + +protected: + virtual State * handle_OnTimerTick() override; +}; + +class LearnAndRepeatApp +{ +public: + LearnAndRepeatApp() + : _state{nullptr} + , _mtx{} + { } + + static IdleState _idle_state; + static RecordState _record_state; + static ReplayState _replay_state; + static ZeroState _zero_state; + + void update(EventSource const evt_src) + { + mbed::ScopedLock lock(_mtx); + + if (!_state) + { + _state = &_zero_state; + _state->onEnter(); + return; + } + + State * next_state = _state->update(evt_src); + + if (next_state->name() != _state->name()) + { + _state->onExit(); + _state = next_state; + _state->onEnter(); + } + } + +private: + State * _state; + rtos::Mutex _mtx; +}; + +#endif /* LEARN_AND_REPEAT_APP_STATE_H_ */ diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index c23946b..f8cdd3e 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -4,6 +4,8 @@ #include +#include "AppState.h" + /************************************************************************************** * DEFINE **************************************************************************************/ @@ -15,33 +17,21 @@ #define BUTTON_ENTER 6 /************************************************************************************** - * TYPEDEF + * GLOBAL CONST **************************************************************************************/ -enum class State -{ - RECORD, - REPLAY, - ZERO_POSITION -}; +static float const homePos[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; /************************************************************************************** * GLOBAL VARIABLES **************************************************************************************/ -State state = State::ZERO_POSITION; - -static int const MAX_SAMPLES = 6*100*2; /* 20 seconds. */ +lv_obj_t * counter; +lv_obj_t * btnm; -float values[MAX_SAMPLES]; -int sample_cnt = 0; -int replay_cnt = 0; -float homePos[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; +const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" }; -static lv_obj_t * counter; -static lv_obj_t * btnm; - -static const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" }; +static LearnAndRepeatApp app; /************************************************************************************** * FUNCTIONS @@ -49,71 +39,24 @@ static const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITIO static void eventHandlerMenu(lv_event_t * e) { - Braccio.lvgl_lock(); lv_event_code_t code = lv_event_get_code(e); - lv_obj_t * obj = lv_event_get_target(e); - if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) + //if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) + if (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER) { - uint32_t id = lv_btnmatrix_get_selected_btn(obj); - const char * txt = lv_btnmatrix_get_btn_text(obj, id); + lv_obj_t * obj = lv_event_get_target(e); + uint32_t const id = lv_btnmatrix_get_selected_btn(obj); switch (id) { - case 0: // if the button pressed is the first one - if (txt == "RECORD") - { - state = State::RECORD; - sample_cnt = 0; - Braccio.disengage(); // allow the user to freely move the braccio - lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); - Serial.println("RECORD"); - lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); // remove disabled state of the replay button - btnm_map[0] = "STOP"; // change the label of the first button to "STOP" - } - else if (txt == "STOP") - { - state = State::ZERO_POSITION; - Braccio.engage(); // enable the steppers so that the braccio stands still - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - } - break; - case 1: - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - if (txt == "REPLAY") - { - state = State::REPLAY; - replay_cnt = 0; - btnm_map[2] = "STOP"; // change the label of the second button to "STOP" - Braccio.engage(); - lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); - } - else if (txt=="STOP") - { - state = State::ZERO_POSITION; - Braccio.engage(); // enable the steppers so that the braccio stands still - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" - } - - break; - - default: - state = State::ZERO_POSITION; - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" - Braccio.engage(); - delay(500); - Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - break; + case 0: app.update(EventSource::Button_Record); break; + case 1: app.update(EventSource::Button_Replay); break; + case 2: app.update(EventSource::Button_ZeroPosition); break; } } - Braccio.lvgl_unlock(); } -void mainMenu() +void custom_main_menu() { Braccio.lvgl_lock(); static lv_style_t style_focus; @@ -134,9 +77,9 @@ void mainMenu() lv_obj_add_style(btnm, &style_btn, LV_PART_ITEMS); lv_obj_add_style(btnm, &style_focus, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); - lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKABLE); + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED); lv_btnmatrix_set_one_checked(btnm, true); lv_btnmatrix_set_selected_btn(btnm, 0); @@ -156,95 +99,24 @@ void mainMenu() * SETUP/LOOP **************************************************************************************/ -void setup() { - Braccio.begin(mainMenu); - delay(500); +void setup() +{ + Braccio.begin(custom_main_menu); - Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); - delay(500); - - Serial.begin(115200); - Serial.println("Replicate a movement"); + /* Enable buttons once init is complete. */ + lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED); } void loop() { - /* Every 100 ms, which is the system sample rate, do ... */ + /* Only execute every 100 ms. */ static auto prev = millis(); auto const now = millis(); - if ((now - prev) >= 100) - { - prev = now; - switch (state) - { - case State::RECORD: state = handle_RECORD(); break; - case State::REPLAY: state = handle_REPLAY(); break; - case State::ZERO_POSITION: state = handle_ZERO_POSITION(); break; - } - } -} - -/************************************************************************************** - * FUNCTION DEFINITIONS - **************************************************************************************/ -State handle_RECORD() -{ - /* Check if we still have space for samples. */ - if (sample_cnt >= MAX_SAMPLES) + if ((now - prev) > 100) { - replay_cnt = 0; - - Braccio.lvgl_lock(); - btnm_map[0] = "RECORD"; - lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); - lv_label_set_text_fmt(counter, "Counter: %d" , 0); - Braccio.lvgl_unlock(); - - Braccio.engage(); - Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); - - return State::ZERO_POSITION; - } - - /* Capture those samples. */ - Braccio.positions(values + sample_cnt); - sample_cnt += 6; - - /* Update sample counter. */ - Braccio.lvgl_lock(); - lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); - Braccio.lvgl_unlock(); - - return State::RECORD; -} - -State handle_REPLAY() -{ - if (replay_cnt >= sample_cnt) - { - Braccio.lvgl_lock(); - btnm_map[2] = "REPLAY"; - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - lv_label_set_text_fmt(counter, "Counter: %d" , 0); - Braccio.lvgl_unlock(); - - Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); - - return State::ZERO_POSITION; + prev = now; + app.update(EventSource::TimerTick); } - - Braccio.moveTo(values[replay_cnt + 0], values[replay_cnt + 1], values[replay_cnt + 2], values[replay_cnt + 3], values[replay_cnt + 4], values[replay_cnt + 5]); - replay_cnt += 6; - - Braccio.lvgl_lock(); - lv_label_set_text_fmt(counter, "Counter: %d" , (replay_cnt / 6)); - Braccio.lvgl_unlock(); - - return State::REPLAY; -} - -State handle_ZERO_POSITION() -{ - return State::ZERO_POSITION; } From e4b1be04ab1e64383faf075ee32864f321dcc848 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 3 May 2022 17:06:25 +0200 Subject: [PATCH 16/24] temp save. --- .../Braccio_Learn_and_Repeat/AppState.cpp | 82 +++++++++++++++++- examples/Braccio_Learn_and_Repeat/AppState.h | 6 ++ .../Braccio_Learn_and_Repeat.ino | 86 +------------------ 3 files changed, 86 insertions(+), 88 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/AppState.cpp b/examples/Braccio_Learn_and_Repeat/AppState.cpp index 5c32f7a..85f2125 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.cpp +++ b/examples/Braccio_Learn_and_Repeat/AppState.cpp @@ -4,6 +4,16 @@ #include "AppState.h" +/************************************************************************************** + * DEFINE + **************************************************************************************/ + +#define COLOR_TEAL 0x00878F +#define COLOR_LIGHT_TEAL 0x62AEB2 +#define COLOR_ORANGE 0xE47128 + +#define BUTTON_ENTER 6 + /************************************************************************************** * CONSTANT **************************************************************************************/ @@ -11,14 +21,13 @@ static int const SAMPLE_BUF_SIZE = 6*100*2; /* 20 seconds. */ static float const HOME_POS[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; - /************************************************************************************** * GLOBAL VARIABLES **************************************************************************************/ -extern const char * btnm_map[]; -extern lv_obj_t * counter; -extern lv_obj_t * btnm; +lv_obj_t * counter; +lv_obj_t * btnm; +const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" }; static float sample_buf[SAMPLE_BUF_SIZE]; static int sample_cnt; @@ -28,6 +37,71 @@ RecordState LearnAndRepeatApp::_record_state; ReplayState LearnAndRepeatApp::_replay_state; ZeroState LearnAndRepeatApp::_zero_state; +extern LearnAndRepeatApp app; + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +static void event_handler_menu(lv_event_t * e) +{ + lv_event_code_t code = lv_event_get_code(e); + + //if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) + if (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER) + { + lv_obj_t * obj = lv_event_get_target(e); + uint32_t const id = lv_btnmatrix_get_selected_btn(obj); + + switch (id) + { + case 0: app.update(EventSource::Button_Record); break; + case 1: app.update(EventSource::Button_Replay); break; + case 2: app.update(EventSource::Button_ZeroPosition); break; + } + } +} + + +void custom_main_menu() +{ + Braccio.lvgl_lock(); + static lv_style_t style_focus; + lv_style_init(&style_focus); + lv_style_set_outline_color(&style_focus, lv_color_hex(COLOR_ORANGE)); + lv_style_set_outline_width(&style_focus, 4); + + static lv_style_t style_btn; + lv_style_init(&style_btn); + lv_style_set_bg_color(&style_btn, lv_color_hex(COLOR_LIGHT_TEAL)); + lv_style_set_text_color(&style_btn, lv_color_white()); + + btnm = lv_btnmatrix_create(lv_scr_act()); + lv_obj_set_size(btnm, 240, 240); + lv_btnmatrix_set_map(btnm, btnm_map); + lv_obj_align(btnm, LV_ALIGN_CENTER, 0, 0); + + lv_obj_add_style(btnm, &style_btn, LV_PART_ITEMS); + lv_obj_add_style(btnm, &style_focus, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); + + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED); + + lv_btnmatrix_set_one_checked(btnm, true); + lv_btnmatrix_set_selected_btn(btnm, 0); + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); + + counter = lv_label_create(btnm); + lv_label_set_text_fmt(counter, "Counter: %d" , 0); + lv_obj_align(counter, LV_ALIGN_CENTER, 0, 80); + + lv_obj_add_event_cb(btnm, event_handler_menu, LV_EVENT_ALL, NULL); + Braccio.lvgl_unlock(); + + Braccio.connectJoystickTo(btnm); +} + /************************************************************************************** * State **************************************************************************************/ diff --git a/examples/Braccio_Learn_and_Repeat/AppState.h b/examples/Braccio_Learn_and_Repeat/AppState.h index fcc7686..5e31dc0 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.h +++ b/examples/Braccio_Learn_and_Repeat/AppState.h @@ -21,6 +21,12 @@ enum class StateName Record, Replay, Idle, Zero }; +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +void custom_main_menu(); + /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index f8cdd3e..16196be 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -6,94 +6,12 @@ #include "AppState.h" -/************************************************************************************** - * DEFINE - **************************************************************************************/ - -#define COLOR_TEAL 0x00878F -#define COLOR_LIGHT_TEAL 0x62AEB2 -#define COLOR_ORANGE 0xE47128 - -#define BUTTON_ENTER 6 - -/************************************************************************************** - * GLOBAL CONST - **************************************************************************************/ - -static float const homePos[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; - /************************************************************************************** * GLOBAL VARIABLES **************************************************************************************/ -lv_obj_t * counter; -lv_obj_t * btnm; - -const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" }; - -static LearnAndRepeatApp app; - -/************************************************************************************** - * FUNCTIONS - **************************************************************************************/ - -static void eventHandlerMenu(lv_event_t * e) -{ - lv_event_code_t code = lv_event_get_code(e); - - //if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) - if (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER) - { - lv_obj_t * obj = lv_event_get_target(e); - uint32_t const id = lv_btnmatrix_get_selected_btn(obj); - - switch (id) - { - case 0: app.update(EventSource::Button_Record); break; - case 1: app.update(EventSource::Button_Replay); break; - case 2: app.update(EventSource::Button_ZeroPosition); break; - } - } -} - -void custom_main_menu() -{ - Braccio.lvgl_lock(); - static lv_style_t style_focus; - lv_style_init(&style_focus); - lv_style_set_outline_color(&style_focus, lv_color_hex(COLOR_ORANGE)); - lv_style_set_outline_width(&style_focus, 4); - - static lv_style_t style_btn; - lv_style_init(&style_btn); - lv_style_set_bg_color(&style_btn, lv_color_hex(COLOR_LIGHT_TEAL)); - lv_style_set_text_color(&style_btn, lv_color_white()); - - btnm = lv_btnmatrix_create(lv_scr_act()); - lv_obj_set_size(btnm, 240, 240); - lv_btnmatrix_set_map(btnm, btnm_map); - lv_obj_align(btnm, LV_ALIGN_CENTER, 0, 0); - - lv_obj_add_style(btnm, &style_btn, LV_PART_ITEMS); - lv_obj_add_style(btnm, &style_focus, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); - - lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); - lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED); - - lv_btnmatrix_set_one_checked(btnm, true); - lv_btnmatrix_set_selected_btn(btnm, 0); - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - - counter = lv_label_create(btnm); - lv_label_set_text_fmt(counter, "Counter: %d" , 0); - lv_obj_align(counter, LV_ALIGN_CENTER, 0, 80); - - lv_obj_add_event_cb(btnm, eventHandlerMenu, LV_EVENT_ALL, NULL); - Braccio.lvgl_unlock(); - - Braccio.connectJoystickTo(btnm); -} +extern lv_obj_t * btnm; +LearnAndRepeatApp app; /************************************************************************************** * SETUP/LOOP From a801ac3463add05c0e606b3b1801698743cc025e Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 4 May 2022 09:46:02 +0200 Subject: [PATCH 17/24] Move button enable code within the application. --- examples/Braccio_Learn_and_Repeat/AppState.cpp | 12 +++++++++++- examples/Braccio_Learn_and_Repeat/AppState.h | 2 ++ .../Braccio_Learn_and_Repeat.ino | 9 +++------ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/AppState.cpp b/examples/Braccio_Learn_and_Repeat/AppState.cpp index 85f2125..1bec4dc 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.cpp +++ b/examples/Braccio_Learn_and_Repeat/AppState.cpp @@ -62,7 +62,6 @@ static void event_handler_menu(lv_event_t * e) } } - void custom_main_menu() { Braccio.lvgl_lock(); @@ -251,3 +250,14 @@ void ZeroState::onExit() { lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); } + +/************************************************************************************** + * LearnAndRepeatApp + **************************************************************************************/ + +void LearnAndRepeatApp::enableButtons() +{ + /* Enable buttons once init is complete. */ + lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED); +} \ No newline at end of file diff --git a/examples/Braccio_Learn_and_Repeat/AppState.h b/examples/Braccio_Learn_and_Repeat/AppState.h index 5e31dc0..330969f 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.h +++ b/examples/Braccio_Learn_and_Repeat/AppState.h @@ -125,6 +125,8 @@ class LearnAndRepeatApp static ReplayState _replay_state; static ZeroState _zero_state; + void enableButtons(); + void update(EventSource const evt_src) { mbed::ScopedLock lock(_mtx); diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 16196be..111c7b7 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -10,7 +10,6 @@ * GLOBAL VARIABLES **************************************************************************************/ -extern lv_obj_t * btnm; LearnAndRepeatApp app; /************************************************************************************** @@ -19,11 +18,9 @@ LearnAndRepeatApp app; void setup() { - Braccio.begin(custom_main_menu); - - /* Enable buttons once init is complete. */ - lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); - lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED); + if (Braccio.begin(custom_main_menu)) { + app.enableButtons(); + } } void loop() From 0a057b54ef4e148e66d758876805d34ff436ed75 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 4 May 2022 09:49:12 +0200 Subject: [PATCH 18/24] Replace static states with dynamic allocation (simplifies init code). --- .../Braccio_Learn_and_Repeat/AppState.cpp | 23 +++++++------------ examples/Braccio_Learn_and_Repeat/AppState.h | 9 +++----- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/AppState.cpp b/examples/Braccio_Learn_and_Repeat/AppState.cpp index 1bec4dc..72da354 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.cpp +++ b/examples/Braccio_Learn_and_Repeat/AppState.cpp @@ -32,11 +32,6 @@ const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n static float sample_buf[SAMPLE_BUF_SIZE]; static int sample_cnt; -IdleState LearnAndRepeatApp::_idle_state; -RecordState LearnAndRepeatApp::_record_state; -ReplayState LearnAndRepeatApp::_replay_state; -ZeroState LearnAndRepeatApp::_zero_state; - extern LearnAndRepeatApp app; /************************************************************************************** @@ -107,7 +102,7 @@ void custom_main_menu() State * State::handle_OnZeroPosition() { - return &LearnAndRepeatApp::_zero_state; + return new ZeroState(); } /************************************************************************************** @@ -126,12 +121,12 @@ void IdleState::onExit() State * IdleState::handle_OnRecord() { - return &LearnAndRepeatApp::_record_state; + return new RecordState(); } State * IdleState::handle_OnReplay() { - return &LearnAndRepeatApp::_replay_state; + return new ReplayState(); } /************************************************************************************** @@ -159,14 +154,14 @@ void RecordState::onExit() State * RecordState::handle_OnRecord() { - return &LearnAndRepeatApp::_idle_state; + return new IdleState(); } State * RecordState::handle_OnTimerTick() { /* The sample buffer is full. */ if (sample_cnt >= SAMPLE_BUF_SIZE) { - return &LearnAndRepeatApp::_idle_state; + return new IdleState(); } /* We still have space, let's sample some data. */ @@ -185,8 +180,6 @@ State * RecordState::handle_OnTimerTick() void ReplayState::onEnter() { - _replay_cnt = 0; - btnm_map[2] = "STOP"; lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); @@ -202,14 +195,14 @@ void ReplayState::onExit() State * ReplayState::handle_OnReplay() { - return &LearnAndRepeatApp::_idle_state; + return new IdleState(); } State * ReplayState::handle_OnTimerTick() { /* All samples have been replayed. */ if (_replay_cnt >= sample_cnt) { - return &LearnAndRepeatApp::_idle_state; + return new IdleState(); } /* Replay recorded movements. */ @@ -232,7 +225,7 @@ State * ReplayState::handle_OnTimerTick() State * ZeroState::handle_OnTimerTick() { - return &LearnAndRepeatApp::_idle_state; + return new IdleState(); } void ZeroState::onEnter() diff --git a/examples/Braccio_Learn_and_Repeat/AppState.h b/examples/Braccio_Learn_and_Repeat/AppState.h index 330969f..036a827 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.h +++ b/examples/Braccio_Learn_and_Repeat/AppState.h @@ -87,6 +87,7 @@ class RecordState : public State class ReplayState : public State { public: + ReplayState() : _replay_cnt{0} { } virtual ~ReplayState() { } virtual StateName name() override { return StateName::Replay; } virtual void onEnter() override; @@ -120,11 +121,6 @@ class LearnAndRepeatApp , _mtx{} { } - static IdleState _idle_state; - static RecordState _record_state; - static ReplayState _replay_state; - static ZeroState _zero_state; - void enableButtons(); void update(EventSource const evt_src) @@ -133,7 +129,7 @@ class LearnAndRepeatApp if (!_state) { - _state = &_zero_state; + _state = new ZeroState(); _state->onEnter(); return; } @@ -143,6 +139,7 @@ class LearnAndRepeatApp if (next_state->name() != _state->name()) { _state->onExit(); + delete _state; _state = next_state; _state->onEnter(); } From 4353e429d8d2e19c5b60df6f5652481a9c113297 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 4 May 2022 09:52:21 +0200 Subject: [PATCH 19/24] Ensure that the REPLAY button gets disabled as soon as you start recordig. --- examples/Braccio_Learn_and_Repeat/AppState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/Braccio_Learn_and_Repeat/AppState.cpp b/examples/Braccio_Learn_and_Repeat/AppState.cpp index 72da354..2526b56 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.cpp +++ b/examples/Braccio_Learn_and_Repeat/AppState.cpp @@ -137,6 +137,7 @@ void RecordState::onEnter() { btnm_map[0] = "STOP"; lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); Braccio.disengage(); sample_cnt = 0; From 0b7749e9143affef8f56170a63816a32c5942090 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 4 May 2022 09:56:01 +0200 Subject: [PATCH 20/24] Restore behaviour that both joystick click and ENTER button work. --- examples/Braccio_Learn_and_Repeat/AppState.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/AppState.cpp b/examples/Braccio_Learn_and_Repeat/AppState.cpp index 2526b56..050b622 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.cpp +++ b/examples/Braccio_Learn_and_Repeat/AppState.cpp @@ -42,8 +42,7 @@ static void event_handler_menu(lv_event_t * e) { lv_event_code_t code = lv_event_get_code(e); - //if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) - if (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER) + if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) { lv_obj_t * obj = lv_event_get_target(e); uint32_t const id = lv_btnmatrix_get_selected_btn(obj); From b2384df1c76afa1a3dadaf216b13304f1fa9ccec Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 4 May 2022 10:18:09 +0200 Subject: [PATCH 21/24] Sampling every 50 instead of very 100 ms yields a smoother replay. --- examples/Braccio_Learn_and_Repeat/AppState.cpp | 2 +- .../Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/Braccio_Learn_and_Repeat/AppState.cpp b/examples/Braccio_Learn_and_Repeat/AppState.cpp index 050b622..d8317d2 100644 --- a/examples/Braccio_Learn_and_Repeat/AppState.cpp +++ b/examples/Braccio_Learn_and_Repeat/AppState.cpp @@ -18,7 +18,7 @@ * CONSTANT **************************************************************************************/ -static int const SAMPLE_BUF_SIZE = 6*100*2; /* 20 seconds. */ +static int const SAMPLE_BUF_SIZE = 6*200*2; /* 20 seconds. */ static float const HOME_POS[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; /************************************************************************************** diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino index 111c7b7..a7e99a7 100644 --- a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino +++ b/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino @@ -25,11 +25,11 @@ void setup() void loop() { - /* Only execute every 100 ms. */ + /* Only execute every 50 ms. */ static auto prev = millis(); auto const now = millis(); - if ((now - prev) > 100) + if ((now - prev) > 50) { prev = now; app.update(EventSource::TimerTick); From ff1afd7c70f61ad2ed9198fbc1ca09e6beceb233 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 10 May 2022 09:43:09 +0200 Subject: [PATCH 22/24] Rename Braccio_Learn_and_Repeat to Braccio_Record_and_Replay. --- .../AppState.cpp | 0 .../AppState.h | 0 .../Braccio_Learn_and_Repeat.ino | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename examples/{Braccio_Learn_and_Repeat => Braccio_Record_and_Replay}/AppState.cpp (100%) rename examples/{Braccio_Learn_and_Repeat => Braccio_Record_and_Replay}/AppState.h (100%) rename examples/{Braccio_Learn_and_Repeat => Braccio_Record_and_Replay}/Braccio_Learn_and_Repeat.ino (100%) diff --git a/examples/Braccio_Learn_and_Repeat/AppState.cpp b/examples/Braccio_Record_and_Replay/AppState.cpp similarity index 100% rename from examples/Braccio_Learn_and_Repeat/AppState.cpp rename to examples/Braccio_Record_and_Replay/AppState.cpp diff --git a/examples/Braccio_Learn_and_Repeat/AppState.h b/examples/Braccio_Record_and_Replay/AppState.h similarity index 100% rename from examples/Braccio_Learn_and_Repeat/AppState.h rename to examples/Braccio_Record_and_Replay/AppState.h diff --git a/examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Record_and_Replay/Braccio_Learn_and_Repeat.ino similarity index 100% rename from examples/Braccio_Learn_and_Repeat/Braccio_Learn_and_Repeat.ino rename to examples/Braccio_Record_and_Replay/Braccio_Learn_and_Repeat.ino From b2b03bbe0ce07287055ad708b82ae651e0bd89f7 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 10 May 2022 09:44:26 +0200 Subject: [PATCH 23/24] Rename p03-learning-mode/align with Braccio_Record_and_Replay. --- ...peat.ino => Braccio_Record_and_Replay.ino} | 0 .../01_Braccio_Record_and_Replay.ino | 37 +++ .../01_Braccio_Record_and_Replay/AppState.cpp | 256 ++++++++++++++++++ .../01_Braccio_Record_and_Replay/AppState.h | 153 +++++++++++ .../01_Braccio_learning_mode.ino | 165 ----------- 5 files changed, 446 insertions(+), 165 deletions(-) rename examples/Braccio_Record_and_Replay/{Braccio_Learn_and_Repeat.ino => Braccio_Record_and_Replay.ino} (100%) create mode 100644 examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/01_Braccio_Record_and_Replay.ino create mode 100644 examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/AppState.cpp create mode 100644 examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/AppState.h delete mode 100644 examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_learning_mode/01_Braccio_learning_mode.ino diff --git a/examples/Braccio_Record_and_Replay/Braccio_Learn_and_Repeat.ino b/examples/Braccio_Record_and_Replay/Braccio_Record_and_Replay.ino similarity index 100% rename from examples/Braccio_Record_and_Replay/Braccio_Learn_and_Repeat.ino rename to examples/Braccio_Record_and_Replay/Braccio_Record_and_Replay.ino diff --git a/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/01_Braccio_Record_and_Replay.ino b/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/01_Braccio_Record_and_Replay.ino new file mode 100644 index 0000000..a7e99a7 --- /dev/null +++ b/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/01_Braccio_Record_and_Replay.ino @@ -0,0 +1,37 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +#include "AppState.h" + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +LearnAndRepeatApp app; + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + if (Braccio.begin(custom_main_menu)) { + app.enableButtons(); + } +} + +void loop() +{ + /* Only execute every 50 ms. */ + static auto prev = millis(); + auto const now = millis(); + + if ((now - prev) > 50) + { + prev = now; + app.update(EventSource::TimerTick); + } +} diff --git a/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/AppState.cpp b/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/AppState.cpp new file mode 100644 index 0000000..d8317d2 --- /dev/null +++ b/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/AppState.cpp @@ -0,0 +1,256 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "AppState.h" + +/************************************************************************************** + * DEFINE + **************************************************************************************/ + +#define COLOR_TEAL 0x00878F +#define COLOR_LIGHT_TEAL 0x62AEB2 +#define COLOR_ORANGE 0xE47128 + +#define BUTTON_ENTER 6 + +/************************************************************************************** + * CONSTANT + **************************************************************************************/ + +static int const SAMPLE_BUF_SIZE = 6*200*2; /* 20 seconds. */ +static float const HOME_POS[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; + +/************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************/ + +lv_obj_t * counter; +lv_obj_t * btnm; +const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" }; + +static float sample_buf[SAMPLE_BUF_SIZE]; +static int sample_cnt; + +extern LearnAndRepeatApp app; + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +static void event_handler_menu(lv_event_t * e) +{ + lv_event_code_t code = lv_event_get_code(e); + + if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER)) + { + lv_obj_t * obj = lv_event_get_target(e); + uint32_t const id = lv_btnmatrix_get_selected_btn(obj); + + switch (id) + { + case 0: app.update(EventSource::Button_Record); break; + case 1: app.update(EventSource::Button_Replay); break; + case 2: app.update(EventSource::Button_ZeroPosition); break; + } + } +} + +void custom_main_menu() +{ + Braccio.lvgl_lock(); + static lv_style_t style_focus; + lv_style_init(&style_focus); + lv_style_set_outline_color(&style_focus, lv_color_hex(COLOR_ORANGE)); + lv_style_set_outline_width(&style_focus, 4); + + static lv_style_t style_btn; + lv_style_init(&style_btn); + lv_style_set_bg_color(&style_btn, lv_color_hex(COLOR_LIGHT_TEAL)); + lv_style_set_text_color(&style_btn, lv_color_white()); + + btnm = lv_btnmatrix_create(lv_scr_act()); + lv_obj_set_size(btnm, 240, 240); + lv_btnmatrix_set_map(btnm, btnm_map); + lv_obj_align(btnm, LV_ALIGN_CENTER, 0, 0); + + lv_obj_add_style(btnm, &style_btn, LV_PART_ITEMS); + lv_obj_add_style(btnm, &style_focus, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); + + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED); + + lv_btnmatrix_set_one_checked(btnm, true); + lv_btnmatrix_set_selected_btn(btnm, 0); + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); + + counter = lv_label_create(btnm); + lv_label_set_text_fmt(counter, "Counter: %d" , 0); + lv_obj_align(counter, LV_ALIGN_CENTER, 0, 80); + + lv_obj_add_event_cb(btnm, event_handler_menu, LV_EVENT_ALL, NULL); + Braccio.lvgl_unlock(); + + Braccio.connectJoystickTo(btnm); +} + +/************************************************************************************** + * State + **************************************************************************************/ + +State * State::handle_OnZeroPosition() +{ + return new ZeroState(); +} + +/************************************************************************************** + * IdleState + **************************************************************************************/ + +void IdleState::onEnter() +{ + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); +} + +void IdleState::onExit() +{ + lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); +} + +State * IdleState::handle_OnRecord() +{ + return new RecordState(); +} + +State * IdleState::handle_OnReplay() +{ + return new ReplayState(); +} + +/************************************************************************************** + * RecordState + **************************************************************************************/ + +void RecordState::onEnter() +{ + btnm_map[0] = "STOP"; + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); + + Braccio.disengage(); + sample_cnt = 0; +} + +void RecordState::onExit() +{ + btnm_map[0] = "RECORD"; + lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); + lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); + lv_label_set_text_fmt(counter, "Counter: %d" , 0); + + Braccio.engage(); +} + +State * RecordState::handle_OnRecord() +{ + return new IdleState(); +} + +State * RecordState::handle_OnTimerTick() +{ + /* The sample buffer is full. */ + if (sample_cnt >= SAMPLE_BUF_SIZE) { + return new IdleState(); + } + + /* We still have space, let's sample some data. */ + Braccio.positions(sample_buf + sample_cnt); + sample_cnt += 6; + + /* Update sample counter. */ + lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6)); + + return this; +} + +/************************************************************************************** + * ReplayState + **************************************************************************************/ + +void ReplayState::onEnter() +{ + btnm_map[2] = "STOP"; + lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); +} + +void ReplayState::onExit() +{ + btnm_map[2] = "REPLAY"; + lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); + lv_label_set_text_fmt(counter, "Counter: %d" , 0); +} + +State * ReplayState::handle_OnReplay() +{ + return new IdleState(); +} + +State * ReplayState::handle_OnTimerTick() +{ + /* All samples have been replayed. */ + if (_replay_cnt >= sample_cnt) { + return new IdleState(); + } + + /* Replay recorded movements. */ + Braccio.moveTo(sample_buf[_replay_cnt + 0], + sample_buf[_replay_cnt + 1], + sample_buf[_replay_cnt + 2], + sample_buf[_replay_cnt + 3], + sample_buf[_replay_cnt + 4], + sample_buf[_replay_cnt + 5]); + _replay_cnt += 6; + + lv_label_set_text_fmt(counter, "Counter: %d" , (_replay_cnt / 6)); + + return this; +} + +/************************************************************************************** + * ReplayState + **************************************************************************************/ + +State * ZeroState::handle_OnTimerTick() +{ + return new IdleState(); +} + +void ZeroState::onEnter() +{ + lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); + + Braccio.engage(); + delay(100); + Braccio.moveTo(HOME_POS[0], HOME_POS[1], HOME_POS[2], HOME_POS[3], HOME_POS[4], HOME_POS[5]); + delay(500); +} + +void ZeroState::onExit() +{ + lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); +} + +/************************************************************************************** + * LearnAndRepeatApp + **************************************************************************************/ + +void LearnAndRepeatApp::enableButtons() +{ + /* Enable buttons once init is complete. */ + lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED); +} \ No newline at end of file diff --git a/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/AppState.h b/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/AppState.h new file mode 100644 index 0000000..036a827 --- /dev/null +++ b/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_Record_and_Replay/AppState.h @@ -0,0 +1,153 @@ +#ifndef LEARN_AND_REPEAT_APP_STATE_H_ +#define LEARN_AND_REPEAT_APP_STATE_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * TYPEDEF + **************************************************************************************/ + +enum class EventSource +{ + Button_Record, Button_Replay, Button_ZeroPosition, TimerTick +}; + +enum class StateName +{ + Record, Replay, Idle, Zero +}; + +/************************************************************************************** + * FUNCTION DECLARATION + **************************************************************************************/ + +void custom_main_menu(); + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class State +{ +public: + virtual ~State() { } + virtual void onEnter() { Serial.println("State::onEnter"); } + virtual void onExit() { Serial.println("State::onExit"); } + virtual StateName name() = 0; + State * update(EventSource const evt_src) + { + State * next_state = this; + switch (evt_src) + { + case EventSource::Button_Record: next_state = handle_OnRecord(); break; + case EventSource::Button_Replay: next_state = handle_OnReplay(); break; + case EventSource::Button_ZeroPosition: next_state = handle_OnZeroPosition(); break; + case EventSource::TimerTick: next_state = handle_OnTimerTick(); break; + } + return next_state; + } + +protected: + virtual State * handle_OnRecord() { return this; } + virtual State * handle_OnReplay() { return this; } + virtual State * handle_OnZeroPosition(); + virtual State * handle_OnTimerTick() { return this; } +}; + +class IdleState : public State +{ +public: + virtual ~IdleState() { } + virtual StateName name() override { return StateName::Idle; } + virtual void onEnter() override; + virtual void onExit() override; + +protected: + virtual State * handle_OnRecord() override; + virtual State * handle_OnReplay() override; +}; + +class RecordState : public State +{ +public: + virtual ~RecordState() { } + virtual StateName name() override { return StateName::Record; } + virtual void onEnter() override; + virtual void onExit() override; + +protected: + virtual State * handle_OnRecord() override; + virtual State * handle_OnTimerTick() override; +}; + +class ReplayState : public State +{ +public: + ReplayState() : _replay_cnt{0} { } + virtual ~ReplayState() { } + virtual StateName name() override { return StateName::Replay; } + virtual void onEnter() override; + virtual void onExit() override; + +protected: + virtual State * handle_OnReplay() override; + virtual State * handle_OnTimerTick() override; + +private: + int _replay_cnt; +}; + +class ZeroState : public State +{ +public: + virtual ~ZeroState() { } + virtual StateName name() override { return StateName::Zero; } + virtual void onEnter() override; + virtual void onExit() override; + +protected: + virtual State * handle_OnTimerTick() override; +}; + +class LearnAndRepeatApp +{ +public: + LearnAndRepeatApp() + : _state{nullptr} + , _mtx{} + { } + + void enableButtons(); + + void update(EventSource const evt_src) + { + mbed::ScopedLock lock(_mtx); + + if (!_state) + { + _state = new ZeroState(); + _state->onEnter(); + return; + } + + State * next_state = _state->update(evt_src); + + if (next_state->name() != _state->name()) + { + _state->onExit(); + delete _state; + _state = next_state; + _state->onEnter(); + } + } + +private: + State * _state; + rtos::Mutex _mtx; +}; + +#endif /* LEARN_AND_REPEAT_APP_STATE_H_ */ diff --git a/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_learning_mode/01_Braccio_learning_mode.ino b/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_learning_mode/01_Braccio_learning_mode.ino deleted file mode 100644 index f9b5564..0000000 --- a/examples/Platform_Tutorials/projects/p03-learning-mode/01_Braccio_learning_mode/01_Braccio_learning_mode.ino +++ /dev/null @@ -1,165 +0,0 @@ -#include - -// Colors -#define COLOR_TEAL 0x00878F -#define COLOR_LIGHT_TEAL 0x62AEB2 -#define COLOR_ORANGE 0xE47128 - -enum states { - RECORD, - REPLAY, - ZERO_POSITION -}; - -int state = ZERO_POSITION; - -float values[10000]; -float* idx = values; -float* final_idx = 0; -float homePos[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0}; - -static lv_obj_t * counter; -static lv_obj_t * btnm; - -static const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" }; - - -static void eventHandlerMenu(lv_event_t * e) { - lv_event_code_t code = lv_event_get_code(e); - lv_obj_t * obj = lv_event_get_target(e); - - if (code == LV_EVENT_KEY && lv_indev_get_key(lv_indev_get_act()) == LV_KEY_HOME) { - state = ZERO_POSITION; - return; - } - - if (code == LV_EVENT_CLICKED) { - uint32_t id = lv_btnmatrix_get_selected_btn(obj); - const char * txt = lv_btnmatrix_get_btn_text(obj, id); - - if (state == RECORD) { - final_idx = idx; - } - - idx = values; - - switch (id) { - case 0: // if the button pressed is the first one - if (txt == "RECORD") { - state = RECORD; - Braccio.disengage(); // allow the user to freely move the braccio - lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED); - Serial.println("RECORD"); - lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); // remove disabled state of the replay button - btnm_map[0] = "STOP"; // change the label of the first button to "STOP" - } - else if (txt == "STOP") { - state = ZERO_POSITION; - Braccio.engage(); // enable the steppers so that the braccio stands still - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - } - break; - case 1: - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - if (txt == "REPLAY"){ - state = REPLAY; - btnm_map[2] = "STOP"; // change the label of the second button to "STOP" - Braccio.engage(); - lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED); - Serial.println("REPLAY"); - } - else if (txt=="STOP"){ - state = ZERO_POSITION; - Braccio.engage(); // enable the steppers so that the braccio stands still - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" - } - - break; - - default: - state = ZERO_POSITION; - btnm_map[0] = "RECORD"; // reset the label of the first button back to "RECORD" - btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" - Braccio.engage(); - delay(500); - Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - Serial.println("ZERO_POSITION"); - break; - } - } -} - -void mainMenu() { - static lv_style_t style_focus; - lv_style_init(&style_focus); - lv_style_set_outline_color(&style_focus, lv_color_hex(COLOR_ORANGE)); - lv_style_set_outline_width(&style_focus, 4); - - static lv_style_t style_btn; - lv_style_init(&style_btn); - lv_style_set_bg_color(&style_btn, lv_color_hex(COLOR_LIGHT_TEAL)); - lv_style_set_text_color(&style_btn, lv_color_white()); - - btnm = lv_btnmatrix_create(lv_scr_act()); - lv_obj_set_size(btnm, 240, 240); - lv_btnmatrix_set_map(btnm, btnm_map); - lv_obj_align(btnm, LV_ALIGN_CENTER, 0, 0); - - lv_obj_add_style(btnm, &style_btn, LV_PART_ITEMS); - lv_obj_add_style(btnm, &style_focus, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); - - lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKABLE); - lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED); - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKABLE); - - lv_btnmatrix_set_one_checked(btnm, true); - lv_btnmatrix_set_selected_btn(btnm, 0); - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - - counter = lv_label_create(btnm); - lv_label_set_text_fmt(counter, "Counter: %d" , 0); - lv_obj_align(counter, LV_ALIGN_CENTER, 0, 80); - - lv_obj_add_event_cb(btnm, eventHandlerMenu, LV_EVENT_ALL, NULL); - - Braccio.connectJoystickTo(btnm); -} - -void setup() { - Braccio.begin(mainMenu); - delay(500); - - Braccio.moveTo(homePos[0], homePos[1], homePos[2], homePos[3], homePos[4], homePos[5]); - delay(500); - - Serial.begin(115200); - Serial.println("Replicate a movement"); -} - -void loop() { - if (state == RECORD) { - Braccio.positions(idx); - idx += 6; - } - if (state == REPLAY) { - Braccio.moveTo(idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]); - idx += 6; - if (idx >= final_idx) { - Serial.println("REPLAY done"); - state = ZERO_POSITION; - btnm_map[2] = "REPLAY"; // reset the label of the first button back to "REPLAY" - lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED); - } - } - if (idx - values >= sizeof(values)) { - Serial.println("ZERO_POSITION"); - state = ZERO_POSITION; - } - delay(100); - if (state != ZERO_POSITION) { - lv_label_set_text_fmt(counter, "Counter: %d" , idx - values); - } -} From 55125546f11f1c342959f58a2806a54b2865371e Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 12 May 2022 15:31:52 +0200 Subject: [PATCH 24/24] Release v1.2.3. --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 4070b00..902b6b5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_Braccio_plusplus -version=1.2.2 +version=1.2.3 author=Arduino maintainer=Arduino sentence=Board support library for the Arduino Braccio++ 6-DOF robot arm.