Wired train control working
This commit is contained in:
parent
dd5cabbf05
commit
8b8891a605
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue