Om de snelheid van de treintjes te kunnen veranderen is een rijregelaar nodig. Ergens heb ik de hier beschreven regelaar gevonden (hier dus): maakt gebruik van PWM (zie ook hier) op de Weistra-manier. Dit principe wordt hier goed uitgelegd.

Een Arduino Nano wekt aan de hand van de stand van potmeter 1 een pwm-signaal met een hogere (harder) dan wel lagere (langzamer) frequentie op. Het signaal wordt via de L298-module (dubbele H-brug motor driver) naar de rails gevoerd.

Met potmeter 2 en 3 is de maximum en minimum snelheid aan te passen. Hieronder de door mij volledig gepikte Arduino sketch.
#include "src/macros.h"
#include "src/weistra.h"
#include "src/stateMachineClass.h"
#include "config.h"
int setPoint ;
int prevSetPoint ;
uint8_t brakeSensor ;
uint8_t lastDir ;
int8_t brakeSpeed ;
int8_t currentSpeed ;
StateMachine sm ;
enum states
{
runMode,
braking,
departing,
} ;
Weistra pwm( in1, in2, Fmin, Fmax ) ;
uint8_t hasMaxSpeedPot ;
uint8_t hasMinSpeedPot ;
uint8_t hasAccelPot ;
uint8_t hasWaitPot ;
uint8_t hasShuttleSerice ;
void setup()
{
pwm.begin() ;
pwm.setCurrentSense( currentSensePin, currentLimit ) ;
sm.setState(runMode);
Serial.begin(115200);
Serial.println("Weistra_pwmController.ino");
// for following 3 pins, I enable pullups and I take a sample, if the sample is < then 1023, I know a potentiometer is attached
pinMode( maxSpeedPin, INPUT_PULLUP ) ;
pinMode( minSpeedPin, INPUT_PULLUP ) ;
pinMode( accelFactorPin, INPUT_PULLUP ) ;
pinMode( waitTimePin, INPUT_PULLUP ) ;
delay(1);
int sample ;
sample = analogRead( maxSpeedPin ) ;
if( sample < 1020 )
{
pinMode( maxSpeedPin, INPUT ) ;
hasMaxSpeedPot = 1 ;
} else Serial.println("no max speed pot");
delay(1);
sample = analogRead( minSpeedPin ) ;
if( sample < 1020 )
{
pinMode( minSpeedPin, INPUT ) ;
hasMinSpeedPot = 1 ;
} else Serial.println("no min speed pot");
delay(1);
sample = analogRead( accelFactorPin ) ;
if( sample < 1020 )
{
pinMode( accelFactorPin, INPUT ) ;
hasAccelPot = 1 ;
}else Serial.println("no accel/brake pot");
delay(1);
sample = analogRead( waitTimePin ) ; // used for adjustable time delay.
if( sample < 1020 )
{
pinMode( waitTimePin, INPUT ) ;
hasWaitPot = 1 ;
hasShuttleSerice = 1 ;
} else Serial.println("no wait time pot");
pinMode( S1, INPUT_PULLUP ) ;
pinMode( S2, INPUT_PULLUP ) ;
}
void loop()
{
pwm.update() ;
control() ;
// read main speed potentiometer
REPEAT_MS( accelerationFactor )
{
setPoint = analogRead( speedPin ) ;
// sample 0 512-50 512 512+50 1023
// speed -100 <-> 0 0 0 <-> 100 // dead zone in middle
if( setPoint <= (512-50)) setPoint = map( setPoint, 0, 512-50, -maxSpeed, minSpeed ) ; // test me
else if( setPoint >= (512+50)) setPoint = map( setPoint, 512+50, 1023, minSpeed, maxSpeed ) ;
else setPoint = 0 ;
// if potentiometer changes, abort shuttle service at once (should discard sensors)?
if( setPoint != currentSpeed )
{
if( currentSpeed < setPoint ) currentSpeed ++ ;
if( currentSpeed > setPoint ) currentSpeed -- ;
if( currentSpeed > -minSpeed && currentSpeed < minSpeed )
{
pwm.setSpeed( 0 ) ;
}
else
{
pwm.setSpeed( currentSpeed ) ;
}
sm.nextState( runMode, 3000 ) ; // go to runmode and lockout sensor for 3 seconds
}
}
END_REPEAT
REPEAT_MS( 1000 ) // 1000ms sample rate suffices
{
int sample ;
if( hasMaxSpeedPot )
{
sample = analogRead( maxSpeedPin ) ;
maxSpeed = map( sample, 0, 1023, 20, 100 ) ;
}
if( hasMinSpeedPot )
{
sample = analogRead( minSpeedPin ) ;
minSpeed = map( sample, 0, 1023, 0, 30 ) ;
}
if( hasAccelPot )
{
sample = analogRead( accelFactorPin ) ;
accelerationFactor = map( sample, 0, 1023, 50, 5 ) ; // CHECK ME
}
if( hasWaitPot )
{
sample = analogRead( waitTimePin ) ;
waitTime = map( sample, 0, 1023, 5000, 60000 ) ; // 5-60 seconds
}
}
END_REPEAT
}
StateFunction( runMode )
{
if( digitalRead( S1 ) == 0 || digitalRead( S2 ) == 0 ) return 1 ;
return 0 ;
}
StateFunction( braking )
{
if( sm.entryState() )
{
brakeSpeed = currentSpeed ;
if( brakeSpeed < 0 ) lastDir = 1 ;
else lastDir = 0 ;
}
if( sm.onState() )
{
if( sm.repeat( accelerationFactor ) )
{
if( brakeSpeed < 0 ) brakeSpeed ++ ;
else if( brakeSpeed > 0 ) brakeSpeed -- ;
else sm.exit() ; // when speed is 0 exit
pwm.setSpeed( brakeSpeed ) ;
}
}
return sm.endState() ;
}
StateFunction( departing )
{
if( sm.repeat( accelerationFactor ) )
{
if( lastDir ) brakeSpeed -- ;
else brakeSpeed ++ ;
pwm.setSpeed( brakeSpeed ) ;
if( brakeSpeed == -maxSpeed
|| brakeSpeed == maxSpeed ) sm.exit() ;
}
return sm.endState() ;
}
uint8_t control()
{
STATE_MACHINE_BEGIN( sm )
{
State( runMode ) {
sm.nextState( braking, 0 ) ; }
State( braking ) {
sm.nextState( departing, waitTime ) ; }
State( departing ) {
sm.nextState( runMode , 8000 ) ; } // 8 seconds lockout for sensors
}
STATE_MACHINE_END( sm )
}
Naast bovenstaande .ino is er een config.h file waarin alle variabelen en constanten zijn opgenomen. Wel een overzichtelijke manier van werken!
#include <Arduino.h>
// maximum current
const int currentLimit = 10 ; // CHECK ME ADD CALCULATION
// used IO PINs
const int speedPin = A0 ;
const int currentSensePin = A1 ;
const int minSpeedPin = A2 ;
const int maxSpeedPin = A3 ;
const int accelFactorPin = A4 ;
const int waitTimePin = A5 ;
const int in1 = 10 ; // h brug
const int in2 = 11 ; // h brug
const int S1 = 3 ;
const int S2 = 4 ;
// PWM parameters
const int Fmin = 50 ;
const int Fmax = 100 ;
int accelerationFactor = 15 ;
int minSpeed = 10 ; // minimum speed. Slow trains start driving at higher throttle levers
int maxSpeed = 100 ; // may NOT be bigger than 100
// shuttle service station wait time
uint32_t waitTime = 30000 ; // 30 seconds

Zelfs op de lage snelheid loopt het locje heel mooi! Met de in een vorig deel beschreven snelheidsmeter gaan we in een volgend deel de snelheid meten! 🙂