Since moving all objects to heap encoder started to lag interrupt not recognizing some single events in MENU fast executen of motordriver setTarget caused the lag, initialize it in STACK while still using a pointer now
407 lines
13 KiB
C++
407 lines
13 KiB
C++
extern "C"
|
|
{
|
|
#include <stdio.h>
|
|
#include <esp_system.h>
|
|
#include <esp_event.h>
|
|
#include <nvs_flash.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "driver/gpio.h"
|
|
#include "esp_log.h"
|
|
#include "sdkconfig.h"
|
|
#include "esp_spiffs.h"
|
|
|
|
//custom C files
|
|
#include "wifi.h"
|
|
}
|
|
|
|
//custom C++ files
|
|
//folder common
|
|
#include "uart_common.hpp"
|
|
#include "motordrivers.hpp"
|
|
#include "http.hpp"
|
|
#include "types.hpp"
|
|
#include "speedsensor.hpp"
|
|
#include "motorctl.hpp"
|
|
|
|
//folder single_board
|
|
#include "config.hpp"
|
|
#include "control.hpp"
|
|
#include "button.hpp"
|
|
#include "display.hpp"
|
|
#include "encoder.hpp"
|
|
|
|
#include <new>
|
|
|
|
//only extends this file (no library):
|
|
//outsourced all configuration related structures
|
|
#include "config.cpp"
|
|
|
|
|
|
|
|
//================================
|
|
//======== declarations ==========
|
|
//================================
|
|
//--- declare all pointers to shared objects ---
|
|
controlledMotor *motorLeft;
|
|
controlledMotor *motorRight;
|
|
|
|
sabertooth2x60a *sabertoothDriver;
|
|
|
|
evaluatedJoystick *joystick;
|
|
|
|
buzzer_t *buzzer;
|
|
|
|
controlledArmchair *control;
|
|
|
|
automatedArmchair_c *automatedArmchair;
|
|
|
|
httpJoystick *httpJoystickMain;
|
|
|
|
speedSensor *speedLeft;
|
|
speedSensor *speedRight;
|
|
|
|
cControlledRest *legRest;
|
|
cControlledRest *backRest;
|
|
|
|
|
|
//--- lambda functions motor-driver ---
|
|
// functions for updating the duty via currently used motor driver (hardware) that can then be passed to controlledMotor
|
|
//-> makes it possible to easily use different motor drivers
|
|
motorSetCommandFunc_t setLeftFunc = [&sabertoothDriver](motorCommand_t cmd)
|
|
{
|
|
sabertoothDriver->setLeft(cmd); //<= note: still using pointer to method in here (but stored in STACK)
|
|
};
|
|
motorSetCommandFunc_t setRightFunc = [&sabertoothDriver](motorCommand_t cmd)
|
|
{
|
|
sabertoothDriver->setRight(cmd); //<= note: still using pointer to method in here (but stored in STACK)
|
|
};
|
|
|
|
//--- lambda function http-joystick ---
|
|
// function that initializes the http server requires a function pointer to function that handels each url
|
|
// the httpd_uri config struct does not accept a pointer to a method of a class instance, directly
|
|
// thus this lambda function is necessary:
|
|
// declare pointer to receiveHttpData method of httpJoystick class
|
|
esp_err_t (httpJoystick::*pointerToReceiveFunc)(httpd_req_t *req) = &httpJoystick::receiveHttpData;
|
|
esp_err_t on_joystick_url(httpd_req_t *req)
|
|
{
|
|
// run pointer to receiveHttpData function of httpJoystickMain instance
|
|
return (httpJoystickMain->*pointerToReceiveFunc)(req);
|
|
}
|
|
|
|
//tag for logging
|
|
static const char * TAG = "main";
|
|
|
|
|
|
|
|
//======================================
|
|
//============ buzzer task =============
|
|
//======================================
|
|
//TODO: move the task creation to buzzer class (buzzer.cpp)
|
|
//e.g. only have function buzzer.createTask() in app_main
|
|
void task_buzzer( void * pvParameters ){
|
|
ESP_LOGI("task_buzzer", "Start of buzzer task...");
|
|
//run function that waits for a beep events to arrive in the queue
|
|
//and processes them
|
|
buzzer->processQueue();
|
|
}
|
|
|
|
|
|
|
|
//=======================================
|
|
//============== fan task ===============
|
|
//=======================================
|
|
//TODO: move this definition to fan.cpp
|
|
//task that controlls fans for cooling the drivers
|
|
void task_fans( void * pvParameters ){
|
|
ESP_LOGI(TAG, "Initializing fans and starting fan handle loop");
|
|
//create fan instances with config defined in config.cpp
|
|
controlledFan fan(configCooling, motorLeft, motorRight);
|
|
//repeatedly run fan handle function in a slow loop
|
|
while(1){
|
|
fan.handle();
|
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//=================================
|
|
//========== init spiffs ==========
|
|
//=================================
|
|
//initialize spi flash filesystem (used for webserver)
|
|
void init_spiffs(){
|
|
ESP_LOGI(TAG, "init spiffs");
|
|
esp_vfs_spiffs_conf_t esp_vfs_spiffs_conf = {
|
|
.base_path = "/spiffs",
|
|
.partition_label = NULL,
|
|
.max_files = 5,
|
|
.format_if_mount_failed = true};
|
|
esp_vfs_spiffs_register(&esp_vfs_spiffs_conf);
|
|
|
|
size_t total = 0;
|
|
size_t used = 0;
|
|
esp_spiffs_info(NULL, &total, &used);
|
|
|
|
ESP_LOGI(TAG, "SPIFFS: total %d, used %d", total, used);
|
|
esp_vfs_spiffs_unregister(NULL);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=================================
|
|
//========= createObjects =========
|
|
//=================================
|
|
//create all shared objects
|
|
//their references can be passed to the tasks that need access in main
|
|
|
|
//Note: the configuration structures (e.g. configMotorControlLeft) are outsourced to file 'config.cpp'
|
|
|
|
void createObjects()
|
|
{
|
|
// create sabertooth motor driver instance
|
|
// sabertooth2x60a sabertoothDriver(sabertoothConfig);
|
|
// with configuration above
|
|
//sabertoothDriver = new sabertooth2x60a(sabertoothConfig);
|
|
|
|
// create controlled motor instances (motorctl.hpp)
|
|
// with configurations above
|
|
motorLeft = new controlledMotor(setLeftFunc, configMotorControlLeft);
|
|
motorRight = new controlledMotor(setRightFunc, configMotorControlRight);
|
|
|
|
// create speedsensor instances
|
|
// with configurations above
|
|
speedLeft = new speedSensor(speedLeft_config);
|
|
speedRight = new speedSensor(speedRight_config);
|
|
|
|
// create joystic instance (joystick.hpp)
|
|
joystick = new evaluatedJoystick(configJoystick);
|
|
|
|
// create httpJoystick object (http.hpp)
|
|
httpJoystickMain = new httpJoystick(configHttpJoystickMain);
|
|
http_init_server(on_joystick_url);
|
|
|
|
// create buzzer object on pin 12 with gap between queued events of 100ms
|
|
buzzer = new buzzer_t(GPIO_NUM_12, 100);
|
|
|
|
// create control object (control.hpp)
|
|
// with configuration above
|
|
control = new controlledArmchair(configControl, buzzer, motorLeft, motorRight, joystick, httpJoystickMain, automatedArmchair, legRest, backRest);
|
|
|
|
// create automatedArmchair_c object (for auto-mode) (auto.hpp)
|
|
automatedArmchair = new automatedArmchair_c(motorLeft, motorRight);
|
|
|
|
// create objects for controlling the chair position
|
|
// gpio_up, gpio_down, name
|
|
legRest = new cControlledRest(GPIO_NUM_4, GPIO_NUM_16, "legRest");
|
|
backRest = new cControlledRest(GPIO_NUM_2, GPIO_NUM_15, "backRest");
|
|
}
|
|
//sabertooth2x60a sabertoothDriver(sabertoothConfig);
|
|
|
|
|
|
|
|
|
|
//=================================
|
|
//=========== app_main ============
|
|
//=================================
|
|
extern "C" void app_main(void) {
|
|
|
|
ESP_LOGW(TAG, "===== INITIAawdfLIZING COMPONENTS =====");
|
|
//--- define log levels ---
|
|
setLoglevels();
|
|
|
|
//--- enable 5V volate regulator ---
|
|
ESP_LOGW(TAG, "enabling 5V regulator...");
|
|
gpio_pad_select_gpio(GPIO_NUM_17);
|
|
gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);
|
|
gpio_set_level(GPIO_NUM_17, 1);
|
|
|
|
//--- initialize nvs-flash and netif (needed for wifi) ---
|
|
wifi_initNvs_initNetif();
|
|
|
|
//--- initialize spiffs ---
|
|
init_spiffs();
|
|
|
|
//--- initialize and start wifi ---
|
|
ESP_LOGD(TAG,"starting wifi...");
|
|
//wifi_init_client(); //connect to existing wifi
|
|
wifi_init_ap(); //start access point
|
|
ESP_LOGD(TAG,"done starting wifi");
|
|
|
|
//--- initialize encoder ---
|
|
const QueueHandle_t encoderQueue = encoder_init();
|
|
|
|
|
|
|
|
//--- create all objects ---
|
|
ESP_LOGW(TAG, "===== CREATING SHARED OBJECTS =====");
|
|
|
|
//initialize sabertooth object in STACK
|
|
sabertoothDriver = static_cast<sabertooth2x60a*>(alloca(sizeof(sabertooth2x60a)));
|
|
new (sabertoothDriver) sabertooth2x60a(sabertoothConfig);
|
|
|
|
//create all class instances used below in HEAP
|
|
createObjects();
|
|
|
|
|
|
|
|
#ifndef ENCODER_TEST
|
|
//--- create tasks ---
|
|
ESP_LOGW(TAG, "===== CREATING TASKS =====");
|
|
|
|
//----------------------------------------------
|
|
//--- create task for controlling the motors ---
|
|
//----------------------------------------------
|
|
//task that receives commands, handles ramp and current limit and executes commands using the motordriver function
|
|
task_motorctl_parameters_t motorctl_param = {motorLeft, motorRight};
|
|
xTaskCreate(&task_motorctl, "task_motor-control", 2*4096, &motorctl_param, 6, NULL);
|
|
|
|
//------------------------------
|
|
//--- create task for buzzer ---
|
|
//------------------------------
|
|
xTaskCreate(&task_buzzer, "task_buzzer", 2048, NULL, 2, NULL);
|
|
|
|
//-------------------------------
|
|
//--- create task for control ---
|
|
//-------------------------------
|
|
//task that generates motor commands depending on the current mode and sends those to motorctl task
|
|
//note: pointer to shared object 'control' is passed as task parameter:
|
|
xTaskCreate(&task_control, "task_control", 4096, control, 5, NULL);
|
|
|
|
//------------------------------
|
|
//--- create task for button ---
|
|
//------------------------------
|
|
//task that handles button/encoder events in any mode except 'MENU' (e.g. switch modes by pressing certain count)
|
|
task_button_parameters_t button_param = {control, joystick, encoderQueue, motorLeft, motorRight, buzzer};
|
|
xTaskCreate(&task_button, "task_button", 4096, &button_param, 4, NULL);
|
|
|
|
//-----------------------------------
|
|
//--- create task for fan control ---
|
|
//-----------------------------------
|
|
//task that controls cooling fans of the motor driver
|
|
xTaskCreate(&task_fans, "task_fans", 2048, NULL, 1, NULL);
|
|
|
|
//-----------------------------------
|
|
//----- create task for display -----
|
|
//-----------------------------------
|
|
////task that handles the display (show stats, handle menu in 'MENU' mode)
|
|
display_task_parameters_t display_param = {control, joystick, encoderQueue, motorLeft, motorRight, speedLeft, speedRight, buzzer};
|
|
xTaskCreate(&display_task, "display_task", 3*2048, &display_param, 1, NULL);
|
|
|
|
|
|
#endif
|
|
|
|
//--- startup finished ---
|
|
ESP_LOGW(TAG, "===== STARTUP FINISHED =====");
|
|
buzzer->beep(3, 70, 50);
|
|
|
|
//--- testing encoder ---
|
|
//xTaskCreate(&task_encoderExample, "task_buzzer", 2048, encoderQueue, 2, NULL);
|
|
|
|
//--- testing http server ---
|
|
// wifi_init_client(); //connect to existing wifi
|
|
// vTaskDelay(2000 / portTICK_PERIOD_MS);
|
|
// ESP_LOGI(TAG, "initializing http server");
|
|
// http_init_server();
|
|
|
|
|
|
//--- testing force specific mode after startup ---
|
|
//control->changeMode(controlMode_t::MENU);
|
|
|
|
|
|
|
|
//--- main loop ---
|
|
//does nothing except for testing things
|
|
while(1){
|
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
//---------------------------------
|
|
//-------- TESTING section --------
|
|
//---------------------------------
|
|
//test sabertooth driver
|
|
// motors.setLeft({motorstate_t::FWD, 70});
|
|
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
// motors.setLeft({motorstate_t::IDLE, 0});
|
|
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
// motors.setLeft({motorstate_t::REV, 50});
|
|
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
// motors.setLeft(-90);
|
|
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
// motors.setLeft(90);
|
|
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
// motors.setLeft(0);
|
|
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
|
|
//--- test controlledMotor --- (ramp)
|
|
// //brake for 1 s
|
|
//motorLeft.setTarget(motorstate_t::BRAKE);
|
|
//vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
//command 90% - reverse
|
|
//motorLeft.setTarget(motorstate_t::REV, 90);
|
|
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
//motorLeft.setTarget(motorstate_t::FWD, 80);
|
|
//vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
//motorLeft.setTarget(motorstate_t::IDLE, 90);
|
|
//vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
|
|
// //--- test functions at mode change HTTP ---
|
|
// control.changeMode(controlMode_t::HTTP);
|
|
// vTaskDelay(10000 / portTICK_PERIOD_MS);
|
|
// control.changeMode(controlMode_t::IDLE);
|
|
// vTaskDelay(10000 / portTICK_PERIOD_MS);
|
|
|
|
|
|
//--- test wifi functions ---
|
|
// ESP_LOGI(TAG, "creating AP");
|
|
// wifi_init_ap(); //start accesspoint
|
|
// vTaskDelay(15000 / portTICK_PERIOD_MS);
|
|
// ESP_LOGI(TAG, "stopping wifi");
|
|
// wifi_deinit_ap(); //stop wifi access point
|
|
// vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
// ESP_LOGI(TAG, "connecting to wifi");
|
|
// wifi_init_client(); //connect to existing wifi
|
|
// vTaskDelay(10000 / portTICK_PERIOD_MS);
|
|
// ESP_LOGI(TAG, "stopping wifi");
|
|
// wifi_deinit_client(); //stop wifi client
|
|
// vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
|
|
|
|
//--- test button ---
|
|
//buttonJoystick.handle();
|
|
// if (buttonJoystick.risingEdge){
|
|
// ESP_LOGI(TAG, "button pressed, was released for %d ms", buttonJoystick.msReleased);
|
|
// buzzer.beep(2, 100, 50);
|
|
|
|
// }else if (buttonJoystick.fallingEdge){
|
|
// ESP_LOGI(TAG, "button released, was pressed for %d ms", buttonJoystick.msPressed);
|
|
// buzzer.beep(1, 200, 0);
|
|
// }
|
|
|
|
|
|
//--- test joystick commands ---
|
|
// motorCommands_t commands = joystick_generateCommandsDriving(joystick);
|
|
// motorRight.setTarget(commands.right.state, commands.right.duty); //TODO make motorctl.setTarget also accept motorcommand struct directly
|
|
// motorLeft.setTarget(commands.left.state, commands.left.duty); //TODO make motorctl.setTarget also accept motorcommand struct directly
|
|
// //motorRight.setTarget(commands.right.state, commands.right.duty);
|
|
|
|
|
|
//--- test joystick class ---
|
|
//joystickData_t data = joystick.getData();
|
|
//ESP_LOGI(TAG, "position=%s, x=%.1f%%, y=%.1f%%, radius=%.1f%%, angle=%.2f",
|
|
// joystickPosStr[(int)data.position], data.x*100, data.y*100, data.radius*100, data.angle);
|
|
|
|
//--- test the motor driver ---
|
|
//fade up duty - forward
|
|
// for (int duty=0; duty<=100; duty+=5) {
|
|
// motorLeft.setTarget(motorstate_t::FWD, duty);
|
|
// vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
// }
|
|
|
|
|
|
}
|
|
|
|
}
|