Cleanup and fixes

This commit is contained in:
Martin Bauer
2023-09-14 16:16:17 +02:00
parent 4900c36e0b
commit 5e56ede55c
14 changed files with 258 additions and 23 deletions

5
testsystem/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

12
testsystem/platformio.ini Normal file
View File

@@ -0,0 +1,12 @@
[platformio]
default_envs = esp
[env:esp]
platform = espressif8266
board = nodemcuv2
framework = arduino
monitor_port = /dev/ttyUSB0
upload_port = /dev/ttyUSB0
monitor_speed = 115200
lib_deps =
ArduinoJson

View File

@@ -0,0 +1,76 @@
#include "MotorControl.h"
#include <Arduino.h>
constexpr int PORT_FORWARD = 4;
constexpr int PORT_BACKWARD = 16;
constexpr int PORT_SPEED = 5;
// PWM settings
constexpr int PWM_FREQ = 20000;
constexpr int PWM_CHANNEL = 0;
constexpr int PWM_RESOLUTION = 255;
void MotorControl::begin()
{
pinMode(PORT_SPEED, OUTPUT);
pinMode(PORT_FORWARD, OUTPUT);
pinMode(PORT_BACKWARD, OUTPUT);
analogWriteRange(PWM_RESOLUTION);
analogWriteFreq(PWM_FREQ);
startTime_ = millis();
}
void MotorControl::addCmd(float signedSpeed, unsigned long duration)
{
if (numCmds_ < MAX_MOTOR_COMMANDS)
motorCommands_[numCmds_++] = {int(signedSpeed * PWM_RESOLUTION), duration};
else
Serial.println("Too many commands");
}
float MotorControl::speed(int cmdIdx) const
{
return float(motorCommands_[cmdIdx].directionAndSpeed) / float(PWM_RESOLUTION);
}
unsigned long MotorControl::duration(int cmdIdx) const
{
return motorCommands_[cmdIdx].delayToNextCmdInMs;
}
void MotorControl::iteration()
{
if (numCmds_ == 0)
{
analogWrite(PORT_SPEED, 0);
return;
}
unsigned long timeElapsed = millis() - startTime_;
while (timeElapsed > motorCommands_[currentCmd_].delayToNextCmdInMs)
{
const auto curCmdDuration = motorCommands_[currentCmd_].delayToNextCmdInMs;
timeElapsed -= curCmdDuration;
startTime_ += curCmdDuration;
currentCmd_ = (currentCmd_ + 1) % numCmds_;
}
const auto &curCmd = motorCommands_[currentCmd_];
const auto &nextCmd = motorCommands_[(currentCmd_ + 1) % numCmds_];
const float fraction = float(timeElapsed) / float(curCmd.delayToNextCmdInMs);
const int interpolated = int((1.f - fraction) * curCmd.directionAndSpeed + fraction * nextCmd.directionAndSpeed);
if (interpolated < 0)
{
analogWrite(PORT_SPEED, -interpolated);
digitalWrite(PORT_FORWARD, 0);
digitalWrite(PORT_BACKWARD, 1);
}
else
{
analogWrite(PORT_SPEED, interpolated);
digitalWrite(PORT_FORWARD, 1);
digitalWrite(PORT_BACKWARD, 0);
}
}

View File

@@ -0,0 +1,31 @@
class MotorControl
{
public:
void begin();
void clear()
{
numCmds_ = 0;
currentCmd_ = 0;
}
void addCmd(float signedSpeed, unsigned long duration);
void iteration();
int numCommands() const { return numCmds_; }
float speed(int cmdIdx) const;
unsigned long duration(int cmdIdx) const;
private:
static constexpr int MAX_MOTOR_COMMANDS = 1024;
struct MotorCmd
{
int directionAndSpeed; // fraction of PWM_RESO
unsigned long delayToNextCmdInMs;
};
int currentCmd_ = 0;
int numCmds_ = 0;
MotorCmd motorCommands_[MAX_MOTOR_COMMANDS];
unsigned long startTime_ = 0;
};

87
testsystem/src/main.cpp Normal file
View File

@@ -0,0 +1,87 @@
#include "MotorControl.h"
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ArduinoJson.h>
ESP8266WebServer server(80);
MotorControl motorCtl;
const char *webBuffer[1024 * 4];
void wifiSetup()
{
static const char *ssid = "WLAN";
static const char *password = "Bau3rWLAN";
WiFi.begin(ssid, password);
WiFi.hostname("swimtracker-tester");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.println("Waiting to connect...");
}
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void handleGetRoot()
{
DynamicJsonDocument doc(motorCtl.numCommands() * 16 + 128);
JsonArray speeds = doc.createNestedArray("speeds");
JsonArray durations = doc.createNestedArray("durations");
for (int i = 0; i < motorCtl.numCommands(); ++i)
{
speeds.add(motorCtl.speed(i));
durations.add(motorCtl.duration(i));
}
size_t length = serializeJson(doc, webBuffer, sizeof(webBuffer));
server.send(200, "application/json", (const char *)webBuffer, length);
}
void handlePostRoot()
{
String postBody = server.arg("plain");
DynamicJsonDocument doc(postBody.length() * 2 + 256);
DeserializationError error = deserializeJson(doc, postBody);
if (error || !doc.containsKey("speeds") || !doc.containsKey("durations"))
server.send(400, "application/json", "{ \"msg\" : \"Parsing error\" }");
else
{
JsonArray speeds = doc["speeds"].as<JsonArray>();
JsonArray durations = doc["durations"].as<JsonArray>();
if (speeds.size() != durations.size())
server.send(400, "application/json", "{ \"msg\" : \"Arrays have to have same length!\" }");
else
{
motorCtl.clear();
auto speedIt = speeds.begin();
auto durationIt = durations.begin();
for (; speedIt != speeds.end() && durationIt != durations.end(); ++durationIt, ++speedIt)
{
motorCtl.addCmd(speedIt->as<float>(), durationIt->as<unsigned long>());
}
server.send(200, "application/json", "{ \"msg\" : \"Ok\" }");
}
}
}
void setup()
{
Serial.begin(115200);
wifiSetup();
server.on("/", HTTP_GET, handleGetRoot);
server.on("/", HTTP_POST, handlePostRoot);
server.begin(); //Start the server
Serial.println("Server listening");
motorCtl.begin();
}
void loop()
{
server.handleClient(); //Handling of incoming client requests
motorCtl.iteration();
}