Wired train control working

This commit is contained in:
Jared Dunbar 2023-02-05 12:07:50 -05:00
parent dd5cabbf05
commit 8b8891a605
9 changed files with 381 additions and 2 deletions

View File

@ -0,0 +1,39 @@
#include "Arduino.h"
#include <stdint.h>
#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));
}

18
lib/Syren50/src/Syren50.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef SYREN50_H
#define SYREN50_H
#include <stdint.h>
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

View File

@ -9,9 +9,23 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[platformio] [platformio]
default_envs = default default_envs = esp12e
name = RemoteTrainControl name = RemoteTrainControl
[env:default] [env:esp12e]
platform = espressif8266 platform = espressif8266
framework = arduino
board = esp12e 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

97
sample.txt Normal file
View File

@ -0,0 +1,97 @@
#include "Arduino.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#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<display.height()/2; i+=2) {
display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
}
delay(2000);
}
void testfillrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2; i+=3) {
// The INVERSE color is used so rectangles alternate white/black
display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
}
delay(2000);
}
void testdrawchar(void) {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
// Not all the characters will fit on the display. This is normal.
// Library will draw what it can and the rest will be clipped.
for(int16_t i=0; i<256; i++) {
if(i == '\n') display.write(' ');
else display.write(i);
}
display.display();
delay(2000);
}
void testdrawstyles(void) {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0,0); // Start at top-left corner
display.println(F("Hello, world!"));
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
display.println(3.141592);
display.setTextSize(2); // Draw 2X-scale text
display.setTextColor(SSD1306_WHITE);
display.print(F("0x")); display.println(0xDEADBEEF, HEX);
display.display();
delay(2000);
}
void setup() {
Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
// Draw a single pixel in white
display.drawPixel(10, 10, SSD1306_WHITE);
// Show the display buffer on the screen. You MUST call display() after
// drawing commands to make them visible on screen!
display.display();
delay(2000);
}
void loop() {
testdrawrect(); // Draw rectangles (outlines)
testfillrect(); // Draw rectangles (filled)
testdrawchar(); // Draw characters of the default font
testdrawstyles(); // Draw 'stylized' characters
}

43
src/controls.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "Arduino.h"
#include <stdint.h>
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
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;
}

8
src/controls.h Normal file
View File

@ -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

50
src/main.cpp Normal file
View File

@ -0,0 +1,50 @@
#include "Arduino.h"
#include "screen.h"
#include "wifi.h"
#include "controls.h"
#include "Syren50.h"
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <string>
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);
}

96
src/screen.cpp Normal file
View File

@ -0,0 +1,96 @@
#include "Arduino.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <string>
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();
}

14
src/screen.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SCREEN_H
#define SCREEN_H
#include <string>
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