Browse Source

Implement basic speed control

- Add speed pedal status read
- Add cruise control
- Add break logic
- Add extra display support and switch speed display position
Alexey Edelev 4 years ago
parent
commit
eda82bf395

+ 95 - 0
Arduino/eScooterControl/accelerationcontrol.cpp

@@ -0,0 +1,95 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of eScooterControl project https://github.com/semlanik/eScooterControl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include "singleton.h"
+#include "accelerationcontrol.h"
+#include "pinconfig.h"
+
+const int AcceleratorSensorDivider = (AcceleratorSensorMaxValue - AcceleratorSensorMinValue) * AcceleratorSensorStep;
+
+AccelerationControl::AccelerationControl() : m_stopState(HIGH)
+  , m_accelerationLevel(0)
+  , m_accelerationVoltage(0)
+  , m_cruiseTime(0)
+  , m_cruiseLevel(0)
+{
+//  m_accelerator.begin(0x62);//TODO address to be setup from pinconfig;
+  pinMode(AcceleratorSensorPin, INPUT);
+  pinMode(StopSensorPin, INPUT_PULLUP);
+  attachInterrupt(digitalPinToInterrupt(StopSensorPin), [](){
+    AccelerationControl::instance()->stop();
+  }, CHANGE);
+
+  m_stopState = digitalRead(StopSensorPin);
+}
+
+
+void AccelerationControl::setAcceleration(const int level)
+{
+  if (level == m_accelerationLevel) {
+    if (m_cruiseLevel < m_accelerationLevel
+          && m_cruiseTime < millis()) {
+      m_cruiseLevel = m_accelerationLevel;
+    }
+    return;
+  }
+
+  if (level > m_accelerationLevel) {
+    m_cruiseLevel = 0; //Reset cruise whenever accelerator level raised, when drop it means we go down
+    m_cruiseTime = millis() + CruiseTime;  
+  }
+
+  m_accelerationLevel = level;
+}
+
+void AccelerationControl::dispatch(unsigned long)
+{  
+  if (m_stopState == HIGH) {
+    setAcceleration(readAcceleratorData());
+  }
+  updateAccelerationVoltage();
+}
+
+void AccelerationControl::stop() {
+  m_stopState = digitalRead(StopSensorPin);
+  if (m_stopState == LOW) {
+    m_cruiseLevel = 0; //reset cruise when stop
+    setAcceleration(0);
+  }
+}
+
+int AccelerationControl::readAcceleratorData()
+{
+  int value = analogRead(AcceleratorSensorPin);
+  return round(100.0*(value - AcceleratorSensorMinValue)/AcceleratorSensorDivider);
+}
+
+void AccelerationControl::updateAccelerationVoltage() {
+  int level = m_accelerationLevel;
+  if (m_cruiseLevel > 0) {//At cruise control
+    level = m_cruiseLevel;
+  }
+
+  int expectedVoltage = 0x0fff / AcceleratorSensorStep * level;
+}

+ 55 - 0
Arduino/eScooterControl/accelerationcontrol.h

@@ -0,0 +1,55 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of eScooterControl project https://github.com/semlanik/eScooterControl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <Adafruit_MCP4725.h>
+#include "singleton.h"
+
+class AccelerationControl : public Singleton<AccelerationControl>
+{
+public:
+  void dispatch(unsigned long);
+
+private:
+  AccelerationControl();
+  friend class Singleton;
+
+  void setAcceleration(int level);
+  int readAcceleratorData();
+  void updateAccelerationVoltage();
+  
+  void stop();
+
+  Adafruit_MCP4725 m_accelerator;
+
+  unsigned int m_stopState;
+  
+  unsigned int m_accelerationLevel;
+  unsigned int m_accelerationVoltage;
+
+  unsigned long m_cruiseTime;
+  unsigned int m_cruiseLevel;
+};

+ 8 - 4
Arduino/eScooterControl/display.cpp

@@ -94,8 +94,8 @@ const PROGMEM byte Digit[10][5] = {
   }
 };
 
-Display::Display() : mLedControl(DisplayDataPin, DisplayClkPin, DisplayCsPin,1)
- ,mDisplayBuffer({
+Display::Display() : mLedControl(DisplayDataPin, DisplayClkPin, DisplayCsPin,2)
+ ,mDisplayBuffer{
   B00000000,
   B00000000,
   B00000000,
@@ -103,11 +103,15 @@ Display::Display() : mLedControl(DisplayDataPin, DisplayClkPin, DisplayCsPin,1)
   B00000000,
   B00000000,
   B00000000,
-  B00000000})
+  B00000000}
 {
   mLedControl.shutdown(0, false);
   mLedControl.setIntensity(0, 0);
   mLedControl.clearDisplay(0);  
+
+  mLedControl.shutdown(1, false);
+  mLedControl.setIntensity(1, 0);
+  mLedControl.clearDisplay(1);  
 }
 
 void Display::drawSpeed(unsigned char number)
@@ -145,6 +149,6 @@ void Display::drawBatteryLevel(unsigned char level)
 void Display::updateDisplayBuffer()
 {
   for(int i = 0; i < 8; i++) {
-    mLedControl.setColumn(0, i, mDisplayBuffer[i]);    
+    mLedControl.setColumn(1, i, mDisplayBuffer[i]);    
   }
 }

+ 12 - 5
Arduino/eScooterControl/eScooterControl.ino

@@ -25,33 +25,40 @@
 #include "thread.h"
 #include "display.h"
 #include "speedometer.h"
+#include "accelerationcontrol.h"
 
 /* we always wait a bit between updates of the display */
+const unsigned long AcceleratorPedalUpdateTime = 200;
 const unsigned long DisplayUpdateTime = 500;
 const unsigned long BatteryUpdateTime = 1000;
 
 Thread gDisplayThread = Thread(DisplayUpdateTime);
 Thread gBatteryThread = Thread(BatteryUpdateTime);
+Thread gAcceleratorPedalThread = Thread(AcceleratorPedalUpdateTime);
 
 unsigned char fakeBatteryLevel = 0;
 
 void setup() {
+//  Serial.begin(115200);
+//  Serial.println("Init");
+
   Speedometer::instance()->attachToDisplay(Display::instance());
   
-  gDisplayThread.assignCallback([](){
+  gDisplayThread.assignCallback([](unsigned long){
     Display::instance()->updateDisplayBuffer();
   });
 
-  gBatteryThread.assignCallback([](){
+  gBatteryThread.assignCallback([](unsigned long){
     Display::instance()->drawBatteryLevel(fakeBatteryLevel);
     fakeBatteryLevel++;
     if (fakeBatteryLevel > 5) {
       fakeBatteryLevel = 0;
     }
   });
-  
-  pinMode(3, OUTPUT);
-  digitalWrite(3, LOW);
+
+  gAcceleratorPedalThread.assignCallback([](unsigned long time){
+    AccelerationControl::instance()->dispatch(time);
+  });
 }
 
 void loop() {

+ 18 - 2
Arduino/eScooterControl/pinconfig.h

@@ -24,8 +24,24 @@
  */
 #pragma once
 
+#if defined(ARDUINO) && ARDUINO >= 100
+  #include <Arduino.h>
+#else
+  #include <WProgram.h>
+#endif
+
 const int HallSensorPin = 2;
+const int StopSensorPin = 3;
 
 const int DisplayDataPin = 10;
-const int DisplayClkPin = 11;
-const int DisplayCsPin = 12;
+const int DisplayCsPin = 11;
+const int DisplayClkPin = 12;
+
+const int AcceleratorSensorPin = A0;
+
+//Align accelerator trigger values
+const int AcceleratorSensorMinValue = 177;
+const int AcceleratorSensorMaxValue = 874;
+const int AcceleratorSensorStep = 10;
+
+const int CruiseTime = 3000; //milliseconds

+ 4 - 0
Arduino/eScooterControl/thread.cpp

@@ -37,6 +37,10 @@ Thread::Thread(unsigned long delay) : mDelay(delay)
 
 void Thread::dispatchThread()
 {
+  if (mCallback == nullptr) {
+    return;
+  }
+  
   unsigned long time = millis();
   unsigned long delay = time - mLastCallTime;
   if (delay >= mDelay) {