Arduino analoge treinsturing.

Projecten die niet passen in bovenstaande onderwerpen
Berichten: 5
Geregistreerd: 13 Jan 2014, 23:29

Arduino analoge treinsturing.

Berichtdoor smits66 » 08 Nov 2014, 01:20

Hoi forum leden

Ik ben nieuw op dit forum en wil me even voorstellen, mijn naam is Paul Smits,
47 jaar en woon in Den Haag.

Ik ben al een tijdje aan het stoeien met de Arduino.

Ik probeer met de Arduino UNO een analoge modelspoor sturing te ontwerpen met de volgende functies.

Voor nu:

Twee blokken in vrij of bezet te melden (later wil ik meer blokken hebben)
Twee treinen te laten rijden met optrek en rem vertraging (niet tegelijk)
Noodstop trein sturing.

Het programma wat ik heb geschreven werkt wel maar is naar mijn idee een beetje dubbel geprogrammeerd, ook krijg ik de optrek en rem vertraging niet goed werkend zonder het delay commando te gebruiken.

Ik heb het mill() commando proberen te gebruiken, ik krijg het niet werkend.

Het is de bedoeling dat de trein gaat rijden in drie stappen en tussen elke stap moet er 2 a 3 seconden gewacht worden voor de trein een stap sneller gaat rijden, dit geld ook voor de rem vertraging.

Ik kan er zelf even niet uit komen, hebben jullie er nog handige tips/code voor mij die evt. kunnen helpen.

Mvg Paul Smits

Het Arduino programma:
Code: Alles selecteren
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

/***** Global vars ***********************************************/


// Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN     3

LiquidCrystal_I2C   lcd(0x27,2,1,0,4,5,6,7); // adressering lcd display

char incomingByte;

/******************************************************************************
 * Definitions
 ******************************************************************************
 *motor A is aangesloten op OUT1 en OUT2 van de motorsturing
 *motor B is aangesloten op OUT3 en OUT4 van de motorsturing
 ******************************************************************************/

const char StringMotorA[] = "motor A: ";
const char StringMotorB[] = "motor B: ";
const char StringFull[] = "full";
const char StringHalf[] = "half";
const char StringLow[] = "low";
const char StringSpeed[] = " speed";

// constants won't change. Used here to
// set pin numbers:

const int ledPin =  13; // Pin nummer LedPin
const int blok1Pin = 6; // Pin nummer Blok 1
const int blok2Pin = 7; // Pin nummer Blok 2

int Interval = 500;
//int wachtTrein = 3000;
//int BlokVrij = 10000; //automatische mode 10 seconden voor het blok vrij gegeven word.
int tijd = 2000;

// Variables will change:

//Motor A

int PWMA = 3; //Speed control
int AIN1 = 9; //Direction
int AIN2 = 8; //Direction

//Motor B

int PWMB = 5; //Speed control
int BIN1 = 11; //Direction
int BIN2 = 12; //Direction

int ledState = LOW;             // ledState used to set the LED
int wachtState = LOW;
int blokState = LOW;

long previousMillis = 0;        // will store last time LED was updated
//long previousMillisWacht = 0;       
//long previousMillisBlok = 0;

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.

//long interval = 500;           // interval at which to blink (milliseconds)

void setup(){

  lcd.begin (16,2);

  // Switch on the backlight

  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home ();                   // go home

  // Print a message to the LCD.

  lcd.setCursor(2,0); //Start at character 2 on line 0
  lcd.print("Arduino Uno");
  lcd.setCursor(1,1);
  lcd.print("L298  M-Sturing");

  Serial.begin(9600);

  Serial.println("Arduino test programma : Motorsturingen en blok meldingen");

  menu();

  // Set all the pins we need to output pins
  // pinMode(STBY, OUTPUT);

  pinMode(PWMA, OUTPUT);
  pinMode(AIN1, OUTPUT);
  pinMode(AIN2, OUTPUT);

  pinMode(PWMB, OUTPUT);
  pinMode(BIN1, OUTPUT);
  pinMode(BIN2, OUTPUT);

  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(ledPin, OUTPUT);
}

void loop (){

  // Controlle led om te zien of het programma nog werkt.

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > Interval) {

    // save the last time you blinked the LED

    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:

    digitalWrite(ledPin, ledState);

  }

  if (Serial.available()) {

    //read serial as a character
    //char ser = Serial.read();

    if (Serial.available() > 0) {  // kijk of de seriele verbinding beschikbaar is.
      incomingByte = Serial.read(); // Lees een 'byte'.
    }

    // Begin Taak 1: Blok1 vrij

    if(incomingByte == '1') {
     
      lcd.home ();
      lcd.setCursor(0,1);
      lcd.print("Blok 1: vrijgave");
     
      Serial.println("Blok 1 : Vrij");
      digitalWrite(blok2Pin, HIGH);

      menu();
      prompt();   

    }

    // Einde Taak 1: Blok1 vrij 

    // Begin Taak 2: Blok 1 bezet 

      if(incomingByte == '2') {
     
       lcd.print("Blok 1: vrijgave");
       
      Serial.println("Blok 1 : Bezet");
      digitalWrite(blok2Pin, LOW);

      menu();
      prompt(); 

    }

    // Einde Taak 2: Blok 1 Bezet 

    // Begin Taak 3: Motor B aan

    if(incomingByte == '3') {
     
      lcd.home ();
      lcd.setCursor(1,1);
      lcd.print("   Speed low    ");
     
      Serial.println("Trein B: Low speed");
     
      move(1, 120, 1); //motor B, low speed, links
      schakeltijd();
     
      lcd.home ();
      lcd.setCursor(1,1);
      lcd.print("   Speed half   ");
     
      Serial.println("Trein B: Half speed");
     
      move(1, 150, 1); //motor B, half speed, links
      schakeltijd();
     
      lcd.home ();
      lcd.setCursor(1,1);
      lcd.print("   Speed full   ");
     
      Serial.println("Trein B: Full speed");
     
      move(1, 200, 1); //motor B, full speed, left
     
      Serial.println("Trein B rijd op full speed totdat er een stop comando komt.");

      menu();
      prompt();

    }

    // Einde Taak 3: Motor B on     

    // Begin Taak 4: Motor B off

    if(incomingByte == '4') {
     
     
      Serial.println("Trein B: Half speed");
     
      displ();
      lcd.print("   Speed half   ");

      move(1, 150, 1); //motor B, half speed, links
      schakeltijd();
     
      Serial.println("Trein B:  Low speed");
     
      displ();
      lcd.print("   Speed low   ");
     
      move(1, 120, 1); //motor B, low speed, links
      schakeltijd();
     
      Serial.println("Trein B: Stop");

      move(1, 0, 0); //motor B, stop

      Serial.println("Motor B staat stil omdat er een stop comando gegeven is.");

      displ();
      lcd.print("  trein stopt  ");
     
      menu();
      prompt();

    }
    // Einde Taak 4: Motor B off

    // Begin Taak 5 : Blok 2 On

    if(incomingByte =='5'){ 

      Serial.println("Blok 2 Vrij");
      digitalWrite(blok1Pin, HIGH);

      menu();
      prompt(); 

    }

    // Einde Taak 5 : Blok On

    // Begin Taak 6: Blok 2 Off

    if(incomingByte == '6') {

      Serial.println("Blok 2 Bezet");
      digitalWrite(blok1Pin, LOW);

      menu();
      prompt(); 

    }

    // Einde Taak 6: Blok 2 bezet

    // Begin Taak 7: Motor A On

    if(incomingByte == '7') {

      Serial.println("Trein A gaat vertrekken");
      Serial.println();
      Serial.println("Trein A: Low speed");
      lcd.print("   Speed low   ");
     
      move(0, 120, 1); //motor A, low speed, rechts
      schakeltijd();
     
      Serial.println("Trein A: Half speed");
      lcd.print("   Speed half   ");

      move(0, 150, 1); //motor A, half speed, rechts
      schakeltijd();
     
      Serial.println("Trein A: Full speed");
      lcd.print("   Speed full   ");

      move(0, 200, 1); //motor A, full speed, rechts

      Serial.println("Trein A rijd op full speed totdat er een stop comando komt.");

      menu();
      prompt();

    }

    // Einde Taak 7: Motor A on 

    // Begin Taak 8: Motor A Off

    if(incomingByte == '8') {

      Serial.println("Trein gaat stoppen");
      Serial.println("Trein A: Half speed");
      lcd.print("   Speed half   ");
     
      move(0, 170, 1); //motor A, half speed, rechts
      schakeltijd();
     
      Serial.println("Trein A:  Low speed");
      lcd.print("   Speed low   ");
     
      move(0, 120, 1); //motor A, low speed, rechts
      schakeltijd();
     
      Serial.println("Trein A: Stop");
      Serial.println("Trein A is gestopt omdat er een stop comando gegeven is.");
     
      move(0, 0, 0); //motor A, stop
     
      menu();
      prompt();

    }

    // Einde Taak 8: Motor B off

    // Begin Taak 9 : Noodstop

    if(incomingByte == '9') {

      Serial.println("Noodstop :Treinen A+B stop en blok 1+2 bezet");

      menu();
      noodstop();
      prompt();

      Serial.println("Trein 1 noodstop");
      Serial.println("Trein 2 noodstop");

      digitalWrite(blok1Pin, LOW);

      Serial.println("Blok 1: Bezet");

      digitalWrite(blok2Pin, LOW);

      Serial.println("Blok 2: Bezet");
     
      displ();
     
      lcd.print("Noodstop gemaakt");

      // Einde Taak 9 : Noodstop

    }
  }
}

void move(int motor, int speed, int direction){

  //Move specific motor at speed and direction
  //motor: 0 for B 1 for A
  //speed: 0 is off, and 255 is full speed
  //direction: 0 clockwise, 1 counter-clockwise

  boolean inPin1 = LOW;
  boolean inPin2 = HIGH;

  if(direction == 1){
    inPin1 = HIGH;
    inPin2 = LOW;

  }

  else{
    if(direction == 0) 
      inPin1 = LOW;
    inPin2 = HIGH;

  }

  if(motor == 1){
    digitalWrite(AIN1, inPin1);
    digitalWrite(AIN2, inPin2);
    analogWrite(PWMA, speed);

  }

  else{
    digitalWrite(BIN1, inPin1);
    digitalWrite(BIN2, inPin2);
    analogWrite(PWMB, speed);

  }
}

void noodstop(){

  //Motor A en B stoppen

  move(1, 0, 0);// motor A stop
  move(0, 0, 0);// motor B stop

}

void displ(){

  lcd.home ();                   // go home
  lcd.setCursor(1,1);
 
}

void schakeltijd(){

  delay(tijd);

}

void menu(){


  Serial.println();
  Serial.println("Stuur comando's");
  Serial.println();
  Serial.println("1 = Blok 1 vrijgeven            5 = Blok 2 vrijgeven");
  Serial.println("2 = Blok 1 bezet melden         6 = Blok 2 bezet melden");
  Serial.println("3 = Motor A starten             7 = Motor B starten");
  Serial.println("4 = Motor A stoppen             8 = Motor B stoppen");
  Serial.println("< = Motor linksom               > = Motor rechtsom");
  Serial.println();
  Serial.println("9 = Motoren A en B stoppen en blok 1 en 2 bezet melden");
  Serial.println();

}

void prompt(){

  Serial.println();
  Serial.println("Volgende comando >");
  Serial.println();

}

 

Advertisement

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: Arduino analoge treinsturing.

Berichtdoor nicoverduin » 08 Nov 2014, 13:56

Op zich is de code zo gek nog niet. Paar tips:
a) ik zou de behandeling van iedere commando in een aparte functie zetten zodat je meer overzicht krijgt en de "mainline" compact blijft
b) ik zou switch case gebruiken ipv. if.

En dan voor wat betreft het gebruik van millis(). Je hebt 2 situaties:
a) je bent nog bezig om een opdracht af te maken (bijvoorbeeld ff wachten).
b) je bent vrij om een nieuwe opdracht op te halen.

Ad b:
Je moet bijhouden een soort Busy flag (bool) die als deze true is, de serial leest en de waarde opslaat (min of meer zoals je nu doet). Zodra er een commando is ontvangen zet je de busy vlag op true.

Ad a:
als de busy vlag aanstaat moet je de switch case aflopen. Is het commando afgewikkeld zet je de busy flag weer op false. en zal hij bij de volgende loop weer een opdracht proberen binnen te halen.

Stel je begint aan een stukje code uit de switch case:

cpp code
case 3:
if (eersteKeer) {
timer = millis();
eersteKeer = false;
}
if (timer != 0){
if (timer - millis() > INTERVAL) {
//
// de tijd is verstreken dus doe iets
//
........
//
// zet de timer op 0 zodat hij hier niet meer kijkt
//
timer = 0;
}
} else {
//
// we zijn helemaal klaar met de opdracht dus zet eersteKeer voor een evt. volgende opdracht
//
eersteKeer = true;
busy = false;
incomingByte = 0;
}
break;

etc
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 4068
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Arduino analoge treinsturing.

Berichtdoor shooter » 08 Nov 2014, 21:14

Ik moet allereerst nico gelijk geven, met alle opmerkingen, switch case is hier veel slimmer.
Op arduino.cc nederlands zag ik ook iemand bezig met een simpele opzet wellicht is samenwerking handig.
Ik ga wel uit van een DC systeem, Marklin is een stuk moeilijker omdat de richting niet vastligt)
Om straks te kunnen uitbreiden volgende opmerkingen:

Je hebt 6 PWM uitgangen, die geef je elk een naam dus PWM1, PWM2 etc.

In een analoge baan is het veel slimmer om de sporen te voeden, met betreffende pwmsignalen en die los te zien van de locomotieven.
(straks komt daar nog een opmerking over.

Dat wil zeggen bijv. je hebt minimaal 4 blokken nodig en een inhaalspoor.
de beide stationssporen krijgen natuurlijk ieder hun eigen pwm, het hoofdspoor krijgt een pwm tot een eind voor het inrijsein, dat wordt dan blok4.

vertrek
Als je een bijv het inhaalspoor wilt laten vertrekken, dan zet je het sein op groen en de rijrichtingrelais goed. dan start je de PWM op van spoor1, het hoofdspoor (en de wissel) laat je dan meeoplopen.
if accelarationtimer is afgelopen dan stapje sneller tot maxspeed natuurlijk.
als spoor 1 leeg is dan kun je sneller want dan is trein van wissel af.

aankomst
Als er een trein het inrijsein voorbij rijdt, dan ga je langzamer rijden geleidelijk, zorg ervoor dat als de locomotief het perron bereikt dat de snelheid laag is, dan langzaam tot het sein en stoppen.

Snelheid is simpel het PWM signaal naar een dikke FET sturen (en een diode natuurlijk)
versnellen door na een wachtijd van bijv 100 ms de snelheid aan te passen, dan kan het 25 seconden duren voor je op max zit.
stel ook een minimum in waarbij de trein begint te rijden, is vaak ook een mooi punt om de trein langzaam te laten doorrollen.
En nu komt dan die opmerking dat kan voor elke locomotief anders zijn, en dus zul je de regelaar moeten vertellen welke loc op welk spoor staat.

Als je later uitbreidt zal het nodig zijn om elk spoor zijn eigen voorziening te geven, dat is het handigste te doen met een stel relais, of handschakelaars.
Rijrichting is een ander probleem, dat kan met een relais bij iedere FET, of een elektronica ding (Bij HO wel 2 Ampere)
Je kunt dus zonder extra dingen max 6 treinen tegelijk regelen. (daarnaast kun je natuurlijk nog de wisselschakelaars, seinschakelaars en handschakelaars gebruiken om meerdere locomotieven op het spoor te zetten, maar niet te besturen.

Die states is leuk, maar dat betekent dat je maar een trein tegelijk kunt besturen, en dat is niet leuk, dus je moet dat anders aanpakken. Elke PWM krijgt zijn eigen stateprogramma mee.
die staan dus niet in de loop maar allemaal in functies (net zoals je al gedaan had voor je move maar niet voor de watchdog)
die move instructie alleen gebruiken als er iets verandert.
Probeer elke functie en dus ook de loop op een pagina te laten passen.
Om dat verhaal met 0 en 1 op te lossen mag je ook define gebruiken dan zeg je bijvoorbeeld motorA=0.
dan kun je in je programma ipv 0 gewoon motora schrijven.
Maak in fritzing een elektrisch schema hoe het in elkaar zit.
en natuurlijk een schema van de sporen.
Je moet wel iets doen aan kortsluiting die op de wissels ontstaat, de elektronica kan er niet goed tegen.

Vragen staat natuurlijk vrij. (ik rij zelf met Z gelijkstroom) (nog niet met arduino maar dat komt er zeker van, als ik tijd heb)
voor vandaag weer genoeg.
paul deelen
shooter@home.nl

Berichten: 5
Geregistreerd: 13 Jan 2014, 23:29

Re: Arduino analoge treinsturing.

Berichtdoor smits66 » 09 Nov 2014, 15:01

Hoi,

@Nico

Bedankt voor het meedenken.

Ik ben nog niet zo lang bezig met de Arduino, de case functie ben ik wel tegengekomen, maar heb er nooit mee gewerkt, ik weet ook niet hoe ik een seriele commando kan geven om een case functie te gebruiken.

Met welk commando, om de case functie te gebruiken met de seriele communicatie, moet ik gebruiken.

@Paul

Bedankt voor het meedenken.

Dat is een lang verhaal, zover heb ik nog niet gedacht, voor mij was het belangrijk dat de treinsturing werkt om zo het programma te kunnen verbeteren en er meer functies in te kunnen bouwen.

Dit is mijn eerste project met een Arduino, ik weet er nog niet zoveel van.

Deze sturing wil ik gaan gebruiken op mijn eigen modelbaan.

Ik Gebruik voor de sturing de volgende componenten :

Arduino Uno
Tweevoudig relais kaart
Een L298 motorsturing kaart
Een i2c lcd display

Ik zal even kijken of ik er een foto van op het forum kan zetten.


Mvg Paul Smits

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: Arduino analoge treinsturing.

Berichtdoor nicoverduin » 09 Nov 2014, 16:38

smits66 schreef:Hoi,

@Nico

Bedankt voor het meedenken.

Ik ben nog niet zo lang bezig met de Arduino, de case functie ben ik wel tegengekomen, maar heb er nooit mee gewerkt, ik weet ook niet hoe ik een seriele commando kan geven om een case functie te gebruiken.

Met welk commando, om de case functie te gebruiken met de seriele communicatie, moet ik gebruiken.


Dat doe je toch al?
cpp code
if (Serial.available()) {

//read serial as a character
//char ser = Serial.read();

if (Serial.available() > 0) { // kijk of de seriele verbinding beschikbaar is.
incomingByte = Serial.read(); // Lees een 'byte'.
}
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 5
Geregistreerd: 13 Jan 2014, 23:29

Re: Arduino analoge treinsturing.

Berichtdoor smits66 » 09 Nov 2014, 17:45

Hoi Nico,

Je geeft aan in een vorig bericht dat ik beter geen if functie kan gebruiken.

In dit stukje programma lees ik een seriele code '1' in, die ik vervolgens in een if functie zet en er daar een actie word ondernomen.
Hoe zet ik dit om in een case functie?

Code: Alles selecteren

  if (Serial.available()) {

    //read serial as a character
    //char ser = Serial.read();

    if (Serial.available() > 0) {  // kijk of de seriele verbinding beschikbaar is.
      incomingByte = Serial.read(); // Lees een 'byte'.
    }

    // Begin Taak 1: Blok1 vrij

    if(incomingByte == '1') {
     
      lcd.home ();
      lcd.setCursor(0,1);
      lcd.print("Blok 1: vrijgave");
     
      Serial.println("Blok 1 : Vrij");
      digitalWrite(blok2Pin, HIGH);

      menu();
      prompt();   

    }

 


Mvg Paul Smits

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: Arduino analoge treinsturing.

Berichtdoor nicoverduin » 09 Nov 2014, 18:02

Je hebt mij verkeerd begrepen. Natuurlijk moet je if's gebruik daar waar dat nodig is.
Als je echter een keuze moet maken uit meerdere mogelijkheden is het handiger en leesbaarder om switch case te gebruiken. daarnaast is het ook wat sneller. Nu loop/test je elke if af ook al is dat voor 90% niet nodig.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 5
Geregistreerd: 13 Jan 2014, 23:29

Re: Arduino analoge treinsturing.

Berichtdoor smits66 » 09 Nov 2014, 18:09

Hoi, nico

Ik ben er nog even mee bezig geweest en ben tot de volgende oplossing gekomen?

Code: Alles selecteren

void loop() {
 
  if (Serial.available() > 0) {
    int incomingByte = Serial.read();
   
    switch (incomingByte) {
     
    case '1': 
   
      lcd.home ();
      lcd.setCursor(0,1);
      lcd.print("Blok 1: vrijgave");
     
      Serial.println("Blok 1 : Vrij");
      digitalWrite(blok2Pin, HIGH);

      menu();
      prompt();   

      break;
     
    case '2':   
   
      lcd.home ();
      lcd.setCursor(0,1);
      lcd.print("Blok 1: bezet");
     
      Serial.println("Blok 1 : Bezet");
      digitalWrite(blok2Pin, HIGH);

      menu();
      prompt();   
     
      break;
    }
  }
}
   
    //enz.

 


Zo zou het moeten werken denk ik, ik heb het nog niet getest, dan moet ik eerst mijn programma aanpassen

Gaat het zo werken ?

Mvg Paul Smits
Laatst gewijzigd door smits66 op 09 Nov 2014, 18:25, in totaal 1 keer gewijzigd.

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: Arduino analoge treinsturing.

Berichtdoor nicoverduin » 09 Nov 2014, 18:22

volgens mij wel..... functioneel geen idee maar technisch in de goede richting. Als je altijd aan het eind menu() en prompt() doet zou je die na de switch case kunnen doen bijvoorbeeld
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 4068
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Arduino analoge treinsturing.

Berichtdoor shooter » 11 Nov 2014, 16:03

en zo stap voor stap, eerst maar eens een trein heen en weer laten gaan op kommando 1 en 2.
einden beveiligen met diodes.
paul deelen
shooter@home.nl

Volgende

Terug naar Overige projecten

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 11 gasten