Auteur Topic: Analoog rijden met geluid - het project.  (gelezen 73202 keer)

0 leden en 1 gast bekijken dit topic.

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Analoog rijden met geluid - het project.
« Gepost op: 28 april 2018, 22:04:45 »
Na alle experimenten met geluid aan boord is het tijd geworden een draadje te starten over het project

Analoog rijden met geluid


Het prototype van de geluid (en licht) module is in de railbus ingebouwd en werkt tot nu toe naar behoren. Hier een filmpje over het prototype en de introductie van het project.



Het geheel bestaat uit 2 onderdelen:
  • De pulsbreedte besturing.
    Deze is opgebouwd rond een Arduino met motorcontroller. Ik ben bezig een versie met een draaiknop (potmeter) in elkaar te zetten. Een bedradingsschema, de Arduino schets (programma) en bouwbeschrijving komt binnenkort.
  • De geluid/licht module aan boord. Deze bestaat uit een Arduino en MP3 speler (DFplayer)
    Ook hiervan komt t.z.t. een gedetailleerde beschrijving. Maar naast de hardware en software bestaat een flink deel van het werk uit het vinden en bewerken van de juiste geluidsfragmenten.

De belangrijkste reden om dit project te starten, en niet over te stappen op bijvoorbeeld een digitaal systeem, is de bestaande analoge verzameling aan locs en treinstellen. Met deze opstelling kunnen alle locs, met of zonder geluidsmodule, op hetzelfde systeem blijven rijden. Ombouw kan dus geleidelijk en tegen relatief lage kosten. Daarnaast vind ik het gewoon leuk een met elektronica, programmeren en geluidsbewerking te stoeien.

Alvast even een indicatie van de kosten. Deze worden sterk bepaald waar je spullen besteld (dichtbij is wat duurder, maar veel sneller dan spullen van tante Ali):
- pulsbreedtebesturing: 15 - 25 euro (relatief duur zijn de knopjes voor de 6 functietoetsen)
- geluidsmodule 10 - 20 euro per stuk
Bij de bouwbeschrijving komt een lijst met benodigde onderdelen en dan kunnen ook de kosten wat nauwkeuriger worden aangegeven.

Zoals in het introductiefilmpje al is aangekondigd, wordt de volgende geluidsmodule in een stoomtrein, de BR50, ingebouwd. Ik heb nog niet alle spullen uit China, maar ondertussen ben ik wel alvast begonnen met het zoeken naar de ruimte voor de componenten van de geluidsmodule in deze loc.



De opbouw van de geluidsmodule is afhankelijk van waar de spullen passen. De voeding op de Arduino is in ieder geval al iets compacter geworden dan het prototype ....

Volgende stap: de bouwbeschrijving van de pulsbreedtebesturing met draaiknop...

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Pierre

  • Super Modelspoorder
  • ******
  • Berichten: 7.918
  • Thanked: 334 times
  • Geslacht: Man
  • Woonplaats: Den Haag (Loosduinen)
    • Haagse Modelbouw Club
Re: Analoog rijden met geluid - het project.
« Reactie #1 Gepost op: 29 april 2018, 12:31:36 »
Ik blijf je vol spanning volgen en wachten op de schema's Rob. Mijn interesse is zeer zeker gewekt door je voor dit project. Top man! ;)
Groet Pierre.

Ik rommel wat met treintjes en bouwwerkjes in H0 (H0e) en ook een klein beetje in N  .... Scratchbuilding, kitbashing en weathering.  ;D Lid van de http://haagsemodelbouwclub.nl/

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #2 Gepost op: 30 april 2018, 18:50:50 »
Dank je, Pierre.
Voor het eerste deel zal ik je niet heel veel langer in spanning laten. Ik ben aardig aan het friemelen geweest om het experimentele gebeuren, dat vooral met proberen tot stand gekomen, om te zetten naar iets reproduceerbaars. Dat is ondertussen gelukt (onder meer door de draadjes van het probeer-spoor vast te solderen!). Aansluitschema, code en filmpje volgt snel.
Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #3 Gepost op: 30 april 2018, 20:46:25 »
De pulsbreedte besturing
Met pulsbreedte besturing kan analoog worden gereden en zijn er mogelijkheden voor geluid aan boord van de treinen. Ook zonder geluid is deze besturing te gebruiken voor analoge treinen. Het voordeel is dat (langzaam) rijden beter gaat.

In dit bericht een filmpje over de bediening van de pulsbreedtebesturing, het aansluitschema, de code voor de Arduino, een stuklijst en wat aanwijzingen voor de opbouw.

Bediening

Hoe het een en ander in de praktijk werkt, is te zien in dit filmpje.



Aansluitschema

Voeding, motorcontroller, Arduino en de bediening wordt als volgt aangesloten.




De ingang van de besturing neemt elke gelijk of wisselspanning tussen 5 en 35 V, dus ook een conventionele treintrafo voldoet. Belangrijk is dat de trafo niet te sterk is; het is de bedoeling dat de spanning 'dipt' als er kortsluiting op de baan ontstaat. Een trafo van rond de 35 Watt (VA) is prima.
De gelijkrichter zorgt er voor dat de ingangstroom altijd goed op de step up/down print komt. Deze is ingeregeld op een uitgangsspanning van 11,5 V. Let op: Deze spanning moet worden ingeregeld voor de rest wordt aangesloten (bij mij was de uitgang 20V af fabriek, en dat is meer dan de Arduino aan kan).
De voeding levert stroom aan de motorcontroller (en daarmee ook aan de trein) en aan de V-IN van de Arduino. De Arduino heeft een ingebouwde uitgang voor een gestabiliseerde 5V, waarmee de potmeter als 'spanningsdeler' naar de massa wordt aangesloten.
De stand van de potmeter wordt uitgelezen op de analoge ingang A7. Deze wordt omgerekend naar een puls voor de rijstroom op 'analoge' uitgangen D09 en D10 van de Arduino. Deze zijn verbonden met de aansturing van de motorcontroller (een pin voor elke richting).
Verder zijn 6 druktoetsen op pinnen A0-A5 verbonden met de massa, dit zijn de functietoetsen voor de geluidsmodule. Een LED op pin D13 geeft informatie over de rijstroom. Dit is dezelfde pin als de op de Arduino ingebouwde LED, dus eventueel kan van deze LED worden afgezien.


Programmacode (sketch)

De code voor de Arduino:
/* PULSBREEDTEBESTURING VOOR MODELTREIN
 * versie 2.0 - mei 2018
 * Rob van Deursen
 *
 * Motor snelheids regeling met potmeter of Infrarood (IR) afstandsbediening.
 * Ook geschikt voor "analoge" geluidsmodules middels 6 functietoetsen.
 *
 * ==> Kies hier welke besturing wordt gebruikt: <==
*/
const bool IRbesturing = false;   // zet deze waarde op true als IR ontvanger wordt gebruikt
                                  // bij false is de besturing met een potmeter en functietoetsen

/*
 * De motorbesturing gebeurt over 2 'analoge' uitvoer pinnen. Hier wordt met pulsbreedte modulatie
 * de (effectieve) uitgangsspanning ingesteld.
 * Elke rij-richting heeft 1 pin waarmee de pulsbreedte tussen 0 (uit) en 255 (maximaal) wordt geregeld.
 *   
 * Potmeter bediening
 * ------------------
 * De potmeter bestuurt de rijstroom volgens het het principe: "draai naar rechts, rij naar rechts".
 * Vanuit de middenpositie kan de snelheid daarmee in 2 richtingen worden geregeld.
 *
 * Bij starten van de Arduino moet de potmeter in de nul stand staan. Zo wordt bij een reset na kortsluiting
 * voorkomen dat er meteen weer spanning op de uitgang komt te staan. De indicator led knippert snel als
 * de potmeter niet op nul staat. De potmeter kan dan alsnog in het midden worden gesteld, waarna de bediening
 * start.
 *
 * Indicaties van de LED:
 *    - continue brandend: potmeter staat in "stop" bereik. Er is geen rijstroom.
 *    - langzaam knipperend: potmeter staat in "geluidsfunctie" bereik. Er is enige rijstroom om de geluidsmodule
 *      te starten, maar niet genoeg om de motor te laten draaien.
 *    - uit: gewone rijstroom in een van de rijrichtingen.
 *    - snel knipperend: potmeter moet eerst naar 0 (midden) worden gedraaid. Geen rijstroom.
 *   
 * Functietoetsen:
 * Er zijn tot 6 functietoetsen aan te sluiten. Elke toets verandert kort de frequentie van de rijstroom.
 * Deze frequentie-veranderingen worden door een geluidsmodule herkent en start daarmee speciale functies.
 *
 * 
 * IR afstandsbediening
 * --------------------
 * Infrarood afstandbedieningen kunnen ook worden gebruikt voor deze pulsbreedtebesturing.
 * Deze werkt als volgt:
 * Een InfraRood ontvanger vangt de signalen van de afstandsbediening op.
 * Deze wordt gedecodeerd en omgezet naar een rijrichting en snelheid.
 * Snelheid wordt geleidelijk geregeld. Elk commando levert een 'gewenste' snelheid
 * en rijrichting op. Vervolgens wordt langzaam geaccelereerd of gedecelereerd.
 * Rijrichting wisselt alleen als de snelheid 0 is.
 *
 * Indicaties met 3 leds:
 * 2 richting leds: geven draai-of rijrichting aan.
 *   - continue brandend: rijrichting is ingesteld en snelheid is de gewenste snelheid
 *   - knipperen: andere gewenste snelheid en/of rijrichting. Verandering is bezig
 * 1 'stop' led:
 *   - continue brandend: motor staat stil (snelheid = 0}
 *   - knipperend: er wordt afgeremd tot stop {gewenste snelheid = 0)
 *   - uit: motor draait / rijdt
 *   
 * Voor het ontvangen van het IR signaal is gebruik gemaakt van de IRremote bibliotheek
 * Elke IR afstandbediening kan worden gebruikt, daarvoer moeten de overeenkomstige codes in
 * dit programma worden gezet. De decosering wordt gedaan in de functie "VertaalIR()".
 * Er is standaard voorzien in het gebruik van de Keyes afstandsbediening, maar deze heeft geen
 * functietoetsen voor eventuele geluidsmodules.
 */


// ------------ Instellingen per invoer apparaat ----------

// === potmeter besturing ===

// gebruiksinstellingen
#define potmeterRuis      3    // drempelwaarde voor ruis op de potmeter, voorkomt 'jutteren'
#define potmeterMidden  512    // middenstand (= 0 stand) van de potmeter. Normaal ligt de waarde tussen 0 en 1023.
#define nulbereik        60    // bereik van de potmeter buiten het midden waarop de rijstroom 0 blijft
#define geluidbereik    120    // bereik van af de nul-grens waarop de rijstroom op de minimale waarde blijft voor de geluidsmodule
#define maximaalbereik  500    // bereik waarop de maximale waarde wordt bereikt

// pin definities
#define potmeter         A7    //potmeter (snelheidsregelaar) pin
#define functietoets1    A0    // functietoetsen 1 t/m 6
#define functietoets2    A1
#define functietoets3    A2
#define functietoets4    A3
#define functietoets5    A4
#define functietoets6    A5
#define ledIndicator     13    // pin voor indicator led (bij gebruik potmeter bediening)

// === IR afstandsbediening ==

// gebruiksinstellingen
#define lusVertraging   30     // delay in ms in de hoofdlus
#define acceleratieStap 0.025  // stappen waarin snelheid toe- of afneemt
#define sprongWaarde    2.5    // snelheids 'sprong', bijvoorbeeld om te koppelen bij rangeren

// pin definities
#define receiver          7    // pin 1 van IR ontvanger naar Arduino digitale pin
#define ledVooruitPin     4    // pinnen voor vooruit/achteruit indicatie (alleen gebruikt bij IR)
#define ledAchteruitPin   2
#define ledStopPin        3    // pin voor stop


// ------------ Instellingen motor controller ----------

// uitvoer pinnen
#define richtingPin1     10    // pinnen voor vooruit en achteruit (dit moeten beide PWM pinnen zijn)
#define richtingPin2      9
#define aanloopPWM      65.0   // Pulsbreedte waarde (0-255) om aanloopweerstand motoren te overwinnen
#define maxPulsBreedte  250    // Maximale pulsbreedte voor de rijstroom (255 of kleiner, met geluid: max 250)


// ------------- Potmeter rijregeling variabelen ------

const int rijbereik = maximaalbereik - geluidbereik;
int potmeterWaarde      = potmeterMidden ;
int vorigePotmeterWaarde= potmeterMidden ;

int functietoets[] {functietoets1, functietoets2, functietoets3, functietoets4, functietoets5, functietoets6};
#define aantalFunctietoetsen 6


// // -------------- Objecten en variabelen t.b.v. IR bediening ------

#include <IRremote.h>
IRrecv irrecv(receiver);       // IR ontvanger object maken
decode_results results;
int IRcode = 0;                // code afgelezen uit IR ontvanger
String IRknop = "";            // de ingedrukte knop (of ingedrukt gehouden)

// regeling van snelheid en richting
int richting = 0;                    // rijrichting
int gewensteRichting = 0;            // gewenste rijrichting (rijrichting schakelt pas om bij snelheid 0)
float snelheid = 0;                  // huidige snelheid
float gewensteSnelheid = 0;          // gewenste snelheid
float acceleratie = acceleratieStap;
float sprong = 0;                    // toename in snelheid bij indrukken 'spring' knop
int richtingPin[] {richtingPin1,richtingPin2}; // pinnen voor vooruit en achteruit (PWM pinnen)


// ------------- Definities en variabelen voor geluidsmodule pulsen -----

#define geluidAan           -.825     // snelheid om geluidsmmodule te starten (kleiner dan 0, snelheid 0 is aanloopPWM motoren)

// rijstroom             ~ 490.0     // gemeten periode (trilligstijd) 2020 us foor standaard PWM rijstroom (~490 Hz)
#define freqFunctie1       667.0     //  667 Hz (periode ~1500 us) ==> 1500
#define freqFunctie2       800.0     //  800 Hz (periode ~1250 us) ==> 1250
#define freqFunctie3      1000.0     // 1000 Hz (periode ~1000 us) ==>  990
#define freqFunctie4      1250.0     // 1250 Hz (periode  ~800 us) ==>  790
#define freqFunctie5      1667.0     // 1667 Hz (periode  ~600 us) ==>  590
#define freqFunctie6      2000.0     // 2000 Hz (periode  ~400 us) ==>  490
#define pulsFunctie         40       // tijdsduur van de puls in ms
#define functiepulsCorrectie 5.0     // correctie voor "handmatige" puls - Arduino tijd 1/4 periode
#define functiePulsIRfactor  0.8     // correctie voor vertraging Arduino door IR

float freqFunctie[] {freqFunctie1, freqFunctie2, freqFunctie3, freqFunctie4, freqFunctie5, freqFunctie6};
#define aantalFreqFuncties    6

int geluidFunctie = 0 ;               // huidige geluid functietoets


// -------------- Overige variabelen ------------------

int t=0;                             // algemene teller voor for... loops
int waardePWM;                       // huidige waarde van de pulsbreedte.
int vorigeWaardePWM;                 // vorige waarde van de pulsbreedte.

// LED indicatoren
unsigned long prevms = 0;            // knipperen laatste keer aan/uit
unsigned long curms = millis();      // knipperen nu
const long blnkint = 250;            // knipper-interval
int ledPins[] {ledVooruitPin, ledAchteruitPin, ledStopPin, ledIndicator} ;
int ledStatus[] {2,0,2,0};             // vooruit (aan), achteruit (uit), stop (aan), indicator (uit).
int blnk = HIGH;


//--------------- Setup na starten Arduino ---------------------

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);     // ingebouwde led op pin 13 uit
  digitalWrite(LED_BUILTIN, LOW); 
 
  // in- en output pinnen initialiseren
  pinMode (richtingPin[0], OUTPUT);
  pinMode (richtingPin[1], OUTPUT);
 
  pinMode (potmeter, INPUT);
  for (t = 0; t < aantalFunctietoetsen; t++) {
    pinMode (functietoets[t],INPUT);
    digitalWrite(functietoets[t],HIGH);
  }

  for (t=0; t<4; t++) {
    pinMode (ledPins[t],OUTPUT);
  } 

  // de gewenste besturing starten
  if (IRbesturing) {                // IR bediening
    irrecv.enableIRIn();            // Start de IR ontvanger
  }
  else {                            // potmeter bediening
    // bij potmeterbesturing moet bij het opstarten snelheid 0 zijn ingesteld
    // bij een reset door kortsliting wordt zo voorkomen dat de rijstroom vanzelf aan gaat
    // led indicator knippert snel zolang potmeter niet op 0 is gesteld
    while (HaalSnelheid(analogRead (potmeter)) != 0) {
      // rijstroom uit bij opstarten
      analogWrite (richtingPin[0], 0);
      analogWrite (richtingPin[1], 0);
      digitalWrite(ledIndicator,digitalRead(ledIndicator) == 0);
      delay(100);
    }
    digitalWrite (ledIndicator,LOW);
  }

}

// --------------- Hoofd lus Arduino ---------------------------

void loop() {
// === IR besturing ===

  if (IRbesturing) {
    sprong = 0;
    if (irrecv.decode(&results)) {
      IRcode = results.value;
      if (IRcode != 0xFFFFFFFF) { // Geen toets herhaling
        IRknop = VertaalIR(IRcode);
      }
      ZetGewensteSnelheidEnRichting (IRknop);
     
      irrecv.resume();            // Doorgaan met IR codes ontvangen
    }
    // snelheid en richting aanpassen
    SnelheidAanpassen() ;
    SnelheidNaarPWM () ;       
    if (snelheid == 0) {          //motor staat stil, dus eventuele richtingverandering doorvoeren
      richting = gewensteRichting ;
    }
    // geluidsmodule bedienen
    if (IRknop.startsWith("-1G0")) {                  // geluid functieknop
      geluidFunctie = VertaalIRfunctie (IRknop);
    }
  }
// === potmeter besturing ===

  else {                                        // geen IR besturing, maar potmeter met functieknoppem
    potmeterWaarde = analogRead (potmeter);
    if (abs(potmeterWaarde - analogRead (potmeter)) < potmeterRuis) {     // stabiele uitlezing
    // verander de snelheid met ruisonderdrukking van de ruis op de potmeter.
      if (abs (potmeterWaarde - vorigePotmeterWaarde) > potmeterRuis) {   // verandering groter dan de ruis
        snelheid = HaalSnelheid (potmeterWaarde);                         
        vorigePotmeterWaarde = potmeterWaarde;
        ledStatus[3] = 2;                         // stop = led continu aan
        if (snelheid == geluidAan) {
          ledStatus[3] = 1;                       // geluid bereik (niet rijden) = lijd knipperen
        } else if (snelheid > 0) {
          ledStatus[3] = 0;                       // rijden = led uit
        }
      }
      richting = (potmeterWaarde < potmeterMidden);
      SnelheidNaarPWM () ;
    }
    // Functietoetsen uitlezen
    geluidFunctie = HaalFunctieToets();
   }
// === voor zowel IR als potmeter ===

  // functie uitvoeren
  if (geluidFunctie > 0) {
    stuurPuls (freqFunctie[geluidFunctie-1],pulsFunctie, true); // stuur een puls voor functie 1-6 op geluidsmodule
    delay(93);                                        // voorkom ongewenste herhaling
    geluidFunctie = 0;                                // functie is uitgevoerd
  }
  // led indicators bijwerken
  ZetLedIndicators();
  for (t=0; t < 4; t++) {
    setLed(t,ledStatus[t]);
  }
 
  delay(lusVertraging);

}
//---------------- Functies --------------------

// === Algemene functies ===

// SNELHEID NAAR PWM OMREKENEN EN OP JUISTE PIN ZETTEN
// naar een pulsbreedte en op de juiste uitvoer pin gezet.
void SnelheidNaarPWM () {
  if (snelheid != 0) {
    waardePWM = aanloopPWM + (maxPulsBreedte-aanloopPWM)/9 * (snelheid + sprong);
  }
  else {
    waardePWM = 0;
  }
  analogWrite(richtingPin[richting == 0],0);      // niet richting pin altijd uit
  if (abs(waardePWM - vorigeWaardePWM) >1) {    // significante verandering PWM
                                                  // voorkom onnodig PWM schrijven: dit verandert de puls
  }
    analogWrite(richtingPin[richting],(waardePWM)); // PWM op richting pin
    vorigeWaardePWM = waardePWM;                  // onthou vorige waarde
  //Serial.print(waardePWM);
}
// ====

// LED AAN, UIT OF KNIPPEREN
// input: led number (0-3)
//        func: 0 = uit, 1=knipper, 2 = aan
void setLed (int led, int func) {
  // knipperstatus bijwerken   
  curms = millis();
  if (curms - prevms >= blnkint) {
    prevms = curms;
    blnk = !blnk;            // wissel blnk status
  }
  // leds uit, aan of knipperstatus
  if (func == 1) {           // dan knipperen
    digitalWrite(ledPins[led], blnk);
  }
 
  if (func == 0) {           // uit
    digitalWrite(ledPins[led], LOW);
  }
  if (func == 2) {           // aan
    digitalWrite(ledPins[led], HIGH);
  }
}
// ====

// STUUR PULS
// zet een signaal puls op de rijstroom met een andere frequentie dan de rijstroom
// Input: frequentie (maximaal 2.000 Hz)
//        tijdsduur van de puls (ms)
//        boolean PWM correctie of niet
void stuurPuls (unsigned int frequentie , unsigned long tijdsduur, boolean PWMcorrectie) {
  unsigned long s;
 
  //golf lengte en -vorm berekenen
  unsigned int kwartGolf = (250000/frequentie) - functiepulsCorrectie;    // lengte kwart cyclus in micro sec, minus Arduino tijd
  if (IRbesturing) {kwartGolf = functiePulsIRfactor * kwartGolf; }
  unsigned int hc = 3* kwartGolf;                       // lengte hoge cyclus, standaard is 3/4 hoog.
  unsigned int lc = kwartGolf;                          // lengte lage cyclus
  if (PWMcorrectie) {                                   // PWM correctie gevraagd
    if (waardePWM < 90) {                               // grove PWM correctie in 1/4, 1/2 of 3/4 pulsbreedte (3/4 is standaard)
      hc = kwartGolf;
      lc = 3 * kwartGolf;
    } else if (waardePWM < 170) {
      hc = 2 * kwartGolf;
      lc = 2 * kwartGolf;
    }
  }
 
  //puls op de rijstroom pin zetten
  s = millis() + tijdsduur;
  while (millis() < s) {
    digitalWrite(richtingPin[richting],HIGH);
    delayMicroseconds (hc);
    digitalWrite(richtingPin[richting],LOW);
    delayMicroseconds (lc);
  }
  analogWrite(richtingPin[richting],(waardePWM));
}

// ===

// === potmeter bediening functies ===

// POTMETER WAARDE OMREKENEN NAAR SNELHEID
// input: AD waarde potmeter

float HaalSnelheid (int ADwaarde) {    // snelheid instellen op basis van de potmeter
  float s = abs (ADwaarde - potmeterMidden);
  if (s < nulbereik) {
    s = 0;
  }
  else {
    if ( s < geluidbereik ){
      s = geluidAan;
      //Serial.println("!!!!");
    }
    else {
      s = (constrain (s, geluidbereik, maximaalbereik) ) - geluidbereik;
      s = 10 * s / maximaalbereik;
    }
  }
 
  return s;
}
//===

// FUNCTIETOETSEN UITLEZEN
// geeft het volgnummer van de ingedrukte functietoets.
// 0 = geen toets
int HaalFunctieToets () {
  int  f = 0;                        // toets volgnnummer
  int  k = 0;                        // ingedrukte toets (0 = geen)
  for (f=0; f < aantalFunctietoetsen; f++) {
    if (digitalRead(functietoets[f]) == LOW) {  //Deze toets is ingedrukt
      k = f+1;                       // onthou toets volgnummer
      //Serial.print(k);
    }
  }
 
  if (k > 0) { delay (60);}
  return k;
}
// ===

// === IR bediening functies ===

// IR CODE VERTALING
// Vertaling van de IR codes naar knoppen c.q. acties
// input: integer met de ontvangen IR code
// output: string met code of actie
//         Numerieke toetsen geven het cijfer als string terug.
//         Alle niet-numerieke toetsen beginnen met "-1", zodat
//         deze makkelijk zijn te onderscheiden van de numerieke toetsen.

String VertaalIR(int code){       

  String b = "";
 
  switch(code) {
    // code vertaling KEYES afstandsbediening
    case 0xFFA25D: b="1"; break;     //numerieke toets is snelheid 0-9
    case 0xFF629D: b="2"; break;
    case 0xFFE21D: b="3"; break;
    case 0xFF22DD: b="4"; break;
    case 0xFF02FD: b="5"; break;
    case 0xFFC23D: b="6"; break;
    case 0xFFE01F: b="7"; break;
    case 0xFFA857: b="8"; break;
    case 0xFF906F: b="9"; break;
    case 0xFF9867: b="0"; break;
    case 0xFF6897: b="-1*"; break;    //* = sprong knop snelheidssprong (t.b.v. koppelen bij rangeren, bijvoorbeeld)
    case 0xFFB04F: b="-1#"; break;    //# = direct naar gewenste snelheid (geen acceleratie/deceleratie)
    case 0xFF18E7: b="-1^"; break;    //omhoog
    case 0xFF10EF: b="-1<"; break;    //links
    case 0xFF38C7: b="-1STOP"; break; //OK = noodstop
    case 0xFF5AA5: b="-1>"; break;    //rechts
    case 0xFF4AB5: b="-1V"; break;    //omlaag
    case 0xFFFFFFFF: b="-1R"; break;  //herhaal (repeat) laatste knop blijft ingedrukt

    // code vertaling SHARP GA074WJSA afstandbediening
    case 0x885B30D5: b="1"; break;
    case 0xE7E0CFB1: b="2"; break;
    case 0xA34F5A01: b="3"; break;
    case 0x22614D75: b="4"; break;
    case 0x96C5A8AB: b="5"; break;
    case 0x44ABD1FD: b="6"; break;
    case 0x1A5C4D:   b="7"; break;
    case 0x57A67691: b="8"; break;
    case 0x9543D7CF: b="9"; break;
    case 0xF4C976AB: b="0"; break;
    case 0x5CC96CE7: b="-1*"; break;    //kanaal wissel = sprong knop snelheidssprong (t.b.v. koppelen bij rangeren, bijvoorbeeld)
    case 0xCC00A5B7: b="-1#"; break;    //TV/VIDEO = direct naar gewenste snelheid (geen acceleratie/deceleratie)
    case 0x3E0C7005: b="-1^"; break;    //omhoog
    case 0xB10C7C8B: b="-1^"; break;    //channel up = ook omhoog
    case 0x503D6F71: b="-1V"; break;    //omlaag
    case 0x10921B67: b="-1V"; break;    //channel down = ook omlaag
    case 0x25D2E369: b="-1STOP"; break; //OK = noodstop
    case 0x6D5D1DB3: b="-1STOP"; break; //AAN/UIT = ook noodstop
    case 0xF43135:   b="-1>"; break;    //rechts
    case 0x4B12992B: b="-1>"; break;    //volume + = ook rechts
    case 0xA574865B: b="-1<"; break;    //links
    case 0x1BE8C80D: b="-1<"; break;    //volume - = ook links

// functietoetsen geluidsmodule
    case 0x47071827: b="-1G01" ; break;    //rood  = F1
    case 0xAA849FD1: b="-1G02" ; break;    //groen = F2
    case 0xA0A3EAD:  b="-1G03" ; break;    //geel  = F3
    case 0xC578C8FD: b="-1G04" ; break;    //blauw = F4
    case 0xAE90AC1D: b="-1G05";  break;    //sound = F5
    case 0xC7E0BECF: b="-1G06" ; break;    //menu  = F6
    case 0x28CBA803: b="-1G04" ; break;    //mute  = F4
     
    case 0x3FE6:     b="-1G<"  ; break;    //subtitle = minimalw PWM links
    case 0xA07CF2DB: b="-1G>"  ; break;    //end      = minimale PWM rechts

  //  case 0xFFFFFFFF: b="-1R"; break;  //herhaal (repeat) laatste knop blijft ingedrukt

 
    // Hier is ruimte om eventueel codes van andere afstandbedieningen te vertalen
 
  default:
    b = "-2Onbekend";
  }// End Case
 
  return b ;
}
// ====

// SNELHEID AANPASSEN - IR
// Deze functie berekent de nieuwe snelheid op basis van de
// ingestelde acceleratie.


void SnelheidAanpassen() {
  if (abs(snelheid - gewensteSnelheid) <= (acceleratieStap / 2)) {
    snelheid = gewensteSnelheid;
    acceleratie= 0;
  } else {
    snelheid += acceleratie;
  }
}
// ===


// ZET DE GEWENSTE SNELHEID EN RICHTING -IR
// Functie zet de gewenste snelheid, gewenste richting en gewenste
// versnelling (of vertraging) op basis van de knoppen die zijn
// ingedrukt op de afstandsbediening.

void ZetGewensteSnelheidEnRichting (String laatsteKnop) {
  if (laatsteKnop.toFloat() >= 0) {    //numerieke toets
    gewensteSnelheid = laatsteKnop.toFloat();
    if (snelheid < gewensteSnelheid) { acceleratie = acceleratieStap; }
    if (snelheid > gewensteSnelheid) {acceleratie = - acceleratieStap; }
  }
  else {                               // niet een numerieke toets
    if (laatsteKnop == "-1STOP") {       // noodstop
      acceleratie = -snelheid;
      gewensteSnelheid = 0;
    }
    if (laatsteKnop == "-1>") {              // knop naar rechts
      if (richting == 1) {                   // omkering tijdens het rijden
        gewensteSnelheid = 0;                // eerst afremmen naar 0
        acceleratie = - acceleratieStap;
        gewensteRichting = 0;
        laatsteKnop ="";
      }
      else {                                 // rijrichting hetzelfde
        if (snelheid == gewensteSnelheid  && snelheid < 9 && richting == 0) {  // gewenste snelheid is bereikt en nog niet max
         gewensteSnelheid  += .5 ;             
         acceleratie = acceleratieStap;
        }
      }
    }
    if (laatsteKnop == "-1<") {              // knop naar links
      if (richting == 0) {                   // omkering tijdens het rijden
        gewensteSnelheid = 0;                // eerst afremmen naar 0
        acceleratie = - acceleratieStap;
        gewensteRichting = 1;
        laatsteKnop ="";
      }
      else {                                 // rijrichting hetzelfde
        if (snelheid == gewensteSnelheid  && snelheid < 9 && richting == 1 ) {  // gewenste snelheid is bereikt en nog niet max
         gewensteSnelheid += 0.5;             
         acceleratie = acceleratieStap;
        }
      }
    }
    if (laatsteKnop == "-1V") {
      if (snelheid == gewensteSnelheid  && snelheid > 0 ) {  // gewenste snelheid is bereikt en nog niet max
         gewensteSnelheid -= 0.25;             
         acceleratie = -acceleratieStap;
      }
    }
    if (laatsteKnop == "-1^") {
      if (snelheid == gewensteSnelheid  && snelheid < 9 ) {  // gewenste snelheid is bereikt en nog niet max
         gewensteSnelheid += 0.25;             
         acceleratie = acceleratieStap;
      }
    }
    if (laatsteKnop == "-1#") {
      snelheid = gewensteSnelheid;      // sla het accelereren/decelereren over: direct naar gewenste snelheid
    }
    if (laatsteKnop == "-1*" && snelheid < 9 - sprongWaarde) {
      sprong = sprongWaarde;            // zet "sprong" aan zolang deze toets is ingedrukt.
    }

   
    if (snelheid == 0 && gewensteSnelheid == 0) {
        if (laatsteKnop == "-1G<" ) {     // minimale stroom geluidsmodule aanzetten
        snelheid = geluidAan ;
        gewensteSnelheid = geluidAan;
        richting = 1;
        gewensteRichting = 1;
      }
      if (laatsteKnop == "-1G>" ) {     // minimale stroom geluidsmodule aanzetten
        snelheid = geluidAan ;
        gewensteSnelheid = geluidAan;
        richting = 0;
        gewensteRichting = 0;
      }
    }
   
  }
}

// ====

// ZET LED INDICATOREN - IR
// zet juiste waarden op LED pinnen: indicatoren voor acties die bezig zijn
// (richting, snelheidsverandering en stop)
void ZetLedIndicators (){
  if (snelheid  == 0) {
    for (t = 0; t < 2 ; t++) {
      ledStatus [t] =0 ;         // richting Leds uit
    }
    ledStatus [2] = 2;           // stop led aan
    ledStatus [richting] = 2;     // juiste richting led aan
  }
  else {                       // motor draait
    if (gewensteSnelheid == 0) {
      ledStatus [2] = 1;         // stop led laten knipperen
    } else {
      ledStatus [2] = 0;
    }
    if (gewensteRichting != richting) { //richting verandering gewenst
      ledStatus [gewensteRichting] = 1;  // gewenste richting knipperen
    } 
    else {
      ledStatus [1-gewensteRichting] = 0; // andere richtingsled uit
      if (gewensteSnelheid != snelheid) { // snelheidsverandering bezig (en niet naar 0)
        ledStatus [gewensteRichting] = 1;
      }
      else {
        ledStatus [gewensteRichting] = 2;
      }
    }
  }
}
// ===

// HAAL IR FUNCTIETOETS OP
int VertaalIRfunctie (String g) {
  int f = 0;
    if (g == "-1G01") {
        f = 1;                                       // functie 1
    }
    if (g == "-1G02") {
        f = 2;                                       // functie 2
    }
    if (g == "-1G03") {
        f = 3;                                       // functie 3
    }
      if (g == "-1G04") {
        f = 4;                                       // functie 4
    }
    if (g == "-1G05") {
         f = 5;                                       // functie 5
    }
    if (g == "-1G06") {
         f = 6;                                       // functie 6
    }
    return f;
}
// ===

// --------------- einde schets ----------------



De code voorziet in bediening van de pulsbreedte met potmeter en functietoetsen of met infrarood afstandsbediening. Standaard staat deze op "potmeter".


Lijst van onderdelen

De volgende onderdelen zijn gebruikt (aangegeven prijzen zijn Nederlandse prijzen)
  • Voeding - step up/down 4A  | 4,95
  • Motorcontroller 4A               | 4,95
  • Arduino Nano met pinnen     | 5,95 (zonder pinnen, zelf solderen 4,95)
  • Brugcel, gelijkrichter 6A       | 0,70
  • Potmeter 10k ohm               | 0,50
  • LEDje                                  | 0,10
  • Weerstandje 1 k ohm           | 0,10
  • Breadboard draadjes fem-fem | 3,95
  • Druktoetsen 6x                     | 3,00 (0,50/stuk, prijs afhankelijk van type)

Totale prijs komt dan op 24,20, zonder verzendkosten.
Bij bestelling van (een deel) van de spullen bij tante Ali, kunnen de kosten flink omlaag (en levertijden omhoog). Zo heb ik 5 Arduino's gekocht voor $12. Deze Arduino's kunnen ook in de geluidsmodules worden gebruikt.


Enkele aanwijzingen voor de opbouw

Enig gereedschap is nodig, zoals een voltmeter (multimeter) voor het instellen van de voeding, een soldeerbout, een computer  met de Arduino software (de zogenaamde IDE, gratis te downloaden), en een USB kabel met mini USB (niet de micro USB van je telefoon, maar de iets grotere stekker).
Zoals gezegd: let op met de voeding: eerst het uitgangsvoltage instellen, dan pas andere spullen aansluiten.


Als de pulsbreedte besturing klaar is, kan elke analoge loc hierop rijden. Dus je hoeft niet te wachten op de geluidsmodules om deze rijstroom besturing te gebruiken.

Tot zover de bouwbeschrijving.

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline mark mms

  • Super Modelspoorder
  • ******
  • Berichten: 1.224
  • Thanked: 26 times
  • Geslacht: Man
Re: Analoog rijden met geluid - het project.
« Reactie #4 Gepost op: 1 mei 2018, 20:58:07 »
Rob, weer bedankt voor de info!

Ik ga eens bedenken of dit een betere oplossing is voor mijn analoog systeem.
Vooral geluid per trein en lichten aan en uit zetten zal doorslag geven.

Mvg mark

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #5 Gepost op: 2 mei 2018, 22:37:50 »
Graag gedaan, Mark. En denk gerust nog na over de oplossing die voor jouw het beste is  :)

Ondertussen heb ik voor de pulsbreedte besturing een paneeltje gemaakt.




Aan de onderkant ziet dat er zo uit. Er is een massa draad die alle knoppen en de LED met de "GND" verbind. Verder zijn alle aansluitingen met stekkertjes gemaakt die zo op de pinnen van de Arduino passen.




En dan alles meteen maar op de "fahrpult" geïnstalleerd. Het is wel een beetje een Tele-Tubby paneel geworden met de gekleurde, ronde knoppen, maar goed... Ik heb dezelfde kleuren gebruikt als de toetsen op de afstandsbediening (daar zijn de gekleurde  teletext knoppen en 2 andere gebruikt als functie toetsen).





Dan wordt het langzamerhand tijd om verder te gaan met geluid in de BR50. Die geluidsmodule wordt alweer wat anders dan het prototype in de railbus. Met name de besturing van de MP3 wordt iets anders, waardoor ik een draad tussen Arduino en MP3 kan besparen en software kan bijwerken met aangekoppelde MP3 speler.

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #6 Gepost op: 5 mei 2018, 18:21:29 »
BR50 met geluid - deel 1: de hardware

Afgelopen dagen aan het priegelen geweest om een geluidsmodule in te bouwen in de BR50. De module komt in de ketel en het speakertje er onder.
Dus eerst het lood in de ketel wat dunner gemaakt. Ik gebruik een stukje karton om de module op te bouwen. Daar kan ik de componenten op lijmen en het isoleert meteen de prints van het lood er onder.




Het was even puzzelen om de module zo laag te houden dat deze in de ketel past. Hij klemt een beetje, dus de gele aansluitdraden dienen meteen als 'trek stang' om de module weer uit de ketel te krijgen. Dat is met name nodig om software te kunnen wijzigen. De opbouw is verder zodanig dat de USB aansluiting met enige moeite is te bereiken. De sleuf voor de geheugenkaart zit op de kop, zodat deze eventueel eenvoudig is te wisselen om de geluidsbestanden te veranderen




Daarna de rijstroom opgepakt van de draden naar de motor, en de speaker onder de ketel geplakt. Tijd om de boel te monteren.




Natuurlijk gaat er nog van alles mis als de boel eenmaal is ingebouwd en soms moet de module even worden "uitgelezen" en nieuwe software worden geüpload.




Maar het werkt!
(in deze video is het geluid nog niet helemaal goed. In het volgende bericht staat een video met sterk verbeterde geluiden)

<a href="" target="_blank" class="aeva_link bbc_link new_win"><strong><span style="color: red;" class="bbc_color">!</span></strong> No longer available</a>



Ik heb nog wat moeite om goede geluidsfragmenten te maken waarbij een rijdende loc voldoende luid is (zodat die boven de motor uit komt). Maar daar ga ik nog even verder mee. Het is in ieder geval vrij eenvoudig het micro-SD kaartje er uit te halen om er nieuwe MP3's op te zetten




Na wat gepuzzel met de hardware, met name consistent de rijstroom kunnen 'lezen' viel niet mee, lijkt dat deel nu redelijk stabiel. Daarvan volgt binnenkort een aansluitschema.

De software is nog in ontwikkeling (met name om te compenseren voor wat storingen bij het rijden en de MP3 speler die daarvan af en toe op hol slaat). Wat stroom opname betreft is de railbus veel gelijkmatiger dan zo'n lange stoomloc.

En natuurlijk nog verder met betere geluiden maken...

Maar tot zover ben ik tevreden...

Rob

Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Pierre

  • Super Modelspoorder
  • ******
  • Berichten: 7.918
  • Thanked: 334 times
  • Geslacht: Man
  • Woonplaats: Den Haag (Loosduinen)
    • Haagse Modelbouw Club
Re: Analoog rijden met geluid - het project.
« Reactie #7 Gepost op: 5 mei 2018, 19:20:51 »
Goed bezig Rob maar ... het gaat mij nu al boven mijn pet. :o
Groet Pierre.

Ik rommel wat met treintjes en bouwwerkjes in H0 (H0e) en ook een klein beetje in N  .... Scratchbuilding, kitbashing en weathering.  ;D Lid van de http://haagsemodelbouwclub.nl/

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #8 Gepost op: 6 mei 2018, 22:01:19 »
Dank, Pierre. Ik probeer (uiteindelijk) tot een zo eenvoudig mogelijke bouwbeschrijving te komen.

Nu was ik wel tevreden met de technische mijlpaal van de inbouw van het geluid in de BR50, maar het geluid zelf was ik nog niet zo blij mee.
Ondertussen wel.

Dus hierbij een "officieel" project bericht.



Aansluitschema's en testsoftware voor de module volgen snel.

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline mark mms

  • Super Modelspoorder
  • ******
  • Berichten: 1.224
  • Thanked: 26 times
  • Geslacht: Man
Re: Analoog rijden met geluid - het project.
« Reactie #9 Gepost op: 6 mei 2018, 22:36:58 »
Ik ben er stil van.  :o

Offline GéJé

  • Super Modelspoorder
  • ******
  • Berichten: 1.672
  • Thanked: 52 times
  • Geslacht: Man
  • Gert-Jan
Re: Analoog rijden met geluid - het project.
« Reactie #10 Gepost op: 7 mei 2018, 00:48:18 »
Ik vind het resultaat echt fantastisch.
Knap werk!

groet,
Gert-Jan

Offline Pierre

  • Super Modelspoorder
  • ******
  • Berichten: 7.918
  • Thanked: 334 times
  • Geslacht: Man
  • Woonplaats: Den Haag (Loosduinen)
    • Haagse Modelbouw Club
Re: Analoog rijden met geluid - het project.
« Reactie #11 Gepost op: 7 mei 2018, 13:18:25 »
Man .. man .. wat een knap werk! :o Zo vind ik het (misschien) ook wel leuk om met mijn treinen te rijden. 8)
Groet Pierre.

Ik rommel wat met treintjes en bouwwerkjes in H0 (H0e) en ook een klein beetje in N  .... Scratchbuilding, kitbashing en weathering.  ;D Lid van de http://haagsemodelbouwclub.nl/

Offline Wim Corduwener

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 10.844
  • Thanked: 300 times
  • Geslacht: Man
  • Enschede (import)
    • Portfolio
Re: Analoog rijden met geluid - het project.
« Reactie #12 Gepost op: 7 mei 2018, 17:08:48 »
Zo vind ik het (misschien) ook wel leuk om met mijn treinen te rijden. 8)
Ook wel lullig: heb je een modelspoorbaan en dan vind je het misschien wel leuk om met treinen rond te rijden.  ::)
Nah, ik heb eigenlijk ook niks met treinen. Eigenlijk heb ik alleen treinen om een beetje mee te kunnen doen op dit forum.  ;D
Trefwoorden:  Mac • Modulebouw • H0, H0e en 0e • Tijdperk III (1950-1960) • Nederlands (H0 en H0e) • Frans (1:45) • Gelijkstroom • Twee rails • Voorlopig nog even analoog • Scratchbuilding en Kitbutchering... en ik maak eigenlijk nooit wat af.

Meest recente projecten: Frans diorama 2.0 (Spoor 0e) en Verbouwing Magic Train (schaal 0e)

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #13 Gepost op: 7 mei 2018, 23:53:24 »
Heren, dank voor alle lof. En dan nu...

Aansluitschema's van de geluidsmodule


De geluidsmodule is opgebouwd rond een Arduino Nano, waaraan vier functionele delen zijn toegevoegd:
  • De voeding: een gelijkrichter met flinke Elco
  • De rijstroom sensoren
  • De MP3 speler
  • Een schakelbare uitgang voor licht (LEDs)


Voeding en sensoren
Om de opbouw overzichtelijk te houden, beginnen we met de eerste 2 delen: de voeding en sensoren. Dat ziet er zo uit




De voeding bestaat uit een bruggelijkrichter (1) met een flinke Elco (of meerdere Elco's parallel) van minstens 1400 uF. Voor de railbus en BR50 had ik ruimte voor 2200 uF. De gelijkrichter zorgt voor de juiste polarisatie in beide rijrichtingen
De + van de gelijkrichter gaat naar de V-IN van de Arduino, de - naar de Groond (GND).
Voor het meten van de pulsbreedte en de veranderingen in de frequentie zijn twee (input) pinnen van de Arduino over weerstanden verbonden met de rijstroom voordat deze gelijk gericht is. Elke pin heeft 2 weerstanden: een van de rijstroom naar de pin en een van de pin naar de GND. Deze opstelling is er een zogenaamde spanningsdeler, waarmee
  • De 10 Volt van de rijspanning bij "hoog" van de puls tot net onder de 5 Volt wordt teruggebracht. Dit is het maximum niveau voor digitale pinnen voor een logische "1"
  • Bij "laag" van de puls van de rijspanning de spanning op de pin voldoende laag wordt. De 0,7 V van de diode in de gelijkrichter ligt anders te dicht bij de 0,8V grenswaarde voor een logische "0". Met de spanningsdelerwordt ook deze spanning gehalveerd, en is er een duidelijker "0" te meten.

Met dit deel aan de Arduino gebouwd (gelijkrichter, Elco en 4 weerstanden) is de 'input' van de module al te testen, voordat de andere delen worden gebouwd. Daar heb ik wat testsoftware voor. Die komt binnenkort met een korte demo.


MP3 speler en LED schakeling
En dan het output gedeelte: MP3 speler en licht (LED) schakeling




Van de MP3 speler worden 6 van de 16 pinnen gebruikt: 2 voor de stroomvoorziening, 2 voor de seriële communicatie waarmee bestanden worden geselecteerd om af te spelen, en 2 voor de speaker. Voor de seriële verbinding zijn 2 weerstanden van 1k ohm tussengevoegd om de verschillende werkspanningen (5V Arduino, 3,3 V MP3 speler) te overbruggen. De MP3 speler krijgt stroom uit de 5V uitgang van de Arduino.

De LED verlichting wordt geschakeld met een NPN transistor op de 3,3V uitgang van de Arduino. De aansturing gebeurt over een 1k ohm weerstand van een output pin. Hier wordt pin D11 gebruikt, waardoor de LED ook te dimmen is. Dat kan handig zijn voor binnenverlichting, maar biedt ook mogelijkheden voor een imitatie van een zwaailicht (afstand bestuurde rangeerloc) of het gloeien van kolen, en zo meer.
In principe is het mogelijk meerdere 'schakelaars' (transistors) aan te brengen. Enige beperking is het relatief geringe vermogen dat beschikbaar is voor de module als de trein stil staat.


De hele module
De module is voor geluid en/of licht. En/of, want de lichtschakelaar kan achterwege worden gelaten als alleen geluid nodig is. En zonder MP3 speler kan alleen licht worden geschakeld. Dit laatste is misschien een optie om licht in wagons aan en uit te doen.

Maar met alle mogelijkheden, is dit het geheel:




De daadwerkelijke opbouw is sterk afhankelijk van de ruimte in de betreffende loc, treinstel of wagon. Eventueel kunnen ook andere pinnen worden gebruikt als daarmee de opbouw beter past in de beschikbare ruimte. Ander pin gebruik is eenvoudig om in de software te definiëren.

Ik ben begonnen aan de 3e geluidsmodule. Binnenkort een bericht over hoe deze wordt gebouwd en getest.

Rob

Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Dirk T

  • Super Modelspoorder
  • ******
  • Berichten: 1.345
  • Thanked: 98 times
  • Geslacht: Man
  • Tweerail DCC, NL 1950-1975 met ruime blik
Re: Analoog rijden met geluid - het project.
« Reactie #14 Gepost op: 8 mei 2018, 09:44:26 »
Je bent weer lekker bezig!

Voor het meten van de pulsbreedte en de veranderingen in de frequentie zijn twee (input) pinnen van de Arduino over weerstanden verbonden met de rijstroom voordat deze gelijk gericht is. Elke pin heeft 2 weerstanden: een van de rijstroom naar de pin en een van de pin naar de GND. Deze opstelling is er een zogenaamde spanningsdeler, ...

Betekent dat, dat D3 (pin 6) en D5 (pin 8 ) in je tekening doorverbonden zijn met D6 (pin 9) en D7 (pin 10)? Anders zie ik niet hoe je spanningsdeler werkt.
Het einde van een weg wordt altijd bereikt door hem stap voor stap af te lopen.

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #15 Gepost op: 8 mei 2018, 11:25:18 »
Goed gezien, Dirk.

Foutje in de tekening!
Ik heb op het laatste moment pinnen D3 en D5 naar pinnen D6 en D7 gezet. En daarmee vergeten de paarse lijnen aan te passen: die moeten dus ook naar D6 en D7.
Ik pas vanavond de tekeningen aan.
Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #16 Gepost op: 8 mei 2018, 19:21:38 »
Tekeningen zijn aangepast. Ik moest wel even de pagina verversen (ctrl + F5) om de nieuwe schema's te zien.
Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #17 Gepost op: 10 mei 2018, 11:35:42 »
Geluidsmodule: opbouw van de voeding en rijstroom sensoren.

Ik ben begonnen met de volgende module in een V100 van Fleischmann. Deze loc is makkelijk te openen en daarmee erg geschikt voor het vervolmaken van de software. In de huidige (erg simpele) aansturing van de MP3 speler gaat tijdens het rijden de module af en toe op stil, met name als de rijstroom enkele keren kort hapert.
Dat is op te lossen door de communicatie met de MP3 speler te verbeteren (zoals ook herkennen dat een foutmelding wordt gestuurd). Maar dan is een loc met makkelijk bij te werken software wel handig.
Bovendien biedt de bouw van deze geluidsmodule de mogelijkheid om een en ander in beeld te brengen.

In dit eerste deel van de opbouw van de module: voeding en rijstroom sensoren. Opbouw en test.



In de video wordt gebruik gemaakt van deze software om de module te testen:

/* GELUIDSMODULE TESTER
 * Testprogramma voor geluidsmodules voor analoge h0 trein
 * Geeft aan welke signalen door de module worden herkend.
 * Meet de puls op 2 pinnen verbonden met de rijstroom.
 * Programma wacht op herkenbaar signaal op een van de pinnen.
 * Bij herkenbaar signaal (d.w.z periode kleiner dan 2020 us
 * en groter dan 0) wordt de rijpin en pulsbreedte in % weergegeven.
 * Ook speciale frequenties voor de functies (1-6) worden herkend
 * en aangegeven.
 * Output op de seriële (USB) poort. Waarden zijn uit te lezen met
 * de serial monitor op de computer.
 *
 * Alleen als de waarde verandert wordt een nieuwe regel met
 * informatie 'geprint'.
 */
 // ==> Geef hier de 2 pinnen op waarmee de rijstroom wordt gemeten <==
#define rijpin1 6
#define rijpin2 7

// --- DEFINITIES ----
#define pullup               false    // geeft aan of de interne pullup weerstand gebruikt moet worden
#define maxpulsbreedte       5000     // hoe lang wachten (minimaal 2x periode)


// Frequenties (Periodes) op de rijstroom
#define rijPeriode            2020    // rijstroom puls in us
#define functie_01_Periode    1500    // Periode (freq.) functie 1
#define functie_02_Periode    1250    // Periode (freq.) functie 2
#define functie_03_Periode     990    // Periode (freq.) functie 3
#define functie_04_Periode     790    // Periode (freq.) functie 4
#define functie_05_Periode     590    // Periode (freq.) functie 5
#define functie_06_Periode     490    // Periode (freq.) functie 6
#define pulsruis                40    // maximaal verschil in gemeten Periodes (ruis)
#define minhoog                200    // minimaal "hoog" signaal

#define elcoLaadtijd          1000    // oplaadtijd van de Elcos (ms) = tijd tot stabiele pulsmeting

// ---- VARIABLEN ----

int rijpin[] {rijpin1, rijpin2};

// pulse meting variabelen: lengte 'hoog', 'laag' en trillingstijd (periode). Alle tijden in us.
double pulsbreedteHoog;
double pulsbreedteLaag;
double pulsPeriode;
double pulsbreedteHoog2;
double pulsbreedteLaag2;
double pulsPeriode2;

int vooruit = 1;                    // richting: bepaalt welke pin wordt uitgelezen voor de rijstroom puls
int pulsbreedte = 0;                // pulsbreedte in %
int vorigePulsbreedte = 0;          // vorige pulsbreedte om verandering vast te stellen
int functie = 0;                    // speciale functie frequentie gemeten
int vorigeFunctie = 0;


void setup() {
   
  pinMode     (rijpin[0],INPUT);
  digitalWrite(rijpin[0],pullup);
  pinMode     (rijpin[1],INPUT);
  digitalWrite(rijpin[1],pullup);

  Serial.begin(9600);
  Serial.println("Geluidsmodule gestart.");

  delay(elcoLaadtijd);       // wacht op stabiele puls (na opladen Elco)

  getSignaal();              // zoek naar signaal op de pinnen
}

void loop() {
// lees de huidige rijpin uit
  pulsbreedteHoog = pulseIn(rijpin[vooruit], HIGH, maxpulsbreedte);
  pulsbreedteLaag = pulseIn(rijpin[vooruit], LOW, maxpulsbreedte );
  pulsbreedteHoog2 = pulseIn(rijpin[vooruit], HIGH, maxpulsbreedte);
  pulsbreedteLaag2 = pulseIn(rijpin[vooruit], LOW, maxpulsbreedte );
  pulsPeriode = pulsbreedteHoog + pulsbreedteLaag;
  pulsPeriode2 = pulsbreedteHoog2 + pulsbreedteLaag2;

// beoordeel het signaal
  if (pulsPeriode > rijPeriode + pulsruis || pulsPeriode < pulsruis ) {
  // geen herkenbaar signaal meer
    getSignaal();             // zoek naar signaal op een van de rojpinnen
    vorigePulsbreedte = 0;    // forceer weergave zodra signaal gevonden
  } else
  // herkenbaar signaal
  {

// bepaal welk signaal (frequentie) is ontvangen en voer bijbehorende functie uit
    if (abs (pulsPeriode - rijPeriode) < pulsruis) {
      // normale rijstroom: bereken pulsbreedte (in %)
      pulsbreedte = 100 * pulsbreedteHoog / rijPeriode;
    }
     
    functie = getFunctie();

    // resultaten weegeven als er iets is veranderd.
    if (abs(vorigePulsbreedte - pulsbreedte) > 1 || functie != vorigeFunctie ) {
      // meer dan 1% pulsbreedte verschil of functietoets ingedrukt
      Serial.print ("Rijpin: ");
      Serial.print (vooruit + 1);
      Serial.print (" || Pulsbreedte: ");
      Serial.print (pulsbreedte);
      Serial.print("% ");
      Serial.print (" || Functie: ");
      Serial.println(functie);
      delay(10);
      vorigePulsbreedte = pulsbreedte;
      vorigeFunctie = functie;
    }   
  }
}

// SIGNAAL ZOEKEN
// functie om te wachten op een herkenbaar signaal op een van de rijpinnen.
void getSignaal() {
  Serial.println ("Module wacht op herkenbaar signaal.");
 
  // zolang geen rijstroom periode en geen "hoog"  signaal is gevonden
  // blijft deze lus om-en-om op elk van de rijpinnenm meten.
  do {
    vooruit = (!vooruit);                   // wissel van rijpin
    pulsbreedteHoog = pulseIn(rijpin[vooruit], HIGH, maxpulsbreedte);
    pulsbreedteLaag = pulseIn(rijpin[vooruit], LOW , maxpulsbreedte);
    pulsPeriode = pulsbreedteHoog + pulsbreedteLaag;
    delay(50);
    Serial.print(".");                      // elke poging: "."
    delay(200);
  } while (abs(pulsPeriode - rijPeriode) > pulsruis || pulsbreedteHoog < minhoog);

  // Signaal gevonden. Geef dit aan op de seriële bus
  Serial.println("!");
  Serial.print("Herkenbaar signaal gevonden op rijpin ");
  Serial.print(vooruit+1);
  Serial.println(".");
}

// HERKEN FUNCTIE-FREQUENTIE
// functie voor het checken van functie-frequenties
// op de puls (functietoets).
int getFunctie () {
  int f = 0;

  if (abs (pulsPeriode - functie_01_Periode) < pulsruis && abs (pulsPeriode2 - functie_01_Periode) > pulsruis) { f = 1;}
  if (abs (pulsPeriode - functie_02_Periode) < pulsruis && abs (pulsPeriode2 - functie_02_Periode) > pulsruis) { f = 2;}
  if (abs (pulsPeriode - functie_03_Periode) < pulsruis && abs (pulsPeriode2 - functie_03_Periode) > pulsruis) { f = 3;}
  if (abs (pulsPeriode - functie_04_Periode) < pulsruis && abs (pulsPeriode2 - functie_04_Periode) > pulsruis) { f = 4;}
  if (abs (pulsPeriode - functie_05_Periode) < pulsruis && abs (pulsPeriode2 - functie_05_Periode) > pulsruis) { f = 5;}
  if (abs (pulsPeriode - functie_06_Periode) < pulsruis && abs (pulsPeriode2 - functie_06_Periode) > pulsruis) { f = 6;}

  return f;
}
// --- einde ---


Ondertussen ga ik de MP3 speler en speaker inbouwen. Verslag volgt...

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #18 Gepost op: 10 mei 2018, 18:47:46 »
Geluidsmodule: De MP3 speler (DFplayer)

Ik was vandaag lekker bezig met de V100, dus hierbij het verslag van het inbouwen van de MP3speler.



En hier de Arduino sketch voor het testen van de MP3 speler:

/* DFPLAYER TESTER
 * Testprogramma voor geluidsmodules voor analoge h0 trein
 * Test de seriële communicatie met de DFplayer (MP3 speler)
 *
 * De communicatie gaat met "soft serial" op 2 digitale pinnen
 * naar keuze. Het programma speelt de bestanden in volgorde
 * af, te beginnen bij 001.mp3, dan 002.mp3, etc.
 * Afspeeltijd per bestand is instelbaar.
 */


#define MP3RX          9    // serial receive pin, verbonden met transmit van DFplayer
#define MP3TX          8    // serial transmit pin, verbonden met receive van DFplayer
#define afspeeltijd 8000    // in ms


# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00  //Returns info with command 0x41 [0x01: info, 0x00: no info]


int LED = 13;
int x=0;
bool MP3play = false;    // MP3 playing y/n

#include <SoftwareSerial.h>

SoftwareSerial MP3Serial(MP3RX, MP3TX); // RX, TX

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);


  MP3Serial.begin(9600);
  pinMode(LED, OUTPUT);
  digitalWrite (LED, HIGH);


  execute_CMD(0x3F, 0, 0); // Send request for initialization parameters
  delay (1000);
  execute_CMD(0x06, 0, 28); // Set the volume to medium (0x00~0x30)
  delay (100);
  execute_CMD(0x07, 0, 0);  //
  delay (100);
}

void loop() {
  // put your main code here, to run repeatedly:
 
 if (MP3Serial.available()) {  // er is iets aangekomen op de seriele bus
    delay(20);
    while(MP3Serial.available()) {  // serieel uitlezen
      Serial.print(MP3Serial.read(),HEX);
      Serial.print(".");
    }
    Serial.println("||");
    MP3play = false;
  }
  if (!MP3play) {
      x++;
      MP3play = true;
      execute_CMD (0x03, 0, x);
      delay(afspeeltijd);
      MP3play=false;
  }
}

// DF serial command code
void execute_CMD(byte CMD, byte Par1, byte Par2) // Excecute the command and parameters
{
 // Calculate the checksum (2 bytes)
 int16_t checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);

 // Build the command line
 byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge, Par1, Par2, checksum >> 8, checksum & 0xFF, End_Byte};

 //Send the command line to the module
 for (byte k=0; k<10; k++)
 {
  MP3Serial.write( Command_line[k]);
 }
}

Tot zover weer...

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #19 Gepost op: 12 mei 2018, 23:44:26 »
Geluidsmodule: geluidsfragmenten maken en lichtschakeling

In dit laatste deel van de opbouw van de geluidsmodule een filmpje over het maken van de geluidsfragmenten en de lichtschakeling van de module.Het is misschien even doorbijten, maar ik heb geprobeerd het bewerken van de geluidsfragmenten duidelijk in beeld te krijgen... Veel computerwerk, dus.

Verder de code voor de Arduino en een stuklijst voor de onderdelen.

Maar eerst: hoe maak je het geluid en het licht.



Arduino programma (sketch)

Dan de code voor de geluidsmodule. Nog in versie 0.9.2.... Ik werk nog aan de laatste verbeteringen bij het haperen van de rijstroom....

/* GELUIDSMODULE
 * versie 0.9.2, Mei 2018 - Rob van Deursen
 * Rijstroom afhankelijk geluid voor analoge modeltreinen.
 * Module vereist rijstroom met pulsbreedte modulatie en heeft dan de volgende functies:
 *    - Startgeluid (starten van een motor, bijvoorbeeld
 *    - Stationair geluid
 *    - Rijstroom afhankelijke geluiden tijdens het rijden
 *    - 4 geluidsfuncties, te bedienen met frequentie-veranderingen op de rijstroom
 *    - 2 andere functies (licht schakelen, bijvoorbeeld)
 * Per loc of treinstel zijn andere definities mogelijk voor de gebruikte pinnen op de
 * Arduino en voor de geluiden op de MP3 speler (DFplayer).
 * De geluiden staan in map "MP3" op de geluidskaart.
 */


// ----- DEFINITIES PER MODULE -----

// === V100 ===
// ----- Pin definities ------
#define pulsbreedtePin1        6       // digitale pin voor PWM rijspanning richting 1
#define pulsbreedtePin2        7       // digitale pin voor PWM rijspanning richting 2
#define lichtPin              11       // Liever niet pin 13, eventueel PWM = dimbaar licht.
#define MP3RX                  9       // serieel receive (van MP3 speler)
#define MP3TX                  8       // serieel transmit (naar MP3 speler
// ----- rijstroom en geluid/licht instellingen ------
#define aantalSnelheden        1.1       // aantal rijsnelheden (exclusief 0), 0 geeft stationair geluid
#define nulPWM               700.0   // PWM pulsbreedte (in us) om aanloopweerstand v.d. motor te overwinnen
#define stapPWM              150.0   // PWM pulsbreedte (in us) verschil om geluidstap te maken (2020 is 100%)
#define startgeluid            1     // 001.mp3
#define stationair             2     // 002.mp3
#define rijden1                3     // 003.mp3
#define geluidsfunctie1        4     // 004.mp3 (bel)
#define geluidsfunctie2        5     // 005.mp3 (Hoorn)
#define geluidsfunctie3        6     // 006.mp3 (kolen scheppen)
#define geluidsfunctie4        7     // 007.mp3 (motor afzetten)
#define lichtfunctie           5     // functie 5 is licht aan/uit
// MP3 speler (DFplayer)
#define volume                22     // geluidsvolume (0-47)
#define equalizer              0     // equaliser 0-5: normal, pop, rock, jazz, classic, base

/*
// === VT98 (RAILBUS) ===
// ----- Pin definities -----
#define pulsbreedtePin1          3       // digitale pin voor PWM rijspanning richting 1
#define pulsbreedtePin2          4       // digitale pin voor PWM rijspanning richting 2
#define lichtPin                11       // Liever niet pin 13, eventueel PWM = dimbaar licht.
//#define MP3RX                  9       // serieel receive (van MP3 speler)
//#define MP3TX                  8       // serieel transmit (naar MP3 speler
// ----- rijstroom en geluid/licht instellingen -----
#define aantalSnelheden        3.1       // aantal rijsnelheden (exclusief 0), 0 geeft stationair geluid
#define nulPWM               515.0   // PWM pulsbreedte (in us) om aanloopweerstand v.d. motor te overwinnen
#define stapPWM              210.0   // PWM pulsbreedte (in us) verschil om geluidstap te maken (2020 is 100%)
#define stationair             1     // 001.mp3
#define rijden1                2     // 002.mp3
#define rijden2                3     // 003.mp3
#define rijden3                4     // 004.mp3
#define startgeluid            5     // 005.mp3
#define geluidsfunctie1        8     // 008.mp3 (hoorn - lang)
#define geluidsfunctie2        7     // 007.mp3 (hoorn - kort)
#define geluidsfunctie3        0     // geen functie
#define geluidsfunctie4        6     // 006.mp3 (motor uitzetten)
#define lichtfunctie           6     // functie 6 is licht aan/uit
// MP3 speler (DFplayer)
#define volume                24     // geluidsvolume (0-47)
#define equalizer              5     // equaliser 0-5: normal, pop, rock, jazz, classic, base
*/
/*
// === BR50 ===
// ----- Pin definities -----
#define pulsbreedtePin1        3       // digitale pin voor PWM rijspanning richting 1
#define pulsbreedtePin2        5       // digitale pin voor PWM rijspanning richting 2
                                       // LET OP! pin 5 lijkt niet de meeest betroubare pin
                                       // hier zit ook een timer/count functie op waarvan het lijkt dat 
                                       // pdeze de ulsbreedte meting verstoort, met name bij het wisselen
                                       // van de pulsbreedte!
#define lichtPin              11       // Liever niet pin 13, eventueel PWM = dimbaar licht.
#define MP3RX                  7       // serieel receive (van MP3 speler)
#define MP3TX                  6       // serieel transmit (naar MP3 speler

// ----- rijstroom en geluid/licht instellingen -----
#define aantalSnelheden        6.1       // aantal rijsnelheden (exclusief 0), 0 geeft stationair geluid
#define nulPWM               510.0   // PWM pulsbreedte (in us) om aanloopweerstand v.d. motor te overwinnen
#define stapPWM              150.0   // PWM pulsbreedte (in us) verschil om geluidstap te maken (2020 is 100%)
#define startgeluid            1     // 001.mp3
#define stationair             2     // 002.mp3
#define rijden1                3     // 003.mp3
#define rijden2                4     // 004.mp3
#define rijden3                5     // 005.mp3
#define rijden4                6     // 006.mp3
#define rijden5                7     // 008.mp3
#define rijden6                8     // 008.mp3
#define geluidsfunctie1        9     // 009.mp3 (fluit - kort)
#define geluidsfunctie2       10     // 010.mp3 (fluit - kort)
#define geluidsfunctie3       11     // 011.mp3 (kolen scheppen)
#define geluidsfunctie4       12     // 012.mp3 (nader te bepalen functie)
#define lichtfunctie           0     //  geen licht functie
//MP3 speler (DFplayer)
#define volume                32     // geluidsvolume (0-47)
#define equalizer              0     // equaliser 0-5: normal, pop, rock, jazz, classic, base
*/


// ----- ALGEMENE DEFINITIES -----
//      technische definities MP3 speler
#define Start_Byte 0x7E
#define Version_Byte 0xFF
#define Command_Length 0x06
#define End_Byte 0xEF
#define Acknowledge 0x00 //Returns info with command 0x41 [0x01: info, 0x00: no info]

// Definities voor de elektronica
#define elcoLaadtijd           800    // oplaadtijd van de Elcos (ms) = tijd tot stabiele pulsmeting
#define pullup false                  // gebruik van interne pullup weerstanden op rijpinnen ja/nee (true/false)

// Frequenties (Periodes) op de rijstroom
#define rijPeriode            2020    // rijstroom puls in us
#define functie_01_Periode    1500    // Periode (freq.) functie 1
#define functie_02_Periode    1250    // Periode (freq.) functie 2
#define functie_03_Periode     990    // Periode (freq.) functie 3
#define functie_04_Periode     790    // Periode (freq.) functie 4
#define functie_05_Periode     590    // Periode (freq.) functie 5
#define functie_06_Periode     490    // Periode (freq.) functie 6
#define pulsruis                40    // maximaal verschil in gemeten Periodes (ruis)
#define minhoog                200

// ---- VARIABELEN ----

int pulsbreedtePin[] {pulsbreedtePin1, pulsbreedtePin2};

double pulsbreedteHoog;
double pulsbreedteLaag;
double pulsbreedteHoog2;
double pulsbreedteLaag2;
double pulsPeriode;
double pulsPeriode2;

int lopendeFunctie = 0;               // > 0 : er wordt een speciale functie uitgevoerd

int snelheid = 0;
int vorigeSnelheid = 0;
int vooruit = 1;                      // richting: bepaalt welke pin wordt uitgelezen voor de rijstroom puls
int MP3klaar;                         // geeft aan of MP3 speelt, , 0 = aan, 1 = uit.
int x = 0;

int geluidsfunctie [] {geluidsfunctie1, geluidsfunctie2, geluidsfunctie3, geluidsfunctie4};

int  MP3count = 0;                    // teller om status op te vragen

// ---- libraries en objecten ----
#include <EEPROM.h>                   // EEPROM om licht aan/uit te onthouden
#include <SoftwareSerial.h>           // // softserial voor mp3

SoftwareSerial MP3Serial(MP3RX, MP3TX); // RX, TX

// ----- Initialiseren -----
void setup() {
  MP3Serial.begin(9600);
 // Serial.begin(9600);
 // Serial.println("Opstarten...");
  pinMode     (pulsbreedtePin[0],INPUT);
  digitalWrite(pulsbreedtePin[0],pullup);
  pinMode     (pulsbreedtePin[1],INPUT);
  digitalWrite(pulsbreedtePin[1],pullup);
 
  pinMode     (lichtPin,OUTPUT);
  digitalWrite(lichtPin,EEPROM.read(0));             // licht aan of uit: waarde uit EEPROM
 
  // gluidsmodule starten
  execute_CMD(0x3F, 0, 0);            // initialiseer MP3 speler
 // Serial.println("MP3 speler initialisatie");
  delay (80); 
  while (MP3status() == 0) {     // wacht op antwoord
   // Serial.println("Wacht op initialisatie");
    delay (50);
  }
  execute_CMD(0x06, 0, volume);       // zet het geluidsvolumevolume
  delay (80);
  execute_CMD(0x07, 0, equalizer);    // equalizer
  delay (80);
  speelGeluid (startgeluid);          // speel startgeluid af
 
  // terwijl de MP3 speler start, wordt de richting alvast gemeten
  delay(elcoLaadtijd);       // wacht op stabiele puls (na opladen Elco)

  do {
    vooruit = (vooruit ==0 );
    pulsbreedteHoog = pulseIn(pulsbreedtePin[vooruit], HIGH);
    pulsbreedteLaag = pulseIn(pulsbreedtePin[vooruit], LOW );
    pulsbreedteHoog2 = pulseIn(pulsbreedtePin[vooruit], HIGH);
    pulsbreedteLaag2 = pulseIn(pulsbreedtePin[vooruit], LOW );
    pulsPeriode = pulsbreedteHoog + pulsbreedteLaag;
    pulsPeriode2 =  pulsbreedteHoog2+ pulsbreedteLaag2;
   // Serial.print("rijpin: ");
   // Serial.print(vooruit + 1);
   // Serial.print(" ");
   // Serial.println(pulsbreedteHoog);

  } while (pulsbreedteHoog < minhoog  || pulsbreedteHoog2 < minhoog );  // "hoog" signaal is pin actief


}

void loop() {
 
  do {
 
    pulsbreedteHoog = pulseIn(pulsbreedtePin[vooruit], HIGH);
    pulsbreedteLaag = pulseIn(pulsbreedtePin[vooruit], LOW );
    pulsbreedteHoog2 = pulseIn(pulsbreedtePin[vooruit], HIGH);
    pulsbreedteLaag2 = pulseIn(pulsbreedtePin[vooruit], LOW );
    pulsPeriode = pulsbreedteHoog + pulsbreedteLaag;
    pulsPeriode2 =  pulsbreedteHoog2+ pulsbreedteLaag2;
 
   // Serial.print("rijpin: ");
   // Serial.print(vooruit + 1);
   // Serial.print(" ");
   // Serial.print(pulsPeriode);
   // Serial.print(" / ");
   // Serial.print(pulsbreedteHoog);
   // Serial.print(" / ");
   // Serial.print(pulsbreedteLaag);
   // Serial.print(" || ");
   // Serial.print(pulsPeriode2);
   // Serial.print(" / ");
   // Serial.print(pulsbreedteHoog2);
   // Serial.print(" / ");
   // Serial.println(pulsbreedteLaag2);
   
  } while (pulsPeriode > rijPeriode + pulsruis || pulsbreedteHoog < minhoog || pulsbreedteLaag < pulsruis  );

// bepaal welk signaal (frequentie) is ontvangen en voer bijbehorende functie uit
  if (abs (pulsPeriode - rijPeriode) < pulsruis) {
    // normale rijstroom
    snelheid = getSnelheid(pulsbreedteHoog);
  } 
  MP3klaar = (MP3status() == 1);

   
  if (lopendeFunctie > 0) {      // er loopt nog een speciale geluidsfunctie
    if (MP3klaar) {              // geluid voor een functie is afgespeeld
      lopendeFunctie = 0;        // gewoon geluid afspelen
    }
  }
   
  //snelheid afhankelijk geluid
  if (lopendeFunctie == 0) {     // Er wordt geen speciaal geluid (meer) afgespeeld
    lopendeFunctie = getFunctie();   
    // geluidsfunctie (1 - 6)
    if (lopendeFunctie > 0) {    // (geluids)functie gestart
      lopendeFunctie = startFunctie(lopendeFunctie);
    }
    else {
    // geen speciale functie nu, dus gewoon geluid spelen
      if (snelheid != vorigeSnelheid || MP3klaar ) {
        // er is een snelheidswissel of MP3 speelt niet meer
       
        speelGeluid(snelheid+2);   // geluidsbestand 002-008
        vorigeSnelheid = snelheid;
      }
    }
  }
}

//



//functie bepalen snelheid op basis van pulsbreedte
int getSnelheid(double pbr){
  int s;

  s = (pbr - nulPWM)/stapPWM;
  s = constrain (s, 0, aantalSnelheden);              // beperk de snelheidswaarde tussen 0 en het maximum
  return s;
}


// functie voor het checken van functie-frequenties op de puls (functietoets)
int getFunctie () {
  int f = 0;
 
  if (abs (pulsPeriode - functie_01_Periode) < pulsruis && abs (pulsPeriode2 - functie_01_Periode) < pulsruis ) { f = 1;}
  if (abs (pulsPeriode - functie_02_Periode) < pulsruis && abs (pulsPeriode2 - functie_02_Periode) < pulsruis ) { f = 2;}
  if (abs (pulsPeriode - functie_03_Periode) < pulsruis && abs (pulsPeriode2 - functie_03_Periode) < pulsruis ) { f = 3;}
  if (abs (pulsPeriode - functie_04_Periode) < pulsruis && abs (pulsPeriode2 - functie_04_Periode) < pulsruis ) { f = 4;}
  if (abs (pulsPeriode - functie_05_Periode) < pulsruis && abs (pulsPeriode2 - functie_05_Periode) < pulsruis ) { f = 5;}
  if (abs (pulsPeriode - functie_06_Periode) < pulsruis && abs (pulsPeriode2 - functie_06_Periode) < pulsruis ) { f = 6;}

  return f;
}

// speciale functie starten
// geeft terug of de functie moet blijven lopen
int startFunctie(int f) {
  int lopen = 0;
  int gn;
  if (f < 5 ){                     // geluidsfunctie (1-4)
    gn = geluidsfunctie [f-1];     // geluidsbestand nummer
    //geluid afspelen
    if (gn > 0) {                  // geluid is gedefinieerd (0 = geen geluid)
      speelGeluid(gn);
      lopen = f;                   // volgende functie wacht op aflopen MP3 geluid
    }
  }
  else if (f == lichtfunctie) {
    digitalWrite(lichtPin, (digitalRead (lichtPin) == LOW) );    // wissel hoog/laag (= aan/uit)
    EEPROM.write(0,digitalRead (lichtPin));                      // onthou licht aan of uit tot volgende opstart.

    delay (100);
  }
  return lopen;                    // 0 = niet wachten, > 0 is wachten op einde geluid 
}

// controleer of geluid is afgespeeld
// met I/O pin is "hoog" klaar
// zonder IO pin is het info ontvangen op soft serial

// Speel geluid af
// stuurt commando naar de MP3 speler
void speelGeluid(int bestandnummer) {
  execute_CMD(0x03, 0, bestandnummer);
 // Serial.print("Geluidsbestand gestart: ");
 // Serial.println(bestandnummer);
  MP3klaar = 0;                         // geluid speelt
  delay (100);
}

// status MP3 speler lezen
// output: 0 = geen info
//         1 = mp3 klaar (speelt niet)
//         2 = mp3 speelt
//         3 = fout / onbekend
int MP3status () {
  int m = 0;
  int t = 0;
  byte b;
  int bstat;                       // status byte
  int btrack;                      // bestand nummer
  if ( !MP3Serial.available()) {   // er is niets aangekomen op de seriele
    MP3count ++;
    if (MP3count > 30000 ) {
       execute_CMD (0x4B,0,0);      // query huidig bestand dat wordt afgespeeld
       //delay (100);
       MP3count = 0;
      // Serial.println("status verzoek");
    }
   }
   else {                           // er is iets op de seriele bus
    delay(80);
    while(MP3Serial.available()) {  // serieel uitlezen
      t++;
      b = MP3Serial.read();
      if (t == 4) {                 // dit is de status byte
        bstat = b;
      }
      if (t == 7) {                 // dit is het bestandsnummer
        btrack = b;
      }
      if (t == 10){                 // meer dan 1 bericht
        t=0;
      }
     // Serial.print(b,HEX);
     // Serial.print(".");
    }
    switch (bstat) {
      case 0x3F:                    // initialisatie parameters ontvangen
        m = 2;                      // speler is bezig
      break;
      case 0x3D:                    // eind van een bestand
        m = 1;                      // speler is klaar
      break;
      case 0x4B:                    // antwoord op bestand dat wordt afgespeeld
        if (btrack > 0) {
          m = 2;                    // bestand speelt
        } else {
          m = 1;                    // er speelt geen bestand, speler is kaar
        }   
      break;
      case 0x40:                    // fout in transmissie
        delay(150);                 // even wachten
        m = 1;                      // speler is klaar
      default:
        m = 3;                      // onbekend = fout
    }
   // Serial.print("||");
   // Serial.print(bstat,HEX);
   // Serial.print(" - ");
   // Serial.print(btrack);
   // Serial.print(" m: ");
   // Serial.println(m);
    return m;
  }
}

/*
// Reset MP3 speler
void resetMP3() {
 // Serial.print("MP3 module reset... ");
  delay (100);                          // even wachten na de foutmelding, MP3 pseler is mogelijk aan het initialiseren.
  execute_CMD(0x0C, 0, 0);              // stuur reset commando
  delay (50);
  execute_CMD(0x3F, 0, 0);            // initialiseer MP3 speler
 // Serial.println("MP3 speler initialisatie");
  delay (800);
  execute_CMD(0x06, 0, volume);       // zet het geluidsvolumevolume
  delay (80);
  execute_CMD(0x07, 0, equalizer);    // equalizer
  delay (80);
  MP3klaar = 1;                       // er wordt geen bestand meer afgespeeld
}
*/
//===
// DF Seriële commando's versturen
void execute_CMD(byte CMD, byte Par1, byte Par2) // Excecute the command and parameters
{
  // Bereken checksum (2 bytes)
  int16_t checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);

  // Bouw het commando op
  byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge, Par1, Par2, checksum >> 8, checksum & 0xFF, End_Byte};

  // Verstuur commando naar MP3 speler
  for (byte k=0; k<10; k++)
  {
    MP3Serial.write( Command_line[k]);
  }
}
--- EINDE ---

Stuklijst

Als laatste nog een lijst van onderdelen met prijsindicatie als je spullen in Nederland koopt.

  • Arduino Uno (zonder 'headers')               | 4,95
  • DFplayer mini                                        | 4,00
  • SD kaart (1GB is ruim voldoende)           | 5,00
  • Gelijkrichter                                          | 0,50
  • Elco (s)                                                 | 0,25 - 0,35/stuk
  • diverse weerstanden (7 stuks)                | 0,70 (0,10/stuk)
  • Transistor NPN (BC547B)                        | 0,05
  • mini speaker                                          | 0,40*
* kleine speakers kon ik alleen bij Ali express vinden. Kosten minder dan $4 per 10 stuks.

Totaal ben je zo'n 15 euro kwijt. Maar dat kan een stuk (per stuk) goedkoper door te bestellen inChina en eventueel meteen onderdelen voor meerdere exemplaren te bestellen.

Ondertussen ben ik alweer aan het nadenken over de geluid/licht wagen voor kleinere locs die zelf geen geluidsmodule kunnen opnemen. Met meerdere geluiden, afhankelijk van het type loc dat er voor zit, en wellicht ook richtingsafhankelijk.
En ik ben al aan het kijken naar verdere verkleining door de Arduino te vervangen door iets kleiners....
Kortom: wordt vervolgd.

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #20 Gepost op: 18 mei 2018, 22:25:57 »
Een universele geluidswagon

Ik ben aardig op dreef met het inbouwen van geluid in verschillende treinen, maar zo gaandeweg vroeg ik mij af of ik mijn doel niet aan het voorbij schieten ben... Nu er enkele treinen met geluid rond rijden, is het zonder geluid meteen wat kaal en daarmee werd de aandrang wel groot om overal geluid in te bouwen.
Maar wat nu als:
  • Een loc te klein is om zo'n geluidsmodule in te passen? Ik kan de modules nog wel wat kleiner maken, maar een BR70 of V60 gaat toch echt niet lukken.
  • Een loc weinig wordt gebruikt? Dan is het inbouwen van zo'n geluidsmodule de investering en moeite niet waard.
  • Een loc nog geen geluidsmodule heeft? De productie van een aantal modules en de bijbehorende geluiden is toch nog wel een klusje.
De oplossing: een wagon die geluiden van verschillende locs kan maken, bijvoorbeeld een bagagewagon.




Met de 4 functie toetsen van de rijstroom bediening kunnen 4 verschillende locs worden gekozen of het geluid helemaal worden uitgezet. Zet de wagon vlak achter de loc, kies het geluid dat er bij hoort, en rijden maar.
Met zo'n wagon aan de voorkant van een trein is het eenvoudig om een loc te wisselen, en toch het juiste geluid te maken. Handig als je meer locs hebt dan je gelijktijdig kunt laten rijden.
En met zo'n wagon aan elke kant van de trein, kun je zelfs de loc omrijden en het geluid steeds van dicht bij de loc laten komen.
Het geluid uitschakelen is ook handig als de trein in een schaduwstation staat: de loc staat dan stroomloos, maar de wagon niet. Met een druk op de functietoets 4 (blauw) gaat het geluid dan uit. Als de trein weer uit het schaduwstation komt rijden, gaat het geluid met een druk op een functietoets weer aan.

Voor deze bagagewagon heb ik een batterij van Elco's gemaakt, die straks dienst doen als lading in de wagon (vaten). Ik was wel benieuwd hoe het geluid zou werken met stroomopname over slechts 2 wielen (een wiel voor elke pool), zoals deze standaard in de wagon was ingebouwd, vandaar een wat ruimere capaciteit aan Elco's




Dat viel nog niet eens tegen. Met enige snelheid konden zelfs vaak zonder storingen worden over wissels worden gereden. Maar voor een betrouwbaar geluid tijdens het rijden, toch nog maar 2 stroomafnemers toegevoegd. Om de extra stoomafname wat eenvoudig te houden, heb ik een van de assen omgedraaid, zodat nu een pool over de beide assen stroom opneemt, en de andere over de wielen aan een zijde.




Ondertussen is de wagon voorzien voor geluiden voor de BR70 en de V60. 2 andere sets van geluiden ga ik nog maken, nog een voor een (middel)zware stoomloc en een voor een v160.

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #21 Gepost op: 20 mei 2018, 21:58:59 »
Met zo gaandeweg 4 geluidsmodules in verschillende hardware en software configuraties heb ik wat tijd besteed aan standaardisatie.De railbus had nog een prototype aan boord met een afwijkende aansturing van de MP3 speler. Bovendien vond ik het storend dat de module bijna tot aan het dak zat. Met name met licht aan was deze duidelijk te zien. Nu begon de elektronica ook wat te haperen, nadat deze -tig keer was bewogen om nieuwe software te laden. Allemaal redenen om de railbus van een nieuw opgebouwde geluid- en lichtmodule te voorzien.

Dit was de  opbouw van het prototype:




Van de nieuw opgebouwde module zijn bijna alle componenten ter plekke gesoldeerd, zodat alles precies pas is op de plek waar het moet komen. Dit mede om de module deze keer onder de onderste  raamstijlen te houden (of in ieder geval zo veel mogelijk). Ook is de gehele opbouw wat overzichtelijker geworden.




Met een paar lichtgekleurde kartonnetjes net onder de ramen, ook in de motorwagen, ziet dit railbusje met verlichting er nu zo uit:




Nu is ook de software en indeling van de MP3 bestanden op de SD kaartjes dezelfde geworden. Ondertussen ben ik er achter hoe de bestanden op "naam" (001.mp3, 002.mp3, etc.) kunnen worden afgespeeld, in plaats van de volgorde waarmee de bestanden op het kaartje zijn gezet. Alle 4 geluidmodules hebben nu dezelfde software en geheugenkaart indeling gekregen.

Deze standaard is ook nodig, omdat vanaf nu er 2 types microcontrollers gebruikt gaan worden: de Arduino Nano en een Digispark met ATtiny. Die laatste is kleiner, heeft net genoeg pinnen en programma opslag geheugen. Hoewel er veel inspanning is gedaan om deze digispark op een Arduino te laten lijken, zijn er op details toch wat verschillen. Dat betekent  software ontwikkeling in 2 parallelle sporen. Dus vanaf dit gezamenlijke startpunt 2 standaarden.
(ik heb wel eens gehoord: "standaarden zijn goed, daar moeten we er zoveel mogelijk van hebben!" Ik doe mijn best...)

Met deze Digispark hoop ik geluidsmodules te kunnen inbouwen in de BR38, de BR78 en misschien zelfs de BR64....
Meer hierover in een volgend bericht.

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #22 Gepost op: 28 mei 2018, 20:06:54 »
DigiSpark i.p.v. Arduino

Met de lengte van de Arduino kwam ik niet meer uit in kleinere locs dan de railbus, BR50 of V100. Na enig onderzoek kwam ik uit op een kleinere variant: de DigiSpark. Met de de informatie die ik had:

"De DigiSpark is geen Arduino, maar we hebben ons best gedaan deze er zoveel mogelijk op te laten lijken", en
"Alle 6 pinnen zijn te gebruiken als input/output voor je project".

Dacht ik: dat moet lukken. Ik ben de afgelopen avonden bezig geweest om het ook te laten lukken. Er waren toch voldoende afwijkingen ten opzichte van de Arduino om verschillende hoofdbrekens te geven  :)

Even een vergelijk: boven de Arduino Nano, onder de DigiSpark (en 50 eurocent ter referentie)




Nu is de Digispark echt kleiner, niet alleen in maatvoering, maar ook in programma opslag ruimte: er staat maar liefst 6012 byte tot je beschikking (dus een kleine 6 kB!). Dat is een fractie van de opslagruimte op je telefoon en evengoed een stuk minder dan de opslagruimte van de Arduino. Omdat de kleine versie van de geluidsmodule gebruikt wordt als de ruimte beperkt is, heb ik de lichtfunctie laten vervallen. Zo is het programma na compileren net klein genoeg om op de DigiSpark te kunnen laden.

Er is in ieder geval (net) voldoende ruimte in de cabine van de BR78 voor voeding, DigiSpark en 'getrimde' MP3 speler.






Dus eerst maar eens de voeding: gelijkrichter met Elco's en weerstanden voor de rijstroom meting.




En dan kan de DigiSpark met daarop de MP3 speler gesoldeerd worden. Deze komt bovenop de voeding.




Dus maar eens testen. Maar dat werkte niet zo maar. Zo gaandeweg ben ik nogal wat uitdagingen tegengekomen, zoals:
  • Computer: de drivers en de bibliotheken installeren. Dat was niet heel moeilijk volgens de video's... Maar op mijn computer had ik een 'halve' installatie waar ik nauwelijks uit kwam. Gelukkig werkte een en ander op mijn oude computer wel volgens het boekje (of YouTubje).
    En na wat kopiëren naar mijn nieuwe laptop werkt het ook daar.
  • Pin gebruik: die was helemaal niet zo duidelijk. ik had geen proefopstelling gemaakt, want alle pinnen waren immers te gebruiken... Toch niet. Na veel proberen en verder onderzoek bleek:
    pin 5 op de chinese kloon van de DigiSparkis  ingesteld als reset,
    pin 3 vanwege de USB voorzien van een zener diode en 1k5 pullup weerstand naar 5V.
    en zit er een LED op pin 1.
    Dat gooit allemaal behoorlijk roet in het eten als je seriele communicatie met de MP3 speler wil doen of rijstroom wil meten op deze pinnen... Ook programma's uploaden gaat niet meer als je "iets" aan pin 3 soldeert: de computer herkent de DigiSpark niet meer op de USB poort.
Dus vele aanpassingen (solderen, desolderen, nieuw programma, solderen, etc...) later ziet het er zo uit.




Het werkt (redelijk) en het past ook nog: de speaker komt net naast de koolborstels in een van de watertanks.

Pfff... missie geslaagd. Gelukkig is voldoening is het product van moeite en resultaat  8)

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...

Offline mark mms

  • Super Modelspoorder
  • ******
  • Berichten: 1.224
  • Thanked: 26 times
  • Geslacht: Man
Re: Analoog rijden met geluid - het project.
« Reactie #23 Gepost op: 2 juni 2018, 08:12:26 »
Wauw Rob,

Is de volgende uitdaging de glaskast of köff?

Offline Rob

  • Forumbeheerder
  • Super Modelspoorder
  • *****
  • Berichten: 2.743
  • Thanked: 161 times
  • Geslacht: Man
  • Rob zegt: denk aan morgen, doe vandaag.
Re: Analoog rijden met geluid - het project.
« Reactie #24 Gepost op: 6 juni 2018, 11:40:55 »
Dank je, Mark

Is de volgende uitdaging de glaskast of köff?
Oepfff… Gelukkig heb ik geen van beide in mijn verzameling  :D
Voorlopig is de BR64 de kleinste die ik wil proberen.... De rest gaat met geluidswagons die geluiden van verschillende locs kunnen produceren.

Rob
Ergens in (West) Duitsland tussen 1960 en 1970 | gelijkstroom analoog, met geluid | kleine vaste baan en uitbreiding met modulebaan.
Nu vooral bezig met van alles en nog wat...