From e9d79aacce34d6c4551f4170f0ab15ebe02495be Mon Sep 17 00:00:00 2001 From: Emilio Corigliano <emilio.corigliano@skywarder.eu> Date: Wed, 2 Oct 2024 15:17:04 +0200 Subject: [PATCH] [AutomatedAntennas] Implemented Actuators and Buses classes and base of test-steps --- CMakeLists.txt | 4 + cmake/dependencies.cmake | 4 + src/boards/AutomatedAntennas/Actuators.cpp | 214 ++++++++++++++++++ src/boards/AutomatedAntennas/Actuators.h | 75 ++++++ .../AutomatedAntennas/ActuatorsConfig.h | 63 ++++++ src/boards/AutomatedAntennas/Buses.h | 55 +++++ .../AutomatedAntennas/test-steps.cpp | 120 ++++++++++ 7 files changed, 535 insertions(+) create mode 100644 src/boards/AutomatedAntennas/Actuators.cpp create mode 100644 src/boards/AutomatedAntennas/Actuators.h create mode 100644 src/boards/AutomatedAntennas/ActuatorsConfig.h create mode 100644 src/boards/AutomatedAntennas/Buses.h create mode 100644 src/entrypoints/Groundstation/AutomatedAntennas/test-steps.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 94185b780..b447dd861 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,3 +108,7 @@ sbs_target(nokia-groundstation-entry stm32f429zi_skyward_groundstation_v2) add_executable(automated-antennas-entry src/entrypoints/Groundstation/AutomatedAntennas/automated-antennas-entry.cpp) target_include_directories(automated-antennas-entry PRIVATE ${OBSW_INCLUDE_DIRS}) sbs_target(automated-antennas-entry stm32f407vg_stm32f4discovery) + +add_executable(test-steps src/entrypoints/Groundstation/AutomatedAntennas/test-steps.cpp ${ANTENNAS}) +target_include_directories(test-steps PRIVATE ${OBSW_INCLUDE_DIRS}) +sbs_target(test-steps stm32f767zi_nucleo) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 1e3364643..bd8e4077e 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -137,4 +137,8 @@ set(GROUNDSTATION_BASE src/boards/Groundstation/Common/Ports/EthernetBase.cpp src/boards/Groundstation/Common/Radio/RadioBase.cpp src/boards/Groundstation/Common/HubBase.cpp +) + +set(ANTENNAS + src/boards/AutomatedAntennas/Actuators.cpp ) \ No newline at end of file diff --git a/src/boards/AutomatedAntennas/Actuators.cpp b/src/boards/AutomatedAntennas/Actuators.cpp new file mode 100644 index 000000000..1274feba2 --- /dev/null +++ b/src/boards/AutomatedAntennas/Actuators.cpp @@ -0,0 +1,214 @@ +/* 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. + */ + +#include "Actuators.h" + +#include "ActuatorsConfig.h" +#include "logger/Logger.h" + +using namespace miosix; +using namespace Boardcore; + +namespace Antennas +{ +// TIM1_CH4 PA11 AF1 +// | +// TIM3_CH2 PC7 AF2 + +// TIM4_CH1 PD12 AF2 +// | +// TIM8_CH4 PC9 AF3 + +GpioPin stepPin1 = GpioPin(GPIOA_BASE, 11); // tim1_ch4 +GpioPin countPin1 = GpioPin(GPIOC_BASE, 7); // tim3_ch2 +GpioPin directionPin1 = GpioPin(GPIOA_BASE, 12); +GpioPin enablePin1 = GpioPin(GPIOA_BASE, 8); + +GpioPin stepPin2 = GpioPin(GPIOD_BASE, 12); // tim4_ch1 +GpioPin countPin2 = GpioPin(GPIOC_BASE, 9); // tim8_ch4 +GpioPin directionPin2 = GpioPin(GPIOD_BASE, 13); +GpioPin enablePin2 = GpioPin(GPIOD_BASE, 3); + +GpioPin ledRGB = GpioPin(GPIOG_BASE, 14); + +CountedPWM countedPwmX(Config::StepperConfig::SERVO1_PULSE_TIM, + Config::StepperConfig::SERVO1_PULSE_CH, + Config::StepperConfig::SERVO1_PULSE_ITR, + Config::StepperConfig::SERVO1_COUNT_TIM, + Config::StepperConfig::SERVO1_COUNT_CH, + Config::StepperConfig::SERVO1_COUNT_ITR); + +CountedPWM countedPwmY(Config::StepperConfig::SERVO2_PULSE_TIM, + Config::StepperConfig::SERVO2_PULSE_CH, + Config::StepperConfig::SERVO2_PULSE_ITR, + Config::StepperConfig::SERVO2_COUNT_TIM, + Config::StepperConfig::SERVO2_COUNT_CH, + Config::StepperConfig::SERVO2_COUNT_ITR); + +Actuators::Actuators() + : stepperX(countedPwmX, stepPin1, directionPin1, 1, 1.8, false, 8, + Stepper::PinConfiguration::COMMON_CATHODE, enablePin1), + stepperY(countedPwmY, stepPin2, directionPin2, 1, 1.8, false, 8, + Stepper::PinConfiguration::COMMON_CATHODE, enablePin2) +{ + stepPin1.mode(Mode::ALTERNATE); + stepPin1.alternateFunction(1); + stepPin2.mode(Mode::ALTERNATE); + stepPin2.alternateFunction(2); + + directionPin1.mode(Mode::OUTPUT); + enablePin1.mode(Mode::OUTPUT); + directionPin2.mode(Mode::OUTPUT); + enablePin2.mode(Mode::OUTPUT); +#ifdef NO_SD_LOGGING + countPin1.mode(Mode::ALTERNATE); + countPin1.alternateFunction(2); + countPin2.mode(Mode::ALTERNATE); + countPin2.alternateFunction(3); +#endif +} + +/** + * @brief Enables all the stepperPWM + */ +void Actuators::start() +{ + stepperX.enable(); + stepperY.enable(); +} + +void Actuators::setSpeed(StepperList axis, float speed) +{ + switch (axis) + { + case StepperList::HORIZONTAL: + stepperX.setSpeed(speed); + break; + case StepperList::VERTICAL: + stepperY.setSpeed(speed); + break; + default: + assert(false && "Non existent stepper"); + break; + } +} + +int16_t Actuators::getCurrentPosition(StepperList axis) +{ + switch (axis) + { + case StepperList::HORIZONTAL: + return stepperX.getCurrentPosition(); + break; + case StepperList::VERTICAL: + return stepperY.getCurrentPosition(); + break; + default: + assert(false && "Non existent stepper"); + break; + } + return 0; +} + +float Actuators::getCurrentDegPosition(StepperList axis) +{ + switch (axis) + { + case StepperList::HORIZONTAL: + return stepperX.getCurrentDegPosition(); + break; + case StepperList::VERTICAL: + return stepperY.getCurrentDegPosition(); + break; + default: + assert(false && "Non existent stepper"); + break; + } + return 0; +} + +void Actuators::moveDeg(StepperList axis, float degrees) +{ + switch (axis) + { + case StepperList::HORIZONTAL: + if (stepperXActive) // Check for emergency stop + { + stepperX.moveDeg(degrees); + Logger::getInstance().log(stepperX.getState(degrees)); + } + break; + case StepperList::VERTICAL: + if (stepperYActive) // Check for emergency stop + { + stepperY.moveDeg(degrees); + Logger::getInstance().log(stepperY.getState(degrees)); + } + break; + default: + assert(false && "Non existent stepper"); + break; + } +} + +void Actuators::setPositionDeg(StepperList axis, float positionDeg) +{ + float currentDegPosition; + switch (axis) + { + case StepperList::HORIZONTAL: + currentDegPosition = stepperX.getCurrentDegPosition(); + break; + case StepperList::VERTICAL: + currentDegPosition = stepperY.getCurrentDegPosition(); + break; + default: + assert(false && "Non existent stepper"); + return; + } + + moveDeg(axis, positionDeg - currentDegPosition); +} + +void Actuators::emergencyStop() +{ + // Do not preempt during this method + PauseKernelLock pkLock; + stepperXActive = false; // Disable actuation of horizontal stepper + stepperYActive = false; // Disable actuation of vertical stepper + stepperX.disable(); // Disable the horizontal movement + stepperY.enable(); // Don't make the antenna fall + countedPwmX.stop(); // Terminate current stepper actuation + countedPwmY.stop(); // Terminate current stepper actuation +} + +void Actuators::emergencyStopRecovery() +{ + // Do not preempt during this method + PauseKernelLock pkLock; + stepperXActive = true; // Re-enable actuation of horizontal stepper + stepperYActive = true; // Re-enable actuation of vertical stepper + stepperX.enable(); // Re-enable horizontal movement + stepperY.enable(); // Re-enable vertical movement +} + +} // namespace Antennas \ No newline at end of file diff --git a/src/boards/AutomatedAntennas/Actuators.h b/src/boards/AutomatedAntennas/Actuators.h new file mode 100644 index 000000000..3dc8ce071 --- /dev/null +++ b/src/boards/AutomatedAntennas/Actuators.h @@ -0,0 +1,75 @@ +/* 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 <utils/ModuleManager/ModuleManager.hpp> + +#include "actuators/stepper/StepperPWM.h" + +// TIM1_CH4 PA11 AF1 +// | +// TIM3_CH2 PC7 AF2 + +// TIM4_CH1 PD12 AF2 +// | +// TIM8_CH4 PC9 AF3 + +namespace Antennas +{ +class Actuators : public Boardcore::Module +{ +public: + enum StepperList + { + HORIZONTAL, // Stepper moving horizontally (x axis) + VERTICAL // Stepper moving vertically (y axis) + }; + + Actuators(); + + /** + * @brief Enables all the servos PWMs + */ + void start(); + + void emergencyStop(); + void emergencyStopRecovery(); + + void setSpeed(StepperList axis, float speed); + + void move(StepperList axis, int16_t steps); + void moveDeg(StepperList axis, float degrees); + void setPosition(StepperList axis, int16_t steps); + void setPositionDeg(StepperList axis, float degrees); + + int16_t getCurrentPosition(StepperList axis); + float getCurrentDegPosition(StepperList axis); + +private: + Boardcore::StepperPWM& getServo(StepperList servo); + + Boardcore::StepperPWM stepperX; + Boardcore::StepperPWM stepperY; + bool stepperXActive = true; // Whether stepper on X axis can accept steps + bool stepperYActive = true; // Whether stepper on Y axis can accept steps +}; +} // namespace Antennas \ No newline at end of file diff --git a/src/boards/AutomatedAntennas/ActuatorsConfig.h b/src/boards/AutomatedAntennas/ActuatorsConfig.h new file mode 100644 index 000000000..43d52bea5 --- /dev/null +++ b/src/boards/AutomatedAntennas/ActuatorsConfig.h @@ -0,0 +1,63 @@ +/* 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 <drivers/timer/PWM.h> +#include <drivers/timer/TimerUtils.h> + +namespace Antennas +{ +namespace Config +{ +namespace StepperConfig +{ +// TIM1_CH4 PA11 AF1 +// | +// TIM3_CH2 PC7 AF2 + +// TIM4_CH1 PD12 AF2 +// | +// TIM8_CH4 PC9 AF3 +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_4; +constexpr Boardcore::TimerUtils::Channel SERVO1_COUNT_CH = + Boardcore::TimerUtils::Channel::CHANNEL_2; +constexpr Boardcore::TimerUtils::Channel SERVO2_PULSE_CH = + Boardcore::TimerUtils::Channel::CHANNEL_1; +constexpr Boardcore::TimerUtils::Channel SERVO2_COUNT_CH = + Boardcore::TimerUtils::Channel::CHANNEL_4; + +constexpr Boardcore::TimerUtils::TriggerSource SERVO1_PULSE_ITR = + Boardcore::TimerUtils::TriggerSource::ITR2; +constexpr Boardcore::TimerUtils::TriggerSource SERVO1_COUNT_ITR = + Boardcore::TimerUtils::TriggerSource::ITR0; +constexpr Boardcore::TimerUtils::TriggerSource SERVO2_PULSE_ITR = + Boardcore::TimerUtils::TriggerSource::ITR3; +constexpr Boardcore::TimerUtils::TriggerSource SERVO2_COUNT_ITR = + Boardcore::TimerUtils::TriggerSource::ITR2; +} // namespace StepperConfig +} // namespace Config +} // namespace Antennas \ No newline at end of file diff --git a/src/boards/AutomatedAntennas/Buses.h b/src/boards/AutomatedAntennas/Buses.h new file mode 100644 index 000000000..b21a2521a --- /dev/null +++ b/src/boards/AutomatedAntennas/Buses.h @@ -0,0 +1,55 @@ +/* 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 <drivers/usart/USART.h> + +#include <utils/ModuleManager/ModuleManager.hpp> + +namespace Antennas +{ + +miosix::GpioPin usart2_tx = miosix::GpioPin(GPIOA_BASE, 2); +miosix::GpioPin usart2_rx = miosix::GpioPin(GPIOA_BASE, 3); +miosix::GpioPin uart4_tx = miosix::GpioPin(GPIOA_BASE, 0); +miosix::GpioPin uart4_rx = miosix::GpioPin(GPIOA_BASE, 1); + +class Buses : public Boardcore::Module +{ +public: + Boardcore::USART usart2; + Boardcore::USART uart4; + + Buses() : usart2(USART2, 115200), uart4(UART4, 115200) + { + usart2_tx.mode(miosix::Mode::ALTERNATE); + usart2_tx.alternateFunction(7); + usart2_rx.mode(miosix::Mode::ALTERNATE); + usart2_rx.alternateFunction(7); + + uart4_tx.mode(miosix::Mode::ALTERNATE); + uart4_tx.alternateFunction(8); + uart4_rx.mode(miosix::Mode::ALTERNATE); + uart4_rx.alternateFunction(8); + } +}; +} // namespace Antennas \ No newline at end of file diff --git a/src/entrypoints/Groundstation/AutomatedAntennas/test-steps.cpp b/src/entrypoints/Groundstation/AutomatedAntennas/test-steps.cpp new file mode 100644 index 000000000..b48cec020 --- /dev/null +++ b/src/entrypoints/Groundstation/AutomatedAntennas/test-steps.cpp @@ -0,0 +1,120 @@ +/* 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. + */ + +#include <AutomatedAntennas/Actuators.h> +#include <AutomatedAntennas/Buses.h> +#include <diagnostic/CpuMeter/CpuMeter.h> +#include <diagnostic/PrintLogger.h> +#include <diagnostic/StackLogger.h> +#include <drivers/timer/TimestampTimer.h> +#include <events/EventBroker.h> +#include <miosix.h> +#include <scheduler/TaskScheduler.h> + +#include <utils/ModuleManager/ModuleManager.hpp> + +#include "actuators/stepper/StepperPWM.h" + +using namespace miosix; +using namespace Boardcore; +using namespace Antennas; + +/** + * Test used to characterize the automated antennas. + */ + +int main() +{ + bool initResult = true; + PrintLogger logger = Logging::getLogger("automated_antennas"); + ModuleManager& modules = ModuleManager::getInstance(); + TaskScheduler* scheduler = new TaskScheduler(); + + // Starting singleton + { + scheduler->start(); +#ifndef NO_SD_LOGGING + printf("Starting Logger\n"); + if (!Logger::getInstance().start()) + { + initResult = false; + printf("Error initializing the Logger\n"); + } + else + { + printf("Logger started successfully\n"); + } +#endif + } + + // Initialize the modules + { + if (!modules.insert<Buses>(new Buses())) + { + initResult = false; + LOG_ERR(logger, "Error inserting the Buses module"); + } + + if (!modules.insert<Actuators>(new Actuators())) + { + initResult = false; + LOG_ERR(logger, "Error inserting the Actuators module"); + } + } + + modules.get<Actuators>()->start(); + + if (!initResult) + { + printf("Errors present during module insertion\n"); + return -1; + } + + // Periodically statistics + for (auto i = 0; i < 50; i++) + { + modules.get<Actuators>()->moveDeg(Actuators::StepperList::VERTICAL, 90); + Thread::sleep(100); + Logger::getInstance().log(CpuMeter::getCpuStats()); + CpuMeter::resetCpuStats(); + Logger::getInstance().logStats(); + StackLogger::getInstance().log(); + } + + for (auto i = 0; i < 50; i++) + { + modules.get<Actuators>()->moveDeg(Actuators::StepperList::HORIZONTAL, + 90); + Thread::sleep(100); + Logger::getInstance().log(CpuMeter::getCpuStats()); + CpuMeter::resetCpuStats(); + Logger::getInstance().logStats(); + StackLogger::getInstance().log(); + } + + printf("Logging finished\n"); + Logger::getInstance().stop(); + printf("Logging stopped\n"); + + while (1) + ; +} -- GitLab