Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
b235825f3This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com>
// Repository: https://github.com/okalachev/flix
// Implementation of command line interface
#include "pid.h"
#include "vector.h"
#include "util.h"
#include "lpf.h"
extern const int MOTOR_REAR_LEFT, MOTOR_REAR_RIGHT, MOTOR_FRONT_RIGHT, MOTOR_FRONT_LEFT;
extern const int RAW, ACRO, STAB, AUTO;
extern float t, dt, loopRate;
extern uint16_t channels[16];
extern float controlTime;
extern int mode;
extern bool armed;
extern LowPassFilter<Vector> gyroBiasFilter;
extern float voltage;
const char* motd =
"\nWelcome to\n"
" _______ __ __ ___ ___\n"
"| ____|| | | | \\ \\ / /\n"
"| |__ | | | | \\ V /\n"
"| __| | | | | > <\n"
"| | | `----.| | / . \\\n"
"|__| |_______||__| /__/ \\__\\\n\n"
"Commands:\n\n"
"help - show help\n"
"p - show all parameters\n"
"p <name> - show parameter\n"
"p <name> <value> - set parameter\n"
"preset - reset parameters\n"
"time - show time info\n"
"ps - show pitch/roll/yaw\n"
"psq - show attitude quaternion\n"
"imu - show IMU data\n"
"arm - arm the drone\n"
"disarm - disarm the drone\n"
"raw/stab/acro/auto - set mode\n"
"rc - show RC data\n"
"pw - show power info\n"
"wifi - show Wi-Fi info\n"
"ap <ssid> <password> - setup Wi-Fi access point\n"
"sta <ssid> <password> - setup Wi-Fi client mode\n"
"mot - show motor output\n"
"log [dump] - print log header [and data]\n"
"cr - calibrate RC\n"
"ca - calibrate accel\n"
"mfr, mfl, mrr, mrl - test motor (remove props)\n"
"sys - show system info\n"
"reset - reset drone's state\n"
"reboot - reboot the drone\n";
void print(const char* format, ...) {
char buf[1000];
va_list args;
va_start(args, format);
vsnprintf(buf, sizeof(buf), format, args);
va_end(args);
Serial.print(buf);
mavlinkPrint(buf);
}
void pause(float duration) {
float start = t;
while (t - start < duration) {
step();
handleInput();
processMavlink();
delay(50);
}
}
void doCommand(String str, bool echo = false) {
// parse command
String command, arg0, arg1;
splitString(str, command, arg0, arg1);
if (command.isEmpty()) return;
// echo command
if (echo) {
print("> %s\n", str.c_str());
}
command.toLowerCase();
// execute command
if (command == "help" || command == "motd") {
print("%s\n", motd);
} else if (command == "p" && arg0 == "") {
printParameters();
} else if (command == "p" && arg0 != "" && arg1 == "") {
print("%s = %g\n", arg0.c_str(), getParameter(arg0.c_str()));
} else if (command == "p") {
bool success = setParameter(arg0.c_str(), arg1.toFloat());
if (success) {
print("%s = %g\n", arg0.c_str(), getParameter(arg0.c_str()));
} else {
print("Parameter not found: %s\n", arg0.c_str());
}
} else if (command == "preset") {
resetParameters();
} else if (command == "time") {
print("Time: %f\n", t);
print("Loop rate: %.0f\n", loopRate);
print("dt: %f\n", dt);
} else if (command == "ps") {
Vector a = attitude.toEuler();
print("roll: %f pitch: %f yaw: %f\n", degrees(a.x), degrees(a.y), degrees(a.z));
} else if (command == "psq") {
print("qw: %f qx: %f qy: %f qz: %f\n", attitude.w, attitude.x, attitude.y, attitude.z);
} else if (command == "imu") {
printIMUInfo();
printIMUCalibration();
print("landed: %d\n", landed);
} else if (command == "arm") {
armed = true;
} else if (command == "disarm") {
armed = false;
} else if (command == "raw") {
mode = RAW;
} else if (command == "stab") {
mode = STAB;
} else if (command == "acro") {
mode = ACRO;
} else if (command == "auto") {
mode = AUTO;
} else if (command == "rc") {
print("channels: ");
for (int i = 0; i < 16; i++) {
print("%u ", channels[i]);
}
print("\nroll: %g pitch: %g yaw: %g throttle: %g mode: %g\n",
controlRoll, controlPitch, controlYaw, controlThrottle, controlMode);
print("time: %.1f\n", controlTime);
print("mode: %s\n", getModeName());
print("armed: %d\n", armed);
} else if (command == "pw") {
print("Voltage: %.1f V\n", voltage);
} else if (command == "wifi") {
printWiFiInfo();
} else if (command == "ap") {
configWiFi(true, arg0.c_str(), arg1.c_str());
} else if (command == "sta") {
configWiFi(false, arg0.c_str(), arg1.c_str());
} else if (command == "mot") {
print("front-right %g front-left %g rear-right %g rear-left %g\n",
motors[MOTOR_FRONT_RIGHT], motors[MOTOR_FRONT_LEFT], motors[MOTOR_REAR_RIGHT], motors[MOTOR_REAR_LEFT]);
} else if (command == "log") {
printLogHeader();
if (arg0 == "dump") printLogData();
} else if (command == "cr") {
calibrateRC();
} else if (command == "ca") {
calibrateAccel();
} else if (command == "mfr") {
testMotor(MOTOR_FRONT_RIGHT);
} else if (command == "mfl") {
testMotor(MOTOR_FRONT_LEFT);
} else if (command == "mrr") {
testMotor(MOTOR_REAR_RIGHT);
} else if (command == "mrl") {
testMotor(MOTOR_REAR_LEFT);
} else if (command == "sys") {
#ifdef ESP32
print("Chip: %s\n", ESP.getChipModel());
print("Temperature: %.1f °C\n", temperatureRead());
print("Free heap: %d\n", ESP.getFreeHeap());
// Print tasks table
print("Num Task Stack Prio Core CPU%%\n");
int taskCount = uxTaskGetNumberOfTasks();
TaskStatus_t *systemState = new TaskStatus_t[taskCount];
uint32_t totalRunTime;
uxTaskGetSystemState(systemState, taskCount, &totalRunTime);
for (int i = 0; i < taskCount; i++) {
String core = systemState[i].xCoreID == tskNO_AFFINITY ? "*" : String(systemState[i].xCoreID);
int cpuPercentage = systemState[i].ulRunTimeCounter / (totalRunTime / 100);
print("%-5d%-20s%-7d%-6d%-6s%d\n",systemState[i].xTaskNumber, systemState[i].pcTaskName,
systemState[i].usStackHighWaterMark, systemState[i].uxCurrentPriority, core, cpuPercentage);
}
delete[] systemState;
#endif
} else if (command == "reset") {
attitude = Quaternion();
gyroBiasFilter.reset();
} else if (command == "reboot") {
ESP.restart();
} else {
print("Invalid command: %s\n", command.c_str());
}
}
void handleInput() {
static bool showMotd = true;
static String input;
if (showMotd) {
print("%s\n", motd);
showMotd = false;
}
while (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
doCommand(input);
input.clear();
} else {
input += c;
}
}
}