diff --git a/CMakeLists.txt b/CMakeLists.txt index 53311e9d981bc77ffbd23d942d41ec22f727eca0..e8d9af4bd870c8f526e8d14396fb65c98c6b655f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,7 +118,6 @@ add_executable(test-trace-logger src/tests/test-trace-logger.cpp) sbs_target(test-trace-logger stm32f429zi_stm32f4discovery) add_executable(test-hil src/tests/hil/test-hil.cpp) -target_compile_definitions(test-hil PRIVATE HILTest) sbs_target(test-hil stm32f767zi_compute_unit) #-----------------------------------------------------------------------------# diff --git a/src/shared/hil/Events.h b/src/shared/hil/Events.h deleted file mode 100644 index 9571ef54aeb0ff4317bef283baf6d403d53bf1ef..0000000000000000000000000000000000000000 --- a/src/shared/hil/Events.h +++ /dev/null @@ -1,293 +0,0 @@ -/* Copyright (c) 2018-2022 Skyward Experimental Rocketry - * Author: Alberto Nidasio - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -#pragma once - -#include <events/Event.h> - -#include <iostream> -#include <map> -#include <string> -#include <vector> - -namespace Common -{ - -enum Events : uint8_t -{ - ABK_DISABLE = Boardcore::EV_FIRST_CUSTOM, - ABK_OPEN, - ABK_RESET, - ABK_SHADOW_MODE_TIMEOUT, - ABK_WIGGLE, - ADA_CALIBRATE, - ADA_PRESS_STAB_TIMEOUT, - ADA_READY, - ADA_FORCE_START, - ADA_FORCE_STOP, - ADA_SHADOW_MODE_TIMEOUT, - ADA_APOGEE_DETECTED, - MEA_SHUTDOWN_DETECTED, - DPL_CUT_DROGUE, - DPL_CUT_TIMEOUT, - DPL_NC_OPEN, - DPL_NC_RESET, - DPL_SERVO_ACTUATION_DETECTED, - DPL_WIGGLE, - DPL_WES_CAL_DONE, - CAN_FORCE_INIT, - CAN_ARM, - CAN_ENTER_TEST_MODE, - CAN_EXIT_TEST_MODE, - CAN_CALIBRATE, - CAN_DISARM, - CAN_LIFTOFF, - CAN_APOGEE_DETECTED, - CAN_IGNITION, - FLIGHT_APOGEE_DETECTED, - FLIGHT_ARMED, - FLIGHT_DROGUE_DESCENT, - FLIGHT_DISARMED, - FLIGHT_DPL_ALT_DETECTED, - FLIGHT_ERROR_DETECTED, - FLIGHT_LANDING_DETECTED, - FLIGHT_LANDING_TIMEOUT, - FLIGHT_LAUNCH_PIN_DETACHED, - FLIGHT_LIFTOFF, - FLIGHT_MOTOR_SHUTDOWN, - FLIGHT_MISSION_TIMEOUT, - FLIGHT_NC_DETACHED, - FLIGHT_WING_DESCENT, - FMM_ASCENDING, - FMM_ALGOS_CAL_DONE, - FMM_STOP_LOGGING, - FMM_INIT_OK, - FMM_INIT_ERROR, - FMM_CALIBRATE, - FMM_ALGOS_CALIBRATE, - FMM_SENSORS_CAL_DONE, - FMM_READY, - FSR_STATS_TIMEOUT, - NAS_CALIBRATE, - NAS_READY, - NAS_FORCE_START, - NAS_FORCE_STOP, - TMTC_ARM, - TMTC_DISARM, - TMTC_CALIBRATE, - TMTC_FORCE_INIT, - TMTC_FORCE_LAUNCH, - TMTC_FORCE_LANDING, - TMTC_FORCE_APOGEE, - TMTC_FORCE_EXPULSION, - TMTC_FORCE_DEPLOYMENT, - TMTC_START_LOGGING, - TMTC_STOP_LOGGING, - TMTC_RESET_BOARD, - TMTC_ENTER_TEST_MODE, - TMTC_EXIT_TEST_MODE, - TMTC_START_RECORDING, - TMTC_STOP_RECORDING, - MOTOR_START_TARS, - MOTOR_STOP_TARS, - MOTOR_OPEN_VENTING_VALVE, - MOTOR_CLOSE_VENTING_VALVE, - MOTOR_OPEN_FILLING_VALVE, - MOTOR_CLOSE_FILLING_VALVE, - MOTOR_OPEN_RELEASE_VALVE, - MOTOR_CLOSE_RELEASE_VALVE, - MOTOR_DISCONNECT, - MOTOR_IGNITION, - MOTOR_OPEN_FEED_VALVE, - MOTOR_CLOSE_FEED_VALVE, - MOTOR_MANUAL_ACTION, - MOTOR_OPEN_OXIDANT, - MOTOR_SHADOW_MODE_TIMEOUT, - TARS_WASHING_DONE, - TARS_CHECK_PRESSURE_STABILIZE, - TARS_PRESSURE_STABILIZED, - TARS_FILLING_DONE, - TARS_REFINING_DONE, - ALTITUDE_TRIGGER_ALTITUDE_REACHED, - LAST_EVENT -}; - -inline std::string getEventString(uint8_t event) -{ - static const std::map<uint8_t, std::string> event_string_map{ - {ABK_DISABLE, "ABK_DISABLE"}, - {ABK_OPEN, "ABK_OPEN"}, - {ABK_RESET, "ABK_RESET"}, - {ABK_SHADOW_MODE_TIMEOUT, "ABK_SHADOW_MODE_TIMEOUT"}, - {ABK_WIGGLE, "ABK_WIGGLE"}, - {ADA_CALIBRATE, "ADA_CALIBRATE"}, - {ADA_PRESS_STAB_TIMEOUT, "ADA_PRESS_STAB_TIMEOUT"}, - {ADA_READY, "ADA_READY"}, - {ADA_FORCE_START, "ADA_FORCE_START"}, - {ADA_FORCE_STOP, "ADA_FORCE_STOP"}, - {ADA_SHADOW_MODE_TIMEOUT, "ADA_SHADOW_MODE_TIMEOUT"}, - {ADA_APOGEE_DETECTED, "ADA_APOGEE_DETECTED"}, - {MEA_SHUTDOWN_DETECTED, "MEA_SHUTDOWN_DETECTED"}, - {DPL_CUT_DROGUE, "DPL_CUT_DROGUE"}, - {DPL_CUT_TIMEOUT, "DPL_CUT_TIMEOUT"}, - {DPL_NC_OPEN, "DPL_NC_OPEN"}, - {DPL_NC_RESET, "DPL_NC_RESET"}, - {DPL_SERVO_ACTUATION_DETECTED, "DPL_SERVO_ACTUATION_DETECTED"}, - {DPL_WIGGLE, "DPL_WIGGLE"}, - {DPL_WES_CAL_DONE, "DPL_WES_CAL_DONE"}, - {CAN_FORCE_INIT, "CAN_FORCE_INIT"}, - {CAN_ARM, "CAN_ARM"}, - {CAN_ENTER_TEST_MODE, "CAN_ENTER_TEST_MODE"}, - {CAN_EXIT_TEST_MODE, "CAN_EXIT_TEST_MODE"}, - {CAN_CALIBRATE, "CAN_CALIBRATE"}, - {CAN_DISARM, "CAN_DISARM"}, - {CAN_LIFTOFF, "CAN_LIFTOFF"}, - {CAN_APOGEE_DETECTED, "CAN_APOGEE_DETECTED"}, - {CAN_IGNITION, "CAN_IGNITION"}, - {FLIGHT_APOGEE_DETECTED, "FLIGHT_APOGEE_DETECTED"}, - {FLIGHT_ARMED, "FLIGHT_ARMED"}, - {FLIGHT_DROGUE_DESCENT, "FLIGHT_DROGUE_DESCENT"}, - {FLIGHT_DISARMED, "FLIGHT_DISARMED"}, - {FLIGHT_DPL_ALT_DETECTED, "FLIGHT_DPL_ALT_DETECTED"}, - {FLIGHT_ERROR_DETECTED, "FLIGHT_ERROR_DETECTED"}, - {FLIGHT_LANDING_DETECTED, "FLIGHT_LANDING_DETECTED"}, - {FLIGHT_LAUNCH_PIN_DETACHED, "FLIGHT_LAUNCH_PIN_DETACHED"}, - {FLIGHT_LIFTOFF, "FLIGHT_LIFTOFF"}, - {FLIGHT_MOTOR_SHUTDOWN, "FLIGHT_MOTOR_SHUTDOWN"}, - {FLIGHT_LANDING_TIMEOUT, "FLIGHT_LANDING_TIMEOUT"}, - {FLIGHT_NC_DETACHED, "FLIGHT_NC_DETACHED"}, - {FLIGHT_MISSION_TIMEOUT, "FLIGHT_MISSION_TIMEOUT"}, - {FLIGHT_WING_DESCENT, "FLIGHT_WING_DESCENT"}, - {FMM_ASCENDING, "FMM_ASCENDING"}, - {FMM_ALGOS_CAL_DONE, "FMM_ALGOS_CAL_DONE"}, - {FMM_STOP_LOGGING, "FMM_STOP_LOGGING"}, - {FMM_INIT_OK, "FMM_INIT_OK"}, - {FMM_INIT_ERROR, "FMM_INIT_ERROR"}, - {FMM_CALIBRATE, "FMM_CALIBRATE"}, - {FMM_ALGOS_CALIBRATE, "FMM_ALGOS_CALIBRATE"}, - {FMM_SENSORS_CAL_DONE, "FMM_SENSORS_CAL_DONE"}, - {FMM_READY, "FMM_READY"}, - {FSR_STATS_TIMEOUT, "FSR_STATS_TIMEOUT"}, - {NAS_CALIBRATE, "NAS_CALIBRATE"}, - {NAS_FORCE_START, "NAS_FORCE_START"}, - {NAS_FORCE_STOP, "NAS_FORCE_STOP"}, - {NAS_READY, "NAS_READY"}, - {TMTC_ARM, "TMTC_ARM"}, - {TMTC_DISARM, "TMTC_DISARM"}, - {TMTC_CALIBRATE, "TMTC_CALIBRATE"}, - {TMTC_FORCE_INIT, "TMTC_FORCE_INIT"}, - {TMTC_FORCE_LAUNCH, "TMTC_FORCE_LAUNCH"}, - {TMTC_FORCE_LANDING, "TMTC_FORCE_LANDING"}, - {TMTC_FORCE_APOGEE, "TMTC_FORCE_APOGEE"}, - {TMTC_FORCE_EXPULSION, "TMTC_FORCE_EXPULSION"}, - {TMTC_FORCE_DEPLOYMENT, "TMTC_FORCE_DEPLOYMENT"}, - {TMTC_START_LOGGING, "TMTC_START_LOGGING"}, - {TMTC_STOP_LOGGING, "TMTC_STOP_LOGGING"}, - {TMTC_RESET_BOARD, "TMTC_RESET_BOARD"}, - {TMTC_ENTER_TEST_MODE, "TMTC_ENTER_TEST_MODE"}, - {TMTC_EXIT_TEST_MODE, "TMTC_EXIT_TEST_MODE"}, - {TMTC_START_RECORDING, "TMTC_START_RECORDING"}, - {TMTC_STOP_RECORDING, "TMTC_STOP_RECORDING"}, - {MOTOR_START_TARS, "MOTOR_START_TARS"}, - {MOTOR_STOP_TARS, "MOTOR_STOP_TARS"}, - {MOTOR_OPEN_VENTING_VALVE, "MOTOR_OPEN_VENTING_VALVE"}, - {MOTOR_CLOSE_VENTING_VALVE, "MOTOR_CLOSE_VENTING_VALVE"}, - {MOTOR_OPEN_FILLING_VALVE, "MOTOR_OPEN_FILLING_VALVE"}, - {MOTOR_CLOSE_FILLING_VALVE, "MOTOR_CLOSE_FILLING_VALVE"}, - {MOTOR_OPEN_RELEASE_VALVE, "MOTOR_OPEN_RELEASE_VALVE"}, - {MOTOR_CLOSE_RELEASE_VALVE, "MOTOR_CLOSE_RELEASE_VALVE"}, - {MOTOR_DISCONNECT, "MOTOR_DISCONNECT"}, - {MOTOR_IGNITION, "MOTOR_IGNITION"}, - {MOTOR_OPEN_FEED_VALVE, "MOTOR_OPEN_FEED_VALVE"}, - {MOTOR_CLOSE_FEED_VALVE, "MOTOR_CLOSE_FEED_VALVE"}, - {MOTOR_MANUAL_ACTION, "MOTOR_MANUAL_ACTION"}, - {MOTOR_OPEN_OXIDANT, "MOTOR_OPEN_OXIDANT"}, - {MOTOR_SHADOW_MODE_TIMEOUT, "MOTOR_SHADOW_MODE_TIMEOUT"}, - {TARS_WASHING_DONE, "TARS_WASHING_DONE"}, - {TARS_CHECK_PRESSURE_STABILIZE, "TARS_CHECK_PRESSURE_STABILIZE"}, - {TARS_PRESSURE_STABILIZED, "TARS_PRESSURE_STABILIZED"}, - {TARS_FILLING_DONE, "TARS_FILLING_DONE"}, - {TARS_REFINING_DONE, "TARS_REFINING_DONE"}, - {ALTITUDE_TRIGGER_ALTITUDE_REACHED, - "ALTITUDE_TRIGGER_ALTITUDE_REACHED"}, - {LAST_EVENT, "LAST_EVENT"}, - }; - - auto it = event_string_map.find(event); - return it == event_string_map.end() ? "EV_UNKNOWN" : it->second; -} - -struct LiftoffEvent -{ - uint64_t timestamp; - - static std::string header() { return "timestamp\n"; } - - void print(std::ostream& os) const { os << timestamp << "\n"; } -}; - -struct ApogeeEvent -{ - uint64_t timestamp; - - static std::string header() { return "timestamp\n"; } - - void print(std::ostream& os) const { os << timestamp << "\n"; } -}; - -struct NoseconeEvent -{ - uint64_t timestamp; - - static std::string header() { return "timestamp\n"; } - - void print(std::ostream& os) const { os << timestamp << "\n"; } -}; - -struct ExpulsionEvent -{ - uint64_t timestamp; - - static std::string header() { return "timestamp\n"; } - - void print(std::ostream& os) const { os << timestamp << "\n"; } -}; - -struct MainEvent -{ - uint64_t timestamp; - - static std::string header() { return "timestamp\n"; } - - void print(std::ostream& os) const { os << timestamp << "\n"; } -}; - -struct LandingEvent -{ - uint64_t timestamp; - - static std::string header() { return "timestamp\n"; } - - void print(std::ostream& os) const { os << timestamp << "\n"; } -}; - -} // namespace Common diff --git a/src/shared/hil/HIL.h b/src/shared/hil/HIL.h index d5e74a07ace7425a7e54aaa72a8609c07fe9651d..e9ba8b49bcbb7199e649afcf82e8cc2dc9f40b8a 100644 --- a/src/shared/hil/HIL.h +++ b/src/shared/hil/HIL.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023 Skyward Experimental Rocketry +/* Copyright (c) 2021-2024 Skyward Experimental Rocketry * Authors: Luca Conterio, Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -23,46 +23,106 @@ #pragma once #include <Singleton.h> +#include <diagnostic/SkywardStack.h> #include <utils/ModuleManager/ModuleManager.hpp> -#include "HILConfig.h" -#include "HILFlightPhasesManager.h" +#include "HILPhasesManager.h" #include "HILTransceiver.h" /** * @brief Single interface to the hardware-in-the-loop framework. */ -class HIL : public Boardcore::Module +template <class FlightPhases, class SimulatorData, class ActuatorData> +class HIL : public Boardcore::Module, public Boardcore::ActiveObject { public: - HIL(Boardcore::USART &hilSerial, - HILFlightPhasesManager *flightPhasesManager) - : flightPhasesManager(flightPhasesManager) + HIL(HILTransceiver<FlightPhases, SimulatorData, ActuatorData> + *hilTransceiver, + HILPhasesManager<FlightPhases, SimulatorData, ActuatorData> + *hilPhasesManager, + std::function<ActuatorData()> updateActuatorData, int updatePeriod) + : Boardcore::ActiveObject(Boardcore::STACK_MIN_FOR_SKYWARD, + miosix::PRIORITY_MAX - 1), + hilTransceiver(hilTransceiver), hilPhasesManager(hilPhasesManager), + updateActuatorData(updateActuatorData), updatePeriod(updatePeriod) { - simulator = new HILTransceiver(hilSerial); - } + if (!Boardcore::ModuleManager::getInstance().insert<HILTransceiverBase>( + hilTransceiver)) + { + LOG_ERR(logger, "HILTransceiver not inserted correctly"); + } - HILTransceiver *simulator; - HILFlightPhasesManager *flightPhasesManager; + if (!Boardcore::ModuleManager::getInstance() + .insert<HILPhasesManagerBase>(hilPhasesManager)) + { + LOG_ERR(logger, "HILPhasesManager not inserted correctly"); + } + } /** * @brief Start the needed hardware-in-the-loop components. */ - [[nodiscard]] bool start() + [[nodiscard]] bool start() override + { + bool initOk = true; + + if (!hilTransceiver->start()) + { + LOG_ERR(logger, "hilTransceiver started with errors"); + initOk = false; + } + + if (!hilPhasesManager->start()) + { + LOG_ERR(logger, "hilPhasesManager started with errors"); + initOk = false; + } + + if (!Boardcore::ActiveObject::start()) + { + LOG_ERR(logger, "hil started with errors"); + initOk = false; + } + + return initOk; + } + + void stop() { - return simulator->start() && flightPhasesManager->start(); + hilTransceiver->stop(); + hilPhasesManager->stop(); + Boardcore::ActiveObject::stop(); + LOG_INFO(logger, "HIL framework stopped"); } - void stop() { simulator->stop(); } + void waitStartSimulation() + { + LOG_INFO(logger, "Waiting for simulation to start..."); + while (!hilPhasesManager->isSimulationRunning()) + { + Thread::sleep(updatePeriod); + } + } - void send(HILConfig::ActuatorData actuatorData) + HILTransceiver<FlightPhases, SimulatorData, ActuatorData> *hilTransceiver; + HILPhasesManager<FlightPhases, SimulatorData, ActuatorData> + *hilPhasesManager; + +private: + void run() override { - simulator->setActuatorData(actuatorData); + while (!shouldStop()) + { + if (hilPhasesManager->isSimulationRunning()) + { + hilTransceiver->setActuatorData(updateActuatorData()); + } + Thread::sleep(updatePeriod); + } } - /** - * @brief Returns if all the schedulers are up and running - */ - bool isStarted(); + Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("HIL"); + std::function<ActuatorData()> updateActuatorData; + int updatePeriod; }; diff --git a/src/shared/hil/HILConfig.h b/src/shared/hil/HILConfig.h deleted file mode 100644 index bf731068f577dd8a9a6a6e64b7999ac1af54aa64..0000000000000000000000000000000000000000 --- a/src/shared/hil/HILConfig.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry - * Author: Emilio Corigliano - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -#pragma once - -/** - * @brief Configuration file that includes only the right structures described - * in the config file of the test. - * - * Usage: - * #elif <Flag> - * #include "<test-directory>/HILSimulationConfig.h" - * - * REMEMBER: - * when defining the entry in "CMakeLists" you should add - * target_compile_definitions(<test-directory> PRIVATE <Flag>) - * - * WARNING: - * You should always CLEAN your board before flashing a new entrypoint. Some - * flags could still be in memory - */ - -/* Hardware in the loop entrypoint */ -#if defined(HILTest) -#include "../tests/hil/HILSimulationConfig.h" -/* -#elif defined(HIL_<tuoFlag>) -#include "<test-directory>/HILSimulationConfig.h" -*/ -#else -#error You have add the flag of your configuration file for the HIL testing! -#endif diff --git a/src/shared/hil/HILFlightPhasesManager.cpp b/src/shared/hil/HILFlightPhasesManager.cpp deleted file mode 100644 index fa833297ca2fb916512142d35f53ab303cbfd936..0000000000000000000000000000000000000000 --- a/src/shared/hil/HILFlightPhasesManager.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* Copyright (c) 2021-2023 Skyward Experimental Rocketry - * Authors: Luca Conterio, Emilio Corigliano - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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 "HILFlightPhasesManager.h" - -#include <events/Event.h> - -#include "events/EventBroker.h" - -using namespace Common; -using namespace HILConfig; - -HILFlightPhasesManager::HILFlightPhasesManager() - : Boardcore::EventHandler(), - flagsFlightPhases({{FlightPhases::SIM_FLYING, false}, - {FlightPhases::SIM_ASCENT, false}, - {FlightPhases::SIM_BURNING, false}, - {FlightPhases::SIM_AEROBRAKES, false}, - {FlightPhases::SIM_PARA1, false}, - {FlightPhases::SIM_PARA2, false}, - {FlightPhases::SIMULATION_STARTED, false}, - {FlightPhases::CALIBRATION, false}, - {FlightPhases::CALIBRATION_OK, false}, - {FlightPhases::ARMED, false}, - {FlightPhases::LIFTOFF_PIN_DETACHED, false}, - {FlightPhases::LIFTOFF, false}, - {FlightPhases::AEROBRAKES, false}, - {FlightPhases::APOGEE, false}, - {FlightPhases::PARA1, false}, - {FlightPhases::PARA2, false}, - {FlightPhases::SIMULATION_STOPPED, false}}) -{ - prev_flagsFlightPhases = flagsFlightPhases; - - auto& eventBroker = Boardcore::EventBroker::getInstance(); - eventBroker.subscribe(this, TOPIC_ABK); - eventBroker.subscribe(this, TOPIC_ADA); - eventBroker.subscribe(this, TOPIC_MEA); - eventBroker.subscribe(this, TOPIC_DPL); - eventBroker.subscribe(this, TOPIC_CAN); - eventBroker.subscribe(this, TOPIC_FLIGHT); - eventBroker.subscribe(this, TOPIC_FMM); - eventBroker.subscribe(this, TOPIC_FSR); - eventBroker.subscribe(this, TOPIC_NAS); - eventBroker.subscribe(this, TOPIC_TMTC); - eventBroker.subscribe(this, TOPIC_MOTOR); - eventBroker.subscribe(this, TOPIC_TARS); - eventBroker.subscribe(this, TOPIC_ALT); -} - -void HILFlightPhasesManager::setCurrentPositionSource( - std::function<Boardcore::TimedTrajectoryPoint()> getCurrentPosition) -{ - this->getCurrentPosition = getCurrentPosition; -} - -bool HILFlightPhasesManager::isFlagActive(FlightPhases flag) -{ - return flagsFlightPhases[flag]; -} - -void HILFlightPhasesManager::registerToFlightPhase(FlightPhases flag, - TCallback func) -{ - callbacks[flag].push_back(func); -} - -void HILFlightPhasesManager::setFlagFlightPhase(FlightPhases flag, - bool isEnable) -{ - flagsFlightPhases[flag] = isEnable; -} - -void HILFlightPhasesManager::processFlags(FlightPhasesFlags hil_flags) -{ - updateSimulatorFlags(hil_flags); - - std::vector<FlightPhases> changed_flags; - - // set true when the first packet from the simulator arrives - if (isSetTrue(FlightPhases::SIMULATION_STARTED)) - { - t_start = Boardcore::TimestampTimer::getTimestamp(); - - TRACE("[HIL] ------- SIMULATION STARTED ! ------- \n"); - changed_flags.push_back(FlightPhases::SIMULATION_STARTED); - } - - if (flagsFlightPhases[FlightPhases::SIM_FLYING]) - { - if (isSetTrue(FlightPhases::SIM_FLYING)) - { - registerOutcomes(FlightPhases::SIM_FLYING); - TRACE("[HIL] ------- SIMULATOR LIFTOFF ! ------- \n"); - changed_flags.push_back(FlightPhases::SIM_FLYING); - } - } - - /* calling the callbacks subscribed to the changed flags */ - for (unsigned int i = 0; i < changed_flags.size(); i++) - { - std::vector<TCallback> callbacksToCall = callbacks[changed_flags[i]]; - for (unsigned int j = 0; j < callbacksToCall.size(); j++) - { - callbacksToCall[j](); - } - } - - prev_flagsFlightPhases = flagsFlightPhases; -} - -void HILFlightPhasesManager::registerOutcomes(FlightPhases phase) -{ - Boardcore::TimedTrajectoryPoint temp = getCurrentPosition(); - outcomes[phase] = Outcomes(temp.z, temp.vz); -} - -void HILFlightPhasesManager::printOutcomes() -{ - printf("OUTCOMES: (times dt from liftoff)\n\n"); - printf("Simulation time: %.3f [sec]\n\n", - (double)(t_stop - t_start) / 1000000.0f); - - printf("Motor stopped burning (simulation flag): \n"); - outcomes[FlightPhases::SIM_BURNING].print(t_liftoff); - - printf("Airbrakes exit shadowmode: \n"); - outcomes[FlightPhases::AEROBRAKES].print(t_liftoff); - - printf("Apogee: \n"); - outcomes[FlightPhases::APOGEE].print(t_liftoff); - - printf("Parachute 1: \n"); - outcomes[FlightPhases::PARA1].print(t_liftoff); - - printf("Parachute 2: \n"); - outcomes[FlightPhases::PARA2].print(t_liftoff); - - printf("Simulation Stopped: \n"); - outcomes[FlightPhases::SIMULATION_STOPPED].print(t_liftoff); - - // auto cpuMeter = Boardcore::CpuMeter::getCpuStats(); - // printf("max cpu usage: %+.3f\n", cpuMeter.maxValue); - // printf("avg cpu usage: %+.3f\n", cpuMeter.mean); - // printf("min free heap: %+.3lu\n", cpuMeter.minFreeHeap); - // printf("max free stack:%+.3lu\n", cpuMeter.minFreeStack); -} - -/** - * @brief Updates the flags of the object with the flags sent from matlab - * and checks for the apogee - */ -void HILFlightPhasesManager::updateSimulatorFlags(FlightPhasesFlags hil_flags) -{ - flagsFlightPhases[FlightPhases::SIM_ASCENT] = hil_flags.flag_ascent; - flagsFlightPhases[FlightPhases::SIM_FLYING] = hil_flags.flag_flight; - flagsFlightPhases[FlightPhases::SIM_BURNING] = hil_flags.flag_burning; - flagsFlightPhases[FlightPhases::SIM_AEROBRAKES] = hil_flags.flag_airbrakes; - flagsFlightPhases[FlightPhases::SIM_PARA1] = hil_flags.flag_para1; - flagsFlightPhases[FlightPhases::SIM_PARA2] = hil_flags.flag_para2; - - flagsFlightPhases[FlightPhases::SIMULATION_STOPPED] = - isSetFalse(FlightPhases::SIM_FLYING) || - prev_flagsFlightPhases[FlightPhases::SIMULATION_STOPPED]; -} - -void HILFlightPhasesManager::handleEvent(const Boardcore::Event& e) -{ - std::vector<FlightPhases> changed_flags; - - switch (e) - { - case FMM_INIT_ERROR: - printf("[HIL] ------- INIT FAILED ! ------- \n"); - case FMM_INIT_OK: - setFlagFlightPhase(FlightPhases::CALIBRATION, true); - TRACE("[HIL] ------- CALIBRATION ! ------- \n"); - changed_flags.push_back(FlightPhases::CALIBRATION); - break; - case FLIGHT_DISARMED: - setFlagFlightPhase(FlightPhases::CALIBRATION_OK, true); - TRACE("[HIL] CALIBRATION OK!\n"); - changed_flags.push_back(FlightPhases::CALIBRATION_OK); - break; - case FLIGHT_ARMED: - setFlagFlightPhase(FlightPhases::ARMED, true); - printf("[HIL] ------- READY TO LAUNCH ! ------- \n"); - changed_flags.push_back(FlightPhases::ARMED); - break; - case FLIGHT_LAUNCH_PIN_DETACHED: - setFlagFlightPhase(FlightPhases::LIFTOFF_PIN_DETACHED, true); - TRACE("[HIL] ------- LIFTOFF PIN DETACHED ! ------- \n"); - changed_flags.push_back(FlightPhases::LIFTOFF_PIN_DETACHED); - break; - case FLIGHT_LIFTOFF: - case TMTC_FORCE_LAUNCH: - t_liftoff = Boardcore::TimestampTimer::getTimestamp(); - printf("[HIL] ------- LIFTOFF -------: %f, %f \n", - getCurrentPosition().z, getCurrentPosition().vz); - changed_flags.push_back(FlightPhases::LIFTOFF); - break; - case ABK_SHADOW_MODE_TIMEOUT: - setFlagFlightPhase(FlightPhases::AEROBRAKES, true); - registerOutcomes(FlightPhases::AEROBRAKES); - TRACE("[HIL] ABK shadow mode timeout\n"); - changed_flags.push_back(FlightPhases::AEROBRAKES); - break; - case ADA_SHADOW_MODE_TIMEOUT: - TRACE("[HIL] ADA shadow mode timeout\n"); - break; - case ABK_DISABLE: - setFlagFlightPhase(FlightPhases::AEROBRAKES, false); - TRACE("[HIL] ABK disabled\n"); - break; - case FLIGHT_APOGEE_DETECTED: - case CAN_APOGEE_DETECTED: - setFlagFlightPhase(FlightPhases::AEROBRAKES, false); - registerOutcomes(FlightPhases::APOGEE); - printf("[HIL] ------- APOGEE DETECTED ! ------- %f, %f \n", - getCurrentPosition().z, getCurrentPosition().vz); - changed_flags.push_back(FlightPhases::APOGEE); - break; - case FLIGHT_DROGUE_DESCENT: - case TMTC_FORCE_EXPULSION: - setFlagFlightPhase(FlightPhases::PARA1, true); - registerOutcomes(FlightPhases::PARA1); - printf("[HIL] ------- PARA1 ! -------%f, %f \n", - getCurrentPosition().z, getCurrentPosition().vz); - changed_flags.push_back(FlightPhases::PARA1); - break; - case FLIGHT_WING_DESCENT: - case FLIGHT_DPL_ALT_DETECTED: - case TMTC_FORCE_DEPLOYMENT: - setFlagFlightPhase(FlightPhases::PARA1, false); - setFlagFlightPhase(FlightPhases::PARA2, true); - registerOutcomes(FlightPhases::PARA2); - printf("[HIL] ------- PARA2 ! ------- %f, %f \n", - getCurrentPosition().z, getCurrentPosition().vz); - changed_flags.push_back(FlightPhases::PARA2); - break; - case FLIGHT_LANDING_DETECTED: - case TMTC_FORCE_LANDING: - t_stop = Boardcore::TimestampTimer::getTimestamp(); - setFlagFlightPhase(FlightPhases::PARA2, false); - setFlagFlightPhase(FlightPhases::SIMULATION_STOPPED, true); - changed_flags.push_back(FlightPhases::SIMULATION_STOPPED); - registerOutcomes(FlightPhases::SIMULATION_STOPPED); - TRACE("[HIL] ------- SIMULATION STOPPED ! -------: %f \n\n\n", - (double)t_stop / 1000000.0f); - printOutcomes(); - break; - default: - TRACE("%s invalid event\n", getEventString(e).c_str()); - } - - /* calling the callbacks subscribed to the changed flags */ - for (unsigned int i = 0; i < changed_flags.size(); i++) - { - std::vector<TCallback> callbacksToCall = callbacks[changed_flags[i]]; - for (unsigned int j = 0; j < callbacksToCall.size(); j++) - { - callbacksToCall[j](); - } - } - - prev_flagsFlightPhases = flagsFlightPhases; -} - -bool HILFlightPhasesManager::isSetTrue(FlightPhases phase) -{ - return flagsFlightPhases[phase] && !prev_flagsFlightPhases[phase]; -} - -bool HILFlightPhasesManager::isSetFalse(FlightPhases phase) -{ - return !flagsFlightPhases[phase] && prev_flagsFlightPhases[phase]; -} diff --git a/src/shared/hil/HILFlightPhasesManager.h b/src/shared/hil/HILPhasesManager.h similarity index 53% rename from src/shared/hil/HILFlightPhasesManager.h rename to src/shared/hil/HILPhasesManager.h index 68390d9839b1cd4d06f77cebb3f50136d590fb2d..0131f20d8fa9e5fecfae99de44f15948629d83d3 100644 --- a/src/shared/hil/HILFlightPhasesManager.h +++ b/src/shared/hil/HILPhasesManager.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023 Skyward Experimental Rocketry +/* Copyright (c) 2021-2024 Skyward Experimental Rocketry * Authors: Luca Conterio, Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,40 +26,13 @@ #include <drivers/timer/TimestampTimer.h> #include <events/Event.h> #include <events/EventHandler.h> -#include <hil/HILTransceiver.h> #include <miosix.h> #include <iostream> #include <map> - -#include "Events.h" +#include <utils/ModuleManager/ModuleManager.hpp> typedef std::function<void()> TCallback; -class HILTransceiver; - -enum class FlightPhases -{ - // simulator flags - SIM_FLYING, - SIM_ASCENT, - SIM_BURNING, - SIM_AEROBRAKES, - SIM_PARA1, - SIM_PARA2, - - // flight flags - SIMULATION_STARTED, - CALIBRATION, - CALIBRATION_OK, - ARMED, - LIFTOFF_PIN_DETACHED, - LIFTOFF, - AEROBRAKES, - APOGEE, - PARA1, - PARA2, - SIMULATION_STOPPED -}; struct Outcomes { @@ -81,53 +54,103 @@ struct Outcomes } }; +class HILPhasesManagerBase : public Boardcore::EventHandler, + public Boardcore::Module +{ +public: + explicit HILPhasesManagerBase( + std::function<Boardcore::TimedTrajectoryPoint()> getCurrentPosition) + : Boardcore::EventHandler(), getCurrentPosition(getCurrentPosition) + { + } + + bool isSimulationRunning() { return (t_start != 0) && (t_stop == 0); } + + virtual void simulationStarted() + { + t_start = Boardcore::TimestampTimer::getTimestamp(); + LOG_INFO(logger, "SIMULATION STARTED!"); + } + + virtual void liftoff() + { + t_liftoff = Boardcore::TimestampTimer::getTimestamp(); + LOG_INFO(logger, "LIFTOFF!"); + } + + virtual void simulationStopped() + { + t_stop = Boardcore::TimestampTimer::getTimestamp(); + LOG_INFO(logger, "SIMULATION STOPPED!"); + } + +protected: + uint64_t t_start = 0; + uint64_t t_liftoff = 0; + uint64_t t_stop = 0; + std::function<Boardcore::TimedTrajectoryPoint()> getCurrentPosition; + Boardcore::PrintLogger logger = + Boardcore::Logging::getLogger("HILPhasesManager"); +}; + /** * @brief Singleton object that manages all the phases of the simulation. * After his instantiation we need to set the source of the current position in * order to be able to save the outcomes for each event. */ -class HILFlightPhasesManager : public Boardcore::EventHandler, - public Boardcore::Module +template <class FlightPhases, class SimulatorData, class ActuatorData> +class HILPhasesManager : public HILPhasesManagerBase { - using FlightPhasesFlags = HILConfig::SimulatorData::Flags; - public: - HILFlightPhasesManager(); + explicit HILPhasesManager( + std::function<Boardcore::TimedTrajectoryPoint()> getCurrentPosition) + : HILPhasesManagerBase(getCurrentPosition) + { + } - void setCurrentPositionSource( - std::function<Boardcore::TimedTrajectoryPoint()> getCurrentPosition); + bool isFlagActive(FlightPhases flag) { return flagsFlightPhases[flag]; } - bool isFlagActive(FlightPhases flag); + void registerToFlightPhase(FlightPhases flag, TCallback func) + { + callbacks[flag].push_back(func); + } - void registerToFlightPhase(FlightPhases flag, TCallback func); + void setFlagFlightPhase(FlightPhases flag, bool isEnable) + { + flagsFlightPhases[flag] = isEnable; + } - void setFlagFlightPhase(FlightPhases flag, bool isEnable); + virtual void processFlags(const SimulatorData& hil_flags) = 0; - virtual void processFlags(FlightPhasesFlags hil_flags); + virtual void printOutcomes() = 0; protected: - virtual void handleEvent(const Boardcore::Event& e) override; - - virtual void registerOutcomes(FlightPhases phase); - - virtual void printOutcomes(); + virtual void handleEvent(const Boardcore::Event& e) = 0; /** - * @brief Updates the flags of the object with the flags sent from matlab - * and checks for the apogee + * @brief Updates the flags of the object with the flags sent from + * matlab and checks for the apogee */ - virtual void updateSimulatorFlags(FlightPhasesFlags hil_flags); + virtual void updateSimulatorFlags(const SimulatorData& hil_flags) = 0; - bool isSetTrue(FlightPhases phase); + void registerOutcomes(FlightPhases phase) + { + Boardcore::TimedTrajectoryPoint temp = getCurrentPosition(); + outcomes[phase] = Outcomes(temp.z, temp.vz); + } - bool isSetFalse(FlightPhases phase); + bool isSetTrue(FlightPhases phase) + { + return flagsFlightPhases[phase] && !prev_flagsFlightPhases[phase]; + } + + bool isSetFalse(FlightPhases phase) + { + return !flagsFlightPhases[phase] && prev_flagsFlightPhases[phase]; + } - uint64_t t_start = 0; - uint64_t t_liftoff = 0; - uint64_t t_stop = 0; std::map<FlightPhases, bool> flagsFlightPhases; std::map<FlightPhases, bool> prev_flagsFlightPhases; std::map<FlightPhases, vector<TCallback>> callbacks; std::map<FlightPhases, Outcomes> outcomes; - std::function<Boardcore::TimedTrajectoryPoint()> getCurrentPosition; }; diff --git a/src/shared/hil/HILTransceiver.cpp b/src/shared/hil/HILTransceiver.cpp deleted file mode 100644 index 8eb5cc26dc636c7848d4c052e726935942cb2c07..0000000000000000000000000000000000000000 --- a/src/shared/hil/HILTransceiver.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry - * Author: Emilio Corigliano - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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 "HIL.h" -#include "drivers/usart/USART.h" - -using namespace HILConfig; - -/** - * @brief Construct a serial connection attached to a control algorithm - */ -HILTransceiver::HILTransceiver(Boardcore::USART &hilSerial) - : hilSerial(hilSerial), actuatorData{} -{ -} - -/** - * @brief sets the actuator data and then wakes up the MatlabTransceiver - * thread in order to send the data back to the simulator (called by the - * control algorithm) - * @param actuatorData sets the data that will be sent to the simulator - */ -void HILTransceiver::setActuatorData(ActuatorData actuatorData) -{ - this->actuatorData = actuatorData; - updated = true; - condVar.signal(); -} - -/** - * @brief returns the reference of the SimulatorData - * - * @return reference to the data simulated by matlab - */ -SimulatorData *HILTransceiver::getSensorData() { return &sensorData; } - -/** - * @brief adds to the resetSampleCounter list an object that has to be - * notified when a new packet of data is arrived from the simulator - * - * @param t SimTimestampManagement object - */ -void HILTransceiver::addResetSampleCounter(HILTimestampManagement *t) -{ - sensorsTimestamp.push_back(t); -} - -/** - * @brief The thread deals with the communication between the simulator and the - * board. - * - * TODO: Check: - * The first read is done in the init() function - * - * After the first time the data is received, the loop of this thread: - * - Reads the simulated data and copies them in the SensorData structure; - * - Notifies every sensor that new data arrived; - * - Waits for the control algorithms to update the actuator data; - * - Sends back the value to the simulator. - */ -void HILTransceiver::run() -{ - TRACE("[HILT] Transceiver started\n"); - bool lostUpdate = false; - hilSerial.clearQueue(); - - while (true) - { - // Pausing the kernel in order to copy the data in the shared structure - { - SimulatorData tempData; - miosix::led3On(); - if (!hilSerial.readBlocking(&tempData, sizeof(SimulatorData))) - { - TRACE("Failed Serial read\n"); - } - hilSerial.clearQueue(); - miosix::led3Off(); - - miosix::PauseKernelLock kLock; - sensorData = tempData; - - if (updated) - { - lostUpdate = true; - updated = false; // We want the last computation - } - } - - // If this is the first packet to be received, then update the flight - // phase manager - if (!receivedFirstPacket) - { - receivedFirstPacket = true; - Boardcore::ModuleManager::getInstance() - .get<HIL>() - ->flightPhasesManager->setFlagFlightPhase( - FlightPhases::SIMULATION_STARTED, true); - } - - // Notify all sensors that a new set of data is arrived - //[REVIEW] Could be moved in HILFlightPhasesManager - for (auto st : sensorsTimestamp) - st->resetSampleCounter(); - - // Trigger events relative to the flight phases - Boardcore::ModuleManager::getInstance() - .get<HIL>() - ->flightPhasesManager->processFlags(sensorData.flags); - - if (lostUpdate) - { - // This means also that the number of samples used for the mean sent - // to the HIL simulator is made up of more than the number of - // samples we though - TRACE("[HILT] lost updates!\n"); - lostUpdate = false; - } - - waitActuatorData(); - miosix::led2On(); - hilSerial.write(&actuatorData, sizeof(ActuatorData)); - miosix::led2Off(); - } -} - -/** - * @brief Waits for the control algorithms to update actuatorData. - */ -void HILTransceiver::waitActuatorData() -{ - miosix::Lock<miosix::FastMutex> l(mutex); - while (!updated) - { - condVar.wait(l); - } - updated = false; -} diff --git a/src/shared/hil/HILTransceiver.h b/src/shared/hil/HILTransceiver.h index 4306f9c8ff91043300f74955027621a672d6e81e..9e15e45a960229fff1079937b0eb6ce739a6908d 100644 --- a/src/shared/hil/HILTransceiver.h +++ b/src/shared/hil/HILTransceiver.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry +/* Copyright (c) 2020-2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -25,36 +25,26 @@ #include <ActiveObject.h> #include <drivers/timer/TimestampTimer.h> #include <drivers/usart/USART.h> -#include <hil/HILConfig.h> #include <sensors/HILSensors/HILTimestampManagement.h> #include <utils/Debug.h> -/** - * @brief HILTransceiver is a Singleton and provides an easy interface for - * the control algorithms to send and receive data during a simulation - */ -class HILTransceiver : public Boardcore::ActiveObject +#include "HIL.h" +#include "drivers/usart/USART.h" + +template <class FlightPhases, class SimulatorData, class ActuatorData> +class HIL; + +class HILTransceiverBase : public Boardcore::ActiveObject, + public Boardcore::Module { public: /** * @brief Construct a serial connection attached to a control algorithm */ - explicit HILTransceiver(Boardcore::USART &hilSerial); - - /** - * @brief sets the actuator data and then wakes up the MatlabTransceiver - * thread in order to send the data back to the simulator (called by the - * control algorithm) - * @param actuatorData sets the data that will be sent to the simulator - */ - void setActuatorData(HILConfig::ActuatorData actuatorData); - - /** - * @brief returns the reference of the SimulatorData - * - * @return reference to the data simulated by matlab - */ - HILConfig::SimulatorData *getSensorData(); + explicit HILTransceiverBase(Boardcore::USART &hilSerial) + : hilSerial(hilSerial) + { + } /** * @brief adds to the resetSampleCounter list an object that has to be @@ -62,22 +52,166 @@ public: * * @param t SimTimestampManagement object */ - void addResetSampleCounter(HILTimestampManagement *t); + void addResetSampleCounter(HILTimestampManagement *t) + { + sensorsTimestamp.push_back(t); + } -private: /** - * @brief Waits for the control algorithm(s) to update actuatorData. + * @brief Returns the number of lost updates. + * @return the number of updates lost due to communication with the + * simulator. */ - void waitActuatorData(); + int getLostUpdates() { return nLostUpdates; } - void run() override; +protected: + /** + * @brief Waits for the control algorithm(s) to update actuatorData. + */ + void waitActuatorData() + { + miosix::Lock<miosix::FastMutex> l(mutex); + while (!updated) + { + condVar.wait(l); + } + updated = false; + } Boardcore::USART &hilSerial; bool receivedFirstPacket = false; bool updated = false; - HILConfig::SimulatorData sensorData; - HILConfig::ActuatorData actuatorData; + int nLostUpdates = 0; std::vector<HILTimestampManagement *> sensorsTimestamp; miosix::FastMutex mutex; miosix::ConditionVariable condVar; + Boardcore::PrintLogger logger = + Boardcore::Logging::getLogger("HILTransceiver"); +}; + +/** + * @brief HILTransceiver is a Singleton and provides an easy interface for + * the control algorithms to send and receive data during a simulation + */ +template <class FlightPhases, class SimulatorData, class ActuatorData> +class HILTransceiver : public HILTransceiverBase +{ +public: + /** + * @brief Construct a serial connection attached to a control algorithm + */ + explicit HILTransceiver(Boardcore::USART &hilSerial) + : HILTransceiverBase(hilSerial), actuatorData() + { + } + + /** + * @brief sets the actuator data and then wakes up the + * MatlabTransceiver thread in order to send the data back to the + * simulator (called by the control algorithm) + * @param actuatorData sets the data that will be sent to the + * simulator + */ + void setActuatorData(ActuatorData actuatorData) + { + miosix::Lock<miosix::FastMutex> l(mutex); + + // If already updated increment lost updates + if (updated) + { + nLostUpdates++; + } + + this->actuatorData = actuatorData; + updated = true; + condVar.signal(); + } + + /** + * @brief returns the reference of the SimulatorData + * + * @return reference to the data simulated by matlab + */ + const SimulatorData *getSensorData() { return &simulatorData; } + +private: + void run() override; + + SimulatorData simulatorData; + ActuatorData actuatorData; }; + +/** + * @brief The thread deals with the communication between the simulator and the + * board. + * + * After the first time the data is received, the loop of this thread: + * - Reads the simulated data and copies them in the SensorData structure; + * - Notifies every sensor that new data arrived; + * - Waits for the control algorithms to update the actuator data; + * - Sends back the value to the simulator. + */ +template <class FlightPhases, class SimulatorData, class ActuatorData> +void HILTransceiver<FlightPhases, SimulatorData, ActuatorData>::run() +{ + LOG_INFO(logger, "HIL Transceiver started"); + auto *hilPhasesManager = + Boardcore::ModuleManager::getInstance() + .get<HIL<FlightPhases, SimulatorData, ActuatorData>>() + ->hilPhasesManager; + bool lostUpdate = false; + hilSerial.clearQueue(); + + while (!shouldStop()) + { + // Pausing the kernel in order to copy the data in the shared structure + { + SimulatorData tempData; + miosix::led3On(); + if (!hilSerial.readBlocking(&tempData, sizeof(SimulatorData))) + { + LOG_ERR(logger, "Failed serial read"); + } + hilSerial.clearQueue(); + miosix::led3Off(); + + miosix::PauseKernelLock kLock; + simulatorData = tempData; + + if (updated) + { + lostUpdate = true; + updated = false; // We want the last computation + } + } + + // If this is the first packet to be received, then update the flight + // phase manager + if (!receivedFirstPacket) + { + receivedFirstPacket = true; + hilPhasesManager->simulationStarted(); + } + + // Notify all sensors that a new set of data is arrived + for (auto st : sensorsTimestamp) + st->resetSampleCounter(); + + // Trigger events relative to the flight phases + hilPhasesManager->processFlags(simulatorData); + + if (lostUpdate) + { + // This means also that the number of samples used for the mean sent + // to the HIL simulator is made up of more than the number of + // samples we though + LOG_WARN(logger, "Lost updates"); + lostUpdate = false; + } + + waitActuatorData(); + miosix::led2On(); + hilSerial.write(&actuatorData, sizeof(ActuatorData)); + miosix::led2Off(); + } +} diff --git a/src/shared/sensors/HILSensors/HILAccelerometer.h b/src/shared/sensors/HILSensors/HILAccelerometer.h index 8542349657720ffe72084f10d6840d34ea49de67..604843ff04db93c2f10aec9d29c241055c730536 100644 --- a/src/shared/sensors/HILSensors/HILAccelerometer.h +++ b/src/shared/sensors/HILSensors/HILAccelerometer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry +/* Copyright (c) 2020-2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,6 +26,12 @@ #include "HILSensor.h" +template <int N_DATA> +struct AccelerometerSimulatorData +{ + float measures[N_DATA][3]; +}; + /** * @brief fake accelerometer sensor used for the simulation. * @@ -33,11 +39,19 @@ * OBSW during the flight, using fake sensors classes instead of the real * ones, taking their data from the data received from a simulator. */ -class HILAccelerometer : public HILSensor<HILAccelerometerData> +template <int N_DATA> +class HILAccelerometer + : public HILSensor<HILAccelerometerData, AccelerometerSimulatorData<N_DATA>, + N_DATA> { + using Base = HILSensor<HILAccelerometerData, + AccelerometerSimulatorData<N_DATA>, N_DATA>; + public: - HILAccelerometer(int n_data_sensor, void *sensorData) - : HILSensor(n_data_sensor, sensorData) + explicit HILAccelerometer( + const AccelerometerSimulatorData<N_DATA> *sensorData) + : HILSensor<HILAccelerometerData, AccelerometerSimulatorData<N_DATA>, + N_DATA>(sensorData) { } @@ -45,17 +59,16 @@ protected: HILAccelerometerData updateData() override { HILAccelerometerData tempData; - - miosix::PauseKernelLock pkLock; - HILConfig::SimulatorData::Accelerometer *accelerometer = - reinterpret_cast<HILConfig::SimulatorData::Accelerometer *>( - sensorData); - - tempData.accelerationX = accelerometer->measures[sampleCounter][0]; - tempData.accelerationY = accelerometer->measures[sampleCounter][1]; - tempData.accelerationZ = accelerometer->measures[sampleCounter][2]; - tempData.accelerationTimestamp = updateTimestamp(); - + { + miosix::PauseKernelLock pkLock; + tempData.accelerationX = + Base::sensorData->measures[Base::sampleCounter][0]; + tempData.accelerationY = + Base::sensorData->measures[Base::sampleCounter][1]; + tempData.accelerationZ = + Base::sensorData->measures[Base::sampleCounter][2]; + tempData.accelerationTimestamp = Base::updateTimestamp(); + } Boardcore::Logger::getInstance().log(tempData); return tempData; diff --git a/src/shared/sensors/HILSensors/HILBarometer.h b/src/shared/sensors/HILSensors/HILBarometer.h index 9e283f925ee7d637f2265f1a027b48c008a4aa01..d146c7ac2f1d37d17ba64aecc02b1c8ac74360af 100644 --- a/src/shared/sensors/HILSensors/HILBarometer.h +++ b/src/shared/sensors/HILSensors/HILBarometer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry +/* Copyright (c) 2020-2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,6 +26,12 @@ #include "HILSensor.h" +template <int N_DATA> +struct BarometerSimulatorData +{ + float measures[N_DATA]; +}; + /** * @brief fake barometer sensor used for the simulation. * @@ -33,11 +39,17 @@ * OBSW during the flight, using fake sensors classes instead of the real * ones, taking their data from the data received from a simulator. */ -class HILBarometer : public HILSensor<HILBarometerData> +template <int N_DATA> +class HILBarometer + : public HILSensor<HILBarometerData, BarometerSimulatorData<N_DATA>, N_DATA> { + using Base = + HILSensor<HILBarometerData, BarometerSimulatorData<N_DATA>, N_DATA>; + public: - HILBarometer(int n_data_sensor, void *sensorData) - : HILSensor(n_data_sensor, sensorData) + explicit HILBarometer(const BarometerSimulatorData<N_DATA> *sensorData) + : HILSensor<HILBarometerData, BarometerSimulatorData<N_DATA>, N_DATA>( + sensorData) { } @@ -45,14 +57,11 @@ protected: HILBarometerData updateData() override { HILBarometerData tempData; - - miosix::PauseKernelLock pkLock; - HILConfig::SimulatorData::Barometer *barometer = - reinterpret_cast<HILConfig::SimulatorData::Barometer *>(sensorData); - - tempData.pressure = barometer->measures[sampleCounter]; - tempData.pressureTimestamp = updateTimestamp(); - + { + miosix::PauseKernelLock pkLock; + tempData.pressure = Base::sensorData->measures[Base::sampleCounter]; + tempData.pressureTimestamp = Base::updateTimestamp(); + } Boardcore::Logger::getInstance().log(tempData); return tempData; diff --git a/src/shared/sensors/HILSensors/HILGps.h b/src/shared/sensors/HILSensors/HILGps.h index aecd70ba9a2bc3aaf3aa0eecaab6b252c76ebe6a..296d5b670fe81749453704f039a6df13e2e93f60 100644 --- a/src/shared/sensors/HILSensors/HILGps.h +++ b/src/shared/sensors/HILSensors/HILGps.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry +/* Copyright (c) 2020-2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -28,6 +28,15 @@ #include "HILSensor.h" +template <int N_DATA> +struct GPSSimulatorData +{ + float positionMeasures[N_DATA][3]; + float velocityMeasures[N_DATA][3]; + float fix; + float num_satellites; +}; + /** * @brief fake gps sensor used for the HILulation. * @@ -35,11 +44,14 @@ * OBSW during the flight, using fake sensors classes instead of the real * ones, taking their data from the data received from a HILulator. */ -class HILGps : public HILSensor<HILGpsData> +template <int N_DATA> +class HILGps : public HILSensor<HILGpsData, GPSSimulatorData<N_DATA>, N_DATA> { + using Base = HILSensor<HILGpsData, GPSSimulatorData<N_DATA>, N_DATA>; + public: - HILGps(int n_data_sensor, void *sensorData) - : HILSensor(n_data_sensor, sensorData) + explicit HILGps(const GPSSimulatorData<N_DATA> *sensorData) + : HILSensor<HILGpsData, GPSSimulatorData<N_DATA>, N_DATA>(sensorData) { } @@ -47,28 +59,34 @@ protected: HILGpsData updateData() override { HILGpsData tempData; + { + miosix::PauseKernelLock pkLock; - miosix::PauseKernelLock pkLock; - HILConfig::SimulatorData::Gps *gps = - reinterpret_cast<HILConfig::SimulatorData::Gps *>(sensorData); - - tempData.latitude = - gps->positionMeasures[sampleCounter][0]; // divide by earth radius - tempData.longitude = gps->positionMeasures[sampleCounter][1]; - tempData.height = gps->positionMeasures[sampleCounter][2]; - - tempData.velocityNorth = gps->velocityMeasures[sampleCounter][0]; - tempData.velocityEast = gps->velocityMeasures[sampleCounter][1]; - tempData.velocityDown = gps->velocityMeasures[sampleCounter][2]; - tempData.speed = sqrtf(tempData.velocityNorth * tempData.velocityNorth + - tempData.velocityDown * tempData.velocityDown); - tempData.positionDOP = 0; + tempData.latitude = + Base::sensorData->positionMeasures[Base::sampleCounter][0]; + tempData.longitude = + Base::sensorData->positionMeasures[Base::sampleCounter][1]; + tempData.height = + Base::sensorData->positionMeasures[Base::sampleCounter][2]; - tempData.fix = static_cast<uint8_t>(gps->fix); - tempData.satellites = static_cast<uint8_t>(gps->num_satellites); + tempData.velocityNorth = + Base::sensorData->velocityMeasures[Base::sampleCounter][0]; + tempData.velocityEast = + Base::sensorData->velocityMeasures[Base::sampleCounter][1]; + tempData.velocityDown = + Base::sensorData->velocityMeasures[Base::sampleCounter][2]; + tempData.speed = + sqrtf(tempData.velocityNorth * tempData.velocityNorth + + tempData.velocityEast * tempData.velocityEast + + tempData.velocityDown * tempData.velocityDown); + tempData.positionDOP = 0; - tempData.gpsTimestamp = updateTimestamp(); + tempData.fix = static_cast<uint8_t>(Base::sensorData->fix); + tempData.satellites = + static_cast<uint8_t>(Base::sensorData->num_satellites); + tempData.gpsTimestamp = Base::updateTimestamp(); + } Boardcore::Logger::getInstance().log(tempData); return tempData; diff --git a/src/shared/sensors/HILSensors/HILGyroscope.h b/src/shared/sensors/HILSensors/HILGyroscope.h index 78b10e9075410005e084a0dcba45f1ac064b41d4..f76ed2c745a77825fcad3c765b90804d738d795e 100644 --- a/src/shared/sensors/HILSensors/HILGyroscope.h +++ b/src/shared/sensors/HILSensors/HILGyroscope.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry +/* Copyright (c) 2020-2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,6 +26,12 @@ #include "HILSensor.h" +template <int N_DATA> +struct GyroscopeSimulatorData +{ + float measures[N_DATA][3]; +}; + /** * @brief fake gyroscope sensor used for the simulation. * @@ -33,11 +39,17 @@ * OBSW during the flight, using fake sensors classes instead of the real * ones, taking their data from the data received from a simulator. */ -class HILGyroscope : public HILSensor<HILGyroscopeData> +template <int N_DATA> +class HILGyroscope + : public HILSensor<HILGyroscopeData, GyroscopeSimulatorData<N_DATA>, N_DATA> { + using Base = + HILSensor<HILGyroscopeData, GyroscopeSimulatorData<N_DATA>, N_DATA>; + public: - HILGyroscope(int n_data_sensor, void *sensorData) - : HILSensor(n_data_sensor, sensorData) + explicit HILGyroscope(const GyroscopeSimulatorData<N_DATA> *sensorData) + : HILSensor<HILGyroscopeData, GyroscopeSimulatorData<N_DATA>, N_DATA>( + sensorData) { } @@ -45,16 +57,16 @@ protected: HILGyroscopeData updateData() override { HILGyroscopeData tempData; - - miosix::PauseKernelLock pkLock; - HILConfig::SimulatorData::Gyro *gyroscope = - reinterpret_cast<HILConfig::SimulatorData::Gyro *>(sensorData); - - tempData.angularSpeedX = gyroscope->measures[sampleCounter][0]; - tempData.angularSpeedY = gyroscope->measures[sampleCounter][1]; - tempData.angularSpeedZ = gyroscope->measures[sampleCounter][2]; - tempData.angularSpeedTimestamp = updateTimestamp(); - + { + miosix::PauseKernelLock pkLock; + tempData.angularSpeedX = + Base::sensorData->measures[Base::sampleCounter][0]; + tempData.angularSpeedY = + Base::sensorData->measures[Base::sampleCounter][1]; + tempData.angularSpeedZ = + Base::sensorData->measures[Base::sampleCounter][2]; + tempData.angularSpeedTimestamp = Base::updateTimestamp(); + } Boardcore::Logger::getInstance().log(tempData); return tempData; diff --git a/src/shared/sensors/HILSensors/HILMagnetometer.h b/src/shared/sensors/HILSensors/HILMagnetometer.h index 8c79ce53a3f6306202346bb2a7e20474ca65d7aa..12ded6df8258ef90e5dae0eece559c749410773b 100644 --- a/src/shared/sensors/HILSensors/HILMagnetometer.h +++ b/src/shared/sensors/HILSensors/HILMagnetometer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry +/* Copyright (c) 2020-2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,6 +26,12 @@ #include "HILSensor.h" +template <int N_DATA> +struct MagnetometerSimulatorData +{ + float measures[N_DATA][3]; +}; + /** * @brief fake magnetometer sensor used for the simulation. * @@ -33,11 +39,19 @@ * OBSW during the flight, using fake sensors classes instead of the real * ones, taking their data from the data received from a simulator. */ -class HILMagnetometer : public HILSensor<HILMagnetometerData> +template <int N_DATA> +class HILMagnetometer + : public HILSensor<HILMagnetometerData, MagnetometerSimulatorData<N_DATA>, + N_DATA> { + using Base = HILSensor<HILMagnetometerData, + MagnetometerSimulatorData<N_DATA>, N_DATA>; + public: - HILMagnetometer(int n_data_sensor, void *sensorData) - : HILSensor(n_data_sensor, sensorData) + explicit HILMagnetometer( + const MagnetometerSimulatorData<N_DATA> *sensorData) + : HILSensor<HILMagnetometerData, MagnetometerSimulatorData<N_DATA>, + N_DATA>(sensorData) { } @@ -45,17 +59,16 @@ protected: HILMagnetometerData updateData() override { HILMagnetometerData tempData; - - miosix::PauseKernelLock pkLock; - HILConfig::SimulatorData::Magnetometer *magnetometer = - reinterpret_cast<HILConfig::SimulatorData::Magnetometer *>( - sensorData); - - tempData.magneticFieldX = magnetometer->measures[sampleCounter][0]; - tempData.magneticFieldY = magnetometer->measures[sampleCounter][1]; - tempData.magneticFieldZ = magnetometer->measures[sampleCounter][2]; - tempData.magneticFieldTimestamp = updateTimestamp(); - + { + miosix::PauseKernelLock pkLock; + tempData.magneticFieldX = + Base::sensorData->measures[Base::sampleCounter][0]; + tempData.magneticFieldY = + Base::sensorData->measures[Base::sampleCounter][1]; + tempData.magneticFieldZ = + Base::sensorData->measures[Base::sampleCounter][2]; + tempData.magneticFieldTimestamp = Base::updateTimestamp(); + } Boardcore::Logger::getInstance().log(tempData); return tempData; diff --git a/src/shared/sensors/HILSensors/HILPitot.h b/src/shared/sensors/HILSensors/HILPitot.h index 13c0b654c27061690442845b404412a555c04e88..a402927d1fc1398fd920a7ba66132f3a646467e9 100644 --- a/src/shared/sensors/HILSensors/HILPitot.h +++ b/src/shared/sensors/HILSensors/HILPitot.h @@ -28,6 +28,13 @@ #include "HILSensor.h" +template <int N_DATA> +struct PitotSimulatorData +{ + float deltaP[N_DATA]; + float airspeed[N_DATA]; +}; + /** * @brief fake pitot (differential pressure) sensor used for the simulation. * @@ -35,27 +42,29 @@ * OBSW during the flight, using fake sensors classes instead of the real * ones, taking their data from the data received from a simulator. */ -class HILPitot : public HILSensor<HILPitotData> +template <int N_DATA> +class HILPitot + : public HILSensor<HILPitotData, PitotSimulatorData<N_DATA>, N_DATA> { + using Base = HILSensor<HILPitotData, PitotSimulatorData<N_DATA>, N_DATA>; + public: - HILPitot(int n_data_sensor, void *sensorData) - : HILSensor(n_data_sensor, sensorData) + explicit HILPitot(const PitotSimulatorData<N_DATA> *sensorData) + : HILSensor<HILPitotData, PitotSimulatorData<N_DATA>, N_DATA>( + sensorData) { } protected: HILPitotData updateData() override { - miosix::PauseKernelLock pkLock; - - auto *pitotData = - reinterpret_cast<HILConfig::SimulatorData::Pitot *>(sensorData); - HILPitotData tempData; - tempData.deltaP = pitotData->deltaP[sampleCounter]; - tempData.airspeed = pitotData->airspeed[sampleCounter]; - tempData.timestamp = updateTimestamp(); - + { + miosix::PauseKernelLock pkLock; + tempData.deltaP = Base::sensorData->deltaP[Base::sampleCounter]; + tempData.airspeed = Base::sensorData->airspeed[Base::sampleCounter]; + tempData.timestamp = Base::updateTimestamp(); + } Boardcore::Logger::getInstance().log(tempData); return tempData; diff --git a/src/shared/sensors/HILSensors/HILSensor.h b/src/shared/sensors/HILSensors/HILSensor.h index d9f185784afc5b56aa88a88f3e3754281d020d72..ce2bfc264b2ed650fbb271584b3538bf9a362d8e 100644 --- a/src/shared/sensors/HILSensors/HILSensor.h +++ b/src/shared/sensors/HILSensors/HILSensor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry +/* Copyright (c) 2020-2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,11 +24,10 @@ #include <typeinfo> -#include "HIL.h" -#include "HILConfig.h" -#include "HILSensorsData.h" #include "HILTimestampManagement.h" #include "drivers/timer/TimestampTimer.h" +#include "hil/HIL.h" +#include "sensors/HILSensors/HILSensorsData.h" #include "sensors/Sensor.h" #include "sensors/SensorData.h" @@ -40,7 +39,7 @@ * OBSW during the flight, using fake sensors classes instead of the real * ones, taking their data from the data received from a simulator. */ -template <typename HILSensorData> +template <typename HILSensorData, typename SimulatorSensorData, int N_DATA> class HILSensor : public virtual HILTimestampManagement, public virtual Boardcore::Sensor<HILSensorData> { @@ -50,18 +49,17 @@ public: * * @param matlab reference of the MatlabTransceiver object that deals with * the simulator - * @param n_data_sensor number of samples in every period of simulation + * @param addResetSampleCounter should be something like: + * Boardcore::ModuleManager::getInstance().get<HIL>()->simulator->addResetSampleCounter() */ - HILSensor(int n_data_sensor, void *sensorData) + explicit HILSensor(const SimulatorSensorData *sensorData) + : sensorData(sensorData) { - this->sensorData = sensorData; - this->n_data_sensor = n_data_sensor; - - /* Registers the sensor on the MatlabTransceiver to be notified when a + /* Registers the sensor on the HILTransceiver to be notified when a * new packet of simulated data arrives */ Boardcore::ModuleManager::getInstance() - .get<HIL>() - ->simulator->addResetSampleCounter(this); + .get<HILTransceiverBase>() + ->addResetSampleCounter(this); } /** @@ -85,7 +83,7 @@ public: if (initialized) { this->lastError = Boardcore::SensorErrors::ALREADY_INIT; - TRACE("ALREADY INITIALIZED!"); + LOG_WARN(logger, "%s already initialized", typeid(this).name()); } else { @@ -110,11 +108,10 @@ protected: if (initialized) { /* updates the last_sensor only if there is still data to be read */ - if (sampleCounter >= n_data_sensor) + if (sampleCounter >= N_DATA) { this->lastError = Boardcore::SensorErrors::NO_NEW_DATA; - /*TRACE("[%s] NO NEW DATA! Simulation error\n", - typeid(this).name());*/ + LOG_WARN(logger, "%s: No new data", typeid(this).name()); } else if (this->lastError != Boardcore::SensorErrors::NO_NEW_DATA) { @@ -124,9 +121,7 @@ protected: else { this->lastError = Boardcore::SensorErrors::NOT_INIT; - TRACE( - "[HILSensor] sampleImpl() : not initialized, unable to " - "sample data \n"); + LOG_WARN(logger, "%s is not initialized", typeid(this).name()); } return this->lastSample; @@ -155,6 +150,7 @@ protected: bool initialized = false; int sampleCounter = 0; /**< counter of the next sample to take */ - int n_data_sensor; /**< number of samples in every period */ - void *sensorData; /**< reference to the Buffer structure */ + const SimulatorSensorData + *sensorData; /**< reference to the Buffer structure */ + Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("HILSensor"); }; diff --git a/src/shared/sensors/HILSensors/HILTemperature.h b/src/shared/sensors/HILSensors/HILTemperature.h index 7653828560d646c5271333cf276aa1e9f463b6f1..f6d8420be7dfbeb6e6e6f967992557efc9274821 100644 --- a/src/shared/sensors/HILSensors/HILTemperature.h +++ b/src/shared/sensors/HILSensors/HILTemperature.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2023 Skyward Experimental Rocketry +/* Copyright (c) 2020-2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,6 +26,12 @@ #include "HILSensor.h" +template <int N_DATA> +struct TemperatureSimulatorData +{ + float measures[N_DATA]; +}; + /** * @brief fake barometer sensor used for the simulation. * @@ -33,11 +39,17 @@ * OBSW during the flight, using fake sensors classes instead of the real * ones, taking their data from the data received from a simulator. */ -class HILTemperature : public HILSensor<HILTempData> +template <int N_DATA> +class HILTemperature + : public HILSensor<HILTempData, TemperatureSimulatorData<N_DATA>, N_DATA> { + using Base = + HILSensor<HILTempData, TemperatureSimulatorData<N_DATA>, N_DATA>; + public: - HILTemperature(int n_data_sensor, void *sensorData) - : HILSensor(n_data_sensor, sensorData) + explicit HILTemperature(const TemperatureSimulatorData<N_DATA> *sensorData) + : HILSensor<HILTempData, TemperatureSimulatorData<N_DATA>, N_DATA>( + sensorData) { } @@ -45,13 +57,12 @@ protected: HILTempData updateData() override { HILTempData tempData; - - tempData.temperature = - reinterpret_cast<HILConfig::SimulatorData::Temperature *>( - sensorData) - ->measure; - tempData.temperatureTimestamp = updateTimestamp(); - + { + miosix::PauseKernelLock pkLock; + tempData.temperature = + Base::sensorData->measures[Base::sampleCounter]; + tempData.temperatureTimestamp = Base::updateTimestamp(); + } Boardcore::Logger::getInstance().log(tempData); return tempData; diff --git a/src/tests/hil/HILSimulationConfig.h b/src/tests/hil/HILSimulationConfig.h index 55dee4d62d51490969bd73800131627405fc72f0..3c71184a316f5626dee79906bf40407c6bf680e3 100644 --- a/src/tests/hil/HILSimulationConfig.h +++ b/src/tests/hil/HILSimulationConfig.h @@ -22,8 +22,15 @@ #pragma once +#include <algorithms/AirBrakes/TrajectoryPoint.h> #include <drivers/timer/TimestampTimer.h> #include <drivers/usart/USART.h> +#include <events/Event.h> +#include <events/EventHandler.h> +#include <hil/HILPhasesManager.h> +#include <hil/HILTransceiver.h> +#include <math.h> +#include <sensors/HILSensors/IncludeHILSensors.h> #include <utils/Debug.h> #include <utils/Stats/Stats.h> @@ -33,6 +40,7 @@ #include "algorithms/ADA/ADAData.h" #include "algorithms/NAS/NAS.h" #include "algorithms/NAS/NASState.h" +#include "events/EventBroker.h" #include "sensors/SensorInfo.h" namespace HILConfig @@ -50,24 +58,18 @@ struct SensorConfig : public Boardcore::SensorInfo const int SIM_BAUDRATE = 115200; /** Period of simulation in milliseconds */ -const int SIMULATION_PERIOD = 100; +constexpr int SIMULATION_PERIOD = 100; /** sample frequency of sensor (samples/second) */ -const int ACCEL_FREQ = 100; -const int GYRO_FREQ = 100; -const int MAGN_FREQ = 100; -const int IMU_FREQ = 100; -const int BARO_FREQ = 20; -const int PITOT_FREQ = 20; -const int TEMP_FREQ = 10; -const int GPS_FREQ = 10; - -// /** update frequency of airbrakes control algorithm */ -// const int CONTROL_FREQ = 10; - -// /** min and max values in radiants of the actuator */ -// const float MinAlphaDegree = 0.0; -// const float MaxAlphaDegree = 0.84; +constexpr int ACCEL_FREQ = 100; +constexpr int GYRO_FREQ = 100; +constexpr int MAGN_FREQ = 100; +constexpr int IMU_FREQ = 100; +constexpr int BARO_FREQ = 50; +constexpr int BARO_CHAMBER_FREQ = 50; +constexpr int PITOT_FREQ = 20; +constexpr int TEMP_FREQ = 10; +constexpr int GPS_FREQ = 10; /** sensors configuration */ const SensorConfig accelConfig("accel", ACCEL_FREQ); @@ -80,248 +82,439 @@ const SensorConfig gpsConfig("gps", GPS_FREQ); const SensorConfig tempConfig("temp", TEMP_FREQ); /** Number of samples per sensor at each simulator iteration */ -const int N_DATA_ACCEL = (ACCEL_FREQ * SIMULATION_PERIOD) / 1000; // 10 -const int N_DATA_GYRO = (GYRO_FREQ * SIMULATION_PERIOD) / 1000; // 10 -const int N_DATA_MAGN = (MAGN_FREQ * SIMULATION_PERIOD) / 1000; // 10 -const int N_DATA_IMU = (IMU_FREQ * SIMULATION_PERIOD) / 1000; // 10 -const int N_DATA_BARO = (BARO_FREQ * SIMULATION_PERIOD) / 1000; // 2 -const int N_DATA_PITOT = (PITOT_FREQ * SIMULATION_PERIOD) / 1000; // 2 -const int N_DATA_GPS = (GPS_FREQ * SIMULATION_PERIOD) / 1000; // 1 -const int N_DATA_TEMP = (TEMP_FREQ * SIMULATION_PERIOD) / 1000; // 1 - -/** - * @brief Data structure used by the simulator in order to directly deserialize - * the data received - * - * This structure then is accessed by sensors and other components in order to - * get the data they need - */ -struct SimulatorData +constexpr int N_DATA_ACCEL = + static_cast<int>((ACCEL_FREQ * SIMULATION_PERIOD) / 1000.0); +constexpr int N_DATA_GYRO = + static_cast<int>((GYRO_FREQ * SIMULATION_PERIOD) / 1000.0); +constexpr int N_DATA_MAGNETO = + static_cast<int>((MAGN_FREQ * SIMULATION_PERIOD) / 1000.0); +constexpr int N_DATA_IMU = + static_cast<int>((IMU_FREQ * SIMULATION_PERIOD) / 1000.0); +constexpr int N_DATA_BARO = + static_cast<int>((BARO_FREQ * SIMULATION_PERIOD) / 1000.0); +constexpr int N_DATA_BARO_CHAMBER = + static_cast<int>((BARO_CHAMBER_FREQ * SIMULATION_PERIOD) / 1000.0); +constexpr int N_DATA_PITOT = + static_cast<int>((PITOT_FREQ * SIMULATION_PERIOD) / 1000.0); +constexpr int N_DATA_GPS = + static_cast<int>((GPS_FREQ * SIMULATION_PERIOD) / 1000.0); +constexpr int N_DATA_TEMP = + static_cast<int>((TEMP_FREQ * SIMULATION_PERIOD) / 1000.0); + +struct FlagsHIL { - struct Accelerometer - { - float measures[N_DATA_ACCEL][3]; - } accelerometer; - - struct Gyro + float flag_flight; + float flag_ascent; + float flag_burning; + float flag_airbrakes; + float flag_para1; + float flag_para2; + + FlagsHIL(float flag_flight, float flag_ascent, float flag_burning, + float flag_airbrakes, float flag_para1, float flag_para2) + : flag_flight(flag_flight), flag_ascent(flag_ascent), + flag_burning(flag_burning), flag_airbrakes(flag_airbrakes), + flag_para1(flag_para1), flag_para2(flag_para2) { - float measures[N_DATA_GYRO][3]; - } gyro; - - struct Magnetometer - { - float measures[N_DATA_MAGN][3]; - } magnetometer; - - struct Gps - { - float positionMeasures[N_DATA_GPS][3]; - float velocityMeasures[N_DATA_GPS][3]; - float fix; - float num_satellites; - } gps; - - struct Barometer - { - float measures[N_DATA_BARO]; - } barometer1, barometer2, barometer3; - - struct Pitot - { - float deltaP[N_DATA_PITOT]; - float staticPressure[N_DATA_PITOT]; - } pitot; - - struct Temperature - { - float measure; - } temperature; + } - struct Flags + FlagsHIL() + : flag_flight(0.0f), flag_ascent(0.0f), flag_burning(0.0f), + flag_airbrakes(0.0f), flag_para1(0.0f), flag_para2(0.0f) { - float flag_flight; - float flag_ascent; - float flag_burning; - float flag_airbrakes; - float flag_para1; - float flag_para2; - } flags; - - void printAccelerometer() - { - TRACE("accel\n"); - for (int i = 0; i < N_DATA_ACCEL; i++) - TRACE("%+.3f\t%+.3f\t%+.3f\n", accelerometer.measures[i][0], - accelerometer.measures[i][1], accelerometer.measures[i][2]); } - void printGyro() + void print() { - TRACE("gyro\n"); - for (int i = 0; i < N_DATA_GYRO; i++) - TRACE("%+.3f\t%+.3f\t%+.3f\n", gyro.measures[i][0], - gyro.measures[i][1], gyro.measures[i][2]); + printf( + "flag_flight: %f\n" + "flag_ascent: %f\n" + "flag_burning: %f\n" + "flag_airbrakes: %f\n" + "flag_para1: %f\n" + "flag_para2: %f\n", + flag_flight, flag_ascent, flag_burning, flag_airbrakes, flag_para1, + flag_para2); } +}; - void printMagnetometer() +/** + * @brief ADA data sent to the simulator + */ +struct ADAStateHIL +{ + float mslAltitude = 0; // Altitude at mean sea level [m]. + float aglAltitude = 0; // Altitude above ground level [m]. + float verticalSpeed = 0; // Vertical speed [m/s]. + float apogeeDetected = 0; // Flag if apogee is detected [bool] + float updating = 0; // + + ADAStateHIL() + : mslAltitude(0), aglAltitude(0), verticalSpeed(0), apogeeDetected(0), + updating(0) { - TRACE("magneto\n"); - for (int i = 0; i < N_DATA_MAGN; i++) - TRACE("%+.3f\t%+.3f\t%+.3f\n", magnetometer.measures[i][0], - magnetometer.measures[i][1], magnetometer.measures[i][2]); } - void printGPS() + void print() { - TRACE("gps\n"); - TRACE("pos\n"); - for (int i = 0; i < N_DATA_GPS; i++) - TRACE("%+.3f\t%+.3f\t%+.3f\n", gps.positionMeasures[i][0], - gps.positionMeasures[i][1], gps.positionMeasures[i][2]); - - TRACE("vel\n"); - for (int i = 0; i < N_DATA_GPS; i++) - TRACE("%+.3f\t%+.3f\t%+.3f\n", gps.velocityMeasures[i][0], - gps.velocityMeasures[i][1], gps.velocityMeasures[i][2]); - TRACE("fix:%+.3f\tnsat:%+.3f\n", gps.fix, gps.num_satellites); + printf( + "mslAltitude: %+.3f\n" + "aglAltitude: %+.3f\n" + "verticalSpeed: %+.3f\n" + "apogeeDetected: %+.3f\n" + "updating: %+.3f\n", + mslAltitude, aglAltitude, verticalSpeed, apogeeDetected, updating); } +}; - void printBarometer1() +/** + * @brief NAS data sent to the simulator + */ +struct NASStateHIL +{ + float n = 0; + float e = 0; + float d = 0; + + // Velocity [m/s] + float vn = 0; + float ve = 0; + float vd = 0; + + // Attitude as quaternion + float qx = 0; + float qy = 0; + float qz = 0; + float qw = 1; + + float updating = 0; // Flag if apogee is detected [bool] + + NASStateHIL() + : n(0), e(0), d(0), vn(0), ve(0), vd(0), qx(0), qy(0), qz(0), qw(1), + updating(0) { - TRACE("press1\n"); - for (int i = 0; i < N_DATA_BARO; i++) - TRACE("%+.3f\n", barometer1.measures[i]); } - void printBarometer2() + void print() { - TRACE("press2\n"); - for (int i = 0; i < N_DATA_BARO; i++) - TRACE("%+.3f\n", barometer2.measures[i]); + printf( + "n: %+.3f\n" + "e: %+.3f\n" + "d: %+.3f\n" + "vn: %+.3f\n" + "ve: %+.3f\n" + "vd: %+.3f\n" + "qx: %+.3f\n" + "qy: %+.3f\n" + "qz: %+.3f\n" + "qw: %+.3f\n" + "updating: %+.3f\n", + n, e, d, vn, ve, vd, qx, qy, qz, qw, updating); } +}; + +/** + * @brief ABK data sent to the simulator + */ +struct AirBrakesStateHIL +{ + float updating = 0; // Flag if apogee is detected [bool] + + AirBrakesStateHIL() : updating(0) {} + + void print() { printf("updating: %+.3f\n", updating); } +}; - void printBarometer3() +/** + * @brief MEA data sent to the simulator + */ +struct MEAStateHIL +{ + float correctedPressure = 0; + + float estimatedMass = 0; + float estimatedApogee = 0; + + float updating = 0; // Flag if apogee is detected [bool] + + MEAStateHIL() + : correctedPressure(0), estimatedMass(0), estimatedApogee(0), + updating(0) { - TRACE("press3\n"); - for (int i = 0; i < N_DATA_BARO; i++) - TRACE("%+.3f\n", barometer3.measures[i]); } - void printPitot() + void print() { - TRACE("pitot\n"); - for (int i = 0; i < N_DATA_PITOT; i++) - TRACE("%+.3f, \n", pitot.staticPressure[i], pitot.deltaP[i]); + printf( + "correctedPressure: %+.3f\n" + "estimatedMass: %+.3f\n" + "estimatedApogee: %+.3f\n" + "updating: %+.3f\n", + correctedPressure, estimatedMass, estimatedApogee, updating); } +}; - void printTemperature() +struct ActuatorsStateHIL +{ + float airbrakesPercentage = 0; + float expulsionPercentage = 0; + float mainValvePercentage = 0; + float ventingValvePercentage = 0; + + ActuatorsStateHIL() + : airbrakesPercentage(0.0f), expulsionPercentage(0.0f), + mainValvePercentage(0.0f), ventingValvePercentage(0.0f) { - TRACE("temp\n"); - for (int i = 0; i < N_DATA_TEMP; i++) - TRACE("%+.3f\n", temperature.measure); } - void printFlags() + ActuatorsStateHIL(float airbrakesPercentage, float expulsionPercentage, + float mainValvePercentage, float ventingValvePercentage) + : airbrakesPercentage(airbrakesPercentage), + expulsionPercentage(expulsionPercentage), + mainValvePercentage(mainValvePercentage), + ventingValvePercentage(ventingValvePercentage) { - TRACE("flags\n"); - TRACE( - "flight:\t%+.3f\n" - "ascent:\t%+.3f\n" - "burning:\t%+.3f\n" - "airbrakes:\t%+.3f\n" - "para1:\t%+.3f\n" - "para2:\t%+.3f\n", - flags.flag_flight, flags.flag_ascent, flags.flag_burning, - flags.flag_airbrakes, flags.flag_para1, flags.flag_para2); } void print() { - printAccelerometer(); - printGyro(); - printMagnetometer(); - printGPS(); - printBarometer1(); - printBarometer2(); - printBarometer3(); - printPitot(); - printTemperature(); - printFlags(); + printf( + "airbrakes: %f perc\n" + "expulsion: %f perc\n" + "mainValve: %f perc\n" + "venting: %f perc\n", + airbrakesPercentage * 100, expulsionPercentage * 100, + mainValvePercentage * 100, ventingValvePercentage * 100); } }; /** - * @brief ADA data sent to the simulator + * @brief Data structure used by the simulator in order to directly deserialize + * the data received + * + * This structure then is accessed by sensors and other components in order to + * get the data they need */ -struct ADAdataHIL +struct SimulatorData { - uint64_t ada_timestamp; - float aglAltitude; // Altitude at mean sea level [m]. - float verticalSpeed; // Vertical speed [m/s]. + struct AccelerometerSimulatorData<N_DATA_ACCEL> accelerometer; + struct GyroscopeSimulatorData<N_DATA_GYRO> gyro; + struct MagnetometerSimulatorData<N_DATA_MAGNETO> magnetometer; + struct GPSSimulatorData<N_DATA_GPS> gps; + struct BarometerSimulatorData<N_DATA_BARO> barometer1, barometer2, + barometer3; + struct BarometerSimulatorData<N_DATA_BARO_CHAMBER> pressureChamber; + struct PitotSimulatorData<N_DATA_PITOT> pitot; + struct TemperatureSimulatorData<N_DATA_TEMP> temperature; + struct FlagsHIL flags; +}; - ADAdataHIL& operator+=(const ADAdataHIL& x) +/** + * @brief Data structure expected by the simulator + */ +struct ActuatorData +{ + ADAStateHIL adaState; + NASStateHIL nasState; + AirBrakesStateHIL airBrakesState; + MEAStateHIL meaState; + ActuatorsStateHIL actuatorsState; + FlagsHIL flags; + + ActuatorData() + : adaState(), nasState(), airBrakesState(), meaState(), + actuatorsState(), flags() { - this->ada_timestamp += x.ada_timestamp; - this->aglAltitude += x.aglAltitude; - this->verticalSpeed += x.verticalSpeed; + } - return *this; // return the result by reference + void print() + { + adaState.print(); + nasState.print(); + airBrakesState.print(); + meaState.print(); + actuatorsState.print(); + flags.print(); } +}; - ADAdataHIL operator/(int x) +enum MainFlightPhases +{ + SIM_FLYING, + SIM_ASCENT, + SIM_BURNING, + SIM_AEROBRAKES, + SIM_PARA1, + SIM_PARA2, + SIMULATION_STARTED, + CALIBRATION, + CALIBRATION_OK, + ARMED, + LIFTOFF_PIN_DETACHED, + LIFTOFF, + AEROBRAKES, + APOGEE, + PARA1, + PARA2, + SIMULATION_STOPPED +}; + +using MainHILAccelerometer = HILAccelerometer<N_DATA_ACCEL>; +using MainHILGyroscope = HILGyroscope<N_DATA_GYRO>; +using MainHILMagnetometer = HILMagnetometer<N_DATA_MAGNETO>; +using MainHILGps = HILGps<N_DATA_GPS>; +using MainHILBarometer = HILBarometer<N_DATA_BARO>; +using MainHILBarometer = HILBarometer<N_DATA_BARO_CHAMBER>; +using MainHILPitot = HILPitot<N_DATA_PITOT>; +using MainHILTemperature = HILTemperature<N_DATA_TEMP>; + +using MainHILTransceiver = + HILTransceiver<MainFlightPhases, SimulatorData, ActuatorData>; +using MainHIL = HIL<MainFlightPhases, SimulatorData, ActuatorData>; + +class MainHILPhasesManager + : public HILPhasesManager<MainFlightPhases, SimulatorData, ActuatorData> +{ +public: + MainHILPhasesManager( + std::function<Boardcore::TimedTrajectoryPoint()> getCurrentPosition) + : HILPhasesManager<MainFlightPhases, SimulatorData, ActuatorData>( + getCurrentPosition) { - return ADAdataHIL{this->ada_timestamp / x, this->aglAltitude / x, - this->verticalSpeed / x}; + flagsFlightPhases = {{MainFlightPhases::SIM_FLYING, false}, + {MainFlightPhases::SIM_ASCENT, false}, + {MainFlightPhases::SIM_BURNING, false}, + {MainFlightPhases::SIM_AEROBRAKES, false}, + {MainFlightPhases::SIM_PARA1, false}, + {MainFlightPhases::SIM_PARA2, false}, + {MainFlightPhases::SIMULATION_STARTED, false}, + {MainFlightPhases::CALIBRATION, false}, + {MainFlightPhases::CALIBRATION_OK, false}, + {MainFlightPhases::ARMED, false}, + {MainFlightPhases::LIFTOFF_PIN_DETACHED, false}, + {MainFlightPhases::LIFTOFF, false}, + {MainFlightPhases::AEROBRAKES, false}, + {MainFlightPhases::APOGEE, false}, + {MainFlightPhases::PARA1, false}, + {MainFlightPhases::PARA2, false}, + {MainFlightPhases::SIMULATION_STOPPED, false}}; + + prev_flagsFlightPhases = flagsFlightPhases; } - ADAdataHIL operator*(int x) + void processFlags(const SimulatorData& simulatorData) override { - return ADAdataHIL{this->ada_timestamp * x, this->aglAltitude * x, - this->verticalSpeed * x}; + updateSimulatorFlags(simulatorData); + + std::vector<MainFlightPhases> changed_flags; + + // set true when the first packet from the simulator arrives + if (isSetTrue(MainFlightPhases::SIMULATION_STARTED)) + { + t_start = Boardcore::TimestampTimer::getTimestamp(); + + TRACE("[HIL] ------- SIMULATION STARTED ! ------- \n"); + changed_flags.push_back(MainFlightPhases::SIMULATION_STARTED); + } + + if (flagsFlightPhases[MainFlightPhases::SIM_FLYING]) + { + if (isSetTrue(MainFlightPhases::SIM_FLYING)) + { + registerOutcomes(MainFlightPhases::SIM_FLYING); + TRACE("[HIL] ------- SIMULATOR LIFTOFF ! ------- \n"); + changed_flags.push_back(MainFlightPhases::SIM_FLYING); + } + } + + /* calling the callbacks subscribed to the changed flags */ + for (unsigned int i = 0; i < changed_flags.size(); i++) + { + std::vector<TCallback> callbacksToCall = + callbacks[changed_flags[i]]; + for (unsigned int j = 0; j < callbacksToCall.size(); j++) + { + callbacksToCall[j](); + } + } + + prev_flagsFlightPhases = flagsFlightPhases; } - static std::string header() + void printOutcomes() { - return "timestamp,aglAltitude,verticalSpeed\n"; + printf("OUTCOMES: (times dt from liftoff)\n\n"); + printf("Simulation time: %.3f [sec]\n\n", + (double)(t_stop - t_start) / 1000000.0f); + + printf("Motor stopped burning (simulation flag): \n"); + outcomes[MainFlightPhases::SIM_BURNING].print(t_liftoff); + + printf("Airbrakes exit shadowmode: \n"); + outcomes[MainFlightPhases::AEROBRAKES].print(t_liftoff); + + printf("Apogee: \n"); + outcomes[MainFlightPhases::APOGEE].print(t_liftoff); + + printf("Parachute 1: \n"); + outcomes[MainFlightPhases::PARA1].print(t_liftoff); + + printf("Parachute 2: \n"); + outcomes[MainFlightPhases::PARA2].print(t_liftoff); + + printf("Simulation Stopped: \n"); + outcomes[MainFlightPhases::SIMULATION_STOPPED].print(t_liftoff); + + // auto cpuMeter = Boardcore::CpuMeter::getCpuStats(); + // printf("max cpu usage: %+.3f\n", cpuMeter.maxValue); + // printf("avg cpu usage: %+.3f\n", cpuMeter.mean); + // printf("min free heap: %+.3lu\n", cpuMeter.minFreeHeap); + // printf("max free stack:%+.3lu\n", cpuMeter.minFreeStack); } - void print(std::ostream& os) const +private: + void handleEvent(const Boardcore::Event& e) override { - os << ada_timestamp << "," << aglAltitude << "," << verticalSpeed - << "\n"; + std::vector<MainFlightPhases> changed_flags; + + TRACE("%d invalid event\n", e); + + /* calling the callbacks subscribed to the changed flags */ + for (unsigned int i = 0; i < changed_flags.size(); i++) + { + std::vector<TCallback> callbacksToCall = + callbacks[changed_flags[i]]; + for (unsigned int j = 0; j < callbacksToCall.size(); j++) + { + callbacksToCall[j](); + } + } + + prev_flagsFlightPhases = flagsFlightPhases; } -}; -/** - * @brief Data structure expected by the simulator - */ -struct ActuatorData -{ - Boardcore::NASState nasState; ///< NAS - ADAdataHIL adaState; ///< ADA - float airbrakes_opening; ///< Airbrakes opening (percentage) - float estimated_mass; ///< Estimated mass of the rocket - float liftoff; ///< Flag for liftoff - float burning_shutdown; ///< Flag for engine shutdown - - void print() const + /** + * @brief Updates the flags of the object with the flags sent from matlab + * and checks for the apogee + */ + void updateSimulatorFlags(const SimulatorData& simulatorData) { - TRACE( - "size:%u, %u, %u\n" - "abk:%f\n" - "tsnas:%f\n" - "ned:%f,%f,%f\n" - "vned:%f,%f,%f\n" - "q:%f,%f,%f,%f\n" - "bias:%f,%f,%f\n" - "tsada:%f\n" - "ada:%f,%f\n\n", - sizeof(airbrakes_opening), sizeof(Boardcore::NASState), - sizeof(ADAdataHIL), airbrakes_opening, nasState.timestamp, - nasState.n, nasState.e, nasState.d, nasState.vn, nasState.ve, - nasState.vd, nasState.qx, nasState.qy, nasState.qz, nasState.qw, - nasState.bx, nasState.by, nasState.bz, adaState.ada_timestamp, - adaState.aglAltitude, adaState.verticalSpeed); + flagsFlightPhases[MainFlightPhases::SIM_ASCENT] = + simulatorData.flags.flag_ascent; + flagsFlightPhases[MainFlightPhases::SIM_FLYING] = + simulatorData.flags.flag_flight; + flagsFlightPhases[MainFlightPhases::SIM_BURNING] = + simulatorData.flags.flag_burning; + flagsFlightPhases[MainFlightPhases::SIM_AEROBRAKES] = + simulatorData.flags.flag_airbrakes; + flagsFlightPhases[MainFlightPhases::SIM_PARA1] = + simulatorData.flags.flag_para1; + flagsFlightPhases[MainFlightPhases::SIM_PARA2] = + simulatorData.flags.flag_para2; + + flagsFlightPhases[MainFlightPhases::SIMULATION_STOPPED] = + isSetFalse(MainFlightPhases::SIM_FLYING) || + prev_flagsFlightPhases[MainFlightPhases::SIMULATION_STOPPED]; } }; diff --git a/src/tests/hil/test-hil.cpp b/src/tests/hil/test-hil.cpp index bd712dfdcccd0d67e7285391ec78cba300a86d45..e17c266ce7c4ac46d88770d961b6f72af8572dd1 100644 --- a/src/tests/hil/test-hil.cpp +++ b/src/tests/hil/test-hil.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023 Skyward Experimental Rocketry +/* Copyright (c) 2024 Skyward Experimental Rocketry * Author: Emilio Corigliano * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -20,6 +20,7 @@ * THE SOFTWARE. */ +#include <algorithms/AirBrakes/TrajectoryPoint.h> #include <diagnostic/CpuMeter/CpuMeter.h> #include <diagnostic/PrintLogger.h> #include <diagnostic/StackLogger.h> @@ -27,10 +28,7 @@ #include <events/EventBroker.h> #include <events/EventData.h> #include <events/utils/EventSniffer.h> -#include <hil/Events.h> #include <hil/HIL.h> -#include <hil/HILConfig.h> -#include <hil/HILFlightPhasesManager.h> #include <scheduler/TaskScheduler.h> #include <utils/ModuleManager/ModuleManager.hpp> @@ -38,23 +36,62 @@ #include "HILSimulationConfig.h" using namespace Boardcore; -using namespace Common; using namespace HILConfig; +static const bool HIL_TEST = true; + int main() { // Overall status, if at some point it becomes false, there is a problem // somewhere bool initResult = true; PrintLogger logger = Logging::getLogger("main"); + Boardcore::TaskScheduler scheduler; // Create modules - USART usart2(USART2, 115200); - HIL* hil = new HIL(usart2, new HILFlightPhasesManager()); - Boardcore::TaskScheduler scheduler; + USART usart2(USART2, SIM_BAUDRATE); + + // Create hil modules + auto* hilTransceiver = new MainHILTransceiver(usart2); + auto* hilPhasesManager = new MainHILPhasesManager( + []() { return Boardcore::TimedTrajectoryPoint(); }); + + auto* sensorData = hilTransceiver->getSensorData(); + + auto* accelerometer = new MainHILAccelerometer(&sensorData->accelerometer); + auto* gyroscope = new MainHILGyroscope(&sensorData->gyro); + auto* magnetometer = new MainHILMagnetometer(&sensorData->magnetometer); + auto* gps = new MainHILGps(&sensorData->gps); + auto* barometer1 = new MainHILBarometer(&sensorData->barometer1); + auto* barometer2 = new MainHILBarometer(&sensorData->barometer2); + auto* barometer3 = new MainHILBarometer(&sensorData->barometer3); + auto* baroChamber = new MainHILBarometer(&sensorData->pressureChamber); + auto* pitot = new MainHILPitot(&sensorData->pitot); + auto* temperature = new MainHILTemperature(&sensorData->temperature); + + // Create HIL class where we specify how to use previous modules to assemble + // ActuatorData + MainHIL* hil = new MainHIL( + hilTransceiver, hilPhasesManager, + [&]() + { + auto actuatorData = ActuatorData(); + + // ada + // const auto gpsSample = gps->getLastSample(); + // actuatorData.adaState.aglAltitude = gpsSample.height; + // actuatorData.adaState.mslAltitude = gpsSample.height - 160; + // actuatorData.adaState.verticalSpeed = -gpsSample.velocityDown; + // actuatorData.adaState.apogeeDetected = static_cast<float>(false); + // actuatorData.adaState.updating = static_cast<float>(true); + + actuatorData.flags = sensorData->flags; + return actuatorData; + }, + SIMULATION_PERIOD); // Insert modules - if (!ModuleManager::getInstance().insert<HIL>(hil)) + if (!ModuleManager::getInstance().insert<MainHIL>(hil)) { initResult = false; LOG_ERR(logger, "Error inserting the HIL module"); @@ -73,40 +110,16 @@ int main() LOG_ERR(logger, "Error starting the board scheduler module"); } - if (!ModuleManager::getInstance().get<HIL>()->start()) + if (HIL_TEST) { - initResult = false; - LOG_ERR(logger, "Error starting the HIL module"); - } - - scheduler.addTask( - [&]() + if (!ModuleManager::getInstance().get<MainHIL>()->start()) { - HILConfig::SimulatorData* sensorData = - ModuleManager::getInstance() - .get<HIL>() - ->simulator->getSensorData(); - HILConfig::ADAdataHIL adaDataHil{ - Boardcore::TimestampTimer::getTimestamp(), - sensorData->gps.positionMeasures[0][2], - sensorData->gps.velocityMeasures[0][2]}; - HILConfig::ActuatorData actuatorData{ - NASState{}, - adaDataHil, - 0, - 30, - sensorData->flags.flag_ascent, - sensorData->flags.flag_burning}; - - // Sending to the simulator - ModuleManager::getInstance().get<HIL>()->send(actuatorData); - }, - HILConfig::SIMULATION_PERIOD); + initResult = false; + LOG_ERR(logger, "Error starting the HIL module"); + } - // scheduler.addTask( - // [&]() { - // ModuleManager::getInstance().get<HIL>()->simulator->getSensorData()->print(); - // }, 1000); + ModuleManager::getInstance().get<MainHIL>()->waitStartSimulation(); + } // Check the init result and launch an event if (initResult)