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> #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 class Config
{ {
public: public:
@ -83,6 +103,10 @@ class Config
static const uint8_t MotorPinSleep = 16; static const uint8_t MotorPinSleep = 16;
static const uint8_t MotorPinCurrentSensing = 17; static const uint8_t MotorPinCurrentSensing = 17;
static const constexpr float MotorCurrentLimit = 6.0;
static const uint16_t MotorCurrentCheckInterval = 100;
/* /*
Colors Colors

View File

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

View File

@ -49,13 +49,17 @@ ControlUpdateResult ControlManager::update()
// Check for over-current // Check for over-current
// TODO: don't check current every update if (moving && CurrentTime - lastCurrentCheck >= Config::MotorCurrentCheckInterval)
if (moving && motorIsOvercurrent())
{ {
dln("[ CONTROL ] Overcurrent detected!"); lastCurrentCheck = CurrentTime;
this->moveStop();
return ControlUpdateResult::Overcurrent; if (motorIsOvercurrent())
{
dln("[ CONTROL ] Overcurrent detected!");
this->moveStop();
return ControlUpdateResult::Overcurrent;
}
} }
// Read sensor // Read sensor
@ -83,6 +87,8 @@ ControlUpdateResult ControlManager::update()
this->currentMeasurement = measurement; this->currentMeasurement = measurement;
this->lastValidMeasurement = CurrentTime; 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 // Check if target has been reached
if (moving && this->targetReached()) if (moving && this->targetReached())
{ {

View File

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

View File

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

View File

@ -1,5 +1,6 @@
#include "./motor.h" #include "./motor.h"
#include "include/config.h" #include "include/config.h"
#include "./debug.h"
#include <Arduino.h> #include <Arduino.h>
@ -13,11 +14,17 @@ void motorInit()
pinMode(Config::MotorPinDirection, OUTPUT); pinMode(Config::MotorPinDirection, OUTPUT);
pinMode(Config::MotorPinCurrentSensing, INPUT); pinMode(Config::MotorPinCurrentSensing, INPUT);
// See motorIsOvercurrent
analogReference(INTERNAL);
delay(10);
} }
void motorStart(MotorDirection direction) void motorStart(MotorDirection direction)
{ {
dl("[ MOTOR ] Starting in direction: "); dln((uint8_t)direction);
digitalWrite(Config::MotorPinDirection, direction == MotorDirection::Up ? HIGH : LOW); digitalWrite(Config::MotorPinDirection, direction == MotorDirection::Up ? HIGH : LOW);
digitalWrite(Config::MotorPinSleep, HIGH); digitalWrite(Config::MotorPinSleep, HIGH);
digitalWrite(Config::MotorPinPWM, HIGH); digitalWrite(Config::MotorPinPWM, HIGH);
@ -26,6 +33,8 @@ void motorStart(MotorDirection direction)
void motorStop() void motorStop()
{ {
dln("[ MOTOR ] Stopping");
digitalWrite(Config::MotorPinPWM, LOW); digitalWrite(Config::MotorPinPWM, LOW);
digitalWrite(Config::MotorPinSleep, LOW); digitalWrite(Config::MotorPinSleep, LOW);
digitalWrite(Config::MotorPinDirection, LOW); digitalWrite(Config::MotorPinDirection, LOW);
@ -34,8 +43,15 @@ void motorStop()
bool motorIsOvercurrent() bool motorIsOvercurrent()
{ {
// TODO: implement motorIsOvercurrent // The Polugu G2 module outputs 20 mV/A plus a 50 mV offset
return false; // 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) if (targetHeight > 0)
{ {
MoveReturnScreen = this->screenId();
Control.moveStart(targetHeight); Control.moveStart(targetHeight);
this->screenManager->show<MoveScreen>(); this->screenManager->show<MoveScreen>();
} }
} }

View File

@ -1,17 +1,41 @@
#include "./manual.h" #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 #define __screen_manual
#include "include/screenids.h" #include "include/screenids.h"
#include "./baseheightentry.h"
#include "../screen.h" #include "../screen.h"
#include "../Control.h" #include "../Control.h"
@ -10,18 +11,24 @@
* Manual screen * Manual screen
* Allows manual entry of the preferred height. * Allows manual entry of the preferred height.
*/ */
class ManualScreen : public BaseScreen class ManualScreen : public BaseHeightEntryScreen
{ {
public: public:
ManualScreen(ScreenManager* screenManager, Adafruit_GFX* display) : BaseScreen(screenManager, display) { } ManualScreen(ScreenManager* screenManager, Adafruit_GFX* display) : BaseHeightEntryScreen(screenManager, display) { }
void onShow();
void onButton(Button button);
void onTick();
ScreenId screenId() { return ScreenId::Manual; }; 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: private:
uint16_t height;
}; };
#endif #endif

View File

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

View File

@ -1,14 +1,39 @@
#include "./move-overcurrent.h" #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() 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) void MoveOvercurrentScreen::onButton(Button button)
{ {
this->screenManager->show<HomeScreen>();
} }

View File

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

View File

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

View File

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