Ich arbeite momentan an meinem ersten "größeren" Software/Hardware-Projekt und möchte diesen Foreneintrag nutzen um dieses Projekt vorzustellen und eventuell Kritik, Anregungen und Ratschläge dazu zu erhalten. Für eine in Modulbauweise konstruierte Modelleisenbahn möchte ich eine intelligente Weichensteuerung erstellen und diese soll grob umrissen wie folgt funktionieren: -auf einem Schaltpult ist der Plan des Bahnhofs aufgedruckt -jeweils an allen Ein/Ausfahrten gibt es einen Start-Taster und an jedem Gleis gibt es ebenso einen Zieltaster -unter jedem Modul des Bahnhofs befindet sich ein Arduino mit Ethernet Shield -an diese Arduinos ist jeweils ein PCA9685 PWM Servo Controller angeschlossen -dieser Servocontroller steuert logischerweise Servomotoren welche schlussendlich das eigentliche Stellen der Weichen übernehmen -ein Raspberry Pi soll die Tastendrücke aufnehmen und wenn eine richtige Kombination aus Start-Zieltaster gedrückt wurde nacheinander ein Signal an einen MQTT-Broker, welcher auf selbigem Raspberry Pi läuft, schicken um die entsprechenden Weichen zu stellen -die Arduinos sind über einen Switch mit dem Raspberry verbunden und reagieren auf die entsprechenden Steuer-Anweisungen und geben eine Rückmeldung sobald der Befehl ausgeführt wurde Aktueller Stand des Ganzen ist, ich habe den MQTT Broker zum laufen gebracht und auf dem Arduino bereits einen laufenden Code der sich in dem Mini-Netzwerk anmeldet, mit dem MQTT-Broker verbindet, im Code vorgegebene Themen abonniert und auf eingehende Nachrichten reagiert. Ich arbeite gerade daran den Code lesbarer und "hübscher" zu gestalten, genauer gesagt versuche ich den Arduino-Code objektorientierter umzusetzen, und den PWM-Controller in das Ganze einzubinden. Da dies mein erster Foren-Eintrag ist gebt mir gerne Tipps, übt Kritik oder stellt fragen wenn euch das Projekt interessiert. Main:
1 | #include "HCPCA9685.h" |
2 | #include "SETUP.h" |
3 | |
4 | void setup() { |
5 | Serial.begin(9600); |
6 | ethernetSetup(); |
7 | mqttSetup(); |
8 | PWMSetup(); |
9 | |
10 | // put your setup code here, to run once:
|
11 | |
12 | }
|
13 | |
14 | |
15 | void loop() { |
16 | // put your main code here, to run repeatedly:
|
17 | mqttLoop(); |
18 | }
|
Setup:
1 | #include "SPI.h" |
2 | #include "Ethernet.h" |
3 | #include "PubSubClient.h" |
4 | #include "Weiche.h" |
5 | |
6 | |
7 | constexpr auto I2CAdd1 = 0x40; |
8 | constexpr auto I2CAdd2 = 0x41; |
9 | HCPCA9685 PWMController1(I2CAdd1); |
10 | |
11 | Weiche W16(160,240,2000,1); |
12 | Weiche W17(120,280,2000,2); |
13 | Weiche W18(120,280,2000,3); |
14 | Weiche W19(120,280,2000,4); |
15 | Weiche W20(120,280,2000,5); |
16 | |
17 | EthernetClient ethernetClient; |
18 | const byte mac[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}; |
19 | const IPAddress deviceIP (255,255,255,255); |
20 | const IPAddress dns (255,255,255,255); |
21 | const IPAddress gateway (255,255,255,255); |
22 | const IPAddress subnet (255,255,255,255); |
23 | const char* deviceID = "Modul1"; |
24 | |
25 | PubSubClient MQTTclient(ethernetClient); |
26 | const IPAddress mqttServerIP(255,255,255,255); |
27 | const char sub[][10]={{"W16/Soll"},{"W17/Soll"},}; |
28 | const int subcnt = 2; |
29 | long lastMsgTime = 0; |
30 | char msg[64]; // A buffer to hold messages to be sent/have been received |
31 | char topic[32]; // The topic in which to publish a message |
32 | int pulseCount = 0; // Counter for number of heartbeat pulses sent |
33 | |
34 | |
35 | void PWMSetup() { |
36 | PWMController1.Init(SERVO_MODE); |
37 | PWMController1.Sleep(false); |
38 | }
|
39 | |
40 | |
41 | void ethernetSetup() { |
42 | Ethernet.init(10); |
43 | Ethernet.begin(mac, deviceIP, dns, gateway, subnet); |
44 | Serial.println("ich lebe"); |
45 | if (Ethernet.hardwareStatus() == EthernetNoHardware) { |
46 | Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); |
47 | while (true) { |
48 | delay(1); // do nothing, no point running without Ethernet hardware |
49 | }
|
50 | }
|
51 | delay(2000); |
52 | |
53 | // Print debug info about the connection
|
54 | Serial.print("Connected! IP address: "); |
55 | Serial.println(Ethernet.localIP()); |
56 | |
57 | }
|
58 | |
59 | void mqttCallback(char* topic, byte* payload, unsigned int length) { |
60 | |
61 | // The message "payload" passed to this function is a byte*
|
62 | // Let's first copy its contents to the msg char[] array
|
63 | int wnr = (int(topic[1])-'0')*10+int(topic[2])-'0'; |
64 | memcpy(msg, payload, length); |
65 | // Add a NULL terminator to the message to make it a correct string
|
66 | msg[length] = '\0'; |
67 | |
68 | // Debug
|
69 | Serial.print("Message received in topic ["); |
70 | Serial.print(topic); |
71 | Serial.print("] "); |
72 | Serial.println(msg); |
73 | |
74 | // Act upon the message received
|
75 | switch (wnr){ |
76 | case 16: if(strcmp(msg,"Rechts") == 0){ |
77 | W16.stellen(rechts); |
78 | Serial.println(W16.get_Zustand()); |
79 | break; |
80 | }
|
81 | if(strcmp(msg,"Links") == 0){ |
82 | W16.stellen(links); |
83 | Serial.println(W16.get_Zustand()); |
84 | break; |
85 | }
|
86 | else { |
87 | Serial.println("Falscher Befehl"); |
88 | break; |
89 | }
|
90 | case 17: if(strcmp(msg,"Rechts") == 0){ |
91 | W17.stellen(rechts); |
92 | Serial.println(W16.get_Zustand()); |
93 | break; |
94 | }
|
95 | if(strcmp(msg,"Links") == 0){ |
96 | W17.stellen(links); |
97 | Serial.println(W16.get_Zustand()); |
98 | break; |
99 | }
|
100 | else { |
101 | Serial.println("Falscher Befehl"); |
102 | break; |
103 | }
|
104 | default: break; |
105 | }
|
106 | }
|
107 | |
108 | void mqttSetup() { |
109 | MQTTclient.setServer(mqttServerIP, 1883); |
110 | MQTTclient.setCallback(mqttCallback); |
111 | }
|
112 | |
113 | void mqttLoop () { |
114 | while (!MQTTclient.connected()) { // Ensure there's a connection to the MQTT server |
115 | Serial.print("Attempting to connect to MQTT broker at "); |
116 | Serial.println(mqttServerIP); |
117 | |
118 | if (MQTTclient.connect(deviceID)) { // Attempt to connect |
119 | // Debug info
|
120 | Serial.println("Connected to MQTT broker"); |
121 | |
122 | for (int i=0; i<2; i++){ |
123 | snprintf(topic, 32, sub[i]); |
124 | MQTTclient.subscribe(topic); |
125 | Serial.println("subscribed to"); |
126 | Serial.println(topic); |
127 | }
|
128 | }
|
129 | else { |
130 | // Debug info why connection could not be made
|
131 | Serial.print("Connection to MQTT server failed, rc="); |
132 | Serial.print(MQTTclient.state()); |
133 | Serial.println(" trying again in 5 seconds"); |
134 | |
135 | // Wait 5 seconds before retrying
|
136 | delay(5000); |
137 | }
|
138 | }
|
139 | |
140 | // Call the main loop to check for and publish messages
|
141 | MQTTclient.loop(); |
142 | }
|
Weiche.h:
1 | #include "Zustand.h" |
2 | #include "HCPCA9685.h" |
3 | |
4 | class Weiche{ |
5 | private:
|
6 | int winkelRechts; |
7 | int winkelLinks; |
8 | int stellzeit; |
9 | int steckplatz; |
10 | Zustand alt; |
11 | |
12 | public:
|
13 | Weiche(int wr, int wl, int wz, int sp); |
14 | int get_WinkelRechts(); |
15 | int get_WinkelLinks(); |
16 | int get_Stellzeit(); |
17 | int get_Steckplatz(); |
18 | Zustand get_Zustand(); |
19 | |
20 | |
21 | void set_WinkelRechts(int wr); |
22 | void set_WinkelLinks(int wl); |
23 | void set_Stellzeit(int sz); |
24 | void set_Steckplatz(int sp); |
25 | void set_Zustand(Zustand neu); |
26 | |
27 | void stellen(Zustand a); |
28 | };
|
Weiche.cpp:
1 | #include "Weiche.h" |
2 | |
3 | |
4 | Weiche::Weiche(int wr, int wl, int sz, int sp){ |
5 | winkelRechts = wr; |
6 | winkelLinks = wl; |
7 | stellzeit = sz; |
8 | steckplatz = sp; |
9 | alt = unbekannt; |
10 | }
|
11 | |
12 | int Weiche::get_WinkelRechts() {return winkelRechts;} |
13 | int Weiche::get_WinkelLinks() {return winkelLinks;} |
14 | int Weiche::get_Stellzeit() {return stellzeit;} |
15 | int Weiche::get_Steckplatz() {return steckplatz;} |
16 | Zustand Weiche::get_Zustand() {return alt;} |
17 | |
18 | |
19 | void Weiche::set_WinkelRechts(int wr) {winkelRechts = wr;} |
20 | void Weiche::set_WinkelLinks(int wl) {winkelLinks = wl;} |
21 | void Weiche::set_Stellzeit(int sz) {stellzeit = sz;} |
22 | void Weiche::set_Zustand(Zustand neu) {alt = neu;} |
23 | void Weiche::set_Steckplatz(int sp) {steckplatz = sp;} |
24 | |
25 | void Weiche::stellen(Zustand neu){ |
26 | if(this->alt==neu){ |
27 | return; |
28 | }
|
29 | else{ |
30 | this->alt=neu; |
31 | return; |
32 | }
|
33 | }
|
Zustand.h:
1 | enum Zustand{ |
2 | unbekannt, rechts, links |
3 | };
|