From b1ff80615f79d2697a9eac85c60bac294c9b7d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Caruso?= <niccolo.caruso@skywarder.eu> Date: Mon, 9 Dec 2024 14:19:55 +0100 Subject: [PATCH] [ARP-RP] Rotation Platform entrypoint and code Rotation Platform code for the ARP configuration with specific head and only yaw stepper going at costant speed. It is another entrypoint for safety reasons. Such that the GS operator can observe is not ARP entrypoint. It has the Actuators and PinHandler specific classes, while Leds is taken from Automated The control is done via the command box and the actuation to the only stepper (yaw) --- CMakeLists.txt | 7 + cmake/dependencies.cmake | 7 + .../RotatingPlatform/Actuators/Actuators.cpp | 246 ++++++++++++++++++ .../RotatingPlatform/Actuators/Actuators.h | 224 ++++++++++++++++ .../Actuators/ActuatorsConfig.h | 66 +++++ .../Actuators/ActuatorsData.h | 48 ++++ .../PinHandler/PinHandler.cpp | 130 +++++++++ .../RotatingPlatform/PinHandler/PinHandler.h | 106 ++++++++ .../RotatingPlatform/rotating-entry.cpp | 137 ++++++++++ 9 files changed, 971 insertions(+) create mode 100644 src/Groundstation/RotatingPlatform/Actuators/Actuators.cpp create mode 100644 src/Groundstation/RotatingPlatform/Actuators/Actuators.h create mode 100644 src/Groundstation/RotatingPlatform/Actuators/ActuatorsConfig.h create mode 100644 src/Groundstation/RotatingPlatform/Actuators/ActuatorsData.h create mode 100644 src/Groundstation/RotatingPlatform/PinHandler/PinHandler.cpp create mode 100644 src/Groundstation/RotatingPlatform/PinHandler/PinHandler.h create mode 100644 src/Groundstation/RotatingPlatform/rotating-entry.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e91c7441..96e274d62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,3 +102,10 @@ add_executable(lyra-gs-entry ) target_include_directories(lyra-gs-entry PRIVATE ${OBSW_INCLUDE_DIRS}) sbs_target(lyra-gs-entry stm32f767zi_lyra_gs) + +add_executable(rotating-entry + src/Groundstation/RotatingPlatform/rotating-entry.cpp + ${ROTATING_PLATFORM} +) +target_include_directories(rotating-entry PRIVATE ${OBSW_INCLUDE_DIRS}) +sbs_target(rotating-entry stm32f767zi_lyra_gs) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 27364e888..cfd4a35b5 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -118,3 +118,10 @@ set (LYRA_GS src/Groundstation/Automated/PinHandler/PinHandler.cpp src/Groundstation/LyraGS/Ports/SerialLyraGS.cpp ) + +set (ROTATING_PLATFORM + src/Groundstation/RotatingPlatform/Actuators/Actuators.cpp + src/Groundstation/RotatingPlatform/PinHandler/PinHandler.cpp + src/Groundstation/Automated/Leds/Leds.cpp +) + diff --git a/src/Groundstation/RotatingPlatform/Actuators/Actuators.cpp b/src/Groundstation/RotatingPlatform/Actuators/Actuators.cpp new file mode 100644 index 000000000..3872d379b --- /dev/null +++ b/src/Groundstation/RotatingPlatform/Actuators/Actuators.cpp @@ -0,0 +1,246 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Authors: Nicolò Caruso + * + * 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 "Actuators.h" + +#include <interfaces-impl/hwmapping.h> + +#include "ActuatorsConfig.h" + +using namespace miosix; +using namespace Boardcore; + +namespace RotatingPlatform +{ + +using namespace Config; + +// TIM1_CH1 PA8 AF1 Stepper H step +// | +// TIM3_CH2 PC7 AF2 Stepper H count + +// TIM4_CH1 PD12 AF2 Stepper V step +// | +// TIM8_CH1 PC6 AF3 Stepper V count + +CountedPWM countedPwmX(StepperSettings::SERVO1_PULSE_TIM, + StepperSettings::SERVO1_PULSE_CH, + StepperSettings::SERVO1_PULSE_ITR, + StepperSettings::SERVO1_COUNT_TIM, + StepperSettings::SERVO1_COUNT_CH, + StepperSettings::SERVO1_COUNT_ITR); + +Actuators::Actuators() + : ActiveObject(STACK_MIN_FOR_SKYWARD, MAIN_PRIORITY), + stepperX(countedPwmX, stepper1::pulseTimer::getPin(), + stepper1::direction::getPin(), stepperXConfig.MAX_SPEED, + stepperXConfig.STEP_ANGLE, false, stepperXConfig.MICROSTEPPING, + Stepper::PinConfiguration::COMMON_CATHODE, + stepper1::enable::getPin()){}; + +Actuators::Actuators(StepperConfig config) + : ActiveObject(STACK_MIN_FOR_SKYWARD, MAIN_PRIORITY), + stepperX(countedPwmX, stepper1::pulseTimer::getPin(), + stepper1::direction::getPin(), config.MAX_SPEED, + config.STEP_ANGLE, false, config.MICROSTEPPING, + Stepper::PinConfiguration::COMMON_CATHODE, + stepper1::enable::getPin()), + configX(config) +{ +} + +void Actuators::run() +{ + { + miosix::Lock<FastMutex> lock(rotationMutex); + + float speed = speedX; + + // Acceleration/stable phase + if (stepperX.isEnabled() && isRotating) + { + if (speed < configX.MAX_SPEED) + speed += 0.1; + if (speed > configX.MAX_SPEED) + speed = configX.MAX_SPEED; + setSpeed(StepperList::STEPPER_X, speed); + } + // Deceleration phase + else + { + if (speedX > 0) + speed -= 0.1; + if (speed < 0) + speed = 0; + setSpeed(StepperList::STEPPER_X, speed); + } + } + Thread::sleep(100); +} + +void Actuators::arm() { stepperX.enable(); } + +void Actuators::disarm() { stepperX.disable(); } + +void Actuators::enableRotation() +{ + miosix::Lock<FastMutex> lock(rotationMutex); + isRotating = true; +} + +void Actuators::disableRotation() +{ + miosix::Lock<FastMutex> lock(rotationMutex); + isRotating = false; +} + +ActuationStatus Actuators::setSpeed(StepperList axis, float speed) +{ + const auto *config = getStepperConfig(axis); + auto *stepper = getStepper(axis); + auto actuationState = ActuationStatus::OK; + auto multiplier = getStepperMultiplier(axis); + + speed *= multiplier; + + if (speed > config->MAX_SPEED) + { + speed = config->MAX_SPEED; + actuationState = ActuationStatus::SPEED_LIMIT; + } + + stepper->setSpeed(speed); + + switch (axis) + { + case StepperList::STEPPER_X: + speedX = speed; + break; + default: + actuationState = ActuationStatus::NO_STEPPER; + break; + } + + return actuationState; +} + +void Actuators::zeroPosition() { stepperX.zeroPosition(); } + +int16_t Actuators::getCurrentPosition(StepperList axis) +{ + return getStepper(axis)->getCurrentPosition(); +} + +float Actuators::getCurrentDegPosition(StepperList axis) +{ + auto multiplier = getStepperMultiplier(axis); + auto *stepper = getStepper(axis); + + return stepper->getCurrentDegPosition() / multiplier; +} + +ActuationStatus Actuators::move(StepperList axis, int16_t steps) +{ + auto *stepper = getStepper(axis); + + ActuationStatus actuationState = + ActuationStatus::OK; //< In case the move command is not limited + + if (!stepper->isEnabled()) + return ActuationStatus::DISABLED; + + const auto *config = getStepperConfig(axis); + float position = getCurrentPosition(axis); + + if (configX.HAS_ANGLE_LIMITS) + { + int16_t maxSteps = + config->MAX_ANGLE * config->MICROSTEPPING / config->STEP_ANGLE; + int16_t minSteps = + config->MIN_ANGLE * config->MICROSTEPPING / config->STEP_ANGLE; + + // POSITION_LIMIT POSITION IN ACCEPTABLE RANGE + if (position + steps > maxSteps) + { + steps = config->MAX_ANGLE - position; + actuationState = ActuationStatus::POSITION_LIMIT; + } + else if (position + steps < minSteps) + { + steps = config->MIN_ANGLE - position; + } + } + stepper->move(steps); + logStepperData(axis, stepper->getState(steps * config->STEP_ANGLE / + config->MICROSTEPPING)); + return actuationState; +} + +ActuationStatus Actuators::moveDeg(StepperList axis, float degrees) +{ + auto *stepper = getStepper(axis); + + ActuationStatus actuationState = + ActuationStatus::OK; //< In case the move command is not limited + + const auto *config = getStepperConfig(axis); + auto multiplier = getStepperMultiplier(axis); + float positionDeg = getCurrentDegPosition(axis); + + if (configX.HAS_ANGLE_LIMITS) + { + // POSITION_LIMIT POSITION IN ACCEPTABLE RANGE + if (positionDeg + degrees > config->MAX_ANGLE) + { + degrees = config->MAX_ANGLE - positionDeg; + actuationState = ActuationStatus::POSITION_LIMIT; + } + else if (positionDeg + degrees < config->MIN_ANGLE) + { + degrees = config->MIN_ANGLE - positionDeg; + } + } + + // Moving stepper of the angle 'degrees' + stepper->moveDeg(degrees * multiplier); + logStepperData(axis, stepper->getState(degrees)); + return actuationState; +} + +ActuationStatus Actuators::setPositionDeg(StepperList axis, float positionDeg) +{ + return moveDeg(axis, positionDeg - getCurrentDegPosition(axis)); +} + +void Actuators::setMultipliers(StepperList axis, float multiplier) +{ + switch (axis) + { + case StepperList::STEPPER_X: + multiplierX = multiplier; + break; + default: + assert(false && "Non existent stepper"); + break; + } +} +} // namespace RotatingPlatform diff --git a/src/Groundstation/RotatingPlatform/Actuators/Actuators.h b/src/Groundstation/RotatingPlatform/Actuators/Actuators.h new file mode 100644 index 000000000..5a1b1e03a --- /dev/null +++ b/src/Groundstation/RotatingPlatform/Actuators/Actuators.h @@ -0,0 +1,224 @@ +/* Copyright (c) 2023-2024 Skyward Experimental Rocketry + * Authors: Emilio Corigliano, Nicolò Caruso + * + * 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 <ActiveObject.h> +#include <common/MavlinkLyra.h> +#include <logger/Logger.h> +#include <utils/DependencyManager/DependencyManager.h> + +#include "ActuatorsConfig.h" +#include "ActuatorsData.h" +#include "actuators/stepper/StepperPWM.h" + +// TIM1_CH1 PA8 AF1 Stepper H step +// | +// TIM3_CH2 PC7 AF2 Stepper H count + +namespace RotatingPlatform +{ + +/** + * @brief Error handling enum for the stepper movement + */ +enum class ActuationStatus : uint8_t +{ + OK, ///< `0` + POSITION_LIMIT, ///< `1` The STEPPER_X reached its actuation limits + SPEED_LIMIT, ///< `2` Stepper reached its velocity limits + NOT_TEST, ///< `3` Such movement is allowed only in test + NO_STEPPER, ///< `4` The specified stepper does not exist + DISABLED, ///< `5` +}; + +/** + * @brief Actuators handles the stepper X and exposes functions to drive it. + * Also, it updates its status by checking the speed and linearly increase and + * decrease it. This is done to avoid issues due to inertia and for safety + * reasons. + */ +class Actuators : public Boardcore::Injectable, public Boardcore::ActiveObject +{ +public: + /** + * @brief Construct a new Actuators object using default stepper + * configurations + * + */ + Actuators(); + + /** + * @brief Construct a new Actuators object using a given configuration for + * the stepper + * + * @param config The stepper configuration, used to override the default one + */ + Actuators(StepperConfig config); + + /** + * @brief Enables the actuators + */ + void arm(); + + /** + * @brief Disables the actuators + */ + void disarm(); + + /** + * @brief Enables the rotational movement + * + */ + void enableRotation(); + + /** + * @brief Disables the rotational movement + * + */ + void disableRotation(); + + ActuationStatus setSpeed(StepperList axis, float speed); + ActuationStatus move(StepperList axis, int16_t steps); + ActuationStatus moveDeg(StepperList axis, float degrees); + ActuationStatus setPosition(StepperList axis, int16_t steps); + ActuationStatus setPositionDeg(StepperList axis, float degrees); + + void setMultipliers(StepperList axis, float multiplier); + bool areMultipliersSet(); + + void zeroPosition(); + + int16_t getCurrentPosition(StepperList axis); + float getCurrentDegPosition(StepperList axis); + + /** + * @brief Getter for the last actuation of the wanted stepper. + * @param axis The stepper from which we want this information. + * @returns The last delta angle the chosen stepper is performing [deg]. + */ + float getDeltaAngleDeg(StepperList axis) const + { + switch (axis) + { + case StepperList::STEPPER_X: + return deltaX; + default: + assert(false && "Non existent stepper"); + return 0; + } + } + + /** + * @brief Getter for the speed of the wanted stepper. + * @param axis The stepper from which we want this information. + * @returns The speed of the chosen stepper [rps]. + */ + float getSpeed(StepperList axis) const + { + switch (axis) + { + case StepperList::STEPPER_X: + return speedX; + default: + assert(false && "Non existent stepper"); + return 0; + } + } + +protected: + /** + * @brief Run function for actuators in rotational platform case. It + * accelerate and then spin to the wanted rotational speed + * @note This function is used to linearly increase and decrease the speed + * of the steppers. + */ + void run() override; + +private: + Boardcore::StepperPWM* getStepper(StepperList stepper) + { + switch (stepper) + { + case StepperList::STEPPER_X: + return &stepperX; + default: + assert(false && "Non existent stepper"); + return nullptr; + } + }; + + const StepperConfig* getStepperConfig(StepperList stepper) const + { + switch (stepper) + { + case StepperList::STEPPER_X: + return &RotatingPlatform::Config::stepperXConfig; + + default: + assert(false && "Non existent stepperConfig"); + return nullptr; + } + }; + + float getStepperMultiplier(StepperList stepper) const + { + switch (stepper) + { + case StepperList::STEPPER_X: + return multiplierX; + default: + assert(false && "Non existent stepperConfig"); + return 0; + } + }; + + void logStepperData(StepperList stepper, Boardcore::StepperData data) + { + switch (stepper) + { + case StepperList::STEPPER_X: + Boardcore::Logger::getInstance().log( + static_cast<StepperXData>(data)); + break; + default: + assert(false && "Non existent stepper"); + break; + } + } + + Boardcore::StepperPWM stepperX; + + // Flags indicating if the multipliers have been set + float multiplierX = 2.2f; // Multiplier for the stepper X + float multiplierY = 2.2f; // Multiplier for the stepper Y + + float deltaX = 0.0f; // Delta angle to perform [deg] + float deltaY = 0.0f; // Delta angle to perform [deg] + float speedX = 0; // Speed of the stepper [rps] + + StepperConfig configX = Config::stepperXConfig; + + // Variables to enable the rotation + bool isRotating = false; + miosix::FastMutex rotationMutex; +}; +} // namespace RotatingPlatform diff --git a/src/Groundstation/RotatingPlatform/Actuators/ActuatorsConfig.h b/src/Groundstation/RotatingPlatform/Actuators/ActuatorsConfig.h new file mode 100644 index 000000000..f076a8f01 --- /dev/null +++ b/src/Groundstation/RotatingPlatform/Actuators/ActuatorsConfig.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Nicolò Caruso + * + * 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 <drivers/timer/PWM.h> +#include <drivers/timer/TimerUtils.h> + +#include "ActuatorsData.h" + +namespace RotatingPlatform +{ +namespace Config +{ + +static const RotatingPlatform::StepperConfig stepperXConfig{ + .MICROSTEPPING = 4, + .STEP_ANGLE = 1.8, + .HAS_ANGLE_LIMITS = false, + .MIN_ANGLE = 0, + .MAX_ANGLE = 0, + .MAX_SPEED = 0.1, //<[RPS] +}; + +namespace StepperSettings +{ +// TIM1_CH1 PA8 AF1 Stepper H step +// | +// TIM3_CH2 PC7 AF2 Stepper H count + +static TIM_TypeDef* const SERVO1_PULSE_TIM = TIM1; +static TIM_TypeDef* const SERVO1_COUNT_TIM = TIM3; +static TIM_TypeDef* const SERVO2_PULSE_TIM = TIM4; +static TIM_TypeDef* const SERVO2_COUNT_TIM = TIM8; + +constexpr Boardcore::TimerUtils::Channel SERVO1_PULSE_CH = + Boardcore::TimerUtils::Channel::CHANNEL_1; +constexpr Boardcore::TimerUtils::Channel SERVO1_COUNT_CH = + Boardcore::TimerUtils::Channel::CHANNEL_2; + +constexpr Boardcore::TimerUtils::TriggerSource SERVO1_PULSE_ITR = + Boardcore::TimerUtils::TriggerSource::ITR2; +constexpr Boardcore::TimerUtils::TriggerSource SERVO1_COUNT_ITR = + Boardcore::TimerUtils::TriggerSource::ITR0; + +} // namespace StepperSettings +} // namespace Config +} // namespace RotatingPlatform diff --git a/src/Groundstation/RotatingPlatform/Actuators/ActuatorsData.h b/src/Groundstation/RotatingPlatform/Actuators/ActuatorsData.h new file mode 100644 index 000000000..0ed512f34 --- /dev/null +++ b/src/Groundstation/RotatingPlatform/Actuators/ActuatorsData.h @@ -0,0 +1,48 @@ +/* Copyright (c) 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 +#include <actuators/stepper/StepperData.h> + +namespace RotatingPlatform +{ + +struct StepperConfig +{ + int MICROSTEPPING; + float STEP_ANGLE; + bool HAS_ANGLE_LIMITS; + float MIN_ANGLE; + float MAX_ANGLE; + float MAX_SPEED; +}; + +struct StepperXData : Boardcore::StepperData +{ + explicit StepperXData() : Boardcore::StepperData() {} + + explicit StepperXData(const Boardcore::StepperData& data) + : Boardcore::StepperData(data) + { + } +}; + +} // namespace RotatingPlatform diff --git a/src/Groundstation/RotatingPlatform/PinHandler/PinHandler.cpp b/src/Groundstation/RotatingPlatform/PinHandler/PinHandler.cpp new file mode 100644 index 000000000..6e513e1f1 --- /dev/null +++ b/src/Groundstation/RotatingPlatform/PinHandler/PinHandler.cpp @@ -0,0 +1,130 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Nicolò Caruso + * + * 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 <Groundstation/RotatingPlatform/PinHandler/PinHandler.h> +#include <common/Events.h> +#include <common/Topics.h> +#include <drivers/timer/TimestampTimer.h> +#include <events/EventBroker.h> +#include <interfaces-impl/hwmapping.h> + +#include <functional> + +using namespace Boardcore; +using namespace std; +using namespace std::placeholders; +using namespace Common; + +namespace RotatingPlatform +{ +PinHandler::PinHandler() : scheduler(), pin_observer(scheduler) +{ + pin_observer.registerPinCallback( + miosix::commBox::switchArm::getPin(), + bind(&PinHandler::onArmTransition, this, _1), + PinHandlerConfig::ARM_SWITCH_THRESHOLD); + + pin_observer.registerPinCallback( + miosix::commBox::switchActive::getPin(), + bind(&PinHandler::onActiveTransition, this, _1), + PinHandlerConfig::ACTIVE_SWITCH_THRESHOLD); +} + +bool PinHandler::start() { return scheduler.start(); } + +bool PinHandler::isStarted() { return scheduler.isRunning(); } + +void PinHandler::onArmTransition(PinTransition transition) +{ + if (transition == Boardcore::PinTransition::RISING_EDGE) + { + getModule<Antennas::Leds>()->setOn(Antennas::LedColor::YELLOW); + getModule<Actuators>()->arm(); + + // Log the event + PinData data = getPinData(PinList::ARM_SWITCH); + PinChangeData log{TimestampTimer::getTimestamp(), PinList::ARM_SWITCH, + data.changesCount}; + Logger::getInstance().log(log); + } + else + { + getModule<Antennas::Leds>()->setFastBlink(Antennas::LedColor::YELLOW); + getModule<Actuators>()->disarm(); + + // Log the event + PinData data = getPinData(PinList::ARM_SWITCH); + PinChangeData log{TimestampTimer::getTimestamp(), PinList::ARM_SWITCH, + data.changesCount}; + Logger::getInstance().log(log); + } +} + +void PinHandler::onActiveTransition(PinTransition transition) +{ + if (transition == Boardcore::PinTransition::RISING_EDGE) + { + getModule<Antennas::Leds>()->setOn(Antennas::LedColor::BLUE); + getModule<Actuators>()->enableRotation(); + + // Log the event + PinData data = getPinData(PinList::ACTIVE_SWITCH); + PinChangeData log{TimestampTimer::getTimestamp(), + PinList::ACTIVE_SWITCH, data.changesCount}; + Logger::getInstance().log(log); + } + + else + { + getModule<Antennas::Leds>()->setFastBlink(Antennas::LedColor::BLUE); + getModule<Actuators>()->disableRotation(); + + // Log the event + PinData data = getPinData(PinList::ACTIVE_SWITCH); + PinChangeData log{TimestampTimer::getTimestamp(), + PinList::ACTIVE_SWITCH, data.changesCount}; + Logger::getInstance().log(log); + } +} + +PinData PinHandler::getPinData(PinList pin) +{ + switch (pin) + { + case PinList::ARM_SWITCH: + { + return pin_observer.getPinData( + miosix::commBox::switchArm::getPin()); + } + case PinList::ACTIVE_SWITCH: + { + return pin_observer.getPinData( + miosix::commBox::switchActive::getPin()); + } + default: + { + LOG_ERR(logger, "Requested non valid pin"); + return PinData{}; + } + } +} +} // namespace RotatingPlatform \ No newline at end of file diff --git a/src/Groundstation/RotatingPlatform/PinHandler/PinHandler.h b/src/Groundstation/RotatingPlatform/PinHandler/PinHandler.h new file mode 100644 index 000000000..cb818b57c --- /dev/null +++ b/src/Groundstation/RotatingPlatform/PinHandler/PinHandler.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Nicolò Caruso + * + * 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 <Groundstation/Automated/PinHandler/PinData.h> +#include <Groundstation/Automated/Leds/Leds.h> +#include <Groundstation/RotatingPlatform/Actuators/Actuators.h> +#include <diagnostic/PrintLogger.h> +#include <scheduler/TaskScheduler.h> +#include <utils/DependencyManager/DependencyManager.h> +#include <utils/PinObserver/PinObserver.h> + +namespace RotatingPlatform +{ + +namespace PinHandlerConfig +{ +constexpr unsigned int ARM_SWITCH_THRESHOLD = 1; +constexpr unsigned int ACTIVE_SWITCH_THRESHOLD = 1; +} // namespace PinHandlerConfig + +struct PinChangeData +{ + uint64_t timestamp = 0; + uint8_t pinID = 0; + uint32_t changesCount = 0; + + PinChangeData(uint64_t timestamp, uint8_t pinID, uint32_t changesCount) + : timestamp(timestamp), pinID(pinID), changesCount(changesCount) + { + } + + PinChangeData() : PinChangeData{0, 0, 0} {} + + static std::string header() { return "timestamp,pinID,changesCount\n"; } + + void print(std::ostream& os) const + { + os << timestamp << "," << (int)pinID << "," << (int)changesCount + << "\n"; + } +}; + +class PinHandler : public Boardcore::InjectableWithDeps<Actuators, Antennas::Leds> +{ +public: + enum PinList : uint8_t + { + ARM_SWITCH, + ACTIVE_SWITCH + }; + + PinHandler(); + + /** + * @brief Starts the PinObserver module thread + */ + bool start(); + + /** + * @brief Checks if the module has started correctly + */ + bool isStarted(); + + /** + * @brief Called when the arm switch has been flipped + */ + void onArmTransition(Boardcore::PinTransition transition); + + /** + * @brief Called when the active switch has been flipped + */ + void onActiveTransition(Boardcore::PinTransition transition); + + /** + * @brief Returns the status of the requested pin + */ + Boardcore::PinData getPinData(PinList pin); + +private: + Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("PinHandler"); + + Boardcore::TaskScheduler scheduler; + Boardcore::PinObserver pin_observer; +}; +} // namespace RotatingPlatform \ No newline at end of file diff --git a/src/Groundstation/RotatingPlatform/rotating-entry.cpp b/src/Groundstation/RotatingPlatform/rotating-entry.cpp new file mode 100644 index 000000000..5610fd0bb --- /dev/null +++ b/src/Groundstation/RotatingPlatform/rotating-entry.cpp @@ -0,0 +1,137 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Authors: Nicolò Caruso + * + * 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 <Groundstation/Automated/Leds/Leds.h> +#include <Groundstation/LyraGS/Buses.h> +#include <Groundstation/RotatingPlatform/Actuators/Actuators.h> +#include <Groundstation/RotatingPlatform/Actuators/ActuatorsConfig.h> +#include <Groundstation/RotatingPlatform/PinHandler/PinHandler.h> +#include <common/Events.h> +#include <drivers/timer/PWM.h> +#include <drivers/timer/TimerUtils.h> +#include <interfaces-impl/hwmapping.h> + +#include <functional> + +using namespace Boardcore; +using namespace std; +using namespace std::placeholders; +using namespace Common; + +using namespace Antennas; +using namespace LyraGS; +using namespace Boardcore; +using namespace miosix; +using namespace RotatingPlatform; + +// Flags indicating if the multipliers have been set +static constexpr float MULTIPLIER_X = 2.2f; // Multiplier for the stepper X +static constexpr uint8_t ARM_SWITCH_THRESHOLD = 1; +static constexpr uint8_t FOLLOW_SWITCH_THRESHOLD = 1; + +void idleLoop() +{ + while (1) + { + Thread::wait(); + } +} + +/** + * @brief Blinking RED led at 5Hz + */ +void errorLoop() +{ + while (1) + { + led3On(); //< Turn on RED led (CU) + Thread::sleep(100); + led3Off(); + Thread::sleep(100); + } +} + +/** + * @brief Entrypoint for the rotational platform. To use it, is needed the + * command box of ARP. The arm switch arms the actuators while the follow one + * activates the rotation with constant speed (except for a linearly accelerated + * start and decelerated end) + * + * @note The rotation is imposed by a configuration parameter given by + * constructor or, in this case, by the ActuatorsData stepper config. + * + * @attention the LED color code is the following: `RED` always `fast blink`; + * `YELLOW` `fast blink`: disarmed, `Y-on`: armed; `BLUE` `fast blink`: not + * rotating, `B-on`: rotating + */ +int main() +{ + DependencyManager manager; + PrintLogger logger = Logging::getLogger("rotation_test"); + TaskScheduler* scheduler_high = new TaskScheduler(); + TaskScheduler* scheduler_low = new TaskScheduler(0); + + Buses* buses = new Buses(); + RotatingPlatform::Actuators* actuators = new RotatingPlatform::Actuators(); + Antennas::Leds* leds = new Antennas::Leds(scheduler_low); + + bool ok = true; + + ok &= manager.insert(buses); + ok &= manager.insert(leds); + ok &= manager.insert(actuators); + + if (!ok) + errorLoop(); + + if (!manager.inject()) + { + std::cout << "[error] Failed to inject the dependencies!" << std::endl; + errorLoop(); + } + + if (!Logger::getInstance().start()) + { + std::cout << "ERROR: Failed to start Logger" << std::endl; + ok = false; + } + + if (!scheduler_high->start()) + { + std::cout << "[error] Failed to start scheduler_high!" << std::endl; + ok = false; + } + + if (!scheduler_low->start()) + { + std::cout << "[error] Failed to start scheduler_low!" << std::endl; + ok = false; + } + + // Fast blink to make the operator aware that this is not an ARP + // entrypoint (lyra-gs-entry) + leds->setFastBlink(LedColor::RED); + leds->setFastBlink(LedColor::YELLOW); + leds->setFastBlink(LedColor::BLUE); + + idleLoop(); +} \ No newline at end of file -- GitLab