mirror of
https://gitlab.dit.htwk-leipzig.de/phillip.kuehne/dezibot.git
synced 2025-05-19 11:01:46 +02:00
Power management progress
This commit is contained in:
parent
8eeb829a91
commit
51a3d9e8f6
@ -3,12 +3,14 @@
|
||||
|
||||
Dezibot dezibot = Dezibot();
|
||||
|
||||
const uint16_t cycleTime = 5e3; //5000 ms = 5 s
|
||||
|
||||
void setup() {
|
||||
#ifdef DEBUG
|
||||
Serial.begin(112500);
|
||||
while (!Serial) {
|
||||
; /* Wait for USB-CDC Serial init to complete. */
|
||||
}
|
||||
#ifdef DEBUG
|
||||
dezibot.display.begin();
|
||||
dezibot.display.println("Debug enabled.");
|
||||
Serial.println("Debug enabled.");
|
||||
@ -31,6 +33,10 @@ void handle_receive(String &message) {
|
||||
|
||||
void loop() {
|
||||
/* Continuously send to consume power on TX */
|
||||
dezibot.communication.sendMessage("Power Test Message");
|
||||
for(int i=0; i<cycleTime; i++) {
|
||||
dezibot.communication.sendMessage("Power Test Message");
|
||||
delay(1);
|
||||
}
|
||||
delay(cycleTime);
|
||||
|
||||
}
|
@ -5,11 +5,11 @@
|
||||
#include "Dezibot.h"
|
||||
#include <Wire.h>
|
||||
|
||||
Dezibot::Dezibot() : multiColorLight() {};
|
||||
|
||||
Dezibot::Dezibot():multiColorLight(){};
|
||||
|
||||
void Dezibot::begin(void) {
|
||||
Wire.begin(SDA_PIN,SCL_PIN);
|
||||
void Dezibot::begin(void)
|
||||
{
|
||||
Wire.begin(SDA_PIN, SCL_PIN);
|
||||
infraredLight.begin();
|
||||
lightDetection.begin();
|
||||
motion.begin();
|
||||
@ -17,6 +17,10 @@ void Dezibot::begin(void) {
|
||||
colorDetection.begin();
|
||||
multiColorLight.begin();
|
||||
display.begin();
|
||||
Power.begin();
|
||||
this->power = Power::getPowerManager();
|
||||
if (!this->power.tryAccquirePowerAllowance(CONSUMPTION_ESP_BASE);)
|
||||
{
|
||||
throw "Could not allocate power for the base consumption of the ESP32";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "infraredLight/InfraredLight.h"
|
||||
#include "communication/Communication.h"
|
||||
#include "display/Display.h"
|
||||
#include "power/Power.h"
|
||||
|
||||
|
||||
class Dezibot {
|
||||
@ -33,6 +34,7 @@ public:
|
||||
InfraredLight infraredLight;
|
||||
Communication communication;
|
||||
Display display;
|
||||
Power power;
|
||||
void begin(void);
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <freertos/task.h>
|
||||
#include "driver/ledc.h"
|
||||
#include "motionDetection/MotionDetection.h"
|
||||
#include "power/Power.h"
|
||||
#define LEDC_MODE LEDC_LOW_SPEED_MODE
|
||||
#define TIMER LEDC_TIMER_2
|
||||
#define CHANNEL_LEFT LEDC_CHANNEL_3
|
||||
@ -52,7 +53,7 @@ class Motor{
|
||||
uint8_t pin;
|
||||
ledc_timer_t timer;
|
||||
ledc_channel_t channel;
|
||||
|
||||
Power powerManager;
|
||||
uint16_t duty;
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ Motor::Motor(uint8_t pin, ledc_timer_t timer, ledc_channel_t channel){
|
||||
this->channel = channel;
|
||||
this->timer = timer;
|
||||
this->duty = 0;
|
||||
this->powerManager = *Power::getPowerManager();
|
||||
};
|
||||
|
||||
void Motor::begin(void){
|
||||
@ -23,7 +24,13 @@ void Motor::begin(void){
|
||||
};
|
||||
|
||||
void Motor::setSpeed(uint16_t duty){
|
||||
|
||||
if(duty>0) {
|
||||
powerManager.waitForPowerAllowance(CONSUMPTION_MOTOR, portMAX_DELAY);
|
||||
Serial.println("Motor got power");
|
||||
} else {
|
||||
powerManager.releasePower(CONSUMPTION_MOTOR);
|
||||
Serial.println("Motor released power");
|
||||
}
|
||||
int difference = duty-this->getSpeed();
|
||||
if (difference > 0){
|
||||
for(int i = 0;i<difference;i+=difference/20){
|
||||
|
34
src/power/Consumptions.h
Normal file
34
src/power/Consumptions.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @file Consumptions.h
|
||||
* @author Phillip Kühne
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2024-11-28
|
||||
*
|
||||
* @copyright (c) 2024
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef Consumptions_h
|
||||
#define Consumptions_h
|
||||
|
||||
// The power budget afforded by the LIR2450 button cell, 700mW
|
||||
#define POWER_BUDGET 700
|
||||
|
||||
// The power consumptions of the different components are defined here.
|
||||
// These are "typical worst case" values for now.
|
||||
#define CONSUMPTION_ESP_BASE 96
|
||||
#define CONSUMPTION_ESP_LOAD 100
|
||||
#define CONSUMPTION_RGB_LED 56
|
||||
#define CONSUMPTION_IR_BOTTOM 327
|
||||
#define CONSUMPTION_IR_FRONT 492
|
||||
#define CONSUMPTION_OLED 92 // Assumes lots of lit pixels
|
||||
#define CONSUMPTION_MOTOR 323
|
||||
// These are placeholders for completeness for now
|
||||
#define CONSUMPTION_RGBW_SENSOR 1
|
||||
#define CONSUMPTION_IR_PT 1
|
||||
#define CONSUMPTION_UV_LED 200
|
||||
#define CONSUMPTION_IMU 1
|
||||
|
||||
|
||||
#endif //Consumptions_h
|
@ -8,17 +8,42 @@
|
||||
*/
|
||||
|
||||
#include "Power.h"
|
||||
static portMUX_TYPE mux;
|
||||
|
||||
Power::Power()
|
||||
{
|
||||
this->free_power_budget = this->total_power_budget;
|
||||
this->freePowerBudget = this->totalPowerBudget;
|
||||
}
|
||||
|
||||
void Power::begin()
|
||||
{
|
||||
if (powerInstance == nullptr)
|
||||
{
|
||||
// Double check locking https://www.aristeia.com/Papers/DDJ%5FJul%5FAug%5F2004%5Frevised.pdf
|
||||
taskENTER_CRITICAL(&mux);
|
||||
if (powerInstance == nullptr)
|
||||
{
|
||||
powerInstance = new Power();
|
||||
}
|
||||
taskEXIT_CRITICAL(&mux);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Power.begin() was called twice!
|
||||
Serial.println("Power.begin() was called twice! No harm done, but this is a bug.");
|
||||
}
|
||||
}
|
||||
|
||||
Power *Power::getPowerManager()
|
||||
{
|
||||
return powerInstance;
|
||||
}
|
||||
|
||||
bool Power::tryAccquirePowerAllowance(uint16_t neededPower)
|
||||
{
|
||||
if (this->free_power_budget >= neededPower)
|
||||
if (this->freePowerBudget >= neededPower)
|
||||
{
|
||||
this->free_power_budget -= neededPower;
|
||||
this->freePowerBudget -= neededPower;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -29,12 +54,69 @@ bool Power::tryAccquirePowerAllowance(uint16_t neededPower)
|
||||
|
||||
void Power::releasePower(uint16_t power)
|
||||
{
|
||||
if (this->free_power_budget + power <= this->total_power_budget)
|
||||
if (this->freePowerBudget + power <= this->totalPowerBudget)
|
||||
{
|
||||
this->free_power_budget += power;
|
||||
this->freePowerBudget += power;
|
||||
}
|
||||
else // TODO: Maybe we should actually throw an error here, since obviouslsy someone used us wrong.
|
||||
{
|
||||
this->free_power_budget = this->total_power_budget;
|
||||
this->freePowerBudget = this->totalPowerBudget;
|
||||
}
|
||||
// Check if there are tasks waiting for power
|
||||
checkWaitingTasks();
|
||||
}
|
||||
|
||||
bool Power::waitForPowerAllowance(uint16_t neededPower, TickType_t ticksToWait)
|
||||
{
|
||||
if (tryAccquirePowerAllowance(neededPower))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Suspend the task while waiting for power to be available
|
||||
TaskHandle_t currentTask = xTaskGetCurrentTaskHandle();
|
||||
TickType_t initialTickCount = xTaskGetTickCount();
|
||||
waitingTasks.push(currentTask);
|
||||
uint32_t notificationValue;
|
||||
BaseType_t notificationStatus = xTaskNotifyWait(0, 0, ¬ificationValue, ticksToWait);
|
||||
// Code below will be executed after the task is woken up
|
||||
while (notificationStatus == pdPASS)
|
||||
{
|
||||
if (notificationValue == POWER_AVAILABLE)
|
||||
{
|
||||
// We were woken up because new power is available, check if it is enough
|
||||
if (tryAccquirePowerAllowance(neededPower))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Still not enough power available for us. Wait the remaining ticks.
|
||||
xTaskNotifyWait(0, 0, ¬ificationValue, ticksToWait - (xTaskGetTickCount() - initialTickCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (notificationStatus == pdFALSE)
|
||||
{
|
||||
// We waited long enough...
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should be impossible to reach
|
||||
throw "Reached impossible state";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Power::checkWaitingTasks(void)
|
||||
{
|
||||
// Check if there are tasks waiting for power
|
||||
if (!waitingTasks.empty())
|
||||
{
|
||||
TaskHandle_t task = waitingTasks.front();
|
||||
waitingTasks.pop();
|
||||
xTaskNotify(task, POWER_AVAILABLE, eSetValueWithOverwrite);
|
||||
}
|
||||
}
|
||||
|
@ -7,29 +7,54 @@
|
||||
* @date 2024-11-23
|
||||
*/
|
||||
|
||||
#include <queue>
|
||||
#include <Arduino.h>
|
||||
#include "Consumptions.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#ifndef Power_h
|
||||
#define Power_h
|
||||
|
||||
#define TOTAL_POWER_MILLIWATTS 700
|
||||
#define TOTAL_POWER_MILLIWATTS POWER_BUDGET
|
||||
|
||||
enum TaskResumptionReason {
|
||||
POWER_AVAILABLE,
|
||||
TIMEOUT
|
||||
};
|
||||
|
||||
class Power {
|
||||
protected:
|
||||
static const uint16_t total_power_budget = TOTAL_POWER_MILLIWATTS;
|
||||
uint16_t free_power_budget;
|
||||
static const uint16_t totalPowerBudget = TOTAL_POWER_MILLIWATTS;
|
||||
uint16_t freePowerBudget;
|
||||
std::queue<TaskHandle_t> waitingTasks;
|
||||
void checkWaitingTasks(void);
|
||||
bool takePowerIfAvailable(uint16_t neededPower);
|
||||
static Power* powerInstance;
|
||||
Power();
|
||||
|
||||
public:
|
||||
Power();
|
||||
static void begin();
|
||||
/// @brief Initialize the singleton instance of the power manager
|
||||
/// @return reference to the power manager
|
||||
static Power *getPowerManager();
|
||||
uint16_t getFreePowerBudget(void);
|
||||
/// @brief Request an allowance of a certain number of milliwatts from the power scheduler
|
||||
/// @param neededPower the amount of power we want to be accounted for (in mW)
|
||||
/// @return whether the power could be successfully allocated
|
||||
bool tryAccquirePowerAllowance(uint16_t neededPower);
|
||||
/// @brief "Return" a certain amount of power when it is no longer needed
|
||||
/// @param power the amount of power to return (in mW)
|
||||
/// @param neededPower the amount of power to return (in mW)
|
||||
/// @return whether the power
|
||||
void releasePower(uint16_t power);
|
||||
|
||||
/// @brief Wait for a certain amount of power to be available
|
||||
/// @param neededPower the amount of power we want to be accounted for (in mW)
|
||||
/// @param TicksToWait the amount of time to wait for the power to become available
|
||||
/// @return whether the power could be successfully allocatedy
|
||||
bool waitForPowerAllowance(uint16_t neededPower,TickType_t TicksToWait);
|
||||
/// @brief Put the ESP32 into deep sleep mode, without a method to wake up again. Basically this is a shutdown.
|
||||
void beginPermanentDeepSleep(void);
|
||||
};
|
||||
|
||||
#endif //Power
|
Loading…
x
Reference in New Issue
Block a user