Implemented overcurrent detection

Implemented manual and overcurrent screens
Basically it's ready for a real world test!
This commit is contained in:
Mark van Renswoude 2020-02-02 12:19:24 +01:00
parent c8ccd519fc
commit b9f5394d53
14 changed files with 145 additions and 29 deletions

View File

@ -4,6 +4,26 @@
#include <stdint.h>
/*
Determines if logging over the serial port is enabled.
Uses a baud rate of 115200.
Verbose logging outputs even more, including logging
every loop. Only turn on when required.
At the time of writing, turning both on uses more RAM
than the ATMega328P has.
Turning DebugLog off saves around 1k of RAM and 3k of flash.
Turning VerboseLog off saves around 300 bytes of RAM and 1k of flash.
*/
//#define DebugLog
//#define VerboseLog
class Config
{
public:
@ -83,6 +103,10 @@ class Config
static const uint8_t MotorPinSleep = 16;
static const uint8_t MotorPinCurrentSensing = 17;
static const constexpr float MotorCurrentLimit = 6.0;
static const uint16_t MotorCurrentCheckInterval = 100;
/*
Colors

View File

@ -3,7 +3,7 @@
enum class ScreenId
{
Home,
Home = 1,
Calibrate,
Move,
MoveOvercurrent,

View File

@ -49,14 +49,18 @@ ControlUpdateResult ControlManager::update()
// Check for over-current
// TODO: don't check current every update
if (moving && motorIsOvercurrent())
if (moving && CurrentTime - lastCurrentCheck >= Config::MotorCurrentCheckInterval)
{
lastCurrentCheck = CurrentTime;
if (motorIsOvercurrent())
{
dln("[ CONTROL ] Overcurrent detected!");
this->moveStop();
return ControlUpdateResult::Overcurrent;
}
}
// Read sensor
if (!asyncReading)
@ -83,6 +87,8 @@ ControlUpdateResult ControlManager::update()
this->currentMeasurement = measurement;
this->lastValidMeasurement = CurrentTime;
// TODO: PWM the motor when we're getting close, if overshoot turns out to be an issue in testing
// Check if target has been reached
if (moving && this->targetReached())
{

View File

@ -64,6 +64,8 @@ class ControlManager
uint16_t lastMeasurement = 0;
uint32_t lastValidMeasurement = 0;
uint32_t lastCurrentCheck = 0;
MoveDirection moveDirection;
uint16_t moveTargetHeight;

View File

@ -2,9 +2,7 @@
#define __debug
#include <Arduino.h>
#define DebugLog
//#define VerboseLog
#include "include/config.h"
#ifdef DebugLog

View File

@ -1,5 +1,6 @@
#include "./motor.h"
#include "include/config.h"
#include "./debug.h"
#include <Arduino.h>
@ -13,11 +14,17 @@ void motorInit()
pinMode(Config::MotorPinDirection, OUTPUT);
pinMode(Config::MotorPinCurrentSensing, INPUT);
// See motorIsOvercurrent
analogReference(INTERNAL);
delay(10);
}
void motorStart(MotorDirection direction)
{
dl("[ MOTOR ] Starting in direction: "); dln((uint8_t)direction);
digitalWrite(Config::MotorPinDirection, direction == MotorDirection::Up ? HIGH : LOW);
digitalWrite(Config::MotorPinSleep, HIGH);
digitalWrite(Config::MotorPinPWM, HIGH);
@ -26,6 +33,8 @@ void motorStart(MotorDirection direction)
void motorStop()
{
dln("[ MOTOR ] Stopping");
digitalWrite(Config::MotorPinPWM, LOW);
digitalWrite(Config::MotorPinSleep, LOW);
digitalWrite(Config::MotorPinDirection, LOW);
@ -34,8 +43,15 @@ void motorStop()
bool motorIsOvercurrent()
{
// TODO: implement motorIsOvercurrent
return false;
// The Polugu G2 module outputs 20 mV/A plus a 50 mV offset
// The analog reference has been set to internal, which is 1.1v for the ATMega328P,
// divided by 1024 units is 1.074mV per unit. This means we can measure up to 52.5A.
// I sure hope we never reach that value :-)
auto value = analogRead(Config::MotorPinCurrentSensing);
float voltage = (float)value * (1100.0 / 1024.0);
float current = (voltage - 50) / 20;
dl("[ MOTOR ] Measured current: value = "); dl(value); dl(", V = "); dl(voltage); dl(", A = "); dln(current);
return current >= Config::MotorCurrentLimit;
}

View File

@ -61,7 +61,9 @@ void HomeScreen::onButton(Button button)
if (targetHeight > 0)
{
MoveReturnScreen = this->screenId();
Control.moveStart(targetHeight);
this->screenManager->show<MoveScreen>();
}
}

View File

@ -1,17 +1,41 @@
#include "./manual.h"
#include "./home.h"
#include "./move.h"
#include "include/metrics.h"
#include "lib/settings.h"
#include "../state.h"
void ManualScreen::onShow()
void ManualScreen::initHeights()
{
// TODO: implement ManualScreen
this->height = Control.getCurrentHeight();
}
void ManualScreen::onButton(Button button)
bool ManualScreen::nextPage()
{
if (this->height == Control.getCurrentHeight())
{
this->screenManager->show<HomeScreen>();
return false;
}
MoveReturnScreen = this->screenId();
Control.moveStart(this->height);
this->screenManager->show<MoveScreen>();
return true;
}
void ManualScreen::onTick()
void ManualScreen::setHeight(uint16_t value)
{
if (value < Settings.Height.Minimum)
this->height = Settings.Height.Minimum;
else if (value > Settings.Height.Maximum)
this->height = Settings.Height.Maximum;
else
this->height = value;
}

View File

@ -2,6 +2,7 @@
#define __screen_manual
#include "include/screenids.h"
#include "./baseheightentry.h"
#include "../screen.h"
#include "../Control.h"
@ -10,18 +11,24 @@
* Manual screen
* Allows manual entry of the preferred height.
*/
class ManualScreen : public BaseScreen
class ManualScreen : public BaseHeightEntryScreen
{
public:
ManualScreen(ScreenManager* screenManager, Adafruit_GFX* display) : BaseScreen(screenManager, display) { }
void onShow();
void onButton(Button button);
void onTick();
ManualScreen(ScreenManager* screenManager, Adafruit_GFX* display) : BaseHeightEntryScreen(screenManager, display) { }
ScreenId screenId() { return ScreenId::Manual; };
protected:
void initHeights();
uint16_t getHeight() { return this->height; }
void setHeight(uint16_t value);
bool nextPage();
bool isValidHeight() { return true; }
const char* getTitle() { return "Manual"; }
private:
uint16_t height;
};
#endif

View File

@ -94,8 +94,7 @@ void MenuScreen::activateMenuItem(MenuItem item)
switch (item)
{
case MenuItem::Manual:
// TODO: show manual screen
//this->screenManager->show<ManualScreen>();
this->screenManager->show<ManualScreen>();
break;
case MenuItem::Presets:

View File

@ -1,14 +1,39 @@
#include "./move-overcurrent.h"
#include "./home.h"
#include "include/config.h"
#include "include/metrics.h"
#include "lib/control.h"
#include "lib/state.h"
void MoveOvercurrentScreen::onShow()
{
// TODO: implement MoveOvercurrentScreen
auto y = Metrics::LargeTextLineHeight + Metrics::LargeTextLineYOffset;
this->display->fillScreen(Config::ColorErrorBackground);
this->display->setFont(Metrics::LargeFont);
this->display->setTextSize(Metrics::LargeFontTextSize);
this->display->setTextColor(Config::ColorErrorText);
this->printCentered("ERROR", y);
y += Metrics::LargeTextLineHeight;
this->display->setFont(Metrics::SmallFont);
this->display->setTextSize(Metrics::SmallFontTextSize);
this->printCentered("motor overcurrent", y);
y += Metrics::SmallTextLineHeight;
this->printCentered("press any button", y);
y += Metrics::SmallTextLineHeight + Metrics::LargeTextLineHeight;
}
void MoveOvercurrentScreen::onButton(Button button)
{
this->screenManager->show<HomeScreen>();
}

View File

@ -1,3 +1,4 @@
#include "Control.h"
#include "state.h"
uint32_t CurrentTime;
ScreenId MoveReturnScreen = (ScreenId)0;

View File

@ -2,7 +2,9 @@
#define __state
#include "stdint.h"
#include "include/screenids.h"
extern uint32_t CurrentTime;
extern ScreenId MoveReturnScreen;
#endif

View File

@ -15,6 +15,7 @@
#include "./lib/state.h"
#include "./lib/screen/home.h"
#include "./lib/screen/calibrate.h"
#include "./lib/screen/manual.h"
#include "./lib/screen/move-overcurrent.h"
#include "./lib/screen/move-sensorerror.h"
@ -175,8 +176,17 @@ void loop()
switch (Control.update())
{
case ControlUpdateResult::TargetReached:
switch (MoveReturnScreen)
{
case ScreenId::Manual:
screenManager.show<ManualScreen>();
break;
default:
screenManager.show<HomeScreen>();
break;
}
break;
case ControlUpdateResult::SensorError:
screenManager.show<MoveSensorErrorScreen>(ScreenId::MoveSensorError);