Doel:€250.00
Donaties:€65.00

Per saldo:€-185.00

Steun ons nu!

Laatst bijgewerkt
op 17-02-2020
Algemeen

De stichting

Recente berichten

Pimpen van Audi 80 (mijn eerste auto) door ReneN
Vandaag om 00:51:44
RAIL 2020 21, 22 en 23 februari, Houten. door arnout
Vandaag om 00:51:41
Mijn eerste H0-modeltreinbaan in aanbouw door barry1972
Vandaag om 00:45:35
Frans diorama 1:48 door Wim Corduwener
Vandaag om 00:36:59
Uhlenbrock goldcap condensator 71800 aansluiten aan decoder? door sneek
Vandaag om 00:22:28
Waterstoftrein als alternatief voor diesel door 72sonett
Vandaag om 00:17:08
Concept en vragen voor eenvoudig bloksysteem met transistors door 72sonett
Vandaag om 00:08:16
Eindelijk de bouw....SS3 nadert voltooing en nu SS4 door Wim Vink
26 februari 2020, 23:50:21
NS modelbaan Hoekdam H0 door Wim Vink
26 februari 2020, 23:48:20
NS C-4704 coupérijtuig in messing. Spoor-0 door FritsT
26 februari 2020, 23:44:40
Diorama in een Billykast door Remco_Nzo
26 februari 2020, 23:23:11
Raadplaatje door GerardvV
26 februari 2020, 23:22:30
EifelBurgenBahn door Reinout van Rees
26 februari 2020, 23:19:08
Bremer Lagerhaus-Gesellschaft Flachwaggon der Bauart 100 door Rockerbox2
26 februari 2020, 23:17:40
Lima en Rivarossi Mat’46 Muizeneus: problemen en oplossingen door prutser
26 februari 2020, 22:54:48
Frans loodsje et cetera door Noordernet
26 februari 2020, 22:43:04
Uhlenbrock 76320 decoder, kortsluiting? door Timo
26 februari 2020, 22:27:28
ESU Lokpilot 4 decoder, verlichting tegengesteld aan rijrichting door Timo
26 februari 2020, 22:18:24
NS 6700 dierenserie etchmodels door Beached
26 februari 2020, 22:08:13
NS DE-5 op basis van Lima Mat'46. door NS8714
26 februari 2020, 22:07:47
Segment draaischijf zelf bouwen? door heuvelbaan
26 februari 2020, 22:01:12
NL-baan in Canada door Eric B
26 februari 2020, 21:56:55
Open rijden wissels door johanw
26 februari 2020, 21:50:15
"Union Pacific's Power Shop", een nieuwe baan in H0 door Ronald Halma
26 februari 2020, 21:49:29
Poolse meuk in 0e. door Stedahult
26 februari 2020, 21:07:04
Oude schilden roesten niet. Fleischmann motorschild voor DCC door Overet
26 februari 2020, 20:58:38
Gezocht deze wagon, gezien in Zweden, wie maken 'm en art.nr.? door nighttrain1
26 februari 2020, 20:35:23
Plaatsing objecten langs het spoor en bij wissels door Mitchell
26 februari 2020, 20:21:38
Mallnitzer Tauernbahnstrecke ÖBB N Spoor door raymond erdtsieck
26 februari 2020, 20:15:34
Schwarzburg-Neuffen-Bahn door Edde
26 februari 2020, 20:12:33
  

Auteur Topic: De CanBus komt naar Kranenberg, Arduino's en de CanBus  (gelezen 11027 keer)

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #75 Gepost op: 06 december 2019, 21:48:46 »
De Bezetmelder Controllers zijn ook weer Arduino Uno's.



Een fotootje van de DTC en PMP7 bezetmelders.



Laten we nu even naar de schets kijken die de Bezetmelder Controller bestuurd.

/*
  A program to monitor occupance detectors and send their status to the S88 interface

  Copyright (C) Meino de Graaf, all rights reserved

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation, version 2
  of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  email: meino@innerside.demon.nl
*/
#include <KB-Bezetmelder.h>
#include <CanBus.h>

#define DEBUG 0

typedef struct {
  short systemId;
  Detector *occ;
} occDt;

Twee bibliotheken worden gebruikt, de Canbus en de KB-Bezetmelder bibliotheek. Verder definieren we een structure die we gebruiken om een array te maken. Hiermee kunnen we bepalen welke Detector objecten door dit specifiek systeem worden gecontroleerd. Ieder systeem krijgt via een paar jumpers zijn eigen uniek id. Hierdoor hoef ik niet voor iedere controller een aparte schets bij te houden.

const int nrOfDetectors = 32;

occDt occDetectors[nrOfDetectors] =
{
  /* Detectors on controller 1 */
  { 1, new DTC8("S4",  2,1, 1)},            //  1.01
  { 1, new DTC8("S4C", 3,2,14)},            //  2.14
  { 1, new DTC8("S5C", 4,2,15)},            //  2.15
  { 1, new DTC8("S6",  5,1, 2)},            //  1.02
  { 1, new DTC8("S6B", 6,1, 8)},            //  1.08
  { 1, new DTC8("S11B",7,1, 6)},            //  1.06

  /* Detectors on controller 2 */
  { 2, new PMP7("S4B", 3,2,12)},            //  2.12
  { 2, new LS("S11A",4,1, 3)},              //  1.03
  { 2, new PMP7("S7A", 5,2,13)},            //  2.13
  { 2, new LS("S10B",6,1,15)},              //  1.15
 
  /* Detectors on controller 3 */
  { 3, new DTC8("S2",  2,1,10)},            //  1.10
  { 3, new PMP7("S3B", 3,2,11)},            //  2.11
  { 3, new PMP7("S7",  4,1,16)},            //  1.16
  { 3, new DTC8("S8A", 5,1, 7)},            //  1.07
  { 3, new PMP7("S9B", 6,1,14)},            //  1.14
  { 3, new PMP7("S10A",7,2,10)},            //  2.10
  { 3, new DTC8("S8",  8,1,13)},            //  1.13
  { 3, new PMP7("S3",  9,1,11)},            //  1.11
 
  /* Detectors on controller 4 */
  { 4, new DTC8("S1B", 2,2, 2)},            //  2.02
  { 4, new DTC8("S4A", 3,2, 9)},            //  2.09
  { 4, new DTC8("S5A", 4,1, 4)},            //  1.04
  { 4, new DTC8("S12C",5,2, 3)},            //  2.03
  { 4, new DTC8("S19A",6,1, 5)},            //  1.05
  { 4, new DTC8("S19C",7,2, 6)},            //  2.06
   
  /* Detectors on controller 5 */
  { 5, new DTC8("S1",  2,1, 9)},            //  1.09
  { 5, new DTC8("S2B", 3,2, 7)},            //  2.07
  { 5, new DTC8("S5B", 4,2, 1)},            //  2.01
  { 5, new DTC8("S8B", 5,2,16)},            //  2.16
  { 5, new DTC8("S9A", 6,2, 8)},            //  2.08
  { 5, new PMP7("S9C", 7,1,12)},            //  1.12
  { 5, new DTC8("S12B",8,2, 4)},            //  2.04
  { 5, new DTC8("S19B",9,2, 5)}             //  2.05
};

In totaal 32 bezetmelders. De eerste parameter is de naam van de sectie die ik in AnyRail aan de specifieke sectie heb gegeven, dit wordt alleen in debugging mode gebruikt. De tweede parameter is de digitale pin waar de detector aan verbonden is. De derde en vierde parameter zijn de S88 adressen zoals die in mijn besturings programma (Koploper) gedefinieerd zijn.

//
//  The CanBus
//
CanBus *canBus;

//
//  Interrupt routine for the detectors, that is called when an
//  Detector wants to report a state.
//
void stateHandler(byte s88Bank, byte s88Id, bool occupiedState)
{
    //
    //  Send the new state to the S88 Interface
    //
    OCC_DT_MSG buf;
    buf.address = ((s88Bank-1)*16)+(s88Id-1); // convert to a bit index
    if (occupiedState)
      buf.state = 1;
    else
      buf.state = 0;

    //
    //  Repeat the message, to cover the occasional mishap
    //
    canBus->sendMsg(OCC_DT,sizeof(OCC_DT_MSG), &buf);
    canBus->sendMsg(OCC_DT, sizeof(OCC_DT_MSG), &buf);

#if (DEBUG)
    Serial.print("[stateHandler], detectornr: ");
    Serial.print(buf.address);
    Serial.print(", state: ");
    Serial.println(buf.state);
    Serial.flush();
#endif // DEBUG
}

Het CanBus object en de stateHandler interrupt routine. In deze stateHandler interrupt routine wordt de informatie komend van de Detector vertaald naar een OCC_DT bericht en op de zend queue van het CanBus object gezet.

//
//  Pins used to define the ID of this controller
//  It is used to filter out all semaphores which aren't controlled by
//  this instance of the SeinController
//
#define PIN_ID_0  A0
#define PIN_ID_1  A1
#define PIN_ID_2  A2
#define PIN_ID_3  A3

//
//  ID that defines this specific instance of the controller.
//  It's actual value is established during setup and is based on some jumpers
//
int systemId = 0;

void setup()
{
  //
  //  Based on which pin is connected to ground, the controller ID is established
  //
  pinMode(PIN_ID_0, INPUT_PULLUP);
  pinMode(PIN_ID_1, INPUT_PULLUP);
  pinMode(PIN_ID_2, INPUT_PULLUP);
  pinMode(PIN_ID_3, INPUT_PULLUP);

  systemId = 0;
  if (!digitalRead(PIN_ID_0)) systemId = systemId+1;
  if (!digitalRead(PIN_ID_1)) systemId = systemId+2;
  if (!digitalRead(PIN_ID_2)) systemId = systemId+4;
  if (!digitalRead(PIN_ID_3)) systemId = systemId+8;
 

#if (DEBUG || BEZETMELDER_DEBUG || CANBUS_DEBUG || CANBUS_DEBUG1)
  Serial.begin(115200);
  while (!Serial);
  Serial.print("Starting Controller ID: ");
  Serial.println(systemId);
  Serial.flush();
#endif //DEBUG

  //
  //  Setup and start the CanBus communication
  //
  canBus = new CanBus(BEZETMELDER_CONTROLLER_ID+systemId, new Mcp2515(10), nullptr); // Only a sender
  canBus->begin();

  //
  //  Activate all the occupancy detectors and attach them to their pins
  //
  for (int i = 0; i < nrOfDetectors; i++)
  {
    if (occDetectors[i].systemId == systemId)
    {
      occDetectors[i].occ->registerStateHandler(stateHandler);
      occDetectors[i].occ->attach();
    }
  }

  //
  // Wait a second, so the S88 interface is ready
  //
  delay(1000);
 
#if (DEBUG)
  Serial.println("ready");
  Serial.flush();
#endif
}

De Arduino setup routine, deze bepaald aan de hand van de PIN_ID pinnen de systemid. Het CanBus object wordt gecreerd en gestart. Vervolgens worden die Detectors uit de occDetectors array met een overeenkomend systemId geactiveerd. Hun pinnen worden in gebruik genomen en de stateHandler wordt geregistreerd bij hen. Om zeker te zijn dat de S88 Interface ook klaar is, wachten we 1 seconde voor we de setup routine verlaten. Dit omdat op het moment dat we de setup verlaten de Bezetmelder Controller direct zal beginnen met het zenden van OCC_DT berichten met de huidige status van de Detectors.

void loop()
{
  //
  //  Monitor all attached occupancy detectors
  //
  for (int i = 0; i < nrOfDetectors; i++)
  {
    if (occDetectors[i].systemId == systemId)
    {
      occDetectors[i].occ->heartBeat();
     
      //
      // Keep the canBus running
      //
      canBus->heartBeat();
    }
  }
}

De Arduino loop functie gaat bij iedere aanroep weer door de occDetectors array en iedere detector die hoort bij onze systemId wordt geactiveerd via de heartBeat method. Ook de canbus wordt actief gehouden door dan ook de heartBeat method op het CanBus object aan te roepen.

Tot zover de Bezetmelder Controller.

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

Timo

  • Team encyclopedie
  • Offline Offline
  • Berichten: 4588
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #76 Gepost op: 12 december 2019, 11:25:12 »
Even een tijdje niet meegelezen dus probeer weer even bij te komen ;D Want je bent erg lekker bezig geweest in de tussentijd! (y)

const int nrOfOccDetectors = 6 * 16;

volatile byte pendingStates[nrOfOccDetectors];
volatile byte dataRegister[nrOfOccDetectors];
Oei, zonde. Waarom niet gewoon de bytes echt vullen? Kost het je maar 1/8e

PS_Int() is een ISR?

  //
  //  Delay makes reading output signal from next Arduino in chain more reliable.
  //
  //delayMicroseconds(2);
Zou niet moeten, zet je de data er wel op de juiste edge op?

Dat wordt gedaan door deze twee interupt routines, die gekoppeld zijn aan pin 2 en 3 (op een Arduino UNO).
Wat doet de tweede ISR dan? ???

void setup()
{
  //
  //  Intialize the dataRegister
  //
  memset(pendingStates,0,nrOfOccDetectors);
  memset(dataRegister,0,nrOfOccDetectors);
Vertrouw je de initialisatie niet? ;D

Pointers kunnen als parameters aan methods door gegeven worden, de physieke objecten niet.
Hoezo niet?  ???

daar heb ik veel meer ervaring in dan C++ en daar is alles "By Reference", lees pointers. Daardoor hoef ik me in de code niet af te vragen of ik een -> of een . moet gebruiken.
Als je voor alles references zou gebruiken ipv pointers is het gewoon altijd een .  ;D (Let op, geen commentaar! Lekker zo doorgaan!)

Als elke s88 melder een 4 of 8 bit Crc achter de data zou plakken en dus 20 of 24 bit zou doorschuiven dan zou dit een prima foutongevoelige bus zijn.
Foutongevoelig, ja. Robuust, nee. De thoughput zal er dan flink onder leiden.

  • DTC8/DTC2 Dit is een stroomdetector die werkt met een resonantie kring.
Is dit niet erg gevoelig voor lange rails etc? Ken het verder niet namelijk.

[edit]Zag later pas aan het plaatje dat ze op basis van CT's zijn. Maakt hij überhaupt wel gebruik van een resonantie kring?

  • PMP7 [...] dat betekend dat voor de bezetmelder sectie beide railstaven onderbroken moeten worden en via de schakeling gevoed worden.
Ook deze ken ik niet, maar de conclusie dat beide staven onderbroken moeten worden voor stroomdetectie is niet standaard.

Waarom heb je doAttach() en doHeartBeat() niet gewoon als attach() en heartBeat() gedefinieerd en uitgebreid in de afgeleiden? (Puur interesse!)

Dit is een abstracte klas omdat hij geen constructor bevat, en kan dus niet zelfstandig geconstrueerd worden,
Dat komt niet door het ontbreken van een constructor. Een abstract mag gewoon een constructor hebben en een (normale) classe hoeft geen expliciete constructor te hebben. De virtuele methodes maken hem abstract.

Misschien nog een dingetje wat je kunt doen, maak 'pinMode', 'waitTimeOn', 'waitTimeOff' etc const als ze toch niet veranderen in de afgeleiden.

  pinMode(PIN_ID_0, INPUT_PULLUP);
  pinMode(PIN_ID_1, INPUT_PULLUP);
  pinMode(PIN_ID_2, INPUT_PULLUP);
  pinMode(PIN_ID_3, INPUT_PULLUP);

  systemId = 0;
  if (!digitalRead(PIN_ID_0)) systemId = systemId+1;
  if (!digitalRead(PIN_ID_1)) systemId = systemId+2;
  if (!digitalRead(PIN_ID_2)) systemId = systemId+4;
  if (!digitalRead(PIN_ID_3)) systemId = systemId+8;
Arrays? :P


Timo
Verzonden vanaf mijn desktop met Firefox

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #77 Gepost op: 12 december 2019, 13:09:07 »
Ik dacht al, geen commentaar van Timo  ;)

Oei, zonde. Waarom niet gewoon de bytes echt vullen? Kost het je maar 1/8e
Dit begrijp ik niet helemaal ???, of bedoel je het gebruik van volatile? Dat is bij mij standaard voor data die in ISR (Interupt Service Routine) gebruikt worden.

Citaat
PS_Int() is een ISR?
Ja, zie setup.
  attachInterrupt(S88_CLOCK_INTERRUPT, clock_Int, RISING);
  attachInterrupt(S88_PS_INTERRUPT, PS_Int, RISING);

Citaat
Zou niet moeten, zet je de data er wel op de juiste edge op?
Stukje oude code, dat niet meer gebruikt wordt. Overigens was dat een advies van Internet.

Citaat
Wat doet de tweede ISR dan? ???
Zie de code. De S88 gebruikt 3 signalen, CLOCK, PS en RESET. Ik heb een ISR op de CLOCK en de PS signalen. RESET wordt niet gebruikt.

Citaat
Vertrouw je de initialisatie niet? ;D
Weet jij wat het verschil tussen C en C++ is? Het niet initialiseren van variabelen in C is een van de grootse valkuilen. Ik kom uit de C wereld, daar leer je op de harde manier dat je variabelen moet initialiseren voor je ze kunt gebruiken. Maar dat zit er bij mij zo ingesleten dat ik dat ook in C++ doe.

Citaat
Is dit niet erg gevoelig voor lange rails etc? Ken het verder niet namelijk.

Zag later pas aan het plaatje dat ze op basis van CT's zijn. Maakt hij überhaupt wel gebruik van een resonantie kring?
Dat is wat ik uit de technische beschrijving begreep. Nee ze zijn in mijn ervaring niet gevoelig voor lange rails (>3M).

Citaat
Ook deze ken ik niet, maar de conclusie dat beide staven onderbroken moeten worden voor stroomdetectie is niet standaard.

Ze moeten gevoed worden vanuit het DCC signaal. Dat beide rails onderbroken moeten worden volgt uit de beschrijving en dat wordt ook bevestigd door mijn ervaring met deze detector.

Citaat
Waarom heb je doAttach() en doHeartBeat() niet gewoon als attach() en heartBeat() gedefinieerd en uitgebreid in de afgeleiden? (Puur interesse!)
Dat doe ik om te voorkomen dat deze routines direct aangeroepen worden. Ik dwing nu dat afgeleide klassen een attach() en heartBeat() method implementeren.

Tot zover.

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

Patrick Smout

  • Offline Offline
  • Berichten: 308
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #78 Gepost op: 12 december 2019, 21:24:52 »
Foutongevoelig, ja. Robuust, nee. De thoughput zal er dan flink onder leiden.

Hangt ervan af wat je flink noemt. 1,25 tot 1,50 maal trager uitlezen van de bus maar wel foutloos. Geen gedoe met 2 x uitlezen, tragere clock of andere pleisters. Geen slecht compromis, althans zo denk ik erover.
En als iemand zou beslissen om de s88 terugmelder met een microcontroller te maken dan kan je een crc8 snel berekenen door een 256 byte lookuptable , de data en de vorige crc waarde.
Fluitje van een cent.

Mvg, Patrick Smout

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #79 Gepost op: 12 december 2019, 23:48:30 »
Dit is natuurlijk een pure "What if" discussie.
De realiteit is dat S88 een standaard is geworden, niet omdat het de beste manier is, maar gewoon omdat het destijds simpel te implementeren was. Dus we moeten het daar mee doen of we dat leuk vinden of niet. Er zijn natuurlijk alternatieven zo als Loconet. Maar dat ondersteund mijn centrale niet.
Daarom gebruik ik de Canbus voor de echte communicatie en blijft de kabel voor de S88 communicatie zo kort mogelijk en gebruik ik een cat5 kabel (S88-n).

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

Patrick Smout

  • Offline Offline
  • Berichten: 308
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #80 Gepost op: 13 december 2019, 06:16:13 »
Meino,

Akkoord mbt de S88 bus standaard. We moeten het er mee doen.  Mijn originele opmerking mbt de crc was een reactie op een vergeljking van de S88 bus en Ethercat. Beiden kan je niet vergelijken en ik heb aangegeven wat er nodig was om een vergelijk mogelijk te maken. Jouw laatste opmerking was, technisch gezien, te kort door de bocht en dat heb ik dan ook even onder ogen gebracht. In mijn zelfbouwcentrale ( zie mijn artikel in Elektor DCC Centrale uit 2008) lees ik de S88 bus 2x uit alvorens er events van te maken ( sliding window principe). De S88 bus op mijn baan is ongeveer 8m lang. Geen last van spookdetecties maar een goede bus vind ik het niet. Vandaag zou ik zeker kiezen voor CAN. Ik moet ook wel zeggen dat al mijn S88 melders zelfbouw zijn. Er is heel wat aandacht gegaan naar PCB layout want, en dat wordt wel eens vergeten, daar kan ook wel wat gewonnen worden. Als het overgelaten wordt aan de software om de boel te redden dan kom je soms van een kale kermis thuis.

Mvg, Patrick


Mvg, Patrick

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #81 Gepost op: 13 december 2019, 12:12:45 »
Patrick

Ik ben het volledig met je eens over de gebreken van S88. We noemen dat een bus (ook ik doe dat) maar eigenlijk is het dat niet. Het is gewoon een schuifregister op afstand. Als ik naar me zelf kijk, dan heb ik alle kennis en kunde om software te ontwikkelen, maar voor de hardware ben ik volledig afhankelijk van standaard componenten , zoals MCP2515 kaartjes voor de Canbus, dus daar moet ik het mee doen.
Ik denk het overgrote deel van de lezers op dit forum niet de diepe kennis van software en electronica hebben om dit soort zaken zelf te kunnen tackelen. Jij hebt duidelijk wel de kennis en kunde om dat anders te kunnen doen, en dat heb je ook gedaan. Als ik zelf de kennis had gehad om mijn eigen electronica te ontwikkelen, dan was er best een grote kans geweest dat ik dat ook had gedaan. Tenslotte ben ik ook met de Canbus aan de gang gegaan, ik had ook iets met een standaard Loconet of ExpressNet kunnen doen.
Overigens zijn dit soort discussies best nuttig, ik hoop alleen dat dit voor lezers met een minder diepere kennis niet al te verwarrend wordt en dat ze afhaken.

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

Klaas Zondervan

  • Offline Offline
  • Berichten: 18279
    • Pagina van klaas
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #82 Gepost op: 13 december 2019, 12:38:24 »
….ik hoop alleen dat dit voor lezers met een minder diepere kennis niet al te verwarrend wordt en dat ze afhaken.
Ik snap lang niet alles wat hier wordt verteld, maar ik ben nog niet afgehaakt.
Wat betreft je opmerking dat s88 geen bus is maar een uit elkaar getrokken schuifregister: ik stond op het punt om zelf die opmerking te maken maar ik heb me even ingehouden. ;D
Spoorbaan "Uit en Thuis" in aanbouw.

bask185

  • Offline Offline
  • Berichten: 351
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #83 Gepost op: 13 december 2019, 13:52:03 »
Op onze clubbaan hang in 1 arduino direct aan onze cs3 + en ik gebruik een zelf bedacht bussysteem.

Ik laat de s88 arduino (de master) via rs485 een bericht sturen naar de Rx van de 1e slave. Dit bericht begint met een ID byte, die de slaves zelf ophogen. Adhv deze byte weet de arduino welke van de te volgen bytes for hem zijn. De 2e byte bevat de packetgrootte. En verder zijn er 2 bytes per arduino slave gereserveerd om input status op te zetten.

De slaves lezen elke byte in, zetten hun input status in de voor hen bestemde byte en sturen de byte meteen weer door naar de volgende. Ik gebruik een 8 polige patchkabel tussen de slaves. In deze kabel loopt dus 1 rs485 bus van slave naar slave en er zit een 2e rs485 bus naast die doorloopt tot aan het einde van de bus. Bij de allerlaatste slave worden de rs 485 lijnen aan elkaar verbonden, zodat de laatste arduino het bericht doorsluist via deze 2e bus helemaal naar de Rx pin van de master.

Samengevat: de master stuurt een hele reeks bytes naar een ring van slaves. Elke slave leest elke byte in, doet iets of niets met de byte en stuurt hem onmiddelijk door naar de volgende slave totdat de bytes weer aankomen bij de master.

Het idee is dat de eerste bytes alweer bij de master terug zijn gekomen alvorens de master het hele packet heeft verstuurd. Ik heb dit idee direct gekopieerd van ethercat en ik gebruikt het principe van informatie on the fly aanpassen en meteen doorsturen. Alleen doe ik het via de seriele port en ik doe het byte voor byte ipv bit voor bit (en ik kan zo natuurlijk geen snelheid van 1GHz behalen en ethercat wel....)

De master berdrijft deze bus continu zodat deze ten alle tijden up-to-date is met de laatste bezetmeldingen. Er kunnen meer dan 100 updates per seconde (<- wat ruim genoeg is) plaatsvinden. Dus op het moment dat de CS3+ om informatie komt vragen, is de informatie er al.

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #84 Gepost op: 13 december 2019, 17:19:53 »
Ethercat ken ik niet echt, maar als ik dit zo lees dan krijg ik een deja vu gevoel, want het lijkt wel op het oude tokenring van IBM. Dat performde voor geen meter, maar had het grote voordeel dat de toenmalige netwerkgurus er aan konden rekenen en dat het een gegarandeerde doorvoersnelheid had. Ik heb in de vroege jaren 80 daar nog wel eens met de netwerk specialisten over gesteggeld, die beweerden dat Ethernet en IP prutprotocollen waren en dat je daar niet een fatsoenlijk netwerk mee kon uitrollen. Leuk voor het kleine grut (unix boxjes), maar niet voor het echte werk voor mainframes. Oorzaak; geen mogelijkheden om berichten te priortiseren, instabiel gedrag bij hoge belastingen (>40-50%) etc, etc  ;D.
Ter informatie, mijn implementatie van de Canbus kan nu ongeveer 250-350 berichten/sec afhandelen. Dat zou hoger kunnen zijn, maar dat kunnen de gebruikte MCP2515 kaartjes niet aan. De maximale bussnelheid die deze kaartjes aankunnen is 500kbps. De 1mbps kan hij niet aan. Ik ben nog van plan om te kijken wat er gebeurt als ik de kristal (8Mhz) vervang door een snellere (16 -20Mhz) de mcp2515 chip zou dat moeten aankunnen. Maar goed, de huidige prestaties zijn voldoende voor wat ik doe en nog van plan ben, ik wil in de toekomst ook de DCC lokcommando's nog over de Canbus verspreiden voor Arduino's met geluid. Dat zijn er ongeveer 220/sec.

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #85 Gepost op: 05 januari 2020, 16:03:36 »
Het is alweer een tijdje geleden, maar ik wil toch nog even wat vertellen over de twee laatste systemen die ik gebruik, n.l. de wisselcontroller en de seincontroller. Deze beide systemen reageren op wissel/sein commando's ontvangen via de DCC interface.
Afgezien van de functionele verschillen, de wisselcontroller zet een wissel om en de Seincontroller bevat veel inteligentie om het seinbeeld voor seinstelsel 46 te bepalen, dat is heel specifiek voor mijn baan, als er simpeler seinen gebruikt worden kan de seincontroller het zelfde zijn als de wisselcontroller. In mijn situatie is het verschil t.a.v. de Canbus, dat de Wisselcontroller ook een bezetmelding doet over de stand van de wissel. Daarom heeft de wisselcontroller ook twee MCP2515 kaartjes.



Zoals ik in mijn draadje over Kranenberg heb geschreven, worden de wissels aangedreven door gemodificeerde micro servo's. De modificatie is het loskoppelen van de interne electronica en het motortje wordt nu direct aangedreven waarbij twee microschakelaars de uitslag beperken en in combinatie met diodes wordt de bewegingsrichting bepaald door de polariteit van de spanning, 3V om de bewging niet al te heftig te maken. Dat was makkelijk op de eerste (analoge) opzet van de baan omdat de wissel simpel met een 2polige schakelaar te zetten was.
Maar nu is dat via een Arduino wat lastiger, een reguliere niet gemodificeerde servo was makkelijker geweest. Het omschakelen van de polariteit gebeurd nu door relais, die via een digitale pin op de Arduino aangestuurd wordt. Per wissel heb ik een relaispaar nodig.
De aansluiting is volgens het volgende schema.



Wat ik niet in het schema heb opgenomen is dat nu de spanning voor de wisselmotor niet rechtstreeks naar de wissel gaat, maar via een bedieningspaneel loopt. Op dit paneel laat ik door leds zien wat de stand van de wissel is. Dat wordt ook weer met diodes geregeld. Ik laat dat hier verder rusten omdat ik van plan ben om dat te veranderen en de wisselcontroller niet meer de leds op het paneel aan te sturen, maar daarvoor een aparte Arduino op te tuigen die het paneel gaat beheren. Ik wil via het paneel in de toekomst ook zaken als rijwegen, en het bezetten van het hoofdspoor voor rangeerbewegingen kunnen regelen, Dit via drukknoppen op het paneel. Het idee is omdat met bezetmeldingen te doen. Deze kunnen dan in Koploper speciale acties triggeren om dit te kunnen integreren met het automatisch rijden. Maar dat is nog toekomst.

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #86 Gepost op: 06 januari 2020, 12:09:04 »
Ok, tijd voor wat code.

Voor de Wisselcontrole heb ik ook een tweetal bibliotheken ontwikkeld. Een bibliotheek bevat de object klassen die de wisselmotoren aansturen, de andere bibliotheek is er voor om de stand van de wissels in EEPROM te kunnen opslaan.
De bibliotheek voor de aansturing van de wisselmotoren heet KB_Turnout. Deze bibliotheek bevat momenteel nog maar een objectklas om de relais voor de wissel aan te sturen. In de planning staat nog een uitbreiding om dit met reguliere servos te doen. Alle klassen in deze bibliotheek zitten weer achter de facade van een interface. Hierdoor isoleer ik de gebruiker van het object van de specifieke eigenschappen van de gebruikte techniek van de wisselmotor. Verder hebben deze klassen ook geen kennis van de omgeving waar ze in werken, dus geen kennis van de Canbus etc. De objecten koppelen het bereiken van een nieuwe stand weer terug via een z.g. "Callback" routine, zodat het aan de gebruiker overgelaten wordt wat er daarna precies mee gedaan kan worden. In mijn Wisselcontroller schets, is het in deze "Callback" routine dat de nieuwe stand in de EEPROM wordt bewaard en dat de Canbus boodschap voor de bezetmelder verzonden wordt.

Ik ga nu weer aan de hand van KB_turnout.h het een en ander bespreken
#define TURNOUT_STRAIGHT  false
#define TURNOUT_DIVERGING true
Twee gemaksdefinities voor de stand van de wissels.

//
//  Type definition for the call-back routine which will handle a state change
//
typedef void (*toStateHandler_t)(int toDccAddress, bool toDirection);
De definitie van de "Callback" routine.

//
//   The abstract base class for handling turnouts
//
class Turnout
{
protected:
    int toPin; //  Arduino pin connected to the relay
    bool targetDirection; //  Straight or Diverging
    bool currentDirection;
    int dccAddress; //  DCC address used for this turnout
   
    toStateHandler_t toStateHandler = nullptr;

    void initTo(int newDccAddress, int newToPin);

public:
    void setTargetDirection(bool newDirection);
    bool getCurrentDirection();
    int  getDccAddress();
    void registerToStateHandler(toStateHandler_t toStateHandler);
   
    virtual void attach(bool initialDirection) = 0;
    virtual void heartBeat() = 0;
};

De interface definitie voor de wissel objecten. De methods/functies setTargetDirection(..), getCurrentDirection(), getDccAdress() en registerToStateHandler(..) zijn voor alle klasimplementaties gelijk en hoeven voor een specifieke klas implementatie niet herschreven te worden.
Voor een specifieke implementatie moeten wel de attach(..) en heartBeat() methods gemaakt te worden. De attach(..) method initialiseert de wisselmotor en zet hem in de gegeven stand. De heartBeat() method zorgt er voor dat de wisselmotor blijft lopen. In de implementatie van de huidige wissels die d.m.v. een relais geschakeld worden doet deze routine niet veel omdat het simpel het hoog of laag zetten van een digitale pin op de Arduino is. Maar bij een echte servo, wil je dat de servo stap voor stap naar zijn nieuwe locatie gaat, dus hier moet de heartBeat() daar voor zorgen.

//
//  Class for turnouts controlled by a relay.
//
class RelayTurnout : public Turnout
{
public:
    RelayTurnout(int newDccAddress, int newToPin);
   
    void attach(bool initialDirection);
    void heartBeat();   
};
Tot nu toe de enige type wisselmotor diet nu in gebruik is.

Tot zover de bibliotheek voor de wisselmotors.

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #87 Gepost op: 06 januari 2020, 14:51:10 »
Zoals genoemd, heb ik ook een kleine bibliotheek gemaakt om de wisselstanden in de EEPROM te kunnen opslaan. Dat doe ik omdat de relais die ik gebruik niet bistabiel zijn, dus tijdens de initialisatie worden alle wissels in de stand rechtdoor gezet. In principe zorgt koploer er wel voor dat de wissels uiteindelijk in de laatst bekende stand komen, maar dat werkt niet altijd goed, als er nog een wagon of loc op een wissel staat, kan er sluiting zijn als de wissel niet correct staat. Dit voorkomt dan het opstarten van het DCC signaal. Daarom sla ik de wisselstanden op in de EEPROM. Dit gebeurd niet continue, maar ik houd een cache bij (2 bytes groot, voor maximaal 16 wissels). Ieder bit in deze buffer vertegenwoordigd de stand van een wissel. Deze twee bytes worden om de minuut naar de EEPROM geschreven. Dit schrijven gebeurd cyclisch, zodat ik iedere keer een nieuwe locatie gebruik. Aan het eind gekomen van de beschikbare EEPROM ruimte begin ik weer aan het begin. Ik doe dit om zolang mogelijk gebruik te kunnen maken van het EEPROM.

#include <Arduino.h>
#include <EEPROM.h>

#define EEPROM_DEBUG 0
De standaard Arduino includes die nodig zijn plus een optie om debugging actief te maken.

class EepromController
{
private:
    const byte eepromStart = 255;
    const byte eepromEnd = 0;
    int eepromLength;
    byte turnoutData[2] = {0, 0};   // For 16 turnouts
    bool eepromRead = false;
    int eepromIndex = 0;
    bool eepromDirty = false;

public:
    EepromController();

    //
    //  Load turnout states from EEPROM into the cache buffer
    //
    void loadData();

    //
    //  Save the cache buffer to EEPROM
    //
    void saveData();
   
    //
    //  Retrieve the direction of a turnout from the cache buufer
    //
    bool getTurnoutDirection(int turnoutId);

    //
    //  Set the direction of a turnout in the cache buffer
    //
    void setTurnoutDirection(int turnoutId, bool turnoutState);
           
};
De klasdefinitie voor de EepromController. Ik denk dat het commentaar voldoende verklaring geeft voor het gebruik.

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #88 Gepost op: 06 januari 2020, 16:08:26 »
Uiteindelijk draait het om de schets,  die is nu aan de beurt

/*
  A program to control turnouts (switches)

  Copyright (C) Meino de Graaf, all rights reserved

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation, version 2
  of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  email: meino@..........
*/
#include "CanBus.h"
#include <KB_Turnout.h>
#include <KB_Eeprom.h>
De inleiding en de includes

//
//  ID that defines this specific instance of the controller.
//  It's actual value is established during setup and is based on some jumpers
//
int systemId = 1;

//
//  Pins used to define the ID of this controller
//  It is used to filter out all semaphores which aren't controlled by
//  this instance of the SeinController
//
#define PIN_ID_0  A0
#define PIN_ID_1  A1
#define PIN_ID_2  A2
#define PIN_ID_3  A3
Ook de wisselcontroller heeft een nummer, zodat ik met 1 schets de verschillende exemplaren kan laden. Dit zijn de pinnen die gebruikt worden om de systeem id te maken.

//
//  The CanBus
//
CanBus *canBus;

//
//  Data that is stored in EEPROM to remember the state of the
//  turnouts. It is handled by a eepromController class
//
EepromController *EepromControl = new EepromController();
De CanBus en EepromController objecten.

typedef struct {
  short toSystemId;
  Turnout *to;
} toTable;

const int nrOfTurnouts = 12;

toTable turnouts[nrOfTurnouts] = {
  {1, new RelayTurnout(1, 25)},
  {1, new RelayTurnout(2, 27)},
  {1, new RelayTurnout(3, 29)},
  {1, new RelayTurnout(4, 31)},
  {1, new RelayTurnout(5, 33)},
  {1, new RelayTurnout(6, 35)},
  {1, new RelayTurnout(7, 37)},
  {1, new RelayTurnout(8, 39)},
  {1, new RelayTurnout(9, 41)},
  {1, new RelayTurnout(10, 43)},
  {1, new RelayTurnout(11, 45)},
  {1, new RelayTurnout(12, 23)} // Replaced to a new shield, one of the originals failed
};
De tabel waarmee de 12 gebruikte wissels gedefineerd worden.

//
//  A function that executes whenever a message is received from the Canbus
//  It's purpose is to analyze the received event (Signal or turnout) and
//  update the proper element in the semaphore table or turnout table.
//
void dccAccReceiver(unsigned char aMsgLen, DCC_ACC_MSG *msgData)
{
  unsigned short dccId = msgData->address;
  byte dccState = msgData->direction;

  //
  //  Find the proper turnout detector with the matching address
  //  and sets its new direction based on the enable field from the
  //  received dcc command
  //
  for (int i = 0; i < nrOfTurnouts; i++)
  {
    if ((turnouts[i].toSystemId == systemId) &&
           (turnouts[i].to->getDccAddress() == dccId))
    {
      if (dccState == 0)
      {
        //
        //  Set the straight direction
        //
        turnouts[i].to->setTargetDirection(TURNOUT_STRAIGHT);
      }
      else
      {
        //
        //  Set the diverging direction
        //
        turnouts[i].to->setTargetDirection(TURNOUT_DIVERGING);
      }

      //
      //  End the for loop
      //
      return;
    }
  }
}
De routine die bij de CanBus is geregistreerd en door het CanBus object aangeroepen wordt als er een wissel commando ontvangen is. Deze routine gaat de wissel uit de tabel opzoeken, en als deze wissel onder controle van deze WisselController is, zal hij de ontvangen richting zetten op het gevonden wisselobject. A;ls het commando voor een wissel is die niet voorkomt, dan wordt het bericht niet verder behandeld.

void turnoutStateHandler(int aDccAddress, bool aDirection)
{
  //
  //  The occupance detectors start on bank 4, each bank has 16 occupancies, so a single
  //  bank is enough for the 12 turnouts in use
  //
  int s88Bank = 4;
 
  //
  //  The turnout tells us that it has reached it new state, so now we can save it to EEPROM
  //
  EepromControl->setTurnoutDirection(aDccAddress, aDirection);

  //
  //  Send the new state to the S88 Interface
  //
  OCC_DT_MSG buf;

  //
  //  At this moment we have no more the 12 turnouts, so don't bother about the S88 bank
  //
  buf.address = ((s88Bank - 1) * 16) + (aDccAddress - 1);
  if (aDirection)
    buf.state = 1;
  else
    buf.state = 0;

  canBus->sendMsg(OCC_DT, sizeof(OCC_DT_MSG), &buf);
}
Dit is de "Callback" routine die bij de wisselobjecten is geregistreerd. Deze routine wordt aangeroepen. Hier wordt de nieuwe richting in de cachebuffer van de EEprom geschreven en de bezetmelding voor deze wissel op de Canbus gezet.

static unsigned long lastTimeSaved = 0;

void setup()
{
  //
  //  Based on which pin is connected to ground, the controller ID is established
  //
  pinMode(PIN_ID_0, INPUT_PULLUP);
  pinMode(PIN_ID_1, INPUT_PULLUP);
  pinMode(PIN_ID_2, INPUT_PULLUP);
  pinMode(PIN_ID_3, INPUT_PULLUP);

  systemId = 0;
  if (!digitalRead(PIN_ID_0)) systemId = systemId + 1;
  if (!digitalRead(PIN_ID_1)) systemId = systemId + 2;
  if (!digitalRead(PIN_ID_2)) systemId = systemId + 4;
  if (!digitalRead(PIN_ID_3)) systemId = systemId + 8;

  //
  //  Setup and start the CanBus communication
  //
  canBus = new CanBus(WISSEL_CONTROLLER_ID + systemId, new Mcp2515(49), new Mcp2515(53)); // Sender + Receiver
  canBus->setMsgReceiver(DCC_ACC, dccAccReceiver);
 
  //
  //  Before we start setting the turnouts, introduce a small delay,
  //  so the S88 interface is ready
  //
  delay(1000);

  //
  //  Start the Canbus
  //
  canBus->begin();

  //
  //  Load the EEPROM data for the turnout directions
  //
  EepromControl->loadData();

  //
  //  Activate the turnout relays
  //  Set them in the direction which was stoored in the EEPROM
  //
  for (int i = 0; i < nrOfTurnouts; i++)
  {
    if (turnouts[i].toSystemId == systemId) // Handle only our turnouts
    {
      //
      //  Set the stateHandler
      //
      turnouts[i].to->registerToStateHandler(turnoutStateHandler);

      //
      //  Activate the pin and set the initial direction
      //
      turnouts[i].to->attach(EepromControl->getTurnoutDirection(turnouts[i].to->getDccAddress()));
    }
  }

  //
  // Initialize the time for the save loop
  //
  lastTimeSaved = millis();

}//--(end setup )---
De Arduino setup routine, waarin we de CanBus initialiseren, de systeem id bepalen en alle wissels die door deze controller worden beheerd in gebruik nemen en de nodige initialisaties doen, zoals de laatst bewaarde stand uit het EEPROM gebruiken om de richting van de wissel te zetten.

void loop()
{
  //
  //  Keep the turnouts and the CanBus busy
  //
  for (int i = 0; i < nrOfTurnouts; i++)
  {
    if (turnouts[i].toSystemId == systemId) // Handle only our turnouts
    {
      //
      // Keep on running
      //
      turnouts[i].to->heartBeat();
      canBus->heartBeat();
    }
  }

  //
  //  Calculate the time interval between two consequtive saves to EEPROM
  //
  long interval = 60000; // Every minute
  long timeDifference = millis() - lastTimeSaved;

  //
  //  When the internal timer does a wrap around, reset stuff
  //
  if (timeDifference < 0)
  {
    lastTimeSaved = 0;
    timeDifference = 0;
  }

  //
  //  When the time exceeds the set interval, save data to EEPROM
  //
  if ( timeDifference > interval )
  {
    EepromControl->saveData();
    lastTimeSaved = millis();
  }

}//-- (end loop)--
De Arduino loop functie. Bij iedere keer dat deze actief is, voeren we de heartBeat op alle actieve wissels en de CanBus uit, zodat die ook bezig blijven. Daarna checken we of de tijdsinterval tussen twee EEPROM saves is verstreken, als dat het geval is schrijven we de cache buffer naar het EEPROM geheugen.

Groet Meino
A clean desk is a sign of an empty mind

Kranenberg

meino

  • Offline Offline
  • Berichten: 625
Re: De CanBus komt naar Kranenberg, Arduino's en de CanBus
« Reactie #89 Gepost op: 06 januari 2020, 20:49:06 »
Als laatste systeem wil ik het nog even over de SeinController hebben. Deze systemen zijn Arduino Mega's. De keuze voor Mega's is gemaakt omdat ik driehoogte seinen, stelsel 46 moest aansturen. Dit gebeurd met 3kleuren RGB ledjes. Om de benodigde kleuren Rood, Groen, Geel en Wit te krijgen, moest er gemengd worden. Dat lukte alleen goed als ik de intensiteit van de leds onderling en ook van de 3 kleuren (RGB) kon instellen. De makkelijkste manier is via een PWM pin. Om een driehoogtesein te kunnen aansturen heb ik 9 pwm pinnen nodig, vandaar de keuze voor de Mega.
Ook hier heb ik weer een bibliotheek ontwikkeld, de KB_Seinstelsel46 bibliotheek. Oorspronkelijk had ik het idee dat de aansturing van deze seinen volledig door Koploper plaats kon vinden. Helaas had Koploper geen ondersteuning van het sein stelsel 46 en om dat te gaan definieren zag ik op dat moment niet zitten. De kennis ontbrak mij en ik vond het erg gecompliceerd. Daarom heb ik het anders opgelost, de seinen zijn in koploper gedefinieerd als simpele armseinen en door Koploper worden ze op veilig of onveilig gezet. Om nu toch het correcte seinbeeld te kunnen tonen wordt in de definitie van een sein ook de route die na het sein gevolgd wordt opgenomen en het volgende sein voor die route be over automatisering kend is. Hierdoor kan de bibliotheek de juiste stand berekenen. Dit heb ik in het draadje https://forum.beneluxspoor.net/index.php?topic=79241.msg3221850071#msg3221850071 ooit eens geprobeerd uit te leggen, dat ga ik hier niet herhalen.

Toch nog een paar stukjes code van de SeinController.

//
//  Table with all active turnouts
//
const int nrOfTurnouts = 12;

Turnout turnouts[nrOfTurnouts] =
{
  Turnout(1),
  Turnout(2),
  Turnout(3),
  Turnout(4),
  Turnout(5),
  Turnout(6),
  Turnout(7),
  Turnout(8),
  Turnout(9),
  Turnout(10),
  Turnout(11),
  Turnout(12)
};

//
//  Table of all defined semaphores
//
const int nrOfSemaphores = 20;

Semaphore semaphores[nrOfSemaphores] = {
 
  // Semaphore 00a on controller 6 (3hoog Voorsein)
  Semaphore(CONTROLLER(6), SEMAPHORE(00), NO_STOP_DELAY,
            new Route(SEMAPHORE(58), SPEED_HIGH, DANGER),
            VOORSEIN46_DRIEHOOG,
            new RGBLed(PWM_PIN(2), INTENSITY(200), PWM_PIN(3), INTENSITY(150), PWM_PIN(4), INTENSITY(100)),
            new RGBLed(PWM_PIN(5), INTENSITY(48), PWM_PIN(6), INTENSITY(20), PWM_PIN(7), INTENSITY(50)),
            new RGBLed(PWM_PIN(8), INTENSITY(175), PWM_PIN(9), INTENSITY(150), PWM_PIN(10), INTENSITY(40))),

 
  // Semaphore 51 on controller 2
  Semaphore(CONTROLLER(2), SEMAPHORE(51), DELAY_STOP,
            new Route(TURNOUT(1),
                      new Route(SEMAPHORE(63)),             // Turnout 1 straight
                      SPEED_HIGH,
                      new Route(ROUTE_BARRED),              // Turnout 1 diverting
                      SPEED_STOP),
            SEIN46_EENHOOG,
            new RGLed(PWM_PIN(2), INTENSITY(18), PWM_PIN(3), INTENSITY(20))),   // (blok 2)
 
  // Semaphore 52 on controller 2
  Semaphore(CONTROLLER(2), SEMAPHORE(52), NO_STOP_DELAY,
            new Route(TURNOUT(3),
                      new Route(TURNOUT(2),               // Turnout 3 straight
                                new Route(ROUTE_BARRED),             // Turnout 2 straight
                                SPEED_STOP,
                                new Route(TURNOUT(1),                // Turnout 2 Diverting
                                          new Route(ROUTE_BARRED),                       // Turnout 1 straight
                                          SPEED_STOP, 
                                          new Route(SEMAPHORE(63),SPEED_LOW,DANGER),     // Turnout 1 diverting
                                          SPEED_LOW),
                                SPEED_LOW),
                      SPEED_LOW,
                      new Route(ROUTE_BARRED),            // Turnout 3 diverting
                      SPEED_STOP),
            SEIN46_EENHOOG,
            new RGLed(PWM_PIN(4), INTENSITY(9), PWM_PIN(5), INTENSITY(10))),     // (blok 6)
........
Dit zijn de  configuraties voor de wissels en de seinen. Daar ga ik hier niet verder op in. Een verklaring is in hier te vinden https://forum.beneluxspoor.net/index.php?topic=79241.msg3221850071#msg3221850071

//
//  A function that executes whenever a message is received from the Canbus
//  It's purpose is to analyze the received event (Signal or turnout) and
//  update the proper element in the semaphore table or turnout table.
//
void dccAccReceiver(unsigned char aMsgLen, DCC_ACC_MSG *msgData)
{
  //
  //  Find the proper turnout detector with the matching address
  //  and sets its state.
  //
  if (Turnout::updateDirection(msgData->address, msgData->direction))
  {
    //
    //  The dcc id matched a turnout no need to try the semaphores
    //
    return;
  }
  else
  {
    //
    //  the dcc id didn't match a turnout, so try the semaphores
    //
    Semaphore::updateState(msgData->address, msgData->direction);
  }
}
Dit is de routine die bij de CanBus is geregistreerd en aangeroepen wordt als er een wissel commando (Accessory decoder bericht) ontvangen is. Als het voor een wissel is, dan wordt de richting van de wissel gezet, is het voor een sein dan wordt de staat (veilig-onveilig) gezet.

in de Arduino setup() routine worden weer de CanBus, seinen en wissel objecten geinitialiseerd. Ook wordt weer een systeem id bepaald aan de hand van een aantal digitale pinnen.

void loop()
{
  //
  //  Are there messages on the CanBus?
  //
  canBus->heartBeat();
 
  //
  //  Trigger an update on all semaphores
  //
  Semaphore::loop();
}
De Arduino loop() functie hoeft slechts de CanBus actief te houden via de heartBeat(). Verder worden de seinen ook actief gehouden door de loop() functie op het overkoepelend statisch Semaphore object. Deze loop() functie zal alle seinen die onder controle van deze SeinControler staan actief houden. Dit houdt in dat het seinbeeld bepaald wordt (alleen als de staat van het sein is gewijzigd) en dat wordt getoond. Ook het knipperen van een geel sein (langzaam en snel knipper) wordt hierdoor gerealiseerd. In het geval van een armsein wordt de servo aangestuurd zodat de seinarm zich langzaam van een positie naar een andere positie beweegt.

Diot zijn tot nu toe de systemen die ik in gebruik heb. Een toekomstige uitbreiding die ik van plan ben te bouwen zijn controllers die luidsprekertjes kunnen aansturen om eventueel het geluid van stoomloks te kunnen maken. Het idee is dat dit geluid ongeveer de lok over de baan blijft volgen. Ik heb in China wat nano's met versterkertjes in bestelling staan. Of dit gaat lukken weet ik nog niet, maar mocht dat lukken, dan volgt daarvan nog wel een update.

Groet Meino
« Laatst bewerkt op: 06 januari 2020, 20:51:15 door meino »
A clean desk is a sign of an empty mind

Kranenberg