diff --git a/Firmware/LowLevel/bin/firmware.elf b/Firmware/LowLevel/bin/firmware.elf deleted file mode 100755 index c71c06d1..00000000 Binary files a/Firmware/LowLevel/bin/firmware.elf and /dev/null differ diff --git a/Firmware/LowLevel/bin/firmware.uf2 b/Firmware/LowLevel/bin/firmware.uf2 deleted file mode 100644 index 9d95facb..00000000 Binary files a/Firmware/LowLevel/bin/firmware.uf2 and /dev/null differ diff --git a/Firmware/LowLevel/include/soundsystem.h b/Firmware/LowLevel/include/soundsystem.h new file mode 100644 index 00000000..7caef121 --- /dev/null +++ b/Firmware/LowLevel/include/soundsystem.h @@ -0,0 +1,72 @@ +// Created by Elmar Elflein on 18/07/22. +// Copyright (c) 2022 Elmar Elflein. All rights reserved. +// +// This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +// +// Feel free to use the design in your private/educational projects, but don't try to sell the design or products based on it without getting my consent first. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// +#ifndef _SOUND_SYSTEM_H_ +#define _SOUND_SYSTEM_H_ + +//#include +#include +#include + +#include +#include +#include + + +#define BUFFERSIZE 100 + +#define NR_SOUNDFILES 3 // Number of Soundfiles on SD-card + + + +class MP3Sound +{ + + + + + public: + + uint32_t anzSoundfiles; // number of files stored on the SD-card + bool playing; + + MP3Sound(); + + bool begin(int anzsoundsOnSD); // init serial stream and soundmodule, anzsoundOnSD : maximum number of available soundfiles on the SD-card + + void playSound(int soundNr); // play soundfile number. This method writes soundfile nr in a list, the method processSounds() (has to run in loop) will play + // the sounds according to the list + + void playSoundAdHoc(int soundNr); // play soundfile number immediately whithout waiting until the end of sound + + void setvolume(int vol); // scales loudness from 0 to 100 % + + int sounds2play(); // returns the number if sounds to play in the list + + int processSounds(); // play all sounds from the list. This method has to be calles cyclic, e.g. every second. + + + private: + std::list active_sounds; + bool sound_available; + + + + +}; + + +#endif // _SOUND_SYSTEM_H_ HEADER_FILE diff --git a/Firmware/LowLevel/platformio.ini b/Firmware/LowLevel/platformio.ini index d86dab3c..7c71a21f 100644 --- a/Firmware/LowLevel/platformio.ini +++ b/Firmware/LowLevel/platformio.ini @@ -27,7 +27,7 @@ lib_deps = debug_tool = custom debug_init_break = debug_load_mode = always -debug_port = tcp:ubuntu:3333 +debug_port = tcp:ubuntu.local:3333 ; 133MHz board_build.f_cpu = 133000000L diff --git a/Firmware/LowLevel/src/main.cpp b/Firmware/LowLevel/src/main.cpp index 1d8256b8..af0cfe21 100644 --- a/Firmware/LowLevel/src/main.cpp +++ b/Firmware/LowLevel/src/main.cpp @@ -19,10 +19,13 @@ #include #include #include -#include + #include "datatypes.h" #include "pins.h" #include "ui_datatypes.h" +#include + + #define IMU_CYCLETIME 20 // cycletime for refresh IMU data #define STATUS_CYCLETIME 100 // cycletime for refresh analog and digital Statusvalues @@ -43,6 +46,9 @@ #define PACKET_SERIAL Serial1 #define UI1_SERIAL Serial2 +#define ANZ_SOUND_SD_FILES 3 + + // Millis after charging is retried #define CHARGING_RETRY_MILLIS 10000 @@ -63,7 +69,7 @@ // Emergency will be engaged, if no heartbeat was received in this time frame. #define HEARTBEAT_MILLIS 500 -NeoPixelConnect p(PIN_NEOPIXEL, 1); +NeoPixelConnect p(PIN_NEOPIXEL, 1, pio1, 0); // use state machine 1, sm 0 is used by hardwareserial class PacketSerial packetSerial; // COBS communication PICO <> Raspi PacketSerial UISerial; // COBS communication PICO UI-Board @@ -73,6 +79,12 @@ FastCRC16 CRC16; MPU9250 IMU(SPI, PIN_IMU_CS); size_t fifoSize; + +//SerialPIO soundSerial( PIN_SOUND_TX, PIN_SOUND_RX); +//DFPlayerMini_Fast myMP3; +MP3Sound my_sound; // Soundsystem + + unsigned long last_imu_millis = 0; unsigned long last_status_update_millis = 0; unsigned long last_heartbeat_millis = 0; @@ -90,13 +102,13 @@ struct ui_command uiCommandStruct = {0}; auto_init_mutex(mtx_status_message); bool emergency_latch = true; - +bool sound_available = false; bool charging_allowed = false; +bool ROS_running = false; unsigned long charging_disabled_time = 0; -bool sound_available = false; -SerialPIO soundSerial(PIN_SOUND_TX, PIN_SOUND_RX); -DFPlayerMini_Fast myMP3; + + void sendMessage(void *message, size_t size); void sendUIMessage(void *message, size_t size); @@ -224,12 +236,12 @@ void manageUILEDS() sendUIMessage(&uiCommandStruct, sizeof(struct ui_command)); // Show Info Battery state - if (status_message.v_battery >= (BATT_FULL - 0.5f)) + if (status_message.v_battery >= (BATT_FULL - 1.5f)) uiCommandStruct.cmd2 = LED_off; else if (status_message.v_battery <= (BATT_EMPTY + 1.8f)) - uiCommandStruct.cmd2 = LED_blink_slow; - else uiCommandStruct.cmd2 = LED_blink_fast; + else + uiCommandStruct.cmd2 = LED_blink_slow; uiCommandStruct.type = Set_LED; uiCommandStruct.cmd1 = BATTERY_LOW; sendUIMessage(&uiCommandStruct, sizeof(struct ui_command)); @@ -336,12 +348,14 @@ void loop1() void setup() { - p.neoPixelSetValue(0, 255, 0, 0, true); + //p.neoPixelSetValue(0, 128, 0, 0, true); // We do hardware init in this core, so that we don't get invalid states. // Therefore, we pause the other core until setup() was a success rp2040.idleOtherCore(); emergency_latch = true; + ROS_running = false; + lift_emergency_started = 0; button_emergency_started = 0; // Initialize messages @@ -361,7 +375,12 @@ void setup() gpio_put(PIN_RASPI_POWER, true); // Enable raspi power + p.neoPixelSetValue(0, 32, 0, 0, true); + delay(1000); setRaspiPower(true); + p.neoPixelSetValue(0, 255, 0, 0, true); + + pinMode(PIN_MUX_OUT, OUTPUT); pinMode(PIN_MUX_ADDRESS_0, OUTPUT); @@ -375,14 +394,21 @@ void setup() analogReadResolution(12); + + + + + #ifdef USB_DEBUG DEBUG_SERIAL.begin(115200); #endif + // init serial com to RasPi PACKET_SERIAL.begin(115200); packetSerial.setStream(&PACKET_SERIAL); packetSerial.setPacketHandler(&onPacketReceived); + // init serial com to UI-board UI1_SERIAL.setRX(5); // set hardware pin UI1_SERIAL.setTX(4); UI1_SERIAL.begin(115200); @@ -392,7 +418,7 @@ void setup() /* * IMU INITIALIZATION */ - + int status = IMU.begin(); if (status < 0) { @@ -404,6 +430,12 @@ void setup() #endif status_message.status_bitmask = 0; while (1) + { + p.neoPixelSetValue(0, 255, 0, 0, true); + delay(500); + p.neoPixelSetValue(0, 0, 0, 0, true); + } + { #ifdef USB_DEBUG DEBUG_SERIAL.println("Error: Imu init failed"); @@ -420,39 +452,47 @@ void setup() #ifdef USB_DEBUG DEBUG_SERIAL.println("Imu initialized"); #endif + p.neoPixelSetValue(0, 255, 255, 0, true); + delay(1000); + /* * /IMU INITIALIZATION */ status_message.status_bitmask |= 1; - - // sound init - soundSerial.begin(9600); - while (soundSerial.available()) - soundSerial.read(); - sound_available = myMP3.begin(soundSerial); - + + sound_available = my_sound.begin(NR_SOUNDFILES); if (sound_available) { p.neoPixelSetValue(0, 0, 0, 255, true); - p.neoPixelShow(); - myMP3.volume(30); - myMP3.play(1); + my_sound.setvolume(10); + delay(100); + my_sound.setvolume(10); + delay(100); + my_sound.playSoundAdHoc(1); + delay(5000); + p.neoPixelSetValue(0, 255, 255, 0, true); + } else { for (uint8_t b = 0; b < 3; b++) { p.neoPixelSetValue(0, 0, 0, 0, true); - p.neoPixelShow(); - delay(100); + delay(200); p.neoPixelSetValue(0, 0, 0, 255, true); - p.neoPixelShow(); - delay(100); + delay(200); } } +// Soundtest + my_sound.playSound(3); + my_sound.playSound(1); + my_sound.playSound(2); + + int i = my_sound.sounds2play(); + rp2040.resumeOtherCore(); // UIboard clear all LEDs @@ -460,6 +500,8 @@ void setup() uiCommandStruct.cmd1 = 0; uiCommandStruct.cmd2 = LED_All_OFF; sendUIMessage(&uiCommandStruct, sizeof(struct ui_command)); + + } @@ -488,6 +530,7 @@ void onUIPacketReceived(const uint8_t *buffer, size_t size) return; struct ui_command *buttonboard = (struct ui_command *)buffer; + // overwrite type for the ROS system buttonboard->type = PACKET_ID_LL_UI_EVENT; sendMessage(buttonboard, sizeof(struct ui_command)); @@ -514,11 +557,13 @@ void onPacketReceived(const uint8_t *buffer, size_t size) if (heartbeat->emergency_release_requested) { emergency_latch = false; + ROS_running = true; } // Check in this order, so we can set it again in the same packet if required. if (heartbeat->emergency_requested) { emergency_latch = true; + ROS_running = false; } } @@ -659,6 +704,7 @@ void loop() manageUILEDS(); last_UILED_millis = now; + my_sound.processSounds(); } } @@ -676,7 +722,13 @@ void sendMessage(void *message, size_t size) data_pointer[size - 1] = (crc >> 8) & 0xFF; data_pointer[size - 2] = crc & 0xFF; - packetSerial.send((uint8_t *)message, size); + if (ROS_running) + { + p.neoPixelSetValue(0, 0, 255, 0, true); + packetSerial.send((uint8_t *)message, size); + } + else + p.neoPixelSetValue(0, 0, 255, 255, true); } void sendUIMessage(void *message, size_t size) diff --git a/Firmware/LowLevel/src/soundsystem.cpp b/Firmware/LowLevel/src/soundsystem.cpp new file mode 100644 index 00000000..fab0a2f4 --- /dev/null +++ b/Firmware/LowLevel/src/soundsystem.cpp @@ -0,0 +1,106 @@ +// Created by Elmar Elflein on 18/07/22. +// Copyright (c) 2022 Elmar Elflein. All rights reserved. +// +// This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +// +// Feel free to use the design in your private/educational projects, but don't try to sell the design or products based on it without getting my consent first. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include + + +SerialPIO soundSerial(PIN_SOUND_TX, PIN_SOUND_RX); +DFPlayerMini_Fast myMP3; + + +MP3Sound::MP3Sound() +{ + + this->anzSoundfiles = 0; // number of files stored on the SD-card + this->playing = false; + this->sound_available = false; + +} + + + +bool MP3Sound::begin(int anzsoundsOnSD) + +{ + + // serial stream init for soundmodule + soundSerial.begin(9600); + while (soundSerial.available()) + soundSerial.read(); + // init soundmodule + sound_available = myMP3.begin(soundSerial,true); + delay(1000); + return (sound_available); +} + + +void MP3Sound::setvolume(int vol) // scales from 0 to 100 % +{ + + // value of 30 is max equivalent to 100 % + int val = (int) (30 / 100.0 * vol); + myMP3.volume(val); + delay(300); + +} + + + +void MP3Sound::playSoundAdHoc(int soundNr) +{ + if(soundNr > NR_SOUNDFILES) return; + + myMP3.play(soundNr); + delay(1000); + +} + + + + +void MP3Sound::playSound(int soundNr) +{ + if((soundNr > NR_SOUNDFILES) || (active_sounds.size() == BUFFERSIZE) ) return; + + active_sounds.push_back(soundNr); + +} + + +int MP3Sound::sounds2play() +{ + + + return active_sounds.size(); + + +} + + + +int MP3Sound::processSounds() +{ + int n = active_sounds.size(); + if (n == 0) return(n); + if (myMP3.isPlaying()) return(n); + + int file2play = active_sounds.back(); + myMP3.play(file2play); + active_sounds.pop_back(); + + return active_sounds.size(); + +} \ No newline at end of file diff --git a/Firmware/LowLevel/src/ui_datatypes.h b/Firmware/LowLevel/src/ui_datatypes.h index e55e6409..61f1cddd 100644 --- a/Firmware/LowLevel/src/ui_datatypes.h +++ b/Firmware/LowLevel/src/ui_datatypes.h @@ -1,3 +1,19 @@ +// Created by Elmar Elflein on 3/07/22. +// Copyright (c) 2022 Elmar Elflein. All rights reserved. +// +// This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +// +// Feel free to use the design in your private/educational projects, but don't try to sell the design or products based on it without getting my consent first. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// #ifndef _UI_DATATYPES_H_ #define _UI_DATATYPES_H_