2 boards: split code, outsource common, remove duplicate files
- outsoruce common files and separate common types from source files (new common/types.hpp) - split source files to 2 board folders (relevant only, no duplicate) - currently boards compile successfull but not functional at all - comment out currently incompatible code
This commit is contained in:
@@ -1,18 +1,12 @@
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"main.cpp"
|
||||
"motordrivers.cpp"
|
||||
"motorctl.cpp"
|
||||
"config.cpp"
|
||||
"joystick.cpp"
|
||||
"buzzer.cpp"
|
||||
"control.cpp"
|
||||
"button.cpp"
|
||||
"fan.cpp"
|
||||
"wifi.c"
|
||||
"http.cpp"
|
||||
"auto.cpp"
|
||||
"currentsensor.cpp"
|
||||
"uart.cpp"
|
||||
INCLUDE_DIRS
|
||||
"."
|
||||
|
||||
@@ -14,75 +14,76 @@ automatedArmchair::automatedArmchair(void) {
|
||||
}
|
||||
|
||||
|
||||
//FIXME motorLeft, Right not available, needs rework to work with uart only
|
||||
|
||||
//==============================
|
||||
//====== generateCommands ======
|
||||
//==============================
|
||||
motorCommands_t automatedArmchair::generateCommands(auto_instruction_t * instruction) {
|
||||
//reset instruction
|
||||
*instruction = auto_instruction_t::NONE;
|
||||
//check if previous command is finished
|
||||
if ( esp_log_timestamp() > timestampCmdFinished ) {
|
||||
//get next command from queue
|
||||
if( xQueueReceive( commandQueue, &cmdCurrent, pdMS_TO_TICKS(500) ) ) {
|
||||
ESP_LOGI(TAG, "running next command from queue...");
|
||||
//copy instruction to be provided to control task
|
||||
*instruction = cmdCurrent.instruction;
|
||||
//set acceleration / fading parameters according to command
|
||||
motorLeft.setFade(fadeType_t::DECEL, cmdCurrent.fadeDecel);
|
||||
motorRight.setFade(fadeType_t::DECEL, cmdCurrent.fadeDecel);
|
||||
motorLeft.setFade(fadeType_t::ACCEL, cmdCurrent.fadeAccel);
|
||||
motorRight.setFade(fadeType_t::ACCEL, cmdCurrent.fadeAccel);
|
||||
//calculate timestamp the command is finished
|
||||
timestampCmdFinished = esp_log_timestamp() + cmdCurrent.msDuration;
|
||||
//copy the new commands
|
||||
motorCommands = cmdCurrent.motorCmds;
|
||||
} else { //queue empty
|
||||
ESP_LOGD(TAG, "no new command in queue -> set motors to IDLE");
|
||||
motorCommands = motorCmds_bothMotorsIdle;
|
||||
}
|
||||
} else { //previous command still running
|
||||
ESP_LOGD(TAG, "command still running -> no change");
|
||||
}
|
||||
|
||||
//TODO also return instructions via call by reference
|
||||
return motorCommands;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================
|
||||
//======== addCommand ========
|
||||
//============================
|
||||
//function that adds a basic command to the queue
|
||||
void automatedArmchair::addCommand(commandSimple_t command) {
|
||||
//add command to queue
|
||||
if ( xQueueSend( commandQueue, ( void * )&command, ( TickType_t ) 0 ) ){
|
||||
ESP_LOGI(TAG, "Successfully inserted command to queue");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to insert new command to queue");
|
||||
}
|
||||
}
|
||||
|
||||
void automatedArmchair::addCommands(commandSimple_t commands[], size_t count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
ESP_LOGI(TAG, "Reading command no. %d from provided array", i);
|
||||
addCommand(commands[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===============================
|
||||
//======== clearCommands ========
|
||||
//===============================
|
||||
//function that deletes all pending/queued commands
|
||||
//e.g. when switching modes
|
||||
motorCommands_t automatedArmchair::clearCommands() {
|
||||
//clear command queue
|
||||
xQueueReset( commandQueue );
|
||||
ESP_LOGW(TAG, "command queue was successfully emptied");
|
||||
//return commands for idling both motors
|
||||
motorCommands = motorCmds_bothMotorsIdle;
|
||||
return motorCmds_bothMotorsIdle;
|
||||
}
|
||||
|
||||
// //==============================
|
||||
// //====== generateCommands ======
|
||||
// //==============================
|
||||
// motorCommands_t automatedArmchair::generateCommands(auto_instruction_t * instruction) {
|
||||
// //reset instruction
|
||||
// *instruction = auto_instruction_t::NONE;
|
||||
// //check if previous command is finished
|
||||
// if ( esp_log_timestamp() > timestampCmdFinished ) {
|
||||
// //get next command from queue
|
||||
// if( xQueueReceive( commandQueue, &cmdCurrent, pdMS_TO_TICKS(500) ) ) {
|
||||
// ESP_LOGI(TAG, "running next command from queue...");
|
||||
// //copy instruction to be provided to control task
|
||||
// *instruction = cmdCurrent.instruction;
|
||||
// //set acceleration / fading parameters according to command
|
||||
// motorLeft.setFade(fadeType_t::DECEL, cmdCurrent.fadeDecel);
|
||||
// motorRight.setFade(fadeType_t::DECEL, cmdCurrent.fadeDecel);
|
||||
// motorLeft.setFade(fadeType_t::ACCEL, cmdCurrent.fadeAccel);
|
||||
// motorRight.setFade(fadeType_t::ACCEL, cmdCurrent.fadeAccel);
|
||||
// //calculate timestamp the command is finished
|
||||
// timestampCmdFinished = esp_log_timestamp() + cmdCurrent.msDuration;
|
||||
// //copy the new commands
|
||||
// motorCommands = cmdCurrent.motorCmds;
|
||||
// } else { //queue empty
|
||||
// ESP_LOGD(TAG, "no new command in queue -> set motors to IDLE");
|
||||
// motorCommands = motorCmds_bothMotorsIdle;
|
||||
// }
|
||||
// } else { //previous command still running
|
||||
// ESP_LOGD(TAG, "command still running -> no change");
|
||||
// }
|
||||
//
|
||||
// //TODO also return instructions via call by reference
|
||||
// return motorCommands;
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //============================
|
||||
// //======== addCommand ========
|
||||
// //============================
|
||||
// //function that adds a basic command to the queue
|
||||
// void automatedArmchair::addCommand(commandSimple_t command) {
|
||||
// //add command to queue
|
||||
// if ( xQueueSend( commandQueue, ( void * )&command, ( TickType_t ) 0 ) ){
|
||||
// ESP_LOGI(TAG, "Successfully inserted command to queue");
|
||||
// } else {
|
||||
// ESP_LOGE(TAG, "Failed to insert new command to queue");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void automatedArmchair::addCommands(commandSimple_t commands[], size_t count) {
|
||||
// for (int i = 0; i < count; i++) {
|
||||
// ESP_LOGI(TAG, "Reading command no. %d from provided array", i);
|
||||
// addCommand(commands[i]);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// //===============================
|
||||
// //======== clearCommands ========
|
||||
// //===============================
|
||||
// //function that deletes all pending/queued commands
|
||||
// //e.g. when switching modes
|
||||
// motorCommands_t automatedArmchair::clearCommands() {
|
||||
// //clear command queue
|
||||
// xQueueReset( commandQueue );
|
||||
// ESP_LOGW(TAG, "command queue was successfully emptied");
|
||||
// //return commands for idling both motors
|
||||
// motorCommands = motorCmds_bothMotorsIdle;
|
||||
// return motorCmds_bothMotorsIdle;
|
||||
// }
|
||||
//
|
||||
|
||||
@@ -10,7 +10,7 @@ extern "C"
|
||||
|
||||
#include "freertos/queue.h"
|
||||
#include <cmath>
|
||||
#include "motorctl.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,200 +16,201 @@ static const char * TAG = "button";
|
||||
|
||||
|
||||
|
||||
//-----------------------------
|
||||
//-------- constructor --------
|
||||
//-----------------------------
|
||||
buttonCommands::buttonCommands(gpio_evaluatedSwitch * button_f, evaluatedJoystick * joystick_f, controlledArmchair * control_f, buzzer_t * buzzer_f, controlledMotor * motorLeft_f, controlledMotor * motorRight_f){
|
||||
//copy object pointers
|
||||
button = button_f;
|
||||
joystick = joystick_f;
|
||||
control = control_f;
|
||||
buzzer = buzzer_f;
|
||||
motorLeft = motorLeft_f;
|
||||
motorRight = motorRight_f;
|
||||
//TODO declare / configure evaluatedSwitch here instead of config (unnecessary that button object is globally available - only used here)?
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------
|
||||
//--------- action -----------
|
||||
//----------------------------
|
||||
//function that runs commands depending on a count value
|
||||
void buttonCommands::action (uint8_t count, bool lastPressLong){
|
||||
//--- variable declarations ---
|
||||
bool decelEnabled; //for different beeping when toggling
|
||||
commandSimple_t cmds[8]; //array for commands for automatedArmchair
|
||||
|
||||
//--- get joystick position ---
|
||||
//joystickData_t stickData = joystick->getData();
|
||||
|
||||
//--- actions based on count ---
|
||||
switch (count){
|
||||
//no such command
|
||||
default:
|
||||
ESP_LOGE(TAG, "no command for count=%d defined", count);
|
||||
buzzer->beep(3, 400, 100);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
//restart contoller when 1x long pressed
|
||||
if (lastPressLong){
|
||||
ESP_LOGW(TAG, "RESTART");
|
||||
buzzer->beep(1,1000,1);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
esp_restart();
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "cmd %d: sending button event to control task", count);
|
||||
//-> define joystick center or toggle freeze input (executed in control task)
|
||||
control->sendButtonEvent(count); //TODO: always send button event to control task (not just at count=1) -> control.cpp has to be changed
|
||||
break;
|
||||
case 2:
|
||||
//run automatic commands to lift leg support when pressed 1x short 1x long
|
||||
if (lastPressLong){
|
||||
//define commands
|
||||
cmds[0] =
|
||||
{
|
||||
.motorCmds = {
|
||||
.left = {motorstate_t::REV, 90},
|
||||
.right = {motorstate_t::REV, 90}
|
||||
},
|
||||
.msDuration = 1200,
|
||||
.fadeDecel = 800,
|
||||
.fadeAccel = 1300,
|
||||
.instruction = auto_instruction_t::NONE
|
||||
};
|
||||
cmds[1] =
|
||||
{
|
||||
.motorCmds = {
|
||||
.left = {motorstate_t::FWD, 70},
|
||||
.right = {motorstate_t::FWD, 70}
|
||||
},
|
||||
.msDuration = 70,
|
||||
.fadeDecel = 0,
|
||||
.fadeAccel = 300,
|
||||
.instruction = auto_instruction_t::NONE
|
||||
};
|
||||
cmds[2] =
|
||||
{
|
||||
.motorCmds = {
|
||||
.left = {motorstate_t::IDLE, 0},
|
||||
.right = {motorstate_t::IDLE, 0}
|
||||
},
|
||||
.msDuration = 10,
|
||||
.fadeDecel = 800,
|
||||
.fadeAccel = 1300,
|
||||
.instruction = auto_instruction_t::SWITCH_JOYSTICK_MODE
|
||||
};
|
||||
|
||||
//send commands to automatedArmchair command queue
|
||||
armchair.addCommands(cmds, 3);
|
||||
|
||||
//change mode to AUTO
|
||||
control->changeMode(controlMode_t::AUTO);
|
||||
return;
|
||||
}
|
||||
|
||||
//toggle idle when 2x pressed
|
||||
ESP_LOGW(TAG, "cmd %d: toggle IDLE", count);
|
||||
control->toggleIdle(); //toggle between idle and previous/default mode
|
||||
break;
|
||||
|
||||
|
||||
case 3:
|
||||
ESP_LOGW(TAG, "cmd %d: switch to JOYSTICK", count);
|
||||
control->changeMode(controlMode_t::JOYSTICK); //switch to JOYSTICK mode
|
||||
break;
|
||||
|
||||
case 4:
|
||||
ESP_LOGW(TAG, "cmd %d: toggle between HTTP and JOYSTICK", count);
|
||||
control->toggleModes(controlMode_t::HTTP, controlMode_t::JOYSTICK); //toggle between HTTP and JOYSTICK mode
|
||||
break;
|
||||
|
||||
case 6:
|
||||
ESP_LOGW(TAG, "cmd %d: toggle between MASSAGE and JOYSTICK", count);
|
||||
control->toggleModes(controlMode_t::MASSAGE, controlMode_t::JOYSTICK); //toggle between MASSAGE and JOYSTICK mode
|
||||
break;
|
||||
|
||||
case 8:
|
||||
//toggle deceleration fading between on and off
|
||||
decelEnabled = motorLeft->toggleFade(fadeType_t::DECEL);
|
||||
motorRight->toggleFade(fadeType_t::DECEL);
|
||||
ESP_LOGW(TAG, "cmd %d: toggle deceleration fading to: %d", count, (int)decelEnabled);
|
||||
if (decelEnabled){
|
||||
buzzer->beep(3, 60, 50);
|
||||
} else {
|
||||
buzzer->beep(1, 1000, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 12:
|
||||
ESP_LOGW(TAG, "cmd %d: sending button event to control task", count);
|
||||
//-> toggle altStickMapping (executed in control task)
|
||||
control->sendButtonEvent(count); //TODO: always send button event to control task (not just at count=1)?
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------
|
||||
//------ startHandleLoop ------
|
||||
//-----------------------------
|
||||
//this function has to be started once in a separate task
|
||||
//repeatedly evaluates and processes button events then takes the corresponding action
|
||||
void buttonCommands::startHandleLoop() {
|
||||
|
||||
while(1) {
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
//run handle function of evaluatedSwitch object
|
||||
button->handle();
|
||||
|
||||
//--- count button presses and run action ---
|
||||
switch(state) {
|
||||
case inputState_t::IDLE: //wait for initial button press
|
||||
if (button->risingEdge) {
|
||||
count = 1;
|
||||
buzzer->beep(1, 65, 0);
|
||||
timestamp_lastAction = esp_log_timestamp();
|
||||
state = inputState_t::WAIT_FOR_INPUT;
|
||||
ESP_LOGI(TAG, "first button press detected -> waiting for further events");
|
||||
}
|
||||
break;
|
||||
|
||||
case inputState_t::WAIT_FOR_INPUT: //wait for further presses
|
||||
//button pressed again
|
||||
if (button->risingEdge){
|
||||
count++;
|
||||
buzzer->beep(1, 65, 0);
|
||||
timestamp_lastAction = esp_log_timestamp();
|
||||
ESP_LOGI(TAG, "another press detected -> count=%d -> waiting for further events", count);
|
||||
}
|
||||
//timeout
|
||||
else if (esp_log_timestamp() - timestamp_lastAction > 1000) {
|
||||
state = inputState_t::IDLE;
|
||||
buzzer->beep(count, 50, 50);
|
||||
//TODO: add optional "bool wait" parameter to beep function to delay until finished beeping
|
||||
ESP_LOGI(TAG, "timeout - running action function for count=%d", count);
|
||||
//--- run action function ---
|
||||
//check if still pressed
|
||||
bool lastPressLong = false;
|
||||
if (button->state == true){
|
||||
//run special case when last press was longer than timeout
|
||||
lastPressLong = true;
|
||||
}
|
||||
//run action function with current count of button presses
|
||||
action(count, lastPressLong);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//FIXME needs rework, motorleft/right objectn not available anymore
|
||||
// //-----------------------------
|
||||
// //-------- constructor --------
|
||||
// //-----------------------------
|
||||
// buttonCommands::buttonCommands(gpio_evaluatedSwitch * button_f, evaluatedJoystick * joystick_f, controlledArmchair * control_f, buzzer_t * buzzer_f, controlledMotor * motorLeft_f, controlledMotor * motorRight_f){
|
||||
// //copy object pointers
|
||||
// button = button_f;
|
||||
// joystick = joystick_f;
|
||||
// control = control_f;
|
||||
// buzzer = buzzer_f;
|
||||
// motorLeft = motorLeft_f;
|
||||
// motorRight = motorRight_f;
|
||||
// //TODO declare / configure evaluatedSwitch here instead of config (unnecessary that button object is globally available - only used here)?
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //----------------------------
|
||||
// //--------- action -----------
|
||||
// //----------------------------
|
||||
// //function that runs commands depending on a count value
|
||||
// void buttonCommands::action (uint8_t count, bool lastPressLong){
|
||||
// //--- variable declarations ---
|
||||
// bool decelEnabled; //for different beeping when toggling
|
||||
// commandSimple_t cmds[8]; //array for commands for automatedArmchair
|
||||
//
|
||||
// //--- get joystick position ---
|
||||
// //joystickData_t stickData = joystick->getData();
|
||||
//
|
||||
// //--- actions based on count ---
|
||||
// switch (count){
|
||||
// //no such command
|
||||
// default:
|
||||
// ESP_LOGE(TAG, "no command for count=%d defined", count);
|
||||
// buzzer->beep(3, 400, 100);
|
||||
// break;
|
||||
//
|
||||
// case 1:
|
||||
// //restart contoller when 1x long pressed
|
||||
// if (lastPressLong){
|
||||
// ESP_LOGW(TAG, "RESTART");
|
||||
// buzzer->beep(1,1000,1);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
// esp_restart();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// ESP_LOGW(TAG, "cmd %d: sending button event to control task", count);
|
||||
// //-> define joystick center or toggle freeze input (executed in control task)
|
||||
// control->sendButtonEvent(count); //TODO: always send button event to control task (not just at count=1) -> control.cpp has to be changed
|
||||
// break;
|
||||
// case 2:
|
||||
// //run automatic commands to lift leg support when pressed 1x short 1x long
|
||||
// if (lastPressLong){
|
||||
// //define commands
|
||||
// cmds[0] =
|
||||
// {
|
||||
// .motorCmds = {
|
||||
// .left = {motorstate_t::REV, 90},
|
||||
// .right = {motorstate_t::REV, 90}
|
||||
// },
|
||||
// .msDuration = 1200,
|
||||
// .fadeDecel = 800,
|
||||
// .fadeAccel = 1300,
|
||||
// .instruction = auto_instruction_t::NONE
|
||||
// };
|
||||
// cmds[1] =
|
||||
// {
|
||||
// .motorCmds = {
|
||||
// .left = {motorstate_t::FWD, 70},
|
||||
// .right = {motorstate_t::FWD, 70}
|
||||
// },
|
||||
// .msDuration = 70,
|
||||
// .fadeDecel = 0,
|
||||
// .fadeAccel = 300,
|
||||
// .instruction = auto_instruction_t::NONE
|
||||
// };
|
||||
// cmds[2] =
|
||||
// {
|
||||
// .motorCmds = {
|
||||
// .left = {motorstate_t::IDLE, 0},
|
||||
// .right = {motorstate_t::IDLE, 0}
|
||||
// },
|
||||
// .msDuration = 10,
|
||||
// .fadeDecel = 800,
|
||||
// .fadeAccel = 1300,
|
||||
// .instruction = auto_instruction_t::SWITCH_JOYSTICK_MODE
|
||||
// };
|
||||
//
|
||||
// //send commands to automatedArmchair command queue
|
||||
// armchair.addCommands(cmds, 3);
|
||||
//
|
||||
// //change mode to AUTO
|
||||
// control->changeMode(controlMode_t::AUTO);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// //toggle idle when 2x pressed
|
||||
// ESP_LOGW(TAG, "cmd %d: toggle IDLE", count);
|
||||
// control->toggleIdle(); //toggle between idle and previous/default mode
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// case 3:
|
||||
// ESP_LOGW(TAG, "cmd %d: switch to JOYSTICK", count);
|
||||
// control->changeMode(controlMode_t::JOYSTICK); //switch to JOYSTICK mode
|
||||
// break;
|
||||
//
|
||||
// case 4:
|
||||
// ESP_LOGW(TAG, "cmd %d: toggle between HTTP and JOYSTICK", count);
|
||||
// control->toggleModes(controlMode_t::HTTP, controlMode_t::JOYSTICK); //toggle between HTTP and JOYSTICK mode
|
||||
// break;
|
||||
//
|
||||
// case 6:
|
||||
// ESP_LOGW(TAG, "cmd %d: toggle between MASSAGE and JOYSTICK", count);
|
||||
// control->toggleModes(controlMode_t::MASSAGE, controlMode_t::JOYSTICK); //toggle between MASSAGE and JOYSTICK mode
|
||||
// break;
|
||||
//
|
||||
// case 8:
|
||||
// //toggle deceleration fading between on and off
|
||||
// decelEnabled = motorLeft->toggleFade(fadeType_t::DECEL);
|
||||
// motorRight->toggleFade(fadeType_t::DECEL);
|
||||
// ESP_LOGW(TAG, "cmd %d: toggle deceleration fading to: %d", count, (int)decelEnabled);
|
||||
// if (decelEnabled){
|
||||
// buzzer->beep(3, 60, 50);
|
||||
// } else {
|
||||
// buzzer->beep(1, 1000, 1);
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case 12:
|
||||
// ESP_LOGW(TAG, "cmd %d: sending button event to control task", count);
|
||||
// //-> toggle altStickMapping (executed in control task)
|
||||
// control->sendButtonEvent(count); //TODO: always send button event to control task (not just at count=1)?
|
||||
// break;
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// //-----------------------------
|
||||
// //------ startHandleLoop ------
|
||||
// //-----------------------------
|
||||
// //this function has to be started once in a separate task
|
||||
// //repeatedly evaluates and processes button events then takes the corresponding action
|
||||
// void buttonCommands::startHandleLoop() {
|
||||
//
|
||||
// while(1) {
|
||||
// vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
// //run handle function of evaluatedSwitch object
|
||||
// button->handle();
|
||||
//
|
||||
// //--- count button presses and run action ---
|
||||
// switch(state) {
|
||||
// case inputState_t::IDLE: //wait for initial button press
|
||||
// if (button->risingEdge) {
|
||||
// count = 1;
|
||||
// buzzer->beep(1, 65, 0);
|
||||
// timestamp_lastAction = esp_log_timestamp();
|
||||
// state = inputState_t::WAIT_FOR_INPUT;
|
||||
// ESP_LOGI(TAG, "first button press detected -> waiting for further events");
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case inputState_t::WAIT_FOR_INPUT: //wait for further presses
|
||||
// //button pressed again
|
||||
// if (button->risingEdge){
|
||||
// count++;
|
||||
// buzzer->beep(1, 65, 0);
|
||||
// timestamp_lastAction = esp_log_timestamp();
|
||||
// ESP_LOGI(TAG, "another press detected -> count=%d -> waiting for further events", count);
|
||||
// }
|
||||
// //timeout
|
||||
// else if (esp_log_timestamp() - timestamp_lastAction > 1000) {
|
||||
// state = inputState_t::IDLE;
|
||||
// buzzer->beep(count, 50, 50);
|
||||
// //TODO: add optional "bool wait" parameter to beep function to delay until finished beeping
|
||||
// ESP_LOGI(TAG, "timeout - running action function for count=%d", count);
|
||||
// //--- run action function ---
|
||||
// //check if still pressed
|
||||
// bool lastPressLong = false;
|
||||
// if (button->state == true){
|
||||
// //run special case when last press was longer than timeout
|
||||
// lastPressLong = true;
|
||||
// }
|
||||
// //run action function with current count of button presses
|
||||
// action(count, lastPressLong);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
@@ -3,51 +3,52 @@
|
||||
#include "gpio_evaluateSwitch.hpp"
|
||||
#include "buzzer.hpp"
|
||||
#include "control.hpp"
|
||||
#include "motorctl.hpp"
|
||||
#include "auto.hpp"
|
||||
#include "config.hpp"
|
||||
#include "joystick.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
|
||||
|
||||
//===================================
|
||||
//====== buttonCommands class =======
|
||||
//===================================
|
||||
//class which runs commands depending on the count a button was pressed
|
||||
class buttonCommands {
|
||||
public:
|
||||
//--- constructor ---
|
||||
buttonCommands (
|
||||
gpio_evaluatedSwitch * button_f,
|
||||
evaluatedJoystick * joystick_f,
|
||||
controlledArmchair * control_f,
|
||||
buzzer_t * buzzer_f,
|
||||
controlledMotor * motorLeft_f,
|
||||
controlledMotor * motorRight_f
|
||||
);
|
||||
|
||||
//--- functions ---
|
||||
//the following function has to be started once in a separate task.
|
||||
//repeatedly evaluates and processes button events then takes the corresponding action
|
||||
void startHandleLoop();
|
||||
|
||||
private:
|
||||
//--- functions ---
|
||||
void action(uint8_t count, bool lastPressLong);
|
||||
|
||||
//--- objects ---
|
||||
gpio_evaluatedSwitch* button;
|
||||
evaluatedJoystick* joystick;
|
||||
controlledArmchair * control;
|
||||
buzzer_t* buzzer;
|
||||
controlledMotor * motorLeft;
|
||||
controlledMotor * motorRight;
|
||||
|
||||
//--- variables ---
|
||||
uint8_t count = 0;
|
||||
uint32_t timestamp_lastAction = 0;
|
||||
enum class inputState_t {IDLE, WAIT_FOR_INPUT};
|
||||
inputState_t state = inputState_t::IDLE;
|
||||
|
||||
};
|
||||
// //===================================
|
||||
// //====== buttonCommands class =======
|
||||
// //===================================
|
||||
// //class which runs commands depending on the count a button was pressed
|
||||
// class buttonCommands {
|
||||
// public:
|
||||
// //--- constructor ---
|
||||
// buttonCommands (
|
||||
// gpio_evaluatedSwitch * button_f,
|
||||
// evaluatedJoystick * joystick_f,
|
||||
// controlledArmchair * control_f,
|
||||
// buzzer_t * buzzer_f,
|
||||
// controlledMotor * motorLeft_f,
|
||||
// controlledMotor * motorRight_f
|
||||
// );
|
||||
//
|
||||
// //--- functions ---
|
||||
// //the following function has to be started once in a separate task.
|
||||
// //repeatedly evaluates and processes button events then takes the corresponding action
|
||||
// void startHandleLoop();
|
||||
//
|
||||
// private:
|
||||
// //--- functions ---
|
||||
// void action(uint8_t count, bool lastPressLong);
|
||||
//
|
||||
// //--- objects ---
|
||||
// gpio_evaluatedSwitch* button;
|
||||
// evaluatedJoystick* joystick;
|
||||
// controlledArmchair * control;
|
||||
// buzzer_t* buzzer;
|
||||
// controlledMotor * motorLeft;
|
||||
// controlledMotor * motorRight;
|
||||
//
|
||||
// //--- variables ---
|
||||
// uint8_t count = 0;
|
||||
// uint32_t timestamp_lastAction = 0;
|
||||
// enum class inputState_t {IDLE, WAIT_FOR_INPUT};
|
||||
// inputState_t state = inputState_t::IDLE;
|
||||
//
|
||||
// };
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
#include "buzzer.hpp"
|
||||
#include "config.hpp"
|
||||
|
||||
static const char *TAG_BUZZER = "buzzer";
|
||||
|
||||
//============================
|
||||
//========== init ============
|
||||
//============================
|
||||
//define gpio pin as output, initialize queue
|
||||
void buzzer_t::init(){
|
||||
//define buzzer pin as output
|
||||
gpio_pad_select_gpio(gpio_pin);
|
||||
gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
|
||||
//create queue
|
||||
beepQueue = xQueueCreate( 20, sizeof( struct beepEntry ) );
|
||||
}
|
||||
|
||||
|
||||
//=============================
|
||||
//======== constructor ========
|
||||
//=============================
|
||||
//copy provided config parameters to private variables, run init function
|
||||
buzzer_t::buzzer_t(gpio_num_t gpio_pin_f, uint16_t msGap_f){
|
||||
ESP_LOGI(TAG_BUZZER, "Initializing buzzer");
|
||||
//copy configuration parameters to variables
|
||||
gpio_pin = gpio_pin_f;
|
||||
msGap = msGap_f;
|
||||
//run init function to initialize gpio and queue
|
||||
init();
|
||||
};
|
||||
|
||||
|
||||
//============================
|
||||
//=========== beep ===========
|
||||
//============================
|
||||
//function to add a beep command to the queue
|
||||
void buzzer_t::beep(uint8_t count, uint16_t msOn, uint16_t msOff){
|
||||
//create entry struct with provided data
|
||||
struct beepEntry entryInsert = {
|
||||
count = count,
|
||||
msOn = msOn,
|
||||
msOff = msOff
|
||||
};
|
||||
|
||||
// Send a pointer to a struct AMessage object. Don't block if the
|
||||
// queue is already full.
|
||||
//struct beepEntry *entryInsertPointer;
|
||||
//entryInsertPointer = &entryInsertData;
|
||||
ESP_LOGW(TAG_BUZZER, "Inserted object to queue - count=%d, msOn=%d, msOff=%d", entryInsert.count, entryInsert.msOn, entryInsert.msOff);
|
||||
//xQueueGenericSend( beepQueue, ( void * ) &entryInsertPointer, ( TickType_t ) 0, queueSEND_TO_BACK );
|
||||
xQueueSend( beepQueue, ( void * )&entryInsert, ( TickType_t ) 0 );
|
||||
}
|
||||
|
||||
|
||||
//==============================
|
||||
//======== processQueue ========
|
||||
//==============================
|
||||
void buzzer_t::processQueue(){
|
||||
//struct for receiving incomming events
|
||||
struct beepEntry entryRead = { };
|
||||
|
||||
//loop forever
|
||||
while(1){
|
||||
ESP_LOGD(TAG_BUZZER, "processQueue: waiting for beep command");
|
||||
|
||||
//if queue is ready
|
||||
if( beepQueue != 0 )
|
||||
{
|
||||
// wait for a queue entry to be available indefinetely if INCLUDE_vTaskSuspend is enabled in the FreeRTOS config
|
||||
// otherwise waits for at least 7 weeks
|
||||
if( xQueueReceive( beepQueue, &entryRead, portMAX_DELAY ) )
|
||||
{
|
||||
ESP_LOGW(TAG_BUZZER, "Read entry from queue: count=%d, msOn=%d, msOff=%d", entryRead.count, entryRead.msOn, entryRead.msOff);
|
||||
|
||||
//beep requested count with requested delays
|
||||
for (int i = entryRead.count; i--;){
|
||||
//turn on
|
||||
ESP_LOGD(TAG_BUZZER, "turning buzzer on");
|
||||
gpio_set_level(gpio_pin, 1);
|
||||
vTaskDelay(entryRead.msOn / portTICK_PERIOD_MS);
|
||||
//turn off
|
||||
ESP_LOGD(TAG_BUZZER, "turning buzzer off");
|
||||
gpio_set_level(gpio_pin, 0);
|
||||
vTaskDelay(entryRead.msOff / portTICK_PERIOD_MS);
|
||||
}
|
||||
//wait for minimum gap between beep events
|
||||
vTaskDelay(msGap / portTICK_PERIOD_MS);
|
||||
}
|
||||
}else{ //wait for queue to become available
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
}
|
||||
|
||||
#include "freertos/queue.h"
|
||||
|
||||
|
||||
|
||||
//===================================
|
||||
//========= buzzer_t class ==========
|
||||
//===================================
|
||||
//class which blinks a gpio pin for the provided count and durations.
|
||||
//- 'processQueue' has to be run in a separate task
|
||||
//- uses a queue to queue up multiple beep commands
|
||||
class buzzer_t {
|
||||
public:
|
||||
//--- constructor ---
|
||||
buzzer_t(gpio_num_t gpio_pin_f, uint16_t msGap_f = 200);
|
||||
|
||||
//--- functions ---
|
||||
void processQueue(); //has to be run once in a separate task, waits for and processes queued events
|
||||
void beep(uint8_t count, uint16_t msOn, uint16_t msOff);
|
||||
//void clear(); (TODO - not implemented yet)
|
||||
//void createTask(); (TODO - not implemented yet)
|
||||
|
||||
//--- variables ---
|
||||
uint16_t msGap; //gap between beep entries (when multiple queued)
|
||||
|
||||
private:
|
||||
//--- functions ---
|
||||
void init();
|
||||
|
||||
//--- variables ---
|
||||
gpio_num_t gpio_pin;
|
||||
|
||||
struct beepEntry {
|
||||
uint8_t count;
|
||||
uint16_t msOn;
|
||||
uint16_t msOff;
|
||||
};
|
||||
|
||||
//queue for queueing up multiple events while one is still processing
|
||||
QueueHandle_t beepQueue = NULL;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,60 +1,5 @@
|
||||
#include "config.hpp"
|
||||
|
||||
//===================================
|
||||
//======= motor configuration =======
|
||||
//===================================
|
||||
//--- configure left motor (hardware) ---
|
||||
single100a_config_t configDriverLeft = {
|
||||
.gpio_pwm = GPIO_NUM_26,
|
||||
.gpio_a = GPIO_NUM_16,
|
||||
.gpio_b = GPIO_NUM_4,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
.aEnabledPinState = false, //-> pins inverted (mosfets)
|
||||
.bEnabledPinState = false,
|
||||
.resolution = LEDC_TIMER_11_BIT,
|
||||
.pwmFreq = 10000
|
||||
};
|
||||
|
||||
//--- configure right motor (hardware) ---
|
||||
single100a_config_t configDriverRight = {
|
||||
.gpio_pwm = GPIO_NUM_27,
|
||||
.gpio_a = GPIO_NUM_2,
|
||||
.gpio_b = GPIO_NUM_14,
|
||||
.ledc_timer = LEDC_TIMER_1,
|
||||
.ledc_channel = LEDC_CHANNEL_1,
|
||||
.aEnabledPinState = false, //-> pin inverted (mosfet)
|
||||
.bEnabledPinState = true, //-> not inverted (direct)
|
||||
.resolution = LEDC_TIMER_11_BIT,
|
||||
.pwmFreq = 10000
|
||||
};
|
||||
|
||||
|
||||
//TODO add motor name string -> then use as log tag?
|
||||
//--- configure left motor (contol) ---
|
||||
motorctl_config_t configMotorControlLeft = {
|
||||
.msFadeAccel = 1900, //acceleration of the motor (ms it takes from 0% to 100%)
|
||||
.msFadeDecel = 1000, //deceleration of the motor (ms it takes from 100% to 0%)
|
||||
.currentLimitEnabled = true,
|
||||
.currentSensor_adc = ADC1_CHANNEL_6, //GPIO34
|
||||
.currentSensor_ratedCurrent = 50,
|
||||
.currentMax = 30,
|
||||
.deadTimeMs = 900 //minimum time motor is off between direction change
|
||||
};
|
||||
|
||||
//--- configure right motor (contol) ---
|
||||
motorctl_config_t configMotorControlRight = {
|
||||
.msFadeAccel = 1900, //acceleration of the motor (ms it takes from 0% to 100%)
|
||||
.msFadeDecel = 1000, //deceleration of the motor (ms it takes from 100% to 0%)
|
||||
.currentLimitEnabled = true,
|
||||
.currentSensor_adc = ADC1_CHANNEL_4, //GPIO32
|
||||
.currentSensor_ratedCurrent = 50,
|
||||
.currentMax = 30,
|
||||
.deadTimeMs = 900 //minimum time motor is off between direction change
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==============================
|
||||
//======= control config =======
|
||||
//==============================
|
||||
@@ -107,29 +52,12 @@ joystick_config_t configJoystick = {
|
||||
|
||||
|
||||
|
||||
//============================
|
||||
//=== configure fan contol ===
|
||||
//============================
|
||||
fan_config_t configCooling = {
|
||||
.gpio_fan = GPIO_NUM_13,
|
||||
.dutyThreshold = 40,
|
||||
.minOnMs = 1500,
|
||||
.minOffMs = 3000,
|
||||
.turnOffDelayMs = 5000,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//=================================
|
||||
//===== create global objects =====
|
||||
//=================================
|
||||
//TODO outsource global variables to e.g. global.cpp and only config options here?
|
||||
|
||||
//create controlled motor instances (motorctl.hpp)
|
||||
controlledMotor motorLeft(configDriverLeft, configMotorControlLeft);
|
||||
controlledMotor motorRight(configDriverRight, configMotorControlRight);
|
||||
|
||||
//create global joystic instance (joystick.hpp)
|
||||
evaluatedJoystick joystick(configJoystick);
|
||||
|
||||
@@ -143,7 +71,7 @@ buzzer_t buzzer(GPIO_NUM_12, 100);
|
||||
httpJoystick httpJoystickMain(configHttpJoystickMain);
|
||||
|
||||
//create global control object (control.hpp)
|
||||
controlledArmchair control(configControl, &buzzer, &motorLeft, &motorRight, &joystick, &httpJoystickMain);
|
||||
//controlledArmchair control(configControl, &buzzer, &motorLeft, &motorRight, &joystick, &httpJoystickMain);
|
||||
|
||||
//create global automatedArmchair object (for auto-mode) (auto.hpp)
|
||||
automatedArmchair armchair;
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "motordrivers.hpp"
|
||||
#include "motorctl.hpp"
|
||||
#include "joystick.hpp"
|
||||
|
||||
#include "gpio_evaluateSwitch.hpp"
|
||||
#include "buzzer.hpp"
|
||||
#include "control.hpp"
|
||||
#include "fan.hpp"
|
||||
#include "http.hpp"
|
||||
#include "auto.hpp"
|
||||
|
||||
@@ -19,10 +16,6 @@
|
||||
|
||||
//TODO outsource global variables to e.g. global.cpp and only config options here?
|
||||
|
||||
//create global controlledMotor instances for both motors
|
||||
extern controlledMotor motorLeft;
|
||||
extern controlledMotor motorRight;
|
||||
|
||||
//create global joystic instance
|
||||
extern evaluatedJoystick joystick;
|
||||
|
||||
@@ -33,14 +26,10 @@ extern gpio_evaluatedSwitch buttonJoystick;
|
||||
extern buzzer_t buzzer;
|
||||
|
||||
//create global control object
|
||||
extern controlledArmchair control;
|
||||
//extern controlledArmchair control;
|
||||
|
||||
//create global automatedArmchair object (for auto-mode)
|
||||
extern automatedArmchair armchair;
|
||||
|
||||
//create global httpJoystick object
|
||||
extern httpJoystick httpJoystickMain;
|
||||
|
||||
//configuration for fans / cooling
|
||||
extern fan_config_t configCooling;
|
||||
|
||||
|
||||
@@ -22,458 +22,459 @@ static const char * TAG = "control";
|
||||
const char* controlModeStr[7] = {"IDLE", "JOYSTICK", "MASSAGE", "HTTP", "MQTT", "BLUETOOTH", "AUTO"};
|
||||
|
||||
|
||||
//-----------------------------
|
||||
//-------- constructor --------
|
||||
//-----------------------------
|
||||
controlledArmchair::controlledArmchair (
|
||||
control_config_t config_f,
|
||||
buzzer_t * buzzer_f,
|
||||
controlledMotor* motorLeft_f,
|
||||
controlledMotor* motorRight_f,
|
||||
evaluatedJoystick* joystick_f,
|
||||
httpJoystick* httpJoystick_f
|
||||
){
|
||||
|
||||
//copy configuration
|
||||
config = config_f;
|
||||
//copy object pointers
|
||||
buzzer = buzzer_f;
|
||||
motorLeft = motorLeft_f;
|
||||
motorRight = motorRight_f;
|
||||
joystick_l = joystick_f,
|
||||
httpJoystickMain_l = httpJoystick_f;
|
||||
//set default mode from config
|
||||
modePrevious = config.defaultMode;
|
||||
|
||||
//TODO declare / configure controlled motors here instead of config (unnecessary that button object is globally available - only used here)?
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------
|
||||
//---------- Handle loop -----------
|
||||
//----------------------------------
|
||||
//function that repeatedly generates motor commands depending on the current mode
|
||||
//also handles fading and current-limit
|
||||
void controlledArmchair::startHandleLoop() {
|
||||
while (1){
|
||||
ESP_LOGV(TAG, "control task executing... mode=%s", controlModeStr[(int)mode]);
|
||||
|
||||
switch(mode) {
|
||||
default:
|
||||
mode = controlMode_t::IDLE;
|
||||
break;
|
||||
|
||||
case controlMode_t::IDLE:
|
||||
//copy preset commands for idling both motors
|
||||
commands = cmds_bothMotorsIdle;
|
||||
motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
#ifdef JOYSTICK_LOG_IN_IDLE
|
||||
//get joystick data here (without using it)
|
||||
//since loglevel is DEBUG, calculateion details is output
|
||||
joystick_l->getData(); //get joystick data here
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
case controlMode_t::JOYSTICK:
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
//get current joystick data with getData method of evaluatedJoystick
|
||||
stickData = joystick_l->getData();
|
||||
//additionaly scale coordinates (more detail in slower area)
|
||||
joystick_scaleCoordinatesLinear(&stickData, 0.6, 0.35); //TODO: add scaling parameters to config
|
||||
//generate motor commands
|
||||
commands = joystick_generateCommandsDriving(stickData, altStickMapping);
|
||||
//apply motor commands
|
||||
motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
//TODO make motorctl.setTarget also accept motorcommand struct directly
|
||||
break;
|
||||
|
||||
|
||||
case controlMode_t::MASSAGE:
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
//--- read joystick ---
|
||||
//only update joystick data when input not frozen
|
||||
if (!freezeInput){
|
||||
stickData = joystick_l->getData();
|
||||
}
|
||||
//--- generate motor commands ---
|
||||
//pass joystick data from getData method of evaluatedJoystick to generateCommandsShaking function
|
||||
commands = joystick_generateCommandsShaking(stickData);
|
||||
//apply motor commands
|
||||
motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
break;
|
||||
|
||||
|
||||
case controlMode_t::HTTP:
|
||||
//--- get joystick data from queue ---
|
||||
//Note this function waits several seconds (httpconfig.timeoutMs) for data to arrive, otherwise Center data or NULL is returned
|
||||
//TODO: as described above, when changing modes it might delay a few seconds for the change to apply
|
||||
stickData = httpJoystickMain_l->getData();
|
||||
//scale coordinates additionally (more detail in slower area)
|
||||
joystick_scaleCoordinatesLinear(&stickData, 0.6, 0.4); //TODO: add scaling parameters to config
|
||||
ESP_LOGD(TAG, "generating commands from x=%.3f y=%.3f radius=%.3f angle=%.3f", stickData.x, stickData.y, stickData.radius, stickData.angle);
|
||||
//--- generate motor commands ---
|
||||
//Note: timeout (no data received) is handled in getData method
|
||||
commands = joystick_generateCommandsDriving(stickData, altStickMapping);
|
||||
|
||||
//--- apply commands to motors ---
|
||||
//TODO make motorctl.setTarget also accept motorcommand struct directly
|
||||
motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
break;
|
||||
|
||||
|
||||
case controlMode_t::AUTO:
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
//generate commands
|
||||
commands = armchair.generateCommands(&instruction);
|
||||
//--- apply commands to motors ---
|
||||
//TODO make motorctl.setTarget also accept motorcommand struct directly
|
||||
motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
|
||||
//process received instruction
|
||||
switch (instruction) {
|
||||
case auto_instruction_t::NONE:
|
||||
break;
|
||||
case auto_instruction_t::SWITCH_PREV_MODE:
|
||||
toggleMode(controlMode_t::AUTO);
|
||||
break;
|
||||
case auto_instruction_t::SWITCH_JOYSTICK_MODE:
|
||||
changeMode(controlMode_t::JOYSTICK);
|
||||
break;
|
||||
case auto_instruction_t::RESET_ACCEL_DECEL:
|
||||
//enable downfading (set to default value)
|
||||
motorLeft->setFade(fadeType_t::DECEL, true);
|
||||
motorRight->setFade(fadeType_t::DECEL, true);
|
||||
//set upfading to default value
|
||||
motorLeft->setFade(fadeType_t::ACCEL, true);
|
||||
motorRight->setFade(fadeType_t::ACCEL, true);
|
||||
break;
|
||||
case auto_instruction_t::RESET_ACCEL:
|
||||
//set upfading to default value
|
||||
motorLeft->setFade(fadeType_t::ACCEL, true);
|
||||
motorRight->setFade(fadeType_t::ACCEL, true);
|
||||
break;
|
||||
case auto_instruction_t::RESET_DECEL:
|
||||
//enable downfading (set to default value)
|
||||
motorLeft->setFade(fadeType_t::DECEL, true);
|
||||
motorRight->setFade(fadeType_t::DECEL, true);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
//TODO: add other modes here
|
||||
}
|
||||
|
||||
|
||||
//--- run actions based on received button button event ---
|
||||
//note: buttonCount received by sendButtonEvent method called from button.cpp
|
||||
//TODO: what if variable gets set from other task during this code? -> mutex around this code
|
||||
switch (buttonCount) {
|
||||
case 1: //define joystick center or freeze input
|
||||
if (mode == controlMode_t::JOYSTICK){
|
||||
//joystick mode: calibrate joystick
|
||||
joystick_l->defineCenter();
|
||||
} else if (mode == controlMode_t::MASSAGE){
|
||||
//massage mode: toggle freeze of input (lock joystick at current values)
|
||||
freezeInput = !freezeInput;
|
||||
if (freezeInput){
|
||||
buzzer->beep(5, 40, 25);
|
||||
} else {
|
||||
buzzer->beep(1, 300, 100);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 12: //toggle alternative joystick mapping (reverse swapped)
|
||||
altStickMapping = !altStickMapping;
|
||||
if (altStickMapping){
|
||||
buzzer->beep(6, 70, 50);
|
||||
} else {
|
||||
buzzer->beep(1, 500, 100);
|
||||
}
|
||||
break;
|
||||
}
|
||||
//--- reset button event --- (only one action per run)
|
||||
if (buttonCount > 0){
|
||||
ESP_LOGI(TAG, "resetting button event/count");
|
||||
buttonCount = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------
|
||||
//------ slow loop ------
|
||||
//-----------------------
|
||||
//this section is run about every 5s (+500ms)
|
||||
if (esp_log_timestamp() - timestamp_SlowLoopLastRun > 5000) {
|
||||
ESP_LOGV(TAG, "running slow loop... time since last run: %.1fs", (float)(esp_log_timestamp() - timestamp_SlowLoopLastRun)/1000);
|
||||
timestamp_SlowLoopLastRun = esp_log_timestamp();
|
||||
|
||||
//run function which detects timeout (switch to idle)
|
||||
handleTimeout();
|
||||
}
|
||||
|
||||
}//end while(1)
|
||||
}//end startHandleLoop
|
||||
|
||||
|
||||
|
||||
//-----------------------------------
|
||||
//---------- resetTimeout -----------
|
||||
//-----------------------------------
|
||||
void controlledArmchair::resetTimeout(){
|
||||
//TODO mutex
|
||||
timestamp_lastActivity = esp_log_timestamp();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------
|
||||
//--------- sendButtonEvent ----------
|
||||
//------------------------------------
|
||||
void controlledArmchair::sendButtonEvent(uint8_t count){
|
||||
//TODO mutex - if not replaced with queue
|
||||
ESP_LOGI(TAG, "setting button event");
|
||||
buttonCount = count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------
|
||||
//---------- handleTimeout -----------
|
||||
//------------------------------------
|
||||
//percentage the duty can vary since last timeout check and still counts as incative
|
||||
//TODO: add this to config
|
||||
float inactivityTolerance = 10;
|
||||
|
||||
//local function that checks whether two values differ more than a given tolerance
|
||||
bool validateActivity(float dutyOld, float dutyNow, float tolerance){
|
||||
float dutyDelta = dutyNow - dutyOld;
|
||||
if (fabs(dutyDelta) < tolerance) {
|
||||
return false; //no significant activity detected
|
||||
} else {
|
||||
return true; //there was activity
|
||||
}
|
||||
}
|
||||
|
||||
//function that evaluates whether there is no activity/change on the motor duty for a certain time. If so, a switch to IDLE is issued. - has to be run repeatedly in a slow interval
|
||||
void controlledArmchair::handleTimeout(){
|
||||
//check for timeout only when not idling already
|
||||
if (mode != controlMode_t::IDLE) {
|
||||
//get current duty from controlled motor objects
|
||||
float dutyLeftNow = motorLeft->getStatus().duty;
|
||||
float dutyRightNow = motorRight->getStatus().duty;
|
||||
|
||||
//activity detected on any of the two motors
|
||||
if (validateActivity(dutyLeft_lastActivity, dutyLeftNow, inactivityTolerance)
|
||||
|| validateActivity(dutyRight_lastActivity, dutyRightNow, inactivityTolerance)
|
||||
){
|
||||
ESP_LOGD(TAG, "timeout check: [activity] detected since last check -> reset");
|
||||
//reset last duty and timestamp
|
||||
dutyLeft_lastActivity = dutyLeftNow;
|
||||
dutyRight_lastActivity = dutyRightNow;
|
||||
resetTimeout();
|
||||
}
|
||||
//no activity on any motor and msTimeout exceeded
|
||||
else if (esp_log_timestamp() - timestamp_lastActivity > config.timeoutMs){
|
||||
ESP_LOGI(TAG, "timeout check: [TIMEOUT], no activity for more than %.ds -> switch to idle", config.timeoutMs/1000);
|
||||
//toggle to idle mode
|
||||
toggleIdle();
|
||||
}
|
||||
else {
|
||||
ESP_LOGD(TAG, "timeout check: [inactive], last activity %.1f s ago, timeout after %d s", (float)(esp_log_timestamp() - timestamp_lastActivity)/1000, config.timeoutMs/1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------
|
||||
//----------- changeMode ------------
|
||||
//-----------------------------------
|
||||
//function to change to a specified control mode
|
||||
void controlledArmchair::changeMode(controlMode_t modeNew) {
|
||||
//reset timeout timer
|
||||
resetTimeout();
|
||||
|
||||
//exit if target mode is already active
|
||||
if (mode == modeNew) {
|
||||
ESP_LOGE(TAG, "changeMode: Already in target mode '%s' -> nothing to change", controlModeStr[(int)mode]);
|
||||
return;
|
||||
}
|
||||
|
||||
//copy previous mode
|
||||
modePrevious = mode;
|
||||
|
||||
ESP_LOGW(TAG, "=== changing mode from %s to %s ===", controlModeStr[(int)mode], controlModeStr[(int)modeNew]);
|
||||
|
||||
//========== commands change FROM mode ==========
|
||||
//run functions when changing FROM certain mode
|
||||
switch(modePrevious){
|
||||
default:
|
||||
ESP_LOGI(TAG, "noting to execute when changing FROM this mode");
|
||||
break;
|
||||
|
||||
#ifdef JOYSTICK_LOG_IN_IDLE
|
||||
case controlMode_t::IDLE:
|
||||
ESP_LOGI(TAG, "disabling debug output for 'evaluatedJoystick'");
|
||||
esp_log_level_set("evaluatedJoystick", ESP_LOG_WARN); //FIXME: loglevel from config
|
||||
break;
|
||||
#endif
|
||||
|
||||
case controlMode_t::HTTP:
|
||||
ESP_LOGW(TAG, "switching from http mode -> disabling http and wifi");
|
||||
//stop http server
|
||||
ESP_LOGI(TAG, "disabling http server...");
|
||||
http_stop_server();
|
||||
|
||||
//FIXME: make wifi function work here - currently starting wifi at startup (see notes main.cpp)
|
||||
//stop wifi
|
||||
//TODO: decide whether ap or client is currently used - which has to be disabled?
|
||||
//ESP_LOGI(TAG, "deinit wifi...");
|
||||
//wifi_deinit_client();
|
||||
//wifi_deinit_ap();
|
||||
ESP_LOGI(TAG, "done stopping http mode");
|
||||
break;
|
||||
|
||||
case controlMode_t::MASSAGE:
|
||||
ESP_LOGW(TAG, "switching from MASSAGE mode -> restoring fading, reset frozen input");
|
||||
//TODO: fix issue when downfading was disabled before switching to massage mode - currently it gets enabled again here...
|
||||
//enable downfading (set to default value)
|
||||
motorLeft->setFade(fadeType_t::DECEL, true);
|
||||
motorRight->setFade(fadeType_t::DECEL, true);
|
||||
//set upfading to default value
|
||||
motorLeft->setFade(fadeType_t::ACCEL, true);
|
||||
motorRight->setFade(fadeType_t::ACCEL, true);
|
||||
//reset frozen input state
|
||||
freezeInput = false;
|
||||
break;
|
||||
|
||||
case controlMode_t::AUTO:
|
||||
ESP_LOGW(TAG, "switching from AUTO mode -> restoring fading to default");
|
||||
//TODO: fix issue when downfading was disabled before switching to auto mode - currently it gets enabled again here...
|
||||
//enable downfading (set to default value)
|
||||
motorLeft->setFade(fadeType_t::DECEL, true);
|
||||
motorRight->setFade(fadeType_t::DECEL, true);
|
||||
//set upfading to default value
|
||||
motorLeft->setFade(fadeType_t::ACCEL, true);
|
||||
motorRight->setFade(fadeType_t::ACCEL, true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//========== commands change TO mode ==========
|
||||
//run functions when changing TO certain mode
|
||||
switch(modeNew){
|
||||
default:
|
||||
ESP_LOGI(TAG, "noting to execute when changing TO this mode");
|
||||
break;
|
||||
|
||||
case controlMode_t::IDLE:
|
||||
buzzer->beep(1, 1500, 0);
|
||||
#ifdef JOYSTICK_LOG_IN_IDLE
|
||||
esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case controlMode_t::HTTP:
|
||||
ESP_LOGW(TAG, "switching to http mode -> enabling http and wifi");
|
||||
//start wifi
|
||||
//TODO: decide wether ap or client should be started
|
||||
ESP_LOGI(TAG, "init wifi...");
|
||||
|
||||
//FIXME: make wifi function work here - currently starting wifi at startup (see notes main.cpp)
|
||||
//wifi_init_client();
|
||||
//wifi_init_ap();
|
||||
|
||||
//wait for wifi
|
||||
//ESP_LOGI(TAG, "waiting for wifi...");
|
||||
//vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
//start http server
|
||||
ESP_LOGI(TAG, "init http server...");
|
||||
http_init_server();
|
||||
ESP_LOGI(TAG, "done initializing http mode");
|
||||
break;
|
||||
|
||||
case controlMode_t::MASSAGE:
|
||||
ESP_LOGW(TAG, "switching to MASSAGE mode -> reducing fading");
|
||||
uint32_t shake_msFadeAccel = 500; //TODO: move this to config
|
||||
|
||||
//disable downfading (max. deceleration)
|
||||
motorLeft->setFade(fadeType_t::DECEL, false);
|
||||
motorRight->setFade(fadeType_t::DECEL, false);
|
||||
//reduce upfading (increase acceleration)
|
||||
motorLeft->setFade(fadeType_t::ACCEL, shake_msFadeAccel);
|
||||
motorRight->setFade(fadeType_t::ACCEL, shake_msFadeAccel);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
//--- update mode to new mode ---
|
||||
//TODO: add mutex
|
||||
mode = modeNew;
|
||||
}
|
||||
|
||||
|
||||
//TODO simplify the following 3 functions? can be replaced by one?
|
||||
|
||||
//-----------------------------------
|
||||
//----------- toggleIdle ------------
|
||||
//-----------------------------------
|
||||
//function to toggle between IDLE and previous active mode
|
||||
void controlledArmchair::toggleIdle() {
|
||||
//toggle between IDLE and previous mode
|
||||
toggleMode(controlMode_t::IDLE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------
|
||||
//----------- toggleModes ------------
|
||||
//------------------------------------
|
||||
//function to toggle between two modes, but prefer first argument if entirely different mode is currently active
|
||||
void controlledArmchair::toggleModes(controlMode_t modePrimary, controlMode_t modeSecondary) {
|
||||
//switch to secondary mode when primary is already active
|
||||
if (mode == modePrimary){
|
||||
ESP_LOGW(TAG, "toggleModes: switching from primaryMode %s to secondarMode %s", controlModeStr[(int)mode], controlModeStr[(int)modeSecondary]);
|
||||
buzzer->beep(2,200,100);
|
||||
changeMode(modeSecondary); //switch to secondary mode
|
||||
}
|
||||
//switch to primary mode when any other mode is active
|
||||
else {
|
||||
ESP_LOGW(TAG, "toggleModes: switching from %s to primary mode %s", controlModeStr[(int)mode], controlModeStr[(int)modePrimary]);
|
||||
buzzer->beep(4,200,100);
|
||||
changeMode(modePrimary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------
|
||||
//----------- toggleMode ------------
|
||||
//-----------------------------------
|
||||
//function that toggles between certain mode and previous mode
|
||||
void controlledArmchair::toggleMode(controlMode_t modePrimary){
|
||||
|
||||
//switch to previous mode when primary is already active
|
||||
if (mode == modePrimary){
|
||||
ESP_LOGW(TAG, "toggleMode: switching from primaryMode %s to previousMode %s", controlModeStr[(int)mode], controlModeStr[(int)modePrevious]);
|
||||
//buzzer->beep(2,200,100);
|
||||
changeMode(modePrevious); //switch to previous mode
|
||||
}
|
||||
//switch to primary mode when any other mode is active
|
||||
else {
|
||||
ESP_LOGW(TAG, "toggleModes: switching from %s to primary mode %s", controlModeStr[(int)mode], controlModeStr[(int)modePrimary]);
|
||||
//buzzer->beep(4,200,100);
|
||||
changeMode(modePrimary);
|
||||
}
|
||||
}
|
||||
//FIXME controlledMotor class not available for this pcb, rework
|
||||
// //-----------------------------
|
||||
// //-------- constructor --------
|
||||
// //-----------------------------
|
||||
// controlledArmchair::controlledArmchair (
|
||||
// control_config_t config_f,
|
||||
// buzzer_t * buzzer_f,
|
||||
// controlledMotor* motorLeft_f,
|
||||
// controlledMotor* motorRight_f,
|
||||
// evaluatedJoystick* joystick_f,
|
||||
// httpJoystick* httpJoystick_f
|
||||
// ){
|
||||
//
|
||||
// //copy configuration
|
||||
// config = config_f;
|
||||
// //copy object pointers
|
||||
// buzzer = buzzer_f;
|
||||
// motorLeft = motorLeft_f;
|
||||
// motorRight = motorRight_f;
|
||||
// joystick_l = joystick_f,
|
||||
// httpJoystickMain_l = httpJoystick_f;
|
||||
// //set default mode from config
|
||||
// modePrevious = config.defaultMode;
|
||||
//
|
||||
// //TODO declare / configure controlled motors here instead of config (unnecessary that button object is globally available - only used here)?
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //----------------------------------
|
||||
// //---------- Handle loop -----------
|
||||
// //----------------------------------
|
||||
// //function that repeatedly generates motor commands depending on the current mode
|
||||
// //also handles fading and current-limit
|
||||
// void controlledArmchair::startHandleLoop() {
|
||||
// while (1){
|
||||
// ESP_LOGV(TAG, "control task executing... mode=%s", controlModeStr[(int)mode]);
|
||||
//
|
||||
// switch(mode) {
|
||||
// default:
|
||||
// mode = controlMode_t::IDLE;
|
||||
// break;
|
||||
//
|
||||
// case controlMode_t::IDLE:
|
||||
// //copy preset commands for idling both motors
|
||||
// commands = cmds_bothMotorsIdle;
|
||||
// motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
// motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
// vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
// #ifdef JOYSTICK_LOG_IN_IDLE
|
||||
// //get joystick data here (without using it)
|
||||
// //since loglevel is DEBUG, calculateion details is output
|
||||
// joystick_l->getData(); //get joystick data here
|
||||
// #endif
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// case controlMode_t::JOYSTICK:
|
||||
// vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
// //get current joystick data with getData method of evaluatedJoystick
|
||||
// stickData = joystick_l->getData();
|
||||
// //additionaly scale coordinates (more detail in slower area)
|
||||
// joystick_scaleCoordinatesLinear(&stickData, 0.6, 0.35); //TODO: add scaling parameters to config
|
||||
// //generate motor commands
|
||||
// commands = joystick_generateCommandsDriving(stickData, altStickMapping);
|
||||
// //apply motor commands
|
||||
// motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
// motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
// //TODO make motorctl.setTarget also accept motorcommand struct directly
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// case controlMode_t::MASSAGE:
|
||||
// vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
// //--- read joystick ---
|
||||
// //only update joystick data when input not frozen
|
||||
// if (!freezeInput){
|
||||
// stickData = joystick_l->getData();
|
||||
// }
|
||||
// //--- generate motor commands ---
|
||||
// //pass joystick data from getData method of evaluatedJoystick to generateCommandsShaking function
|
||||
// commands = joystick_generateCommandsShaking(stickData);
|
||||
// //apply motor commands
|
||||
// motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
// motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// case controlMode_t::HTTP:
|
||||
// //--- get joystick data from queue ---
|
||||
// //Note this function waits several seconds (httpconfig.timeoutMs) for data to arrive, otherwise Center data or NULL is returned
|
||||
// //TODO: as described above, when changing modes it might delay a few seconds for the change to apply
|
||||
// stickData = httpJoystickMain_l->getData();
|
||||
// //scale coordinates additionally (more detail in slower area)
|
||||
// joystick_scaleCoordinatesLinear(&stickData, 0.6, 0.4); //TODO: add scaling parameters to config
|
||||
// ESP_LOGD(TAG, "generating commands from x=%.3f y=%.3f radius=%.3f angle=%.3f", stickData.x, stickData.y, stickData.radius, stickData.angle);
|
||||
// //--- generate motor commands ---
|
||||
// //Note: timeout (no data received) is handled in getData method
|
||||
// commands = joystick_generateCommandsDriving(stickData, altStickMapping);
|
||||
//
|
||||
// //--- apply commands to motors ---
|
||||
// //TODO make motorctl.setTarget also accept motorcommand struct directly
|
||||
// motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
// motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// case controlMode_t::AUTO:
|
||||
// vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
// //generate commands
|
||||
// commands = armchair.generateCommands(&instruction);
|
||||
// //--- apply commands to motors ---
|
||||
// //TODO make motorctl.setTarget also accept motorcommand struct directly
|
||||
// motorRight->setTarget(commands.right.state, commands.right.duty);
|
||||
// motorLeft->setTarget(commands.left.state, commands.left.duty);
|
||||
//
|
||||
// //process received instruction
|
||||
// switch (instruction) {
|
||||
// case auto_instruction_t::NONE:
|
||||
// break;
|
||||
// case auto_instruction_t::SWITCH_PREV_MODE:
|
||||
// toggleMode(controlMode_t::AUTO);
|
||||
// break;
|
||||
// case auto_instruction_t::SWITCH_JOYSTICK_MODE:
|
||||
// changeMode(controlMode_t::JOYSTICK);
|
||||
// break;
|
||||
// case auto_instruction_t::RESET_ACCEL_DECEL:
|
||||
// //enable downfading (set to default value)
|
||||
// motorLeft->setFade(fadeType_t::DECEL, true);
|
||||
// motorRight->setFade(fadeType_t::DECEL, true);
|
||||
// //set upfading to default value
|
||||
// motorLeft->setFade(fadeType_t::ACCEL, true);
|
||||
// motorRight->setFade(fadeType_t::ACCEL, true);
|
||||
// break;
|
||||
// case auto_instruction_t::RESET_ACCEL:
|
||||
// //set upfading to default value
|
||||
// motorLeft->setFade(fadeType_t::ACCEL, true);
|
||||
// motorRight->setFade(fadeType_t::ACCEL, true);
|
||||
// break;
|
||||
// case auto_instruction_t::RESET_DECEL:
|
||||
// //enable downfading (set to default value)
|
||||
// motorLeft->setFade(fadeType_t::DECEL, true);
|
||||
// motorRight->setFade(fadeType_t::DECEL, true);
|
||||
// break;
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
//
|
||||
// //TODO: add other modes here
|
||||
// }
|
||||
//
|
||||
//
|
||||
// //--- run actions based on received button button event ---
|
||||
// //note: buttonCount received by sendButtonEvent method called from button.cpp
|
||||
// //TODO: what if variable gets set from other task during this code? -> mutex around this code
|
||||
// switch (buttonCount) {
|
||||
// case 1: //define joystick center or freeze input
|
||||
// if (mode == controlMode_t::JOYSTICK){
|
||||
// //joystick mode: calibrate joystick
|
||||
// joystick_l->defineCenter();
|
||||
// } else if (mode == controlMode_t::MASSAGE){
|
||||
// //massage mode: toggle freeze of input (lock joystick at current values)
|
||||
// freezeInput = !freezeInput;
|
||||
// if (freezeInput){
|
||||
// buzzer->beep(5, 40, 25);
|
||||
// } else {
|
||||
// buzzer->beep(1, 300, 100);
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case 12: //toggle alternative joystick mapping (reverse swapped)
|
||||
// altStickMapping = !altStickMapping;
|
||||
// if (altStickMapping){
|
||||
// buzzer->beep(6, 70, 50);
|
||||
// } else {
|
||||
// buzzer->beep(1, 500, 100);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// //--- reset button event --- (only one action per run)
|
||||
// if (buttonCount > 0){
|
||||
// ESP_LOGI(TAG, "resetting button event/count");
|
||||
// buttonCount = 0;
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //-----------------------
|
||||
// //------ slow loop ------
|
||||
// //-----------------------
|
||||
// //this section is run about every 5s (+500ms)
|
||||
// if (esp_log_timestamp() - timestamp_SlowLoopLastRun > 5000) {
|
||||
// ESP_LOGV(TAG, "running slow loop... time since last run: %.1fs", (float)(esp_log_timestamp() - timestamp_SlowLoopLastRun)/1000);
|
||||
// timestamp_SlowLoopLastRun = esp_log_timestamp();
|
||||
//
|
||||
// //run function which detects timeout (switch to idle)
|
||||
// handleTimeout();
|
||||
// }
|
||||
//
|
||||
// }//end while(1)
|
||||
// }//end startHandleLoop
|
||||
//
|
||||
//
|
||||
//
|
||||
// //-----------------------------------
|
||||
// //---------- resetTimeout -----------
|
||||
// //-----------------------------------
|
||||
// void controlledArmchair::resetTimeout(){
|
||||
// //TODO mutex
|
||||
// timestamp_lastActivity = esp_log_timestamp();
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //------------------------------------
|
||||
// //--------- sendButtonEvent ----------
|
||||
// //------------------------------------
|
||||
// void controlledArmchair::sendButtonEvent(uint8_t count){
|
||||
// //TODO mutex - if not replaced with queue
|
||||
// ESP_LOGI(TAG, "setting button event");
|
||||
// buttonCount = count;
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //------------------------------------
|
||||
// //---------- handleTimeout -----------
|
||||
// //------------------------------------
|
||||
// //percentage the duty can vary since last timeout check and still counts as incative
|
||||
// //TODO: add this to config
|
||||
// float inactivityTolerance = 10;
|
||||
//
|
||||
// //local function that checks whether two values differ more than a given tolerance
|
||||
// bool validateActivity(float dutyOld, float dutyNow, float tolerance){
|
||||
// float dutyDelta = dutyNow - dutyOld;
|
||||
// if (fabs(dutyDelta) < tolerance) {
|
||||
// return false; //no significant activity detected
|
||||
// } else {
|
||||
// return true; //there was activity
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //function that evaluates whether there is no activity/change on the motor duty for a certain time. If so, a switch to IDLE is issued. - has to be run repeatedly in a slow interval
|
||||
// void controlledArmchair::handleTimeout(){
|
||||
// //check for timeout only when not idling already
|
||||
// if (mode != controlMode_t::IDLE) {
|
||||
// //get current duty from controlled motor objects
|
||||
// float dutyLeftNow = motorLeft->getStatus().duty;
|
||||
// float dutyRightNow = motorRight->getStatus().duty;
|
||||
//
|
||||
// //activity detected on any of the two motors
|
||||
// if (validateActivity(dutyLeft_lastActivity, dutyLeftNow, inactivityTolerance)
|
||||
// || validateActivity(dutyRight_lastActivity, dutyRightNow, inactivityTolerance)
|
||||
// ){
|
||||
// ESP_LOGD(TAG, "timeout check: [activity] detected since last check -> reset");
|
||||
// //reset last duty and timestamp
|
||||
// dutyLeft_lastActivity = dutyLeftNow;
|
||||
// dutyRight_lastActivity = dutyRightNow;
|
||||
// resetTimeout();
|
||||
// }
|
||||
// //no activity on any motor and msTimeout exceeded
|
||||
// else if (esp_log_timestamp() - timestamp_lastActivity > config.timeoutMs){
|
||||
// ESP_LOGI(TAG, "timeout check: [TIMEOUT], no activity for more than %.ds -> switch to idle", config.timeoutMs/1000);
|
||||
// //toggle to idle mode
|
||||
// toggleIdle();
|
||||
// }
|
||||
// else {
|
||||
// ESP_LOGD(TAG, "timeout check: [inactive], last activity %.1f s ago, timeout after %d s", (float)(esp_log_timestamp() - timestamp_lastActivity)/1000, config.timeoutMs/1000);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //-----------------------------------
|
||||
// //----------- changeMode ------------
|
||||
// //-----------------------------------
|
||||
// //function to change to a specified control mode
|
||||
// void controlledArmchair::changeMode(controlMode_t modeNew) {
|
||||
// //reset timeout timer
|
||||
// resetTimeout();
|
||||
//
|
||||
// //exit if target mode is already active
|
||||
// if (mode == modeNew) {
|
||||
// ESP_LOGE(TAG, "changeMode: Already in target mode '%s' -> nothing to change", controlModeStr[(int)mode]);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// //copy previous mode
|
||||
// modePrevious = mode;
|
||||
//
|
||||
// ESP_LOGW(TAG, "=== changing mode from %s to %s ===", controlModeStr[(int)mode], controlModeStr[(int)modeNew]);
|
||||
//
|
||||
// //========== commands change FROM mode ==========
|
||||
// //run functions when changing FROM certain mode
|
||||
// switch(modePrevious){
|
||||
// default:
|
||||
// ESP_LOGI(TAG, "noting to execute when changing FROM this mode");
|
||||
// break;
|
||||
//
|
||||
// #ifdef JOYSTICK_LOG_IN_IDLE
|
||||
// case controlMode_t::IDLE:
|
||||
// ESP_LOGI(TAG, "disabling debug output for 'evaluatedJoystick'");
|
||||
// esp_log_level_set("evaluatedJoystick", ESP_LOG_WARN); //FIXME: loglevel from config
|
||||
// break;
|
||||
// #endif
|
||||
//
|
||||
// case controlMode_t::HTTP:
|
||||
// ESP_LOGW(TAG, "switching from http mode -> disabling http and wifi");
|
||||
// //stop http server
|
||||
// ESP_LOGI(TAG, "disabling http server...");
|
||||
// http_stop_server();
|
||||
//
|
||||
// //FIXME: make wifi function work here - currently starting wifi at startup (see notes main.cpp)
|
||||
// //stop wifi
|
||||
// //TODO: decide whether ap or client is currently used - which has to be disabled?
|
||||
// //ESP_LOGI(TAG, "deinit wifi...");
|
||||
// //wifi_deinit_client();
|
||||
// //wifi_deinit_ap();
|
||||
// ESP_LOGI(TAG, "done stopping http mode");
|
||||
// break;
|
||||
//
|
||||
// case controlMode_t::MASSAGE:
|
||||
// ESP_LOGW(TAG, "switching from MASSAGE mode -> restoring fading, reset frozen input");
|
||||
// //TODO: fix issue when downfading was disabled before switching to massage mode - currently it gets enabled again here...
|
||||
// //enable downfading (set to default value)
|
||||
// motorLeft->setFade(fadeType_t::DECEL, true);
|
||||
// motorRight->setFade(fadeType_t::DECEL, true);
|
||||
// //set upfading to default value
|
||||
// motorLeft->setFade(fadeType_t::ACCEL, true);
|
||||
// motorRight->setFade(fadeType_t::ACCEL, true);
|
||||
// //reset frozen input state
|
||||
// freezeInput = false;
|
||||
// break;
|
||||
//
|
||||
// case controlMode_t::AUTO:
|
||||
// ESP_LOGW(TAG, "switching from AUTO mode -> restoring fading to default");
|
||||
// //TODO: fix issue when downfading was disabled before switching to auto mode - currently it gets enabled again here...
|
||||
// //enable downfading (set to default value)
|
||||
// motorLeft->setFade(fadeType_t::DECEL, true);
|
||||
// motorRight->setFade(fadeType_t::DECEL, true);
|
||||
// //set upfading to default value
|
||||
// motorLeft->setFade(fadeType_t::ACCEL, true);
|
||||
// motorRight->setFade(fadeType_t::ACCEL, true);
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// //========== commands change TO mode ==========
|
||||
// //run functions when changing TO certain mode
|
||||
// switch(modeNew){
|
||||
// default:
|
||||
// ESP_LOGI(TAG, "noting to execute when changing TO this mode");
|
||||
// break;
|
||||
//
|
||||
// case controlMode_t::IDLE:
|
||||
// buzzer->beep(1, 1500, 0);
|
||||
// #ifdef JOYSTICK_LOG_IN_IDLE
|
||||
// esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG);
|
||||
// #endif
|
||||
// break;
|
||||
//
|
||||
// case controlMode_t::HTTP:
|
||||
// ESP_LOGW(TAG, "switching to http mode -> enabling http and wifi");
|
||||
// //start wifi
|
||||
// //TODO: decide wether ap or client should be started
|
||||
// ESP_LOGI(TAG, "init wifi...");
|
||||
//
|
||||
// //FIXME: make wifi function work here - currently starting wifi at startup (see notes main.cpp)
|
||||
// //wifi_init_client();
|
||||
// //wifi_init_ap();
|
||||
//
|
||||
// //wait for wifi
|
||||
// //ESP_LOGI(TAG, "waiting for wifi...");
|
||||
// //vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
//
|
||||
// //start http server
|
||||
// ESP_LOGI(TAG, "init http server...");
|
||||
// http_init_server();
|
||||
// ESP_LOGI(TAG, "done initializing http mode");
|
||||
// break;
|
||||
//
|
||||
// case controlMode_t::MASSAGE:
|
||||
// ESP_LOGW(TAG, "switching to MASSAGE mode -> reducing fading");
|
||||
// uint32_t shake_msFadeAccel = 500; //TODO: move this to config
|
||||
//
|
||||
// //disable downfading (max. deceleration)
|
||||
// motorLeft->setFade(fadeType_t::DECEL, false);
|
||||
// motorRight->setFade(fadeType_t::DECEL, false);
|
||||
// //reduce upfading (increase acceleration)
|
||||
// motorLeft->setFade(fadeType_t::ACCEL, shake_msFadeAccel);
|
||||
// motorRight->setFade(fadeType_t::ACCEL, shake_msFadeAccel);
|
||||
// break;
|
||||
//
|
||||
// }
|
||||
//
|
||||
// //--- update mode to new mode ---
|
||||
// //TODO: add mutex
|
||||
// mode = modeNew;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// //TODO simplify the following 3 functions? can be replaced by one?
|
||||
//
|
||||
// //-----------------------------------
|
||||
// //----------- toggleIdle ------------
|
||||
// //-----------------------------------
|
||||
// //function to toggle between IDLE and previous active mode
|
||||
// void controlledArmchair::toggleIdle() {
|
||||
// //toggle between IDLE and previous mode
|
||||
// toggleMode(controlMode_t::IDLE);
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //------------------------------------
|
||||
// //----------- toggleModes ------------
|
||||
// //------------------------------------
|
||||
// //function to toggle between two modes, but prefer first argument if entirely different mode is currently active
|
||||
// void controlledArmchair::toggleModes(controlMode_t modePrimary, controlMode_t modeSecondary) {
|
||||
// //switch to secondary mode when primary is already active
|
||||
// if (mode == modePrimary){
|
||||
// ESP_LOGW(TAG, "toggleModes: switching from primaryMode %s to secondarMode %s", controlModeStr[(int)mode], controlModeStr[(int)modeSecondary]);
|
||||
// buzzer->beep(2,200,100);
|
||||
// changeMode(modeSecondary); //switch to secondary mode
|
||||
// }
|
||||
// //switch to primary mode when any other mode is active
|
||||
// else {
|
||||
// ESP_LOGW(TAG, "toggleModes: switching from %s to primary mode %s", controlModeStr[(int)mode], controlModeStr[(int)modePrimary]);
|
||||
// buzzer->beep(4,200,100);
|
||||
// changeMode(modePrimary);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //-----------------------------------
|
||||
// //----------- toggleMode ------------
|
||||
// //-----------------------------------
|
||||
// //function that toggles between certain mode and previous mode
|
||||
// void controlledArmchair::toggleMode(controlMode_t modePrimary){
|
||||
//
|
||||
// //switch to previous mode when primary is already active
|
||||
// if (mode == modePrimary){
|
||||
// ESP_LOGW(TAG, "toggleMode: switching from primaryMode %s to previousMode %s", controlModeStr[(int)mode], controlModeStr[(int)modePrevious]);
|
||||
// //buzzer->beep(2,200,100);
|
||||
// changeMode(modePrevious); //switch to previous mode
|
||||
// }
|
||||
// //switch to primary mode when any other mode is active
|
||||
// else {
|
||||
// ESP_LOGW(TAG, "toggleModes: switching from %s to primary mode %s", controlModeStr[(int)mode], controlModeStr[(int)modePrimary]);
|
||||
// //buzzer->beep(4,200,100);
|
||||
// changeMode(modePrimary);
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,130 +1,130 @@
|
||||
#pragma once
|
||||
|
||||
#include "motordrivers.hpp"
|
||||
#include "motorctl.hpp"
|
||||
#include "buzzer.hpp"
|
||||
#include "http.hpp"
|
||||
#include "auto.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
|
||||
//--------------------------------------------
|
||||
//---- struct, enum, variable declarations ---
|
||||
//--------------------------------------------
|
||||
//enum that decides how the motors get controlled
|
||||
enum class controlMode_t {IDLE, JOYSTICK, MASSAGE, HTTP, MQTT, BLUETOOTH, AUTO};
|
||||
//string array representing the mode enum (for printing the state as string)
|
||||
extern const char* controlModeStr[7];
|
||||
|
||||
//--- control_config_t ---
|
||||
//struct with config parameters
|
||||
typedef struct control_config_t {
|
||||
controlMode_t defaultMode; //default mode after startup and toggling IDLE
|
||||
//timeout options
|
||||
uint32_t timeoutMs; //time of inactivity after which the mode gets switched to IDLE
|
||||
float timeoutTolerancePer; //percentage the duty can vary between timeout checks considered still inactive
|
||||
} control_config_t;
|
||||
|
||||
|
||||
|
||||
|
||||
//==================================
|
||||
//========= control class ==========
|
||||
//==================================
|
||||
//controls the mode the armchair operates
|
||||
//repeatedly generates the motor commands corresponding to current mode and sends those to motorcontrol
|
||||
class controlledArmchair {
|
||||
public:
|
||||
//--- constructor ---
|
||||
controlledArmchair (
|
||||
control_config_t config_f,
|
||||
buzzer_t* buzzer_f,
|
||||
controlledMotor* motorLeft_f,
|
||||
controlledMotor* motorRight_f,
|
||||
evaluatedJoystick* joystick_f,
|
||||
httpJoystick* httpJoystick_f
|
||||
);
|
||||
|
||||
//--- functions ---
|
||||
//task that repeatedly generates motor commands depending on the current mode
|
||||
void startHandleLoop();
|
||||
|
||||
//function that changes to a specified control mode
|
||||
void changeMode(controlMode_t modeNew);
|
||||
|
||||
//function that toggle between IDLE and previous active mode (or default if not switched to certain mode yet)
|
||||
void toggleIdle();
|
||||
|
||||
//function that toggles between two modes, but prefers first argument if entirely different mode is currently active
|
||||
void toggleModes(controlMode_t modePrimary, controlMode_t modeSecondary);
|
||||
|
||||
//toggle between certain mode and previous mode
|
||||
void toggleMode(controlMode_t modePrimary);
|
||||
|
||||
//function that restarts timer which initiates the automatic timeout (switch to IDLE) after certain time of inactivity
|
||||
void resetTimeout();
|
||||
|
||||
//function for sending a button event (e.g. from button task at event) to control task
|
||||
//TODO: use queue instead?
|
||||
void sendButtonEvent(uint8_t count);
|
||||
|
||||
private:
|
||||
|
||||
//--- functions ---
|
||||
//function that evaluates whether there is no activity/change on the motor duty for a certain time, if so a switch to IDLE is issued. - has to be run repeatedly in a slow interval
|
||||
void handleTimeout();
|
||||
|
||||
//--- objects ---
|
||||
buzzer_t* buzzer;
|
||||
controlledMotor* motorLeft;
|
||||
controlledMotor* motorRight;
|
||||
httpJoystick* httpJoystickMain_l;
|
||||
evaluatedJoystick* joystick_l;
|
||||
|
||||
//---variables ---
|
||||
//struct for motor commands returned by generate functions of each mode
|
||||
motorCommands_t commands;
|
||||
//struct with config parameters
|
||||
control_config_t config;
|
||||
|
||||
//store joystick data
|
||||
joystickData_t stickData;
|
||||
bool altStickMapping; //alternative joystick mapping (reverse mapped differently)
|
||||
|
||||
//variables for http mode
|
||||
uint32_t http_timestamp_lastData = 0;
|
||||
|
||||
//variables for MASSAGE mode
|
||||
bool freezeInput = false;
|
||||
|
||||
//variables for AUTO mode
|
||||
auto_instruction_t instruction = auto_instruction_t::NONE; //variable to receive instructions from automatedArmchair
|
||||
|
||||
//variable to store button event
|
||||
uint8_t buttonCount = 0;
|
||||
|
||||
//definition of mode enum
|
||||
controlMode_t mode = controlMode_t::IDLE;
|
||||
|
||||
//variable to store mode when toggling IDLE mode
|
||||
controlMode_t modePrevious; //default mode
|
||||
|
||||
//command preset for idling motors
|
||||
const motorCommand_t cmd_motorIdle = {
|
||||
.state = motorstate_t::IDLE,
|
||||
.duty = 0
|
||||
};
|
||||
const motorCommands_t cmds_bothMotorsIdle = {
|
||||
.left = cmd_motorIdle,
|
||||
.right = cmd_motorIdle
|
||||
};
|
||||
|
||||
//variable for slow loop
|
||||
uint32_t timestamp_SlowLoopLastRun = 0;
|
||||
|
||||
//variables for detecting timeout (switch to idle, after inactivity)
|
||||
float dutyLeft_lastActivity = 0;
|
||||
float dutyRight_lastActivity = 0;
|
||||
uint32_t timestamp_lastActivity = 0;
|
||||
};
|
||||
|
||||
|
||||
//FIXME controlledMotor class not available for this pcb, rework
|
||||
//--------------------------------------------
|
||||
//---- struct, enum, variable declarations ---
|
||||
//--------------------------------------------
|
||||
//enum that decides how the motors get controlled
|
||||
enum class controlMode_t {IDLE, JOYSTICK, MASSAGE, HTTP, MQTT, BLUETOOTH, AUTO};
|
||||
//string array representing the mode enum (for printing the state as string)
|
||||
extern const char* controlModeStr[7];
|
||||
|
||||
//--- control_config_t ---
|
||||
//struct with config parameters
|
||||
typedef struct control_config_t {
|
||||
controlMode_t defaultMode; //default mode after startup and toggling IDLE
|
||||
//timeout options
|
||||
uint32_t timeoutMs; //time of inactivity after which the mode gets switched to IDLE
|
||||
float timeoutTolerancePer; //percentage the duty can vary between timeout checks considered still inactive
|
||||
} control_config_t;
|
||||
|
||||
|
||||
|
||||
|
||||
// //==================================
|
||||
// //========= control class ==========
|
||||
// //==================================
|
||||
// //controls the mode the armchair operates
|
||||
// //repeatedly generates the motor commands corresponding to current mode and sends those to motorcontrol
|
||||
// class controlledArmchair {
|
||||
// public:
|
||||
// //--- constructor ---
|
||||
// controlledArmchair (
|
||||
// control_config_t config_f,
|
||||
// buzzer_t* buzzer_f,
|
||||
// controlledMotor* motorLeft_f,
|
||||
// controlledMotor* motorRight_f,
|
||||
// evaluatedJoystick* joystick_f,
|
||||
// httpJoystick* httpJoystick_f
|
||||
// );
|
||||
//
|
||||
// //--- functions ---
|
||||
// //task that repeatedly generates motor commands depending on the current mode
|
||||
// void startHandleLoop();
|
||||
//
|
||||
// //function that changes to a specified control mode
|
||||
// void changeMode(controlMode_t modeNew);
|
||||
//
|
||||
// //function that toggle between IDLE and previous active mode (or default if not switched to certain mode yet)
|
||||
// void toggleIdle();
|
||||
//
|
||||
// //function that toggles between two modes, but prefers first argument if entirely different mode is currently active
|
||||
// void toggleModes(controlMode_t modePrimary, controlMode_t modeSecondary);
|
||||
//
|
||||
// //toggle between certain mode and previous mode
|
||||
// void toggleMode(controlMode_t modePrimary);
|
||||
//
|
||||
// //function that restarts timer which initiates the automatic timeout (switch to IDLE) after certain time of inactivity
|
||||
// void resetTimeout();
|
||||
//
|
||||
// //function for sending a button event (e.g. from button task at event) to control task
|
||||
// //TODO: use queue instead?
|
||||
// void sendButtonEvent(uint8_t count);
|
||||
//
|
||||
// private:
|
||||
//
|
||||
// //--- functions ---
|
||||
// //function that evaluates whether there is no activity/change on the motor duty for a certain time, if so a switch to IDLE is issued. - has to be run repeatedly in a slow interval
|
||||
// void handleTimeout();
|
||||
//
|
||||
// //--- objects ---
|
||||
// buzzer_t* buzzer;
|
||||
// controlledMotor* motorLeft;
|
||||
// controlledMotor* motorRight;
|
||||
// httpJoystick* httpJoystickMain_l;
|
||||
// evaluatedJoystick* joystick_l;
|
||||
//
|
||||
// //---variables ---
|
||||
// //struct for motor commands returned by generate functions of each mode
|
||||
// motorCommands_t commands;
|
||||
// //struct with config parameters
|
||||
// control_config_t config;
|
||||
//
|
||||
// //store joystick data
|
||||
// joystickData_t stickData;
|
||||
// bool altStickMapping; //alternative joystick mapping (reverse mapped differently)
|
||||
//
|
||||
// //variables for http mode
|
||||
// uint32_t http_timestamp_lastData = 0;
|
||||
//
|
||||
// //variables for MASSAGE mode
|
||||
// bool freezeInput = false;
|
||||
//
|
||||
// //variables for AUTO mode
|
||||
// auto_instruction_t instruction = auto_instruction_t::NONE; //variable to receive instructions from automatedArmchair
|
||||
//
|
||||
// //variable to store button event
|
||||
// uint8_t buttonCount = 0;
|
||||
//
|
||||
// //definition of mode enum
|
||||
// controlMode_t mode = controlMode_t::IDLE;
|
||||
//
|
||||
// //variable to store mode when toggling IDLE mode
|
||||
// controlMode_t modePrevious; //default mode
|
||||
//
|
||||
// //command preset for idling motors
|
||||
// const motorCommand_t cmd_motorIdle = {
|
||||
// .state = motorstate_t::IDLE,
|
||||
// .duty = 0
|
||||
// };
|
||||
// const motorCommands_t cmds_bothMotorsIdle = {
|
||||
// .left = cmd_motorIdle,
|
||||
// .right = cmd_motorIdle
|
||||
// };
|
||||
//
|
||||
// //variable for slow loop
|
||||
// uint32_t timestamp_SlowLoopLastRun = 0;
|
||||
//
|
||||
// //variables for detecting timeout (switch to idle, after inactivity)
|
||||
// float dutyLeft_lastActivity = 0;
|
||||
// float dutyRight_lastActivity = 0;
|
||||
// uint32_t timestamp_lastActivity = 0;
|
||||
// };
|
||||
//
|
||||
//
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
extern "C" {
|
||||
#include "hal/timer_types.h"
|
||||
#include "esp_log.h"
|
||||
}
|
||||
|
||||
#include "currentsensor.hpp"
|
||||
|
||||
//tag for logging
|
||||
static const char * TAG = "current-sensors";
|
||||
|
||||
|
||||
|
||||
//--------------------------
|
||||
//------- getVoltage -------
|
||||
//--------------------------
|
||||
//local function to get average voltage from adc
|
||||
float getVoltage(adc1_channel_t adc, uint32_t samples){
|
||||
//measure voltage
|
||||
int measure = 0;
|
||||
for (int j=0; j<samples; j++){
|
||||
measure += adc1_get_raw(adc);
|
||||
ets_delay_us(50);
|
||||
}
|
||||
return (float)measure / samples / 4096 * 3.3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================
|
||||
//======== constructor ========
|
||||
//=============================
|
||||
currentSensor::currentSensor (adc1_channel_t adcChannel_f, float ratedCurrent_f){
|
||||
//copy config
|
||||
adcChannel = adcChannel_f;
|
||||
ratedCurrent = ratedCurrent_f;
|
||||
//init adc
|
||||
adc1_config_width(ADC_WIDTH_BIT_12); //max resolution 4096
|
||||
adc1_config_channel_atten(adcChannel, ADC_ATTEN_DB_11); //max voltage
|
||||
//calibrate
|
||||
calibrateZeroAmpere();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================
|
||||
//=========== read ===========
|
||||
//============================
|
||||
float currentSensor::read(void){
|
||||
//measure voltage
|
||||
voltage = getVoltage(adcChannel, 30);
|
||||
|
||||
//scale voltage to current
|
||||
if (voltage < centerVoltage){
|
||||
current = (1 - voltage / centerVoltage) * -ratedCurrent;
|
||||
} else if (voltage > centerVoltage){
|
||||
current = (voltage - centerVoltage) / (3.3 - centerVoltage) * ratedCurrent;
|
||||
}else {
|
||||
current = 0;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "read sensor adc=%d: voltage=%.3fV, centerVoltage=%.3fV => current=%.3fA", (int)adcChannel, voltage, centerVoltage, current);
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===============================
|
||||
//===== calibrateZeroAmpere =====
|
||||
//===============================
|
||||
void currentSensor::calibrateZeroAmpere(void){
|
||||
//measure voltage
|
||||
float prev = centerVoltage;
|
||||
centerVoltage = getVoltage(adcChannel, 100);
|
||||
ESP_LOGW(TAG, "defined centerVoltage (0A) to %.3f (previous %.3f)", centerVoltage, prev);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#include <driver/adc.h>
|
||||
|
||||
//supported current sensor working method:
|
||||
//0V = -ratedCurrent
|
||||
//centerVoltage = 0A
|
||||
//3.3V = ratedCurrent
|
||||
|
||||
class currentSensor{
|
||||
public:
|
||||
currentSensor (adc1_channel_t adcChannel_f, float ratedCurrent);
|
||||
void calibrateZeroAmpere(void); //set current voltage to voltage representing 0A
|
||||
float read(void); //get current ampere
|
||||
private:
|
||||
adc1_channel_t adcChannel;
|
||||
float ratedCurrent;
|
||||
uint32_t measure;
|
||||
float voltage;
|
||||
float current;
|
||||
float centerVoltage = 3.3/2;
|
||||
};
|
||||
@@ -1,82 +0,0 @@
|
||||
extern "C"
|
||||
{
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
}
|
||||
|
||||
#include "fan.hpp"
|
||||
|
||||
|
||||
//tag for logging
|
||||
static const char * TAG = "fan-control";
|
||||
|
||||
|
||||
//-----------------------------
|
||||
//-------- constructor --------
|
||||
//-----------------------------
|
||||
controlledFan::controlledFan (fan_config_t config_f, controlledMotor* motor1_f, controlledMotor* motor2_f ){
|
||||
//copy config
|
||||
config = config_f;
|
||||
//copy pointer to motor objects
|
||||
motor1 = motor1_f;
|
||||
motor2 = motor2_f;
|
||||
//initialize gpio pin
|
||||
gpio_pad_select_gpio(config.gpio_fan);
|
||||
gpio_set_direction(config.gpio_fan, GPIO_MODE_OUTPUT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------
|
||||
//--------- handle ---------
|
||||
//--------------------------
|
||||
void controlledFan::handle(){
|
||||
//get current state of the motor (motorctl.cpp)
|
||||
motor1Status = motor1->getStatus();
|
||||
motor2Status = motor2->getStatus();
|
||||
|
||||
//--- handle duty threshold ---
|
||||
//update timestamp if any threshold exceeded
|
||||
if (motor1Status.duty > config.dutyThreshold
|
||||
|| motor2Status.duty > config.dutyThreshold){ //TODO add temperature threshold
|
||||
if (!needsCooling){
|
||||
timestamp_needsCoolingSet = esp_log_timestamp();
|
||||
needsCooling = true;
|
||||
}
|
||||
timestamp_lastThreshold = esp_log_timestamp();
|
||||
} else {
|
||||
needsCooling = false;
|
||||
}
|
||||
|
||||
//--- turn off condition ---
|
||||
if (fanRunning
|
||||
&& !needsCooling //no more cooling required
|
||||
&& (motor1Status.duty == 0) && (motor2Status.duty == 0) //both motors are off
|
||||
//-> keeps fans running even when lower than threshold already, however turnOffDelay already started TODO: start turn off delay after motor stop only?
|
||||
&& (esp_log_timestamp() - timestamp_lastThreshold) > config.turnOffDelayMs){ //turn off delay passed
|
||||
fanRunning = false;
|
||||
gpio_set_level(config.gpio_fan, 0);
|
||||
timestamp_turnedOff = esp_log_timestamp();
|
||||
ESP_LOGI(TAG, "turned fan OFF gpio=%d, minOnMs=%d, WasOnMs=%d", (int)config.gpio_fan, config.minOnMs, esp_log_timestamp()-timestamp_turnedOn);
|
||||
}
|
||||
|
||||
//--- turn on condition ---
|
||||
if (!fanRunning
|
||||
&& needsCooling
|
||||
&& ((esp_log_timestamp() - timestamp_turnedOff) > config.minOffMs) //fans off long enough
|
||||
&& ((esp_log_timestamp() - timestamp_needsCoolingSet) > config.minOnMs)){ //motors on long enough
|
||||
fanRunning = true;
|
||||
gpio_set_level(config.gpio_fan, 1);
|
||||
timestamp_turnedOn = esp_log_timestamp();
|
||||
ESP_LOGI(TAG, "turned fan ON gpio=%d, minOffMs=%d, WasOffMs=%d", (int)config.gpio_fan, config.minOffMs, esp_log_timestamp()-timestamp_turnedOff);
|
||||
}
|
||||
|
||||
//TODO Add statemachine for more specific control? Exponential average?
|
||||
//TODO idea: try other aproach? increment a variable with certain weights e.g. integrate over duty, then turn fans on and decrement the variable again
|
||||
|
||||
ESP_LOGD(TAG, "fanState=%d, duty1=%f, duty2=%f, needsCooling=%d", fanRunning, motor1Status.duty, motor2Status.duty, needsCooling);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "driver/gpio.h"
|
||||
}
|
||||
|
||||
#include "motorctl.hpp"
|
||||
|
||||
|
||||
//--- fan_config_t ---
|
||||
//struct with all config parameters for a fan
|
||||
typedef struct fan_config_t {
|
||||
gpio_num_t gpio_fan;
|
||||
float dutyThreshold;
|
||||
uint32_t minOnMs;
|
||||
uint32_t minOffMs;
|
||||
uint32_t turnOffDelayMs;
|
||||
} fan_config;
|
||||
|
||||
|
||||
|
||||
//==================================
|
||||
//====== controlledFan class =======
|
||||
//==================================
|
||||
class controlledFan {
|
||||
public:
|
||||
//--- constructor ---
|
||||
controlledFan (fan_config_t config_f, controlledMotor* motor1_f, controlledMotor* motor2_f );
|
||||
|
||||
//--- functions ---
|
||||
void handle(); //has to be run repeatedly in a slow loop
|
||||
|
||||
|
||||
private:
|
||||
//--- variables ---
|
||||
bool fanRunning = false;
|
||||
bool needsCooling = false;
|
||||
uint32_t timestamp_needsCoolingSet;
|
||||
uint32_t timestamp_lastThreshold = 0;
|
||||
uint32_t timestamp_turnedOn = 0;
|
||||
uint32_t timestamp_turnedOff = 0;
|
||||
fan_config_t config;
|
||||
controlledMotor * motor1;
|
||||
controlledMotor * motor2;
|
||||
|
||||
motorCommand_t motor1Status;
|
||||
motorCommand_t motor2Status;
|
||||
};
|
||||
@@ -11,7 +11,7 @@ extern "C"
|
||||
}
|
||||
|
||||
#include <cmath>
|
||||
#include "motorctl.hpp" //for declaration of motorCommands_t struct
|
||||
#include "types.hpp"
|
||||
|
||||
|
||||
//======================================
|
||||
|
||||
@@ -1,330 +0,0 @@
|
||||
#include "motorctl.hpp"
|
||||
|
||||
//tag for logging
|
||||
static const char * TAG = "motor-control";
|
||||
|
||||
|
||||
//=============================
|
||||
//======== constructor ========
|
||||
//=============================
|
||||
//constructor, simultaniously initialize instance of motor driver 'motor' and current sensor 'cSensor' with provided config (see below lines after ':')
|
||||
controlledMotor::controlledMotor(single100a_config_t config_driver, motorctl_config_t config_control):
|
||||
motor(config_driver),
|
||||
cSensor(config_control.currentSensor_adc, config_control.currentSensor_ratedCurrent) {
|
||||
//copy parameters for controlling the motor
|
||||
config = config_control;
|
||||
//copy configured default fading durations to actually used variables
|
||||
msFadeAccel = config.msFadeAccel;
|
||||
msFadeDecel = config.msFadeDecel;
|
||||
|
||||
init();
|
||||
//TODO: add currentsensor object here
|
||||
//currentSensor cSensor(config.currentSensor_adc, config.currentSensor_ratedCurrent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================
|
||||
//========== init ============
|
||||
//============================
|
||||
void controlledMotor::init(){
|
||||
commandQueue = xQueueCreate( 1, sizeof( struct motorCommand_t ) );
|
||||
//cSensor.calibrateZeroAmpere(); //currently done in currentsensor constructor TODO do this regularly e.g. in idle?
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------
|
||||
//----- fade -----
|
||||
//----------------
|
||||
//local function that fades a variable
|
||||
//- increments a variable (pointer) by given value
|
||||
//- sets to target if already closer than increment
|
||||
//TODO this needs testing
|
||||
void fade(float * dutyNow, float dutyTarget, float dutyIncrement){
|
||||
float dutyDelta = dutyTarget - *dutyNow;
|
||||
if ( fabs(dutyDelta) > fabs(dutyIncrement) ) { //check if already close to target
|
||||
*dutyNow = *dutyNow + dutyIncrement;
|
||||
}
|
||||
//already closer to target than increment
|
||||
else {
|
||||
*dutyNow = dutyTarget;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------
|
||||
//----- getStateFromDuty -----
|
||||
//----------------------------
|
||||
//local function that determines motor the direction from duty range -100 to 100
|
||||
motorstate_t getStateFromDuty(float duty){
|
||||
if(duty > 0) return motorstate_t::FWD;
|
||||
if (duty < 0) return motorstate_t::REV;
|
||||
return motorstate_t::IDLE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============================
|
||||
//=========== handle ===========
|
||||
//==============================
|
||||
//function that controls the motor driver and handles fading/ramp, current limit and deadtime
|
||||
void controlledMotor::handle(){
|
||||
|
||||
//TODO: History: skip fading when motor was running fast recently / alternatively add rot-speed sensor
|
||||
|
||||
//--- receive commands from queue ---
|
||||
if( xQueueReceive( commandQueue, &commandReceive, ( TickType_t ) 0 ) )
|
||||
{
|
||||
ESP_LOGD(TAG, "Read command from queue: state=%s, duty=%.2f", motorstateStr[(int)commandReceive.state], commandReceive.duty);
|
||||
state = commandReceive.state;
|
||||
dutyTarget = commandReceive.duty;
|
||||
|
||||
//--- convert duty ---
|
||||
//define target duty (-100 to 100) from provided duty and motorstate
|
||||
//this value is more suitable for the fading algorithm
|
||||
switch(commandReceive.state){
|
||||
case motorstate_t::BRAKE:
|
||||
//update state
|
||||
state = motorstate_t::BRAKE;
|
||||
dutyTarget = 0;
|
||||
break;
|
||||
case motorstate_t::IDLE:
|
||||
dutyTarget = 0;
|
||||
break;
|
||||
case motorstate_t::FWD:
|
||||
dutyTarget = fabs(commandReceive.duty);
|
||||
break;
|
||||
case motorstate_t::REV:
|
||||
dutyTarget = - fabs(commandReceive.duty);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--- calculate increment ---
|
||||
//calculate increment for fading UP with passed time since last run and configured fade time
|
||||
int64_t usPassed = esp_timer_get_time() - timestampLastRunUs;
|
||||
if (msFadeAccel > 0){
|
||||
dutyIncrementAccel = ( usPassed / ((float)msFadeAccel * 1000) ) * 100; //TODO define maximum increment - first run after startup (or long) pause can cause a very large increment
|
||||
} else {
|
||||
dutyIncrementAccel = 100;
|
||||
}
|
||||
|
||||
//calculate increment for fading DOWN with passed time since last run and configured fade time
|
||||
if (msFadeDecel > 0){
|
||||
dutyIncrementDecel = ( usPassed / ((float)msFadeDecel * 1000) ) * 100;
|
||||
} else {
|
||||
dutyIncrementDecel = 100;
|
||||
}
|
||||
|
||||
|
||||
//--- BRAKE ---
|
||||
//brake immediately, update state, duty and exit this cycle of handle function
|
||||
if (state == motorstate_t::BRAKE){
|
||||
motor.set(motorstate_t::BRAKE, 0);
|
||||
dutyNow = 0;
|
||||
return; //no need to run the fade algorithm
|
||||
}
|
||||
|
||||
|
||||
//--- calculate difference ---
|
||||
dutyDelta = dutyTarget - dutyNow;
|
||||
//positive: need to increase by that value
|
||||
//negative: need to decrease
|
||||
|
||||
|
||||
//----- FADING -----
|
||||
//fade duty to target (up and down)
|
||||
//TODO: this needs optimization (can be more clear and/or simpler)
|
||||
if (dutyDelta > 0) { //difference positive -> increasing duty (-100 -> 100)
|
||||
if (dutyNow < 0) { //reverse, decelerating
|
||||
fade(&dutyNow, dutyTarget, dutyIncrementDecel);
|
||||
}
|
||||
else if (dutyNow >= 0) { //forward, accelerating
|
||||
fade(&dutyNow, dutyTarget, dutyIncrementAccel);
|
||||
}
|
||||
}
|
||||
else if (dutyDelta < 0) { //difference negative -> decreasing duty (100 -> -100)
|
||||
if (dutyNow <= 0) { //reverse, accelerating
|
||||
fade(&dutyNow, dutyTarget, - dutyIncrementAccel);
|
||||
}
|
||||
else if (dutyNow > 0) { //forward, decelerating
|
||||
fade(&dutyNow, dutyTarget, - dutyIncrementDecel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----- CURRENT LIMIT -----
|
||||
if ((config.currentLimitEnabled) && (dutyDelta != 0)){
|
||||
currentNow = cSensor.read();
|
||||
if (fabs(currentNow) > config.currentMax){
|
||||
float dutyOld = dutyNow;
|
||||
//adaptive decrement:
|
||||
//Note current exceeded twice -> twice as much decrement: TODO: decrement calc needs finetuning, currently random values
|
||||
dutyIncrementDecel = (currentNow/config.currentMax) * ( usPassed / ((float)msFadeDecel * 1500) ) * 100;
|
||||
float currentLimitDecrement = ( (float)usPassed / ((float)1000 * 1000) ) * 100; //1000ms from 100 to 0
|
||||
if (dutyNow < -currentLimitDecrement) {
|
||||
dutyNow += currentLimitDecrement;
|
||||
} else if (dutyNow > currentLimitDecrement) {
|
||||
dutyNow -= currentLimitDecrement;
|
||||
}
|
||||
ESP_LOGW(TAG, "current limit exceeded! now=%.3fA max=%.1fA => decreased duty from %.3f to %.3f", currentNow, config.currentMax, dutyOld, dutyNow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--- define new motorstate --- (-100 to 100 => direction)
|
||||
state=getStateFromDuty(dutyNow);
|
||||
|
||||
|
||||
//--- DEAD TIME ----
|
||||
//ensure minimum idle time between direction change to prevent driver overload
|
||||
//FWD -> IDLE -> FWD continue without waiting
|
||||
//FWD -> IDLE -> REV wait for dead-time in IDLE
|
||||
//TODO check when changed only?
|
||||
if ( //not enough time between last direction state
|
||||
( state == motorstate_t::FWD && (esp_log_timestamp() - timestampsModeLastActive[(int)motorstate_t::REV] < config.deadTimeMs))
|
||||
|| (state == motorstate_t::REV && (esp_log_timestamp() - timestampsModeLastActive[(int)motorstate_t::FWD] < config.deadTimeMs))
|
||||
){
|
||||
ESP_LOGD(TAG, "waiting dead-time... dir change %s -> %s", motorstateStr[(int)statePrev], motorstateStr[(int)state]);
|
||||
if (!deadTimeWaiting){ //log start
|
||||
deadTimeWaiting = true;
|
||||
ESP_LOGW(TAG, "starting dead-time... %s -> %s", motorstateStr[(int)statePrev], motorstateStr[(int)state]);
|
||||
}
|
||||
//force IDLE state during wait
|
||||
state = motorstate_t::IDLE;
|
||||
dutyNow = 0;
|
||||
} else {
|
||||
if (deadTimeWaiting){ //log end
|
||||
deadTimeWaiting = false;
|
||||
ESP_LOGW(TAG, "dead-time ended - continue with %s", motorstateStr[(int)state]);
|
||||
}
|
||||
ESP_LOGV(TAG, "deadtime: no change below deadtime detected... dir=%s, duty=%.1f", motorstateStr[(int)state], dutyNow);
|
||||
}
|
||||
|
||||
|
||||
//--- save current actual motorstate and timestamp ---
|
||||
//needed for deadtime
|
||||
timestampsModeLastActive[(int)getStateFromDuty(dutyNow)] = esp_log_timestamp();
|
||||
//(-100 to 100 => direction)
|
||||
statePrev = getStateFromDuty(dutyNow);
|
||||
|
||||
|
||||
//--- apply new target to motor ---
|
||||
motor.set(state, fabs(dutyNow));
|
||||
//note: BRAKE state is handled earlier
|
||||
|
||||
|
||||
//--- update timestamp ---
|
||||
timestampLastRunUs = esp_timer_get_time(); //update timestamp last run with current timestamp in microseconds
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===============================
|
||||
//========== setTarget ==========
|
||||
//===============================
|
||||
//function to set the target mode and duty of a motor
|
||||
//puts the provided command in a queue for the handle function running in another task
|
||||
void controlledMotor::setTarget(motorstate_t state_f, float duty_f){
|
||||
commandSend = {
|
||||
.state = state_f,
|
||||
.duty = duty_f
|
||||
};
|
||||
|
||||
ESP_LOGD(TAG, "Inserted command to queue: state=%s, duty=%.2f", motorstateStr[(int)commandSend.state], commandSend.duty);
|
||||
//send command to queue (overwrite if an old command is still in the queue and not processed)
|
||||
xQueueOverwrite( commandQueue, ( void * )&commandSend);
|
||||
//xQueueSend( commandQueue, ( void * )&commandSend, ( TickType_t ) 0 );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===============================
|
||||
//========== getStatus ==========
|
||||
//===============================
|
||||
//function which returns the current status of the motor in a motorCommand_t struct
|
||||
motorCommand_t controlledMotor::getStatus(){
|
||||
motorCommand_t status = {
|
||||
.state = state,
|
||||
.duty = dutyNow
|
||||
};
|
||||
//TODO: mutex
|
||||
return status;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//===============================
|
||||
//=========== setFade ===========
|
||||
//===============================
|
||||
//function for editing or enabling the fading/ramp of the motor control
|
||||
|
||||
//set/update fading duration/amount
|
||||
void controlledMotor::setFade(fadeType_t fadeType, uint32_t msFadeNew){
|
||||
//TODO: mutex for msFade variable also used in handle function
|
||||
switch(fadeType){
|
||||
case fadeType_t::ACCEL:
|
||||
msFadeAccel = msFadeNew;
|
||||
break;
|
||||
case fadeType_t::DECEL:
|
||||
msFadeDecel = msFadeNew;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//enable (set to default value) or disable fading
|
||||
void controlledMotor::setFade(fadeType_t fadeType, bool enabled){
|
||||
uint32_t msFadeNew = 0; //define new fade time as default disabled
|
||||
if(enabled){ //enable
|
||||
//set to default/configured value
|
||||
switch(fadeType){
|
||||
case fadeType_t::ACCEL:
|
||||
msFadeNew = config.msFadeAccel;
|
||||
break;
|
||||
case fadeType_t::DECEL:
|
||||
msFadeNew = config.msFadeDecel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//apply new Fade value
|
||||
setFade(fadeType, msFadeNew);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================================
|
||||
//=========== toggleFade ===========
|
||||
//==================================
|
||||
//toggle fading between OFF and default value
|
||||
bool controlledMotor::toggleFade(fadeType_t fadeType){
|
||||
uint32_t msFadeNew = 0;
|
||||
bool enabled = false;
|
||||
switch(fadeType){
|
||||
case fadeType_t::ACCEL:
|
||||
if (msFadeAccel == 0){
|
||||
msFadeNew = config.msFadeAccel;
|
||||
enabled = true;
|
||||
} else {
|
||||
msFadeNew = 0;
|
||||
}
|
||||
break;
|
||||
case fadeType_t::DECEL:
|
||||
if (msFadeDecel == 0){
|
||||
msFadeNew = config.msFadeAccel;
|
||||
enabled = true;
|
||||
} else {
|
||||
msFadeNew = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//apply new Fade value
|
||||
setFade(fadeType, msFadeNew);
|
||||
|
||||
//return new state (fading enabled/disabled)
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
}
|
||||
|
||||
#include "motordrivers.hpp"
|
||||
#include "currentsensor.hpp"
|
||||
|
||||
|
||||
//=======================================
|
||||
//====== struct/type declarations ======
|
||||
//=======================================
|
||||
|
||||
//struct for sending command for one motor in the queue
|
||||
struct motorCommand_t {
|
||||
motorstate_t state;
|
||||
float duty;
|
||||
};
|
||||
|
||||
//struct containing commands for two motors
|
||||
typedef struct motorCommands_t {
|
||||
motorCommand_t left;
|
||||
motorCommand_t right;
|
||||
} motorCommands_t;
|
||||
|
||||
//struct with all config parameters for a motor regarding ramp and current limit
|
||||
typedef struct motorctl_config_t {
|
||||
uint32_t msFadeAccel; //acceleration of the motor (ms it takes from 0% to 100%)
|
||||
uint32_t msFadeDecel; //deceleration of the motor (ms it takes from 100% to 0%)
|
||||
bool currentLimitEnabled;
|
||||
adc1_channel_t currentSensor_adc;
|
||||
float currentSensor_ratedCurrent;
|
||||
float currentMax;
|
||||
uint32_t deadTimeMs; //time motor stays in IDLE before direction change
|
||||
} motorctl_config_t;
|
||||
|
||||
//enum fade type (acceleration, deceleration)
|
||||
//e.g. used for specifying which fading should be modified with setFade, togleFade functions
|
||||
enum class fadeType_t {ACCEL, DECEL};
|
||||
|
||||
|
||||
|
||||
//===================================
|
||||
//====== controlledMotor class ======
|
||||
//===================================
|
||||
class controlledMotor {
|
||||
public:
|
||||
//--- functions ---
|
||||
controlledMotor(single100a_config_t config_driver, motorctl_config_t config_control); //constructor with structs for configuring motordriver and parameters for control TODO: add configuration for currentsensor
|
||||
void handle(); //controls motor duty with fade and current limiting feature (has to be run frequently by another task)
|
||||
void setTarget(motorstate_t state_f, float duty_f = 0); //adds target command to queue for handle function
|
||||
motorCommand_t getStatus(); //get current status of the motor (returns struct with state and duty)
|
||||
|
||||
void setFade(fadeType_t fadeType, bool enabled); //enable/disable acceleration or deceleration fading
|
||||
void setFade(fadeType_t fadeType, uint32_t msFadeNew); //set acceleration or deceleration fade time
|
||||
bool toggleFade(fadeType_t fadeType); //toggle acceleration or deceleration on/off
|
||||
|
||||
//TODO set current limit method
|
||||
|
||||
private:
|
||||
//--- functions ---
|
||||
void init(); //creates currentsensor objects, motordriver objects and queue
|
||||
|
||||
//--- objects ---
|
||||
//motor driver
|
||||
single100a motor;
|
||||
//queue for sending commands to the separate task running the handle() function very fast
|
||||
QueueHandle_t commandQueue = NULL;
|
||||
//current sensor
|
||||
currentSensor cSensor;
|
||||
|
||||
//--- variables ---
|
||||
//struct for storing control specific parameters
|
||||
motorctl_config_t config;
|
||||
motorstate_t state = motorstate_t::IDLE;
|
||||
|
||||
float currentMax;
|
||||
float currentNow;
|
||||
|
||||
float dutyTarget;
|
||||
float dutyNow;
|
||||
float dutyIncrementAccel;
|
||||
float dutyIncrementDecel;
|
||||
float dutyDelta;
|
||||
|
||||
uint32_t msFadeAccel;
|
||||
uint32_t msFadeDecel;
|
||||
|
||||
uint32_t ramp;
|
||||
int64_t timestampLastRunUs;
|
||||
|
||||
bool deadTimeWaiting = false;
|
||||
uint32_t timestampsModeLastActive[4] = {};
|
||||
motorstate_t statePrev = motorstate_t::FWD;
|
||||
|
||||
struct motorCommand_t commandReceive = {};
|
||||
struct motorCommand_t commandSend = {};
|
||||
};
|
||||
@@ -1,129 +0,0 @@
|
||||
#include "motordrivers.hpp"
|
||||
|
||||
//TODO: move from ledc to mcpwm?
|
||||
//https://docs.espressif.com/projects/esp-idf/en/v4.3/esp32/api-reference/peripherals/mcpwm.html#
|
||||
//https://github.com/espressif/esp-idf/tree/v4.3/examples/peripherals/mcpwm/mcpwm_basic_config
|
||||
|
||||
//Note fade functionality provided by LEDC would be very useful but unfortunately is not usable here because:
|
||||
//"Due to hardware limitations, there is no way to stop a fade before it reaches its target duty."
|
||||
|
||||
//definition of string array to be able to convert state enum to readable string
|
||||
const char* motorstateStr[4] = {"IDLE", "FWD", "REV", "BRAKE"};
|
||||
|
||||
//tag for logging
|
||||
static const char * TAG = "motordriver";
|
||||
|
||||
|
||||
|
||||
//====================================
|
||||
//===== single100a motor driver ======
|
||||
//====================================
|
||||
|
||||
//-----------------------------
|
||||
//-------- constructor --------
|
||||
//-----------------------------
|
||||
//copy provided struct with all configuration and run init function
|
||||
single100a::single100a(single100a_config_t config_f){
|
||||
config = config_f;
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------
|
||||
//---------- init ------------
|
||||
//----------------------------
|
||||
//function to initialize pwm output, gpio pins and calculate maxDuty
|
||||
void single100a::init(){
|
||||
|
||||
//--- configure ledc timer ---
|
||||
ledc_timer_config_t ledc_timer;
|
||||
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
ledc_timer.timer_num = config.ledc_timer;
|
||||
ledc_timer.duty_resolution = config.resolution; //13bit gives max 5khz freq
|
||||
ledc_timer.freq_hz = config.pwmFreq;
|
||||
ledc_timer.clk_cfg = LEDC_AUTO_CLK;
|
||||
//apply configuration
|
||||
ledc_timer_config(&ledc_timer);
|
||||
|
||||
//--- configure ledc channel ---
|
||||
ledc_channel_config_t ledc_channel;
|
||||
ledc_channel.channel = config.ledc_channel;
|
||||
ledc_channel.duty = 0;
|
||||
ledc_channel.gpio_num = config.gpio_pwm;
|
||||
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
ledc_channel.hpoint = 0;
|
||||
ledc_channel.timer_sel = config.ledc_timer;
|
||||
ledc_channel.intr_type = LEDC_INTR_DISABLE;
|
||||
ledc_channel.flags.output_invert = 0; //TODO: add config option to invert the pwm output?
|
||||
//apply configuration
|
||||
ledc_channel_config(&ledc_channel);
|
||||
|
||||
//--- define gpio pins as outputs ---
|
||||
gpio_pad_select_gpio(config.gpio_a);
|
||||
gpio_set_direction(config.gpio_a, GPIO_MODE_OUTPUT);
|
||||
gpio_pad_select_gpio(config.gpio_b);
|
||||
gpio_set_direction(config.gpio_b, GPIO_MODE_OUTPUT);
|
||||
|
||||
//--- calculate max duty according to selected resolution ---
|
||||
dutyMax = pow(2, ledc_timer.duty_resolution) -1;
|
||||
ESP_LOGI(TAG, "initialized single100a driver");
|
||||
ESP_LOGI(TAG, "resolution=%dbit, dutyMax value=%d, resolution=%.4f %%", ledc_timer.duty_resolution, dutyMax, 100/(float)dutyMax);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------
|
||||
//----------- set -----------
|
||||
//---------------------------
|
||||
//function to put the h-bridge module in the desired state and duty cycle
|
||||
void single100a::set(motorstate_t state_f, float duty_f){
|
||||
|
||||
//scale provided target duty in percent to available resolution for ledc
|
||||
uint32_t dutyScaled;
|
||||
if (duty_f > 100) { //target duty above 100%
|
||||
dutyScaled = dutyMax;
|
||||
} else if (duty_f <= 0) { //target at or below 0%
|
||||
state_f = motorstate_t::IDLE;
|
||||
dutyScaled = 0;
|
||||
} else { //target duty 0-100%
|
||||
//scale duty to available resolution
|
||||
dutyScaled = duty_f / 100 * dutyMax;
|
||||
}
|
||||
|
||||
//put the single100a h-bridge module in the desired state update duty-cycle
|
||||
switch (state_f){
|
||||
case motorstate_t::IDLE:
|
||||
ledc_set_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel, dutyScaled);
|
||||
ledc_update_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel);
|
||||
//TODO: to fix bugged state of h-bridge module when idle and start again, maybe try to leave pwm signal on for some time before updating a/b pins?
|
||||
//no brake: (freewheel)
|
||||
//gpio_set_level(config.gpio_a, config.aEnabledPinState);
|
||||
//gpio_set_level(config.gpio_b, !config.bEnabledPinState);
|
||||
gpio_set_level(config.gpio_a, config.aEnabledPinState);
|
||||
gpio_set_level(config.gpio_b, config.bEnabledPinState);
|
||||
break;
|
||||
case motorstate_t::BRAKE:
|
||||
ledc_set_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel, 0);
|
||||
ledc_update_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel);
|
||||
//brake:
|
||||
gpio_set_level(config.gpio_a, !config.aEnabledPinState);
|
||||
gpio_set_level(config.gpio_b, !config.bEnabledPinState);
|
||||
break;
|
||||
case motorstate_t::FWD:
|
||||
ledc_set_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel, dutyScaled);
|
||||
ledc_update_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel);
|
||||
//forward:
|
||||
gpio_set_level(config.gpio_a, config.aEnabledPinState);
|
||||
gpio_set_level(config.gpio_b, !config.bEnabledPinState);
|
||||
break;
|
||||
case motorstate_t::REV:
|
||||
ledc_set_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel, dutyScaled);
|
||||
ledc_update_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel);
|
||||
//reverse:
|
||||
gpio_set_level(config.gpio_a, !config.aEnabledPinState);
|
||||
gpio_set_level(config.gpio_b, config.bEnabledPinState);
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "set module to state=%s, duty=%d/%d, duty_input=%.3f%%", motorstateStr[(int)state_f], dutyScaled, dutyMax, duty_f);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
}
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
//====================================
|
||||
//===== single100a motor driver ======
|
||||
//====================================
|
||||
|
||||
//--------------------------------------------
|
||||
//---- struct, enum, variable declarations ---
|
||||
//--------------------------------------------
|
||||
|
||||
//class which controls a motor using a 'single100a' h-bridge module
|
||||
enum class motorstate_t {IDLE, FWD, REV, BRAKE};
|
||||
//definition of string array to be able to convert state enum to readable string (defined in motordrivers.cpp)
|
||||
extern const char* motorstateStr[4];
|
||||
|
||||
//struct with all config parameters for single100a motor driver
|
||||
typedef struct single100a_config_t {
|
||||
gpio_num_t gpio_pwm;
|
||||
gpio_num_t gpio_a;
|
||||
gpio_num_t gpio_b;
|
||||
ledc_timer_t ledc_timer;
|
||||
ledc_channel_t ledc_channel;
|
||||
bool aEnabledPinState;
|
||||
bool bEnabledPinState;
|
||||
ledc_timer_bit_t resolution;
|
||||
int pwmFreq;
|
||||
} single100a_config_t;
|
||||
|
||||
|
||||
|
||||
//--------------------------------
|
||||
//------- single100a class -------
|
||||
//--------------------------------
|
||||
class single100a {
|
||||
public:
|
||||
//--- constructor ---
|
||||
single100a(single100a_config_t config_f); //provide config struct (see above)
|
||||
|
||||
//--- functions ---
|
||||
void set(motorstate_t state, float duty_f = 0); //set mode and duty of the motor (see motorstate_t above)
|
||||
//TODO: add functions to get the current state and duty
|
||||
|
||||
private:
|
||||
//--- functions ---
|
||||
void init(); //initialize pwm and gpio outputs, calculate maxDuty
|
||||
|
||||
//--- variables ---
|
||||
single100a_config_t config;
|
||||
uint32_t dutyMax;
|
||||
motorstate_t state = motorstate_t::IDLE;
|
||||
};
|
||||
@@ -20,23 +20,6 @@ extern "C"
|
||||
static const char * TAG = "uart";
|
||||
|
||||
|
||||
void uart_init(void){
|
||||
uart_config_t uart1_config = {
|
||||
.baud_rate = 115198,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_EVEN,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
};
|
||||
ESP_LOGW(TAG, "config...");
|
||||
ESP_ERROR_CHECK(uart_param_config(UART_NUM_1, &uart1_config));
|
||||
ESP_LOGW(TAG, "setpins...");
|
||||
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_1, 23, 22, 0, 0));
|
||||
ESP_LOGW(TAG, "init...");
|
||||
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_1, 1024, 1024, 10, NULL, 0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void uart_task_testing(void *arg){
|
||||
//repeatedly send 8 bit count and log received 1 byte
|
||||
@@ -100,11 +83,6 @@ void task_uartReceiveQueue(void *arg){
|
||||
// }
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t timestamp;
|
||||
int id;
|
||||
float value;
|
||||
} uartDataStruct;
|
||||
|
||||
//send struct
|
||||
void task_uartSend(void *arg){
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "uart_common.hpp"
|
||||
|
||||
void uart_init(void);
|
||||
void uart_task_testing(void *arg);
|
||||
void task_uartReceive(void *arg);
|
||||
void task_uartSend(void *arg);
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t timestamp;
|
||||
int id;
|
||||
float value;
|
||||
} uartDataStruct;
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_mac.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "wifi.h"
|
||||
|
||||
|
||||
|
||||
//--- variables used for ap and wifi ---
|
||||
static const char *TAG = "wifi";
|
||||
static esp_event_handler_instance_t instance_any_id;
|
||||
|
||||
|
||||
//============================================
|
||||
//============ init nvs and netif ============
|
||||
//============================================
|
||||
//initialize nvs-flash and netif (needed for both AP and CLIENT)
|
||||
//has to be run once at startup
|
||||
void wifi_initNvs_initNetif(){
|
||||
//Initialize NVS (needed for wifi)
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
}
|
||||
|
||||
|
||||
//===========================================
|
||||
//============ init access point ============
|
||||
//===========================================
|
||||
|
||||
//--------------------------------------------
|
||||
//------ configuration / declarations --------
|
||||
//--------------------------------------------
|
||||
#define EXAMPLE_ESP_WIFI_SSID_AP "armchair"
|
||||
#define EXAMPLE_ESP_WIFI_PASS_AP ""
|
||||
#define EXAMPLE_ESP_WIFI_CHANNEL_AP 1
|
||||
#define EXAMPLE_MAX_STA_CONN_AP 4
|
||||
|
||||
static esp_netif_t *ap;
|
||||
|
||||
static void wifi_event_handler_ap(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
|
||||
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
|
||||
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
|
||||
MAC2STR(event->mac), event->aid);
|
||||
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
|
||||
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
|
||||
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
|
||||
MAC2STR(event->mac), event->aid);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
//------ init ap --------
|
||||
//-----------------------
|
||||
void wifi_init_ap(void)
|
||||
{
|
||||
ap = esp_netif_create_default_wifi_ap();
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
&wifi_event_handler_ap,
|
||||
NULL,
|
||||
&instance_any_id));
|
||||
|
||||
wifi_config_t wifi_config = {
|
||||
.ap = {
|
||||
.ssid = EXAMPLE_ESP_WIFI_SSID_AP,
|
||||
.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID_AP),
|
||||
.channel = EXAMPLE_ESP_WIFI_CHANNEL_AP,
|
||||
.password = EXAMPLE_ESP_WIFI_PASS_AP,
|
||||
.max_connection = EXAMPLE_MAX_STA_CONN_AP,
|
||||
.authmode = WIFI_AUTH_WPA_WPA2_PSK
|
||||
},
|
||||
};
|
||||
if (strlen(EXAMPLE_ESP_WIFI_PASS_AP) == 0) {
|
||||
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
|
||||
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
|
||||
EXAMPLE_ESP_WIFI_SSID_AP, EXAMPLE_ESP_WIFI_PASS_AP, EXAMPLE_ESP_WIFI_CHANNEL_AP);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================
|
||||
//========= deinit AP =========
|
||||
//=============================
|
||||
void wifi_deinit_ap(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
||||
esp_wifi_stop();
|
||||
esp_wifi_deinit();
|
||||
esp_netif_destroy_default_wifi(ap);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===========================================
|
||||
//=============== init client ===============
|
||||
//===========================================
|
||||
|
||||
//--------------------------------------------
|
||||
//------ configuration / declarations --------
|
||||
//--------------------------------------------
|
||||
#define EXAMPLE_ESP_WIFI_SSID_CLIENT "BKA-network"
|
||||
#define EXAMPLE_ESP_WIFI_PASS_CLIENT "airwaveslogitech410"
|
||||
#define EXAMPLE_ESP_MAXIMUM_RETRY_CLIENT 10
|
||||
|
||||
static esp_netif_t *sta;
|
||||
static esp_event_handler_instance_t instance_got_ip;
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected*/
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event, but we only care about two events:
|
||||
* - we are connected to the AP with an IP
|
||||
* - we failed to connect after the maximum amount of retries */
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
static int s_retry_num = 0;
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY_CLIENT) {
|
||||
esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
ESP_LOGI(TAG, "retry to connect to the AP");
|
||||
} else {
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||||
}
|
||||
ESP_LOGI(TAG,"connect to the AP fail");
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num = 0;
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
//---------------------------
|
||||
//------ init client --------
|
||||
//---------------------------
|
||||
void wifi_init_client(void)
|
||||
{
|
||||
s_wifi_event_group = xEventGroupCreate();
|
||||
sta = esp_netif_create_default_wifi_sta();
|
||||
|
||||
|
||||
|
||||
//set static ip
|
||||
esp_netif_dhcpc_stop(sta);
|
||||
|
||||
esp_netif_ip_info_t ip_info;
|
||||
IP4_ADDR(&ip_info.ip, 10, 0, 0, 66);
|
||||
IP4_ADDR(&ip_info.gw, 10, 0, 0, 1);
|
||||
IP4_ADDR(&ip_info.netmask, 255, 255, 0, 0);
|
||||
|
||||
esp_netif_set_ip_info(sta, &ip_info);
|
||||
|
||||
|
||||
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
&event_handler,
|
||||
NULL,
|
||||
&instance_any_id));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
|
||||
IP_EVENT_STA_GOT_IP,
|
||||
&event_handler,
|
||||
NULL,
|
||||
&instance_got_ip));
|
||||
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = EXAMPLE_ESP_WIFI_SSID_CLIENT,
|
||||
.password = EXAMPLE_ESP_WIFI_PASS_CLIENT,
|
||||
/* Setting a password implies station will connect to all security modes including WEP/WPA.
|
||||
* However these modes are deprecated and not advisable to be used. Incase your Access point
|
||||
* doesn't support WPA2, these mode can be enabled by commenting below line */
|
||||
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
|
||||
ESP_ERROR_CHECK(esp_wifi_start() );
|
||||
|
||||
ESP_LOGI(TAG, "wifi_init_sta finished.");
|
||||
|
||||
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
|
||||
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
||||
pdFALSE,
|
||||
pdFALSE,
|
||||
portMAX_DELAY);
|
||||
|
||||
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
|
||||
* happened. */
|
||||
if (bits & WIFI_CONNECTED_BIT) {
|
||||
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
|
||||
EXAMPLE_ESP_WIFI_SSID_CLIENT, EXAMPLE_ESP_WIFI_PASS_CLIENT);
|
||||
} else if (bits & WIFI_FAIL_BIT) {
|
||||
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
|
||||
EXAMPLE_ESP_WIFI_SSID_CLIENT, EXAMPLE_ESP_WIFI_PASS_CLIENT);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "UNEXPECTED EVENT");
|
||||
}
|
||||
|
||||
// /* The event will not be processed after unregister */
|
||||
// ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
|
||||
// ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
||||
// vEventGroupDelete(s_wifi_event_group);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================================
|
||||
//========= deinit client =========
|
||||
//=================================
|
||||
void wifi_deinit_client(void)
|
||||
{
|
||||
/* The event will not be processed after unregister */
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
||||
vEventGroupDelete(s_wifi_event_group);
|
||||
esp_wifi_stop();
|
||||
esp_wifi_deinit();
|
||||
esp_netif_destroy_default_wifi(sta);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//TODO: currently wifi names and passwords are configured in wifi.c -> move this to config?
|
||||
|
||||
//initialize nvs-flash and netif (needed for both AP and CLIENT)
|
||||
//has to be run once at startup
|
||||
//Note: this cant be put in wifi_init functions because this may not be in deinit functions
|
||||
void wifi_initNvs_initNetif();
|
||||
|
||||
|
||||
//function to start an access point
|
||||
void wifi_init_ap(void);
|
||||
//function to disable/deinit access point
|
||||
void wifi_deinit_ap(void);
|
||||
|
||||
//function to connect to existing wifi network
|
||||
void wifi_init_client(void);
|
||||
//function to disable/deinit client
|
||||
void wifi_deinit_client(void);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user