Skip to content

Commit

Permalink
Refactor CLI submodule
Browse files Browse the repository at this point in the history
Move command parsing to doCommand
Parse command with splitString instead of stringToken
Trim commands
Move cliTestMotor to the bottom
Rename parseInput to handleInput, which is more clear
Move motor test function to motors.ino
Remove parameters table functionality to simplify the code
  • Loading branch information
okalachev committed Feb 28, 2025
1 parent 67e4a95 commit 6058e8e
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 86 deletions.
96 changes: 17 additions & 79 deletions flix/cli.ino
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ const char* motd =
"|__| |_______||__| /__/ \\__\\\n\n"
"Commands:\n\n"
"help - show help\n"
"show - show all parameters\n"
"<name> <value> - set parameter\n"
"ps - show pitch/roll/yaw\n"
"psq - show attitude quaternion\n"
"imu - show IMU data\n"
Expand All @@ -35,36 +33,14 @@ const char* motd =
"mfr, mfl, mrr, mrl - test motor (remove props)\n"
"reset - reset drone's state\n";

const struct Param {
const char* name;
float* value;
float* value2;
} params[] = {
{"rp", &rollRatePID.p, &pitchRatePID.p},
{"ri", &rollRatePID.i, &pitchRatePID.i},
{"rd", &rollRatePID.d, &pitchRatePID.d},
void doCommand(String str) {
// parse command
String command, arg0, arg1;
splitString(str, command, arg0, arg1);

{"ap", &rollPID.p, &pitchPID.p},
{"ai", &rollPID.i, &pitchPID.i},
{"ad", &rollPID.d, &pitchPID.d},

{"yp", &yawRatePID.p, nullptr},
{"yi", &yawRatePID.i, nullptr},
{"yd", &yawRatePID.d, nullptr},

{"lpr", &ratesFilter.alpha, nullptr},
{"lpd", &rollRatePID.lpf.alpha, &pitchRatePID.lpf.alpha},

{"ss", &loopRate, nullptr},
{"dt", &dt, nullptr},
{"t", &t, nullptr},
};

void doCommand(String& command, String& value) {
// execute command
if (command == "help" || command == "motd") {
Serial.println(motd);
} else if (command == "show") {
showTable();
} else if (command == "ps") {
Vector a = attitude.toEulerZYX();
Serial.printf("roll: %f pitch: %f yaw: %f\n", a.x * RAD_TO_DEG, a.y * RAD_TO_DEG, a.z * RAD_TO_DEG);
Expand Down Expand Up @@ -96,76 +72,38 @@ void doCommand(String& command, String& value) {
} else if (command == "ca") {
calibrateAccel();
} else if (command == "mfr") {
cliTestMotor(MOTOR_FRONT_RIGHT);
testMotor(MOTOR_FRONT_RIGHT);
} else if (command == "mfl") {
cliTestMotor(MOTOR_FRONT_LEFT);
testMotor(MOTOR_FRONT_LEFT);
} else if (command == "mrr") {
cliTestMotor(MOTOR_REAR_RIGHT);
testMotor(MOTOR_REAR_RIGHT);
} else if (command == "mrl") {
cliTestMotor(MOTOR_REAR_LEFT);
testMotor(MOTOR_REAR_LEFT);
} else if (command == "reset") {
attitude = Quaternion();
} else if (command == "") {
// do nothing
} else {
float val = value.toFloat();
// TODO: on error returns 0, check invalid value

for (uint8_t i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
if (command == params[i].name) {
*params[i].value = val;
if (params[i].value2 != nullptr) *params[i].value2 = val;
Serial.print(command);
Serial.print(" = ");
Serial.println(val, 4);
return;
}
}
Serial.println("Invalid command: " + command);
}
}

void showTable() {
for (uint8_t i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
Serial.print(params[i].name);
Serial.print(" ");
Serial.println(*params[i].value, 5);
}
}

void cliTestMotor(uint8_t n) {
Serial.printf("Testing motor %d\n", n);
motors[n] = 1;
delay(50); // ESP32 may need to wait until the end of the current cycle to change duty https://github.com/espressif/arduino-esp32/issues/5306
sendMotors();
delay(3000);
motors[n] = 0;
sendMotors();
Serial.println("Done");
}

void parseInput() {
void handleInput() {
static bool showMotd = true;
static String command;
static String value;
static bool parsingCommand = true;
static String input;

if (showMotd) {
Serial.println(motd);
Serial.printf("%s\n", motd);
showMotd = false;
}

while (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
parsingCommand = true;
if (!command.isEmpty()) {
doCommand(command, value);
}
command.clear();
value.clear();
} else if (c == ' ') {
parsingCommand = false;
doCommand(input);
input.clear();
} else {
(parsingCommand ? command : value) += c;
input += c;
}
}
}
4 changes: 0 additions & 4 deletions flix/control.ino
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,6 @@ void controlTorque() {
motors[3] = constrain(motors[3], 0, 1);
}

bool motorsActive() {
return motors[0] > 0 || motors[1] > 0 || motors[2] > 0 || motors[3] > 0;
}

const char* getModeName() {
switch (mode) {
case MANUAL: return "MANUAL";
Expand Down
2 changes: 1 addition & 1 deletion flix/flix.ino
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void loop() {
estimate();
control();
sendMotors();
parseInput();
handleInput();
#if WIFI_ENABLED
processMavlink();
#endif
Expand Down
15 changes: 15 additions & 0 deletions flix/motors.ino
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,18 @@ void sendMotors() {
ledcWrite(MOTOR_2_PIN, getDutyCycle(motors[2]));
ledcWrite(MOTOR_3_PIN, getDutyCycle(motors[3]));
}

bool motorsActive() {
return motors[0] != 0 || motors[1] != 0 || motors[2] != 0 || motors[3] != 0;
}

void testMotor(uint8_t n) {
Serial.printf("Testing motor %d\n", n);
motors[n] = 1;
delay(50); // ESP32 may need to wait until the end of the current cycle to change duty https://github.com/espressif/arduino-esp32/issues/5306
sendMotors();
delay(3000);
motors[n] = 0;
sendMotors();
Serial.printf("Done\n");
}
10 changes: 10 additions & 0 deletions flix/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,13 @@ void printArray(T arr[], int size) {
void disableBrownOut() {
REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ENA);
}

// Trim and split string by spaces
void splitString(String& str, String& token0, String& token1, String& token2) {
str.trim();
char chars[str.length() + 1];
str.toCharArray(chars, str.length() + 1);
token0 = strtok(chars, " ");
token1 = strtok(NULL, " "); // String(NULL) creates empty string
token2 = strtok(NULL, "");
}
8 changes: 8 additions & 0 deletions gazebo/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,17 @@ class __FlashStringHelper;
// https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/
class String: public std::string {
public:
String(const char *str = "") : std::string(str ? str : "") {}
long toInt() const { return atol(this->c_str()); }
float toFloat() const { return atof(this->c_str()); }
bool isEmpty() const { return this->empty(); }
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const {
strlcpy(buf, this->c_str() + index, bufsize);
}
void trim() {
this->erase(0, this->find_first_not_of(" \t\n\r"));
this->erase(this->find_last_not_of(" \t\n\r") + 1);
}
};

class Print;
Expand Down
3 changes: 2 additions & 1 deletion gazebo/flix.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ void controlTorque();
void showTable();
void sendMotors();
bool motorsActive();
void cliTestMotor(uint8_t n);
void doCommand(String str);
void normalizeRC();
void printRCCal();
void processMavlink();
void sendMavlink();
Expand Down
2 changes: 1 addition & 1 deletion gazebo/simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class ModelFlix : public ModelPlugin {
attitude.setYaw(this->model->WorldPose().Yaw());

control();
parseInput();
handleInput();
processMavlink();

applyMotorForces();
Expand Down

0 comments on commit 6058e8e

Please sign in to comment.