diff --git a/lib/Syren50/src/Syren50.cpp b/lib/Syren50/src/Syren50.cpp new file mode 100644 index 0000000..c60abc0 --- /dev/null +++ b/lib/Syren50/src/Syren50.cpp @@ -0,0 +1,39 @@ +#include "Arduino.h" +#include +#include "Syren50.h" + +void Syren50::init() { + Serial1.begin(9600); + delay(1000); // Give about 1 second to boot up, per datasheet + Serial.write(0b10101010); +} + +void Syren50::command(uint8_t command, uint8_t data) { + Serial1.write(0x80); // Address + Serial1.write(command); // Command + Serial1.write(data); + Serial1.write((0x80 + command + data) & 0b01111111); // Checksum + Serial1.flush(); +} + +void Syren50::forwards(uint8_t speed) { + command(0x00, speed); +} + +void Syren50::reverse(uint8_t speed) { + command(0x01, speed); +} + +void Syren50::move(int8_t direction, uint8_t speed) { + if (direction == 1) { + forwards(speed); + } else if (direction == -1) { + reverse(speed); + } else { + forwards(0); + } +} + +void Syren50::minInputVoltage(float voltage) { + command(0x03, (uint8_t)((voltage - 6.0) * 5.0)); +} diff --git a/lib/Syren50/src/Syren50.h b/lib/Syren50/src/Syren50.h new file mode 100644 index 0000000..94f956d --- /dev/null +++ b/lib/Syren50/src/Syren50.h @@ -0,0 +1,18 @@ +#ifndef SYREN50_H +#define SYREN50_H + +#include + +class Syren50 { +public: + void init(); + void forwards(uint8_t speed); + void reverse(uint8_t speed); + void move(int8_t direction, uint8_t speed); + void minInputVoltage(float voltage); + + private: + void command(uint8_t command, uint8_t data); +}; + +#endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 06d0c4c..996ca53 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,9 +9,23 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = default +default_envs = esp12e name = RemoteTrainControl -[env:default] +[env:esp12e] platform = espressif8266 +framework = arduino board = esp12e +lib_deps = + adafruit/Adafruit ADS1X15@^2.4.0 + SPI + adafruit/Adafruit SSD1306@^2.5.7 + +[env:nodemcuv2] +platform = espressif8266 +framework = arduino +board = nodemcuv2 +lib_deps = + adafruit/Adafruit ADS1X15@^2.4.0 + SPI + adafruit/Adafruit SSD1306@^2.5.7 diff --git a/sample.txt b/sample.txt new file mode 100644 index 0000000..05ac127 --- /dev/null +++ b/sample.txt @@ -0,0 +1,97 @@ +#include "Arduino.h" +#include +#include +#include +#include + +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 32 // OLED display height, in pixels + +#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) +#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); + +void testdrawrect(void) { + display.clearDisplay(); + + for(int16_t i=0; i +#include +#include + +Adafruit_ADS1115 ads1115; + +void controlsInit() { + ads1115.begin(); + ads1115.setGain(GAIN_ONE); +} + +float map(float x, float in_min, float in_max, float out_min, float out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +void getControlsState(float &throttle, int &direction, bool &horn, bool &bell, bool &lights) { + float throttle_volts = ads1115.computeVolts(ads1115.readADC_SingleEnded(0)); + float direction_volts = ads1115.computeVolts(ads1115.readADC_SingleEnded(1)); + + float throt = map(throttle_volts, 1.0f, 2.0f, 0.0f, 1.0f); + + if (throt > 1.0f) { + throt = 1.0f; + } + if (throt < 0.0f) { + throt = 0.0f; + } + + if (direction_volts < 3.3/3.0) { + direction = -1; + throttle = throt; + } else if (direction_volts > (3.3 / 3.0) * 2.0) { + direction = 1; + throttle = throt; + } else { + direction = 0; + } + horn = false; + bell = false; + lights = false; +} diff --git a/src/controls.h b/src/controls.h new file mode 100644 index 0000000..2a862a1 --- /dev/null +++ b/src/controls.h @@ -0,0 +1,8 @@ +#ifndef CONTROLS_H +#define CONTROLS_H + +void controlsInit(); +float map(float x, float in_min, float in_max, float out_min, float out_max); +void getControlsState(float &throttle, int &direction, bool &horn, bool &bell, bool &lights); + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..9a53495 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,50 @@ +#include "Arduino.h" +#include "screen.h" +#include "wifi.h" +#include "controls.h" +#include "Syren50.h" +#include +#include +#include +using namespace std; + +Syren50 motor; + +void setup() { + Serial.begin(9600); + displayInit(); + controlsInit(); + WiFi.softAP(WIFI_SSID, WIFI_PASS); + displayWiFiInformation(WIFI_SSID, WIFI_PASS); + delay(1000); + motor.init(); +} + +float throttle = 0.0f; +int direction = 0; +bool horn = false; +bool bell = false; +bool lights = false; + +int last_direction = 0; +float last_throttle = 0.0f; + +void inertia(float throttle, int direction, float &inertial_throttle, int &inertial_direction) { + + inertial_throttle = throttle; + inertial_direction = direction; +} + + +void loop() { + getControlsState(throttle, direction, horn, bell, lights); + + float motor_throttle; + int motor_direction; + inertia(throttle, direction, motor_throttle, motor_direction); + + displayControlStatus(motor_throttle, motor_direction, horn, bell, lights); + motor.move(motor_direction, motor_throttle * 127.0f); + + delay(1); +} \ No newline at end of file diff --git a/src/screen.cpp b/src/screen.cpp new file mode 100644 index 0000000..dc56b6d --- /dev/null +++ b/src/screen.cpp @@ -0,0 +1,96 @@ +#include "Arduino.h" +#include +#include +#include +#include +#include +using namespace std; + +#define SCREEN_WIDTH 128 +#define SCREEN_HEIGHT 32 + +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire); + +bool displayEnabled = false; + +void displayInit() { + displayEnabled = display.begin(SSD1306_SWITCHCAPVCC, 0x3C); + if(displayEnabled) { + display.clearDisplay(); + display.display(); + } +} + +void displayString(string inputString) { + if (!displayEnabled) { + return; + } + for (char c: inputString) { + display.write(c); + } +} + +void displayWiFiInformation(string wifiSSID, string wifiPassword) { + if (!displayEnabled) { + return; + } + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0,0); + displayString("WiFi Information:"); + display.setCursor(0,8); + displayString("SSID: "); + displayString(wifiSSID); + display.setCursor(0,16); + displayString("Pass: "); + displayString(wifiPassword); + display.display(); +} + +void displayDirection(int &direction) { + if (direction == 0) { + displayString("N"); + } else if (direction == 1) { + displayString("F"); + } else if (direction == -1) { + displayString("R"); + } else { + displayString("?"); + } +} + +void displayBool(bool &state) { + if (state) { + displayString("1"); + } else { + displayString("0"); + } +} + +void displayControlStatus(float &throttle, int &direction, bool &horn, bool &bell, bool &lights) { + if (!displayEnabled) { + return; + } + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0,0); + displayString("Throttle: "); + display.println(throttle * 100.0f); + displayString("%"); + display.setCursor(0,8); + displayString("Direction: "); + displayDirection(direction); + display.setCursor(0,16); + displayString("H B L "); + display.setCursor(0,24); + displayBool(horn); + displayString(" "); + displayBool(bell); + displayString(" "); + displayBool(lights); + displayString(" "); + display.println((uint8_t)(throttle * 127.0f)); + display.display(); +} \ No newline at end of file diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..30dd7ad --- /dev/null +++ b/src/screen.h @@ -0,0 +1,14 @@ +#ifndef SCREEN_H +#define SCREEN_H + +#include +using namespace std; + +void displayInit(); +void displayString(string inputString); +void displayWiFiInformation(string wifiSSID, string wifiPassword); +void displayDirection(int &direction); +void displayBool(bool &state); +void displayControlStatus(float &throttle, int &direction, bool &horn, bool &bell, bool &lights); + +#endif \ No newline at end of file