Ich suchte vor etwa zwei Jahren nach einen neuen Schreibtisch, dieser sollte Elektrisch Höhenverstellbar sein. Doch nach ein wenig Sucherei im Internet war ich erstaunt wie Teuer die alle waren. Ich bin dann aber schlussendlich auf einen Schreibtisch mit elektrischem Defekt gestoßen. Bei diesem war das Mainboard komplett verschmort.
Die Platine war so Zerstört, dass mir eine Rekonstruktion zu aufwendig war. Zudem weiß ich auch nicht ob der Mikrocontroller der alles steuert überhaupt noch funktioniert. Daher musste also eine eignende Lösung her.
Ich habe also auch zwei Relais genommen wie es oben auf dem alten Mainboard der Fall war. Das eine Relais schaltet die Drehrichtung des Motors und das andere schaltet ihn an. Zusätzlich ist noch ein N-Channel Mosfet verbaut um die Drehgeschwindigkeit zu regeln.
Der Motor ist ein Garagentor Motor mit eingebauten Hall Sensor. Siehe Datenblatt
Zur Steuerung wollte ich natürlich das bestehende Bedienfeld weiter nutzen. Daher habe ich es mir erstmal angesehen wie dieses Aufgebaut ist.
Man sieht ja das ist nicht gerade Kompliziert aufgebaut. Also einfach das Weiße Kabel mit GND Verbinden und die anderen beiden mit einem IO-Pin mit aktiviertem Pullup verbinden. Schon ist das Feld fertig verkabelt.
Es gibt dann noch vier Endschalter die, die Bewegung des Schreibtisches begrenzen. Zwei davon sind auf dem Bild zu sehen. Zwei weitere sind am Rand der Brücke und in Reihe mit dem Endschalter für unten. Diese haben die Aufgabe zu verhindern das nichts zerquetscht wird was auf der „Brücke“ liegt wenn der Schreibtisch runter fährt.
Als Mikrocontroller nutze ich einen Arduino Pro Mini. Dieser hat keinen direkten USB Anschluss wie es der Arduino Uno hätte. Auf beiden sitzt der Atmel ATmega328.
Nun kommen wir zum Pinout:
Pin | Funktion |
---|---|
2 | Hall Sensor Puls |
3 | Relais welches den Motor einschaltet |
5 | Relais welches die Drehrichtung festlegt |
6 | Endschalter unten |
7 | Endschalter oben |
8 | Bedienfeld Taste Hoch |
9 | Bedienfeld Taste Hoch |
10 | PWM für den Mosfet zum Drehgeschwindigkeit regeln |
Ich nutze zwar 5V Relais aber diese kann man nicht direkt an mit dem Arduino ansteuern. Daher habe ein ULN2003 als Relais Treiber genutzt.
Ich habe dann am selben Tag noch ein primitives Programm geschrieben um dem Schreibtisch dann erstmal auszuprobieren. Mit diesem habe ich den Schreibtisch dann zwei Jahre genutzt.
Jetzt nach dem der Schreibtisch mit mir Umgezogen ist habe ich eine neue Software geschrieben die den Schreibtisch um eine Funktionen ergänzt.
- Die Geschwindigkeit kann angegeben werden
- Es können Positionen über die Serielle Schnittstelle angefahren werden
- Es wird immer die aktuelle Position ausgegeben
- Es wird immer die angegebene Geschwindigkeiten genutzt, egal wie der Schreibtisch beladen ist
Damit sich der Schreibtisch immer auf Anhieb Smooth bewegt sollte man als erstes den Motor für die einzelnen Geschwindigkeitsstufen einmessen.
Das geht mit dem Seriellen Befehl: ParamsMessen
Der Schreibtisch fährt danach jede Geschwindigkeit einmal ab und Speichert die zugehörigen Paramenter im EEPROM. Bei mir hat das ca 60 Minuten gedauert. Es wird alle 5 „Einmessungen“ eine kurze Pause gemacht damit der Mosfet und der Motor nicht zu heiß werden.
Die Parameter lassen sich mit dem Befehl: GetParams auch auslesen.
Während des normalen Betriebs werden diese Paramenter nach korrigiert, möchte man, dass die neuen Werte ebenfalls gespeichert werden kann man sie mit dem Befehl: SaveParams erneut speichern.
Mit dem SetPosXXXX setzte man die Höhe auf den der Schreibtisch fahren soll. Die XXXX sind mit der Höhe anzugeben. Die Höhe wird in Pulsen gemessen.
Mit GetPos kann man sich die aktuelle Position geben lassen. Diese wird aber automatisch bei einer Änderung ausgegeben.
Mit SetManSpeedXXX kann man die Bewegungsgeschwindigkeit für das Bedienfeld angeben. Die Geschwindigkeit wird in Pulsen/Sekunden angegeben bzw. gemessen.
Und zu guter letzt gibt es noch den Befehl test um zu sehen ob die Verbindung zum Schreibtisch steht. Man erhält als Antwort immer test-ok
Der Nächste Schritt ist, dass ich einen ESP8266 einbaue damit ich den Schreibtisch über den PC ohne Kabelverbindung steuern kann. So kann ich dann auch Höhen Profile einstellen.
Hier ist jetzt endlich der Quellcode von meinem Arduino:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
/* Pinout * Schalter sind nach GND -> interner Pullup * Pin * 2 Puls Signal -> ca 936 Pulse auf 49,5cm -> ca 0,5mm pro Puls * 3 Power Relias * 5 Richtung Relais * 6 Stop Taster unten * 7 Stop Taster oben * 8 Interface Hoch * 9 Interface Runter * 10 Motor Mosfet * */ #include #define PinPuls 2 #define PinRelaisPower 3 #define PinMOSFET 10 #define PinRelaisRichtung 5 #define PinEndschalterUnten 6 #define PinEndschalterOben 7 #define PinHoch 8 #define PinRunter 9 #define AutomaktikGenauigkeit 2 #define BremsenAbOben 800 #define BremsenAbUnten 100 volatile bool richtungHoch = 1; volatile bool automatik = 0; volatile unsigned long istPos = 2000; volatile unsigned long lastSendIstPos = 0; volatile unsigned long lastPosSpeed = 0; volatile unsigned long sollPos = 0; volatile unsigned long lastmillis = 0; volatile unsigned long lastmillisSpeed = 0; volatile double driveSpeed = 0; volatile unsigned int manSpeed = 85; void constSpeed(unsigned int constSpeedVar, int addierer = 1); typedef struct SpeedToOut { byte AnalogWriteValueUp = 80; byte AnalogWriteValueDown = 100; }; SpeedToOut SpeedListe [201]; void setup() { pinMode(PinPuls,INPUT); pinMode(PinEndschalterUnten, INPUT_PULLUP); pinMode(PinEndschalterOben, INPUT_PULLUP); pinMode(PinHoch, INPUT_PULLUP); pinMode(PinRunter, INPUT_PULLUP); pinMode(PinRelaisPower, OUTPUT); digitalWrite(PinRelaisPower, LOW); pinMode(PinRelaisRichtung, OUTPUT); digitalWrite(PinRelaisRichtung, LOW); pinMode(PinMOSFET, OUTPUT); attachInterrupt(digitalPinToInterrupt(PinPuls), pulsTrigger, CHANGE); analogWrite(PinMOSFET, 100); Serial.begin(9600); RestorParamsFromEEPROM(); Serial.println("Init..."); initPos(); } void loop() { GeschwindigkeitBerechen(); manualPos(); automatikPos(); if ((millis() - lastmillis) > 100) { if (lastSendIstPos != istPos) { Serial.print("pos-"); Serial.print(istPos); Serial.print("-"); Serial.println((int)driveSpeed); if (digitalRead(PinEndschalterOben)) {Serial.println("endschalter-Oben");} if (digitalRead(PinEndschalterUnten)) {Serial.println("endschalter-Unten");} } lastSendIstPos = istPos; lastmillis = millis(); } if (Serial.available()) { char charPC[30]; for (int i=0; i<31; i++) { charPC[i] = Serial.read(); } if( strstr(charPC, "SetPos")!= NULL) //SetPos0000 { String stringPC = charPC; sollPos = stringPC.substring(6,10).toInt(); Serial.print("fahrezu-"); Serial.println(sollPos); automatik = 1; } if( strstr(charPC, "GetPos")!= NULL) { Serial.print("Pos-"); Serial.println(istPos); if (digitalRead(PinEndschalterOben)) {Serial.println("Endschalter-oben");} if (digitalRead(PinEndschalterUnten)) {Serial.println("Endschalter-unten");} } if( strstr(charPC, "test")!= NULL) { Serial.println("test-ok"); } if( strstr(charPC, "GetParams")!= NULL) { for (int i = 0; i<201;i++) { Serial.print("SpeedParams-"); Serial.print(i); Serial.print("-"); Serial.print(SpeedListe[i].AnalogWriteValueUp); Serial.print("-"); Serial.println(SpeedListe[i].AnalogWriteValueDown); } } if( strstr(charPC, "SaveParams")!= NULL) { Serial.println("SaveParams-wait"); for (int i = 0; i<201;i++) { StoreParamsInEEPROM(); } Serial.println("SaveParams-ok"); } if( strstr(charPC, "SetManSpeed")!= NULL) //SetManSpeed000 { String stringPC = charPC; manSpeed = stringPC.substring(11,14).toInt(); Serial.print("manSpeed-"); Serial.println(manSpeed); } if( strstr(charPC, "ParamsMessen")!= NULL) { MesseParams(); } } } void MesseParams() { bool keinError = true; Serial.println("einmessen-start"); for (int i = 1; i<201;i++) { if (i % 5 == 0) { Serial.println("einmessen-abkuehlPause"); delay(30000); } automatik = 1; sollPos = 100; Serial.println("einmessen-ausgangsposition"); while (istPos > 104 || istPos < 96) { automatikPos(); GeschwindigkeitBerechen(); } Serial.print("einmessen-speed-"); Serial.println(i); setzteinRichtungHoch(1); Serial.println("einmessen-hoch"); int oberePosVar = i*5; if (oberePosVar < 150) { oberePosVar = 150; } while ( istPos < 600 && keinError) { GeschwindigkeitBerechen(); constSpeed(i); if (!digitalRead(PinEndschalterOben) && !digitalRead(PinEndschalterUnten)) { digitalWrite(PinRelaisRichtung, HIGH); delay(50); digitalWrite(PinRelaisPower, HIGH); } else { digitalWrite(PinRelaisPower, LOW); delay(60); digitalWrite(PinRelaisRichtung, LOW); Serial.println("Error-Endschalter"); } } digitalWrite(PinRelaisPower, LOW); setzteinRichtungHoch(0); Serial.println("einmessen-runter"); while (istPos > 100 && keinError) { GeschwindigkeitBerechen(); constSpeed(i); if (!digitalRead(PinEndschalterOben) && !digitalRead(PinEndschalterUnten)) { digitalWrite(PinRelaisRichtung, LOW); delay(50); digitalWrite(PinRelaisPower, HIGH); } else { digitalWrite(PinRelaisPower, LOW); delay(60); digitalWrite(PinRelaisRichtung, LOW); Serial.println("Error-Endschalter"); } } digitalWrite(PinRelaisPower, LOW); if (keinError) { Serial.println("einmessen-speichern"); unsigned int eeAdress = i*sizeof(SpeedToOut); EEPROM.put(eeAdress,SpeedListe[i]); Serial.print("SpeedParams-"); Serial.print(i); Serial.print("-"); Serial.print(SpeedListe[i].AnalogWriteValueUp); Serial.print("-"); Serial.println(SpeedListe[i].AnalogWriteValueDown); } else { i = 201; } } if (keinError) { Serial.println("einmessen-fetig"); } else { Serial.println("einmessen-cancel"); } } void StoreParamsInEEPROM() { for (int i = 0; i<201;i++) { unsigned int eeAdress = i*sizeof(SpeedToOut); EEPROM.put(eeAdress,SpeedListe[i]); } } void RestorParamsFromEEPROM() { SpeedToOut ReadVar; // prüfe ob erstes Element leer ist EEPROM.get(0,ReadVar); if (ReadVar.AnalogWriteValueUp > 0 && ReadVar.AnalogWriteValueUp < 220) { for (int i = 0; i<201;i++) { unsigned int eeAdress = i*sizeof(SpeedToOut); EEPROM.get(eeAdress,SpeedListe[i]); } } } void GeschwindigkeitBerechen() { if ((millis() - lastmillisSpeed) > 100) // Pulse/Sekunde { if (istPos > lastPosSpeed) { driveSpeed = (double)(istPos - lastPosSpeed) / (double)(millis() - lastmillisSpeed) * 1000.0; } else { driveSpeed = (double)(lastPosSpeed - istPos) / (double)(millis() - lastmillisSpeed) * 1000.0; } lastmillisSpeed = millis(); lastPosSpeed = istPos; } } void initPos(){ while (!digitalRead(PinEndschalterUnten)) // Kalibriere nach unten { richtungHoch = 0; constSpeed(45); GeschwindigkeitBerechen(); digitalWrite(PinRelaisRichtung, LOW); delay(60); digitalWrite(PinRelaisPower, HIGH); } digitalWrite(PinRelaisPower, LOW); delay(60); digitalWrite(PinRelaisRichtung, LOW); delay(150); volatile unsigned long altePosVorBootUP = 2000 - istPos; sollPos = altePosVorBootUP; istPos = 0; automatik = 1; } void automatikPos(){ if (automatik) { volatile unsigned long minPos = 0; if (sollPos - AutomaktikGenauigkeit /2 > 10000) { minPos = 0; } else { minPos = sollPos - AutomaktikGenauigkeit /2; } if (minPos > istPos) //Hoch { if (!digitalRead(PinEndschalterOben)) { setzteinRichtungHoch(1); setzteSpeed(); digitalWrite(PinRelaisRichtung, HIGH); delay(50); digitalWrite(PinRelaisPower, HIGH); } else { digitalWrite(PinRelaisPower, LOW); delay(80); digitalWrite(PinRelaisRichtung, LOW); } } else if ((sollPos + AutomaktikGenauigkeit /2) < istPos) //Runter { if (!digitalRead(PinEndschalterUnten)) { setzteinRichtungHoch(0); setzteSpeed(); digitalWrite(PinRelaisRichtung, LOW); delay(50); digitalWrite(PinRelaisPower, HIGH); } else { digitalWrite(PinRelaisPower, LOW); delay(50); digitalWrite(PinRelaisRichtung, LOW); istPos = 0; } } else { if (automatik) { digitalWrite(PinRelaisPower, LOW); delay(100); digitalWrite(PinRelaisRichtung, LOW); } } } } void setzteSpeed() { unsigned int speedvar = 0; unsigned int abstand = 0; if (sollPos > istPos) { abstand = sollPos - istPos; } else { abstand = istPos - sollPos ; } speedvar = 80; if (abstand < 60) {speedvar = 45;} if (abstand < 50) {speedvar = 40;} if (abstand < 40) {speedvar = 30;} if (abstand < 30) {speedvar = 20;} if (abstand < 20) {speedvar = 10;} constSpeed(speedvar,1); } void manualPos(){ if (!digitalRead(PinHoch)) { automatik = 0; if (!digitalRead(PinEndschalterOben)) { setzteinRichtungHoch(1); constSpeed(manSpeed); digitalWrite(PinRelaisRichtung, HIGH); delay(50); digitalWrite(PinRelaisPower, HIGH); } else { digitalWrite(PinRelaisPower, LOW); delay(50); digitalWrite(PinRelaisRichtung, LOW); } } else if (!digitalRead(PinRunter)) { automatik = 0; if (!digitalRead(PinEndschalterUnten)) { setzteinRichtungHoch(0); constSpeed(manSpeed); digitalWrite(PinRelaisRichtung, LOW); delay(50); digitalWrite(PinRelaisPower, HIGH); } else { digitalWrite(PinRelaisPower, LOW); delay(50); digitalWrite(PinRelaisRichtung, LOW); istPos = 0; } } else { if (!automatik) { digitalWrite(PinRelaisPower, LOW); delay(100); digitalWrite(PinRelaisRichtung, LOW); } } } void constSpeed(unsigned int constSpeedVar, int addierer = 1) { byte pwmValue = 100; if (richtungHoch) { if (istPos > BremsenAbOben && constSpeedVar > 40) { constSpeedVar = 40; } pwmValue = SpeedListe[constSpeedVar].AnalogWriteValueUp; } else { if (istPos < BremsenAbUnten && constSpeedVar > 40) { constSpeedVar = 40; } pwmValue = SpeedListe[constSpeedVar].AnalogWriteValueDown; } if (constSpeedVar > driveSpeed) { pwmValue = pwmValue + addierer; } if (constSpeedVar < driveSpeed) { pwmValue= pwmValue - addierer; } if (pwmValue < 2) { pwmValue = 1; } if (pwmValue > 200) { pwmValue = 200; } if (richtungHoch) { SpeedListe[constSpeedVar].AnalogWriteValueUp = pwmValue; } else { SpeedListe[constSpeedVar].AnalogWriteValueDown = pwmValue; } analogWrite(PinMOSFET, pwmValue); } void setzteinRichtungHoch(bool richtungHochVar) { int altePos = istPos; unsigned long alteZeit = millis(); if (richtungHoch != richtungHochVar) { digitalWrite(PinRelaisPower, LOW); while ((millis() - alteZeit) < 200) { if (altePos != istPos) { altePos = istPos; alteZeit = millis(); } } richtungHoch = richtungHochVar; } } void pulsTrigger(){ if (richtungHoch) { istPos++; } else { if (istPos > 0) { istPos--; } } } |