1 - Introduction
This page is describing the construction of an Arduino-based electric device and program i created. I could not find a proper/cheap solution that fitted my needs to remotely control speed and direction of a G-scale train pulling my 10 month old on a homemade G-scale flat car (picture below).
It is perfect too for any type of mobile control of a DC train outside or inside (range +/-100m).
This is based on special ball bearings mounted wheels and homemade steel trucks to accomodate the always heavier baby. Note the truck-car attachment s also made with ball bearings to limit side wiggeling.
Parts needed:
- Pcb board with holes ready to solder
- Female plugs : 2.54mm single row female pitch header socket connector (ebay) (for arduino nano on pcb)
- 2 position switch for invertion of track power (manual toggle, the software also inverts it!)
Arduino Nano and Bluesmirf power board:
Note: the only PMW compatible pins of the arduino nano are the following 3, 5, 6, 9, 10, 11. If changes are done to the pin output, make sure you use those pins for PMW.
3- The program
Beta version of the arduino program is below.
A version with inertial support is not yet ready. Make the below text " .ino" and load it in Arduino IDE program.
Arduino program v0.4 (speed+ direction only):
<99 br="" cmdindex="">/*****************************************************************************
//created by Maxime G. Cuypers on 23-fev-2018 for Jamie s train control by bluetooth with roboremo
//adaptated from rc car control sketch for direction control
//adaptated from MD10c sketches to control pmw
//bluetooth module Bluesmirf gold
* AUTHOR : Maxime Cuypers
* COMPANY : private
* REVISION : 0.4
* DATE : 26/04/2021
********************************************************************************/
//v0.4 has inertial acceleration and deceleration, full smooth automatic reverse, emergency stop.
#include <SoftwareSerial.h>
/*******************************************************************************
* IO DEFINITION *
*******************************************************************************/
//setup bluetooth bluesmirf port
int bluetoothTx = 2; // TX-O pin of BT module to Arduino pin2
int bluetoothRx = 3; // RX-I pin of B module to Arduino pin3
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
//const = variable "read-only".
const int pinPwm = 5; // PWM is connected to pin 5.
const int dirPin = 6; //direction signal connected to pin 6.
/*******************************************************************************
* PRIVATE GLOBAL VARIABLES *
*******************************************************************************/
int val = 0; //Desired speed value
int vitesse = 0; //Actual speed train runs
int accel = 150; // Speed to accelerate, lower numbers are faster
int decel = 60; //Speed to decelerate, lower numbers are faster
int accraw = 150; // Speed to accelerate, lower numbers are faster
int decraw = 60; //Speed to decelerate, lower numbers are faster
int inversion = false; // inversion in progress = true
int valapresinv = 0;
static unsigned long lastAccelTime = 0; //declared static so that it stores values in between function calls, but no other functions can change its value
static unsigned long lastDecelTime = 0;
char cmd[1000];
int cmdIndex;
/*******************************************************************************
* FUNCTIONS *
*******************************************************************************/
void setup() { // at power on
delay(500); // wait for bluetooth module to start
pinMode(dirPin, OUTPUT);
digitalWrite(dirPin, LOW); //Low to high status changes direction
// pinMode(forwardPin, OUTPUT);
// digitalWrite(forwardPin, LOW);
// pinMode(backwardPin, OUTPUT);
// digitalWrite(backwardPin, LOW);
// Initialize the PWM and DIR pins as digital outputs.(upon reset)
pinMode(pinPwm, OUTPUT);
// pinMode(pinDir, OUTPUT);
// change Bluetooth module baud rate to 9600:
bluetooth.begin(115200); // Bluetooth default baud is 115200
bluetooth.print("$");
bluetooth.print("$");
bluetooth.print("$"); // enter cmd mode
delay(250);
bluetooth.println("U,9600,N"); // change baud to 9600
bluetooth.begin(9600);
cmdIndex = 0;
}
void exeCmd() {
if( cmd[0]=='f') {
if (vitesse == 0 ) {
digitalWrite(dirPin, !digitalRead(6)); // toggle direction on pin 6 if full stop
}
if( vitesse > 0 ) { // if train moving
inversion = true;
valapresinv = val; // store in memory to resume speed after inversion
val = 0; //start deceleration
}
}
if( cmd[0]=='v' &&
cmd[1]=='i' &&
cmd[2]=='t' &&
cmd[3]=='e' &&
cmd[4]=='s' &&
cmd[5]=='s' &&
cmd[6]=='e' &&
cmd[7]==' ') {
String cmdStr;
String valueStr;
cmdStr = String(cmd);
valueStr = cmdStr.substring(8);
val = valueStr.toInt(); // target speed value 0-255 from bluetooth
inversion = false;
}
if( cmd[0]=='r') { // r for reglage
String cmdStr;
String valueStr;
cmdStr = String(cmd);
valueStr = cmdStr.substring(1);
accraw = valueStr.toInt(); // target inertal acceleration value 0-9 from bluetooth
accel = 20 * accraw;
decel = 20 * accraw;
}
if( cmd[0]=='a') { // stop - arret
analogWrite(pinPwm, 0); //emergency stop
val = 0;
vitesse = 0;
}
}
void loop() {
if(bluetooth.available()) {
char c = (char)bluetooth.read();
cmd[cmdIndex] = c;
if(cmdIndex<99) cmdIndex++;
if(c=='\n') { // each command ends with '\n'
exeCmd();
cmdIndex = 0;
}
}
unsigned long currentTime = millis();
// ****Acceleration****
if (currentTime - lastAccelTime > accel) {
lastAccelTime = currentTime;
if (vitesse < val) {
vitesse++;
analogWrite(pinPwm, vitesse);
}
}
// ****Deceleration****
if (currentTime - lastDecelTime > decel) {
lastDecelTime = currentTime;
if (vitesse > val) {
vitesse = vitesse / 1.01;
analogWrite(pinPwm, vitesse);
}
}
//inertial invertion upon reverse request in "void exeCmd"
if ((inversion == true) && (vitesse == 0)) { //when deceleration completes...
digitalWrite(dirPin, !digitalRead(6)); // toggle direction on pin 6 after full deceleration before resuming reverse speed
val = valapresinv; //resume previous speed
inversion = false; //reset inversion & continue acceleration
}
}
99>
This page is describing the construction of an Arduino-based electric device and program i created. I could not find a proper/cheap solution that fitted my needs to remotely control speed and direction of a G-scale train pulling my 10 month old on a homemade G-scale flat car (picture below).
It is perfect too for any type of mobile control of a DC train outside or inside (range +/-100m).
The flat car with dolls enjoying the ride.
This is based on special ball bearings mounted wheels and homemade steel trucks to accomodate the always heavier baby. Note the truck-car attachment s also made with ball bearings to limit side wiggeling.
------------------------------------------------------------------------------------
2- the deviceParts needed:
- Pcb board with holes ready to solder
- Female plugs : 2.54mm single row female pitch header socket connector (ebay) (for arduino nano on pcb)
- 2 position switch for invertion of track power (manual toggle, the software also inverts it!)
Electronics:
- Arduino nano (or uno or mega)(ebay)
- Md10c (Cytron 13A, 5-30V Single DC Motor Controller) (14$ ebay)
- Bluetooth Modem - BlueSMiRF Silver (silver or gold) (25$ amazon or ebay)
- 5vdc regulator 7805 (ebay) + heat sink (or piece of metal and a screw)
- 6A diode (A6A)
- 1 A diode 1n 4007 (ebay by 100pcs)
- 470uf capacitor
- Terminals for pcb (ebay)
- 100nf capacitor
- LED of your choice
- 470 ohm 1/4 W resistor
- plastic box (Lowes)
- soldering iron
- 4h of your time
-----------------
Manuals:
-how to program the bluetooth module on arduino:
https://learn.sparkfun.com/tutorials/using-the-bluesmirf
-How to configure ROBOREMO on android phone:
https://www.roboremo.com/arduino-bluetooth-dc-motor-speed.html
Arduino Nano and Bluesmirf power board:
Note: the only PMW compatible pins of the arduino nano are the following 3, 5, 6, 9, 10, 11. If changes are done to the pin output, make sure you use those pins for PMW.
This PCB board connects 3 modules : the arduino nano, the Sparkfun Bluesmirf modules and the DC motor controller module MD10C
This board can also be used to configure the Bluesmirf with the arduino using the program present on the sparkfun link above (the Tx and RX ports common to the USB ports are not used here).
---------------------------
3- The program
Beta version of the arduino program is below.
A version with inertial support is not yet ready. Make the below text " .ino" and load it in Arduino IDE program.
Arduino program v0.4 (speed+ direction only):
//created by Maxime G. Cuypers on 23-fev-2018 for Jamie s train control by bluetooth with roboremo
//adaptated from rc car control sketch for direction control
//adaptated from MD10c sketches to control pmw
//bluetooth module Bluesmirf gold
* AUTHOR : Maxime Cuypers
* COMPANY : private
* REVISION : 0.4
* DATE : 26/04/2021
********************************************************************************/
//v0.4 has inertial acceleration and deceleration, full smooth automatic reverse, emergency stop.
#include <SoftwareSerial.h>
/*******************************************************************************
* IO DEFINITION *
*******************************************************************************/
//setup bluetooth bluesmirf port
int bluetoothTx = 2; // TX-O pin of BT module to Arduino pin2
int bluetoothRx = 3; // RX-I pin of B module to Arduino pin3
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
//const = variable "read-only".
const int pinPwm = 5; // PWM is connected to pin 5.
const int dirPin = 6; //direction signal connected to pin 6.
/*******************************************************************************
* PRIVATE GLOBAL VARIABLES *
*******************************************************************************/
int val = 0; //Desired speed value
int vitesse = 0; //Actual speed train runs
int accel = 150; // Speed to accelerate, lower numbers are faster
int decel = 60; //Speed to decelerate, lower numbers are faster
int accraw = 150; // Speed to accelerate, lower numbers are faster
int decraw = 60; //Speed to decelerate, lower numbers are faster
int inversion = false; // inversion in progress = true
int valapresinv = 0;
static unsigned long lastAccelTime = 0; //declared static so that it stores values in between function calls, but no other functions can change its value
static unsigned long lastDecelTime = 0;
char cmd[1000];
int cmdIndex;
/*******************************************************************************
* FUNCTIONS *
*******************************************************************************/
void setup() { // at power on
delay(500); // wait for bluetooth module to start
pinMode(dirPin, OUTPUT);
digitalWrite(dirPin, LOW); //Low to high status changes direction
// pinMode(forwardPin, OUTPUT);
// digitalWrite(forwardPin, LOW);
// pinMode(backwardPin, OUTPUT);
// digitalWrite(backwardPin, LOW);
// Initialize the PWM and DIR pins as digital outputs.(upon reset)
pinMode(pinPwm, OUTPUT);
// pinMode(pinDir, OUTPUT);
// change Bluetooth module baud rate to 9600:
bluetooth.begin(115200); // Bluetooth default baud is 115200
bluetooth.print("$");
bluetooth.print("$");
bluetooth.print("$"); // enter cmd mode
delay(250);
bluetooth.println("U,9600,N"); // change baud to 9600
bluetooth.begin(9600);
cmdIndex = 0;
}
void exeCmd() {
if( cmd[0]=='f') {
if (vitesse == 0 ) {
digitalWrite(dirPin, !digitalRead(6)); // toggle direction on pin 6 if full stop
}
if( vitesse > 0 ) { // if train moving
inversion = true;
valapresinv = val; // store in memory to resume speed after inversion
val = 0; //start deceleration
}
}
if( cmd[0]=='v' &&
cmd[1]=='i' &&
cmd[2]=='t' &&
cmd[3]=='e' &&
cmd[4]=='s' &&
cmd[5]=='s' &&
cmd[6]=='e' &&
cmd[7]==' ') {
String cmdStr;
String valueStr;
cmdStr = String(cmd);
valueStr = cmdStr.substring(8);
val = valueStr.toInt(); // target speed value 0-255 from bluetooth
inversion = false;
}
if( cmd[0]=='r') { // r for reglage
String cmdStr;
String valueStr;
cmdStr = String(cmd);
valueStr = cmdStr.substring(1);
accraw = valueStr.toInt(); // target inertal acceleration value 0-9 from bluetooth
accel = 20 * accraw;
decel = 20 * accraw;
}
if( cmd[0]=='a') { // stop - arret
analogWrite(pinPwm, 0); //emergency stop
val = 0;
vitesse = 0;
}
}
void loop() {
if(bluetooth.available()) {
char c = (char)bluetooth.read();
cmd[cmdIndex] = c;
if(cmdIndex<99) cmdIndex++;
if(c=='\n') { // each command ends with '\n'
exeCmd();
cmdIndex = 0;
}
}
unsigned long currentTime = millis();
// ****Acceleration****
if (currentTime - lastAccelTime > accel) {
lastAccelTime = currentTime;
if (vitesse < val) {
vitesse++;
analogWrite(pinPwm, vitesse);
}
}
// ****Deceleration****
if (currentTime - lastDecelTime > decel) {
lastDecelTime = currentTime;
if (vitesse > val) {
vitesse = vitesse / 1.01;
analogWrite(pinPwm, vitesse);
}
}
//inertial invertion upon reverse request in "void exeCmd"
if ((inversion == true) && (vitesse == 0)) { //when deceleration completes...
digitalWrite(dirPin, !digitalRead(6)); // toggle direction on pin 6 after full deceleration before resuming reverse speed
val = valapresinv; //resume previous speed
inversion = false; //reset inversion & continue acceleration
}
}
99>
No comments:
Post a Comment