{"id":2812,"date":"2023-09-27T17:32:13","date_gmt":"2023-09-27T16:32:13","guid":{"rendered":"http:\/\/lisby.dk\/wordpress\/?p=2812"},"modified":"2026-04-14T15:02:37","modified_gmt":"2026-04-14T14:02:37","slug":"elevator-design-software","status":"publish","type":"post","link":"https:\/\/lisby.dk\/wordpress\/?p=2812","title":{"rendered":"Elevatordesign &#8211; software"},"content":{"rendered":"\n<p>Software er som s\u00e6dvanlig det der usynlige, der bringer det hele til live, binder alle komponenter sammen og f\u00e5r det hele til at fungere. Desuden skal det indeholde en WEB server, s\u00e5 man fra en PC eller en tablet kan styre elevatoren og se samme information som p\u00e5 displayet.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Kravspecifikationen:<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Det skal v\u00e6re h\u00e5rdt kodet (eller bedre: gemt p\u00e5 SD kort eller i intern flash memory), hvor lang afstanden er mellem de 12 etager. Der er 12 etager, fordi det er urealistisk at f\u00e5 de to elevatorstole og oph\u00e6nget af dem pr\u00e6cis nok til at have 6 dobbelt-etager, hvor begge elevatorstole er pr\u00e6cis ud for skinnerne, s\u00e5 tog kan k\u00f8re ud og ind. For at tage h\u00f8jde for sm\u00e5 sk\u00e6vheder i tr\u00e6v\u00e6rk m.v. skal dette ske ud fra m\u00e5linger og ikke kun ud fra CAD tegningen. Det giver et afledet krav om noget software til at foretage denne kalibrering af disse h\u00f8jder.<\/li>\n\n\n\n<li>N\u00e5r str\u00f8mmen t\u00e6ndes, skal elevatoren selv finde til etage 1. Dvs. check konstant sensorer for endestop, idet der g\u00f8res f\u00f8lgende: Indtil elevatoren er ved endestop: K\u00f8r langsomt nedad. Derefter: K\u00f8r langsomt opad indtil endestop netop er deaktiveret. Elevatoren er nu i nul-position. K\u00f8r til etage 1 ud fra det kalibrerede antal steps. Husk, at der er to sider, der begge skal ramme samme etage.<\/li>\n\n\n\n<li>Displayet skal vise, hvilken etage elevatoren er p\u00e5 (\u201c?\u201d under initialisering), seneste kommando (DCC eller WEB samt etage) og status (\u201cst\u00e5r stille\u201d, \u201ck\u00f8rer op\u201d, \u201ck\u00f8rer ned\u201d eller forskellige fejlmeddelelser, som f.eks. \u201cflere etager aktive\u201d eller \u201cindk\u00f8rsel blokeret\u201d).<\/li>\n\n\n\n<li>Elevatoren m\u00e5 ikke s\u00e6ttes i bev\u00e6gelse, hvis der befinder sig en genstand i en af de fire \u201cporte\u201d ind i elevatoren.<\/li>\n\n\n\n<li>WEB siden skal vise samme information som displayet.<\/li>\n\n\n\n<li>Der skal konstant lyttes efter og reageres p\u00e5 ordrer fra b\u00e5de WEB side og DCC interface.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Design:<\/h4>\n\n\n\n<p>For at implementere disse krav skal der implementeres f\u00f8lgende objekter (definition af klasserne f\u00f8lger) i C++ koden p\u00e5 ESP32. Derudover noget JavaScript i HTML siden, som eksekveres i browseren:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>To positionssensorer (<strong>PosSensor<\/strong>): Et endestop i hver side.<\/li>\n\n\n\n<li>Fire IR sikkerheds-sensorer (<strong>SecSensor<\/strong>) til sikring af krav 4.<\/li>\n\n\n\n<li>To stepper motorer (<strong>StepMotor<\/strong>).<\/li>\n\n\n\n<li>En positionerings logik (<strong>PosLogic<\/strong>), der dels kan initialisere til etage 1 og dels flytte til en anden etage &#8211; begge dele koordineret mellem h\u00f8jre og venstre side.<\/li>\n\n\n\n<li>Kalibreringsfunktionalitet (<strong>Calibrator<\/strong>), der kan bruges til at lave og gemme et antal steps i forhold til nul nivauet pr. 12 etager pr. side i en fil p\u00e5 SD kortet.<\/li>\n\n\n\n<li>WEB server (<strong>WebServer<\/strong>), der kan kommunikere med JavaScript koden i browseren p\u00e5 PC\/tablet og med JMRI og derved modtage kommandoer og vise status.<\/li>\n\n\n\n<li>Display styring (<strong>Display<\/strong>), der kan vise status.<\/li>\n\n\n\n<li>DCC interface styring (<strong>DccInterface<\/strong>), der kan modtage kommandoer.<\/li>\n<\/ol>\n\n\n\n<p>Derudover skal der v\u00e6re et JMRI script, der sammen med Warrant afvikleren (se&nbsp;<a href=\"http:\/\/lisby.dk\/wordpress\/?page_id=2424\">http:\/\/lisby.dk\/wordpress\/?page_id=2424<\/a>) hele tiden ved hvilket tog, der findes p\u00e5 hvilken hylde i elevatoren &#8211; og hvordan toget vender.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Definition af de enkelte klasser<\/strong>:<\/h4>\n\n\n\n<p><strong>Klasse<\/strong>: PosSensor (m\u00e5ske er der ikke brug for en klasse &#8211; det er vel bare en I\/O pin)<br><strong>Metoder<\/strong>: Constructor, IsActive<br><strong>Semantik<\/strong>: Repr\u00e6senterer en micro switch, som bruges til at positionere (\u201chome\u201d hedder det vist nok p\u00e5 en 3D printer) elevatoren.<br>&#8211; <strong>Constructor<\/strong>: Initialiserer den input port, som switchen er forbundet til.<br>&#8211; <strong>IsActive<\/strong>: Returnerer sand, hvis switchen er aktiv. Ellers falsk.<\/p>\n\n\n\n<p><strong>Klasse<\/strong>: SecSensor (m\u00e5ske er der ikke brug for en klasse &#8211; det er vel bare en I\/O pin)<br><strong>Metoder<\/strong>: Constructor, IsActive<br><strong>Semantik<\/strong>: Repr\u00e6senterer en IR sensor, som f\u00f8ler p\u00e5, om der er et tog eller et andet fysisk objekt i en \u201cindk\u00f8rsel\u201d til elevatoren.<br>&#8211; <strong>Constructor<\/strong>: Initialiserer den input port, som sensoren er forbundet til.<br>&#8211; <strong>IsActive<\/strong>: Returnerer sand, hvis IR sensoren er aktiv. Ellers falsk.<\/p>\n\n\n\n<p><strong>Klasse<\/strong>: StepMotor (M\u00e5ske er det bare AccelStepper klassen?)<br><strong>Metoder<\/strong>: Constructor, Move<br><strong>Semantik<\/strong>: Repr\u00e6senterer en stepper motor, som kan bev\u00e6ges et antal steps den ene eller den anden vej.<br>&#8211; <strong>Constructor<\/strong>: Initialiser motoren inklusive de tre I\/O porte, der bruges til motoren.<br>&#8211; <strong>Move<\/strong>: F\u00e5 motoren til at bev\u00e6ge sig det angivne antal steps i den angivne retning.<\/p>\n\n\n\n<p><strong>Klasse<\/strong>: PosLogic<br><strong>Metoder<\/strong>: Init, Home, MoveTo, GetStatus<br><strong>Semantik<\/strong>: Logik til at bev\u00e6ge hele elevatoren til en bestemt etage under anvendelse af kalibreringsdata. S\u00f8rger ogs\u00e5 for initielt at bev\u00e6ge elevatoren til etage 1 vha. endestop sensorerne, samt at begge sider f\u00f8lges ad. Og endelig kan JMRI koden sp\u00f8rge, om elevatoren er i en veldefineret position og i givet fald hvilken etage.<br>&#8211; <strong>Init<\/strong>: S\u00e6tter steppermotorer og sensorer op.<br>&#8211; <strong>Home<\/strong>: Initialiserer elevatoren, dvs. ved anvendelse af begge endestop micro-switche og begge motorer at f\u00e5 elevatoren i nul-positionen og derfra vha. kalibreringsdata til etage 1. Samt s\u00e6tte status og statusmeddelelser p\u00e5 display og WEB side.<br>&#8211; <strong>MoveTo<\/strong>: Flyt elevatoren til den angivne etage. Opdater status og status meddelelser som ovenfor.<br>&#8211; <strong>GetStatus<\/strong>: Bruges af JMRI til at sikre, at elevatoren st\u00e5r stille det rigtige sted, f\u00f8r toget k\u00f8res ud eller ind i elevatoren.<br>&#8211; <strong>Lock og Unlock<\/strong>: Bruges af JMRI koden til at sikre, at elevatoren ikke bev\u00e6ges via WEB siden eller direkte p\u00e5 ECOS, mens tog k\u00f8res ud og ind af elvatoren. Dvs. WEB og DCC kalder blot MoveTo, mens JMRI udf\u00f8rer en hel sekvens: MoveTo, Lock, poll GetStatus indtil elevatoren er p\u00e5 rette etage, k\u00f8r tog ud eller ind af elevatoren Unlock.<\/p>\n\n\n\n<p><strong>Klasse<\/strong>: Calibrator<br><strong>Metoder<\/strong>: GetOffset, SetOffset, ReadFromSD, WriteToSD<br><strong>Semantik<\/strong>: Ved anvendelse af WEB serveren og JavaScript koden i browseren vises og justeres kalibreringsdata, dvs. antal steps pr. etage pr. side, som motoren skal bev\u00e6ges i forhold til nul-positionen for at ramme p\u00e5g\u00e6ldende etage pr\u00e6cist.<br>&#8211; <strong>GetOffset<\/strong>: Returner offset for en side af en etage.<br>&#8211; <strong>SetOffset<\/strong>: S\u00e6t nyt offset (i RAM) for en etage.<br>&#8211; <strong>ReadFromSD<\/strong>: L\u00e6s alt kalibreringsdata fra SD kortet (efter power up).<br>&#8211; <strong>WriteToSD<\/strong>: Skriv alt kalibreringsdata til SD kortet for at bevare det efter power off.<\/p>\n\n\n\n<p><strong>Klasse<\/strong>: WebServer<br><strong>Metoder<\/strong>: Init, m.fl.<br><strong>Semantik<\/strong>: Genbrug af WebServer koden fra havetoget. Se&nbsp;<a rel=\"noreferrer noopener\" href=\"http:\/\/lisby.dk\/wordpress\/?p=2143\" target=\"_blank\">Software til havetog.<\/a> Eller rettere <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/kjlisby\/arduino_train\/tree\/master\/ReverseLoop\" target=\"_blank\">SDWebServer klassen her<\/a>.  Som s\u00e5 igen kr\u00e6ver en tilpasset version af AjaxHandler samme sted fra. AjaxHandler h\u00e5ndterer kommandoer fra den JavaScript kode, der k\u00f8rer i browseren. Dvs. de filer, der anbringes p\u00e5 micro SD kortet. Det handler for havetogets vedkommende om disse tre filer: <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/kjlisby\/arduino_train\/tree\/master\/webpage\" target=\"_blank\">index.html, togbane.css og togbane.jss, der findes her.<\/a> Bem\u00e6rk i \u00f8vrigt, at der ingen events flyder imellem WEB server og JavaScript koden i forbindelse med styring af havetoget. Og det er kun JavaScript koden, der sender kommandoer &#8211; herunder en GetStatus kommando med faste tidsintervaller. Der er dog ogs\u00e5 en WEB socket, som bruges til at sende log information til client siden. Den kunne s\u00e5dan set godt bruges til at opdatere status p\u00e5 WEB siden. Det skal overvejes, hvad der er smartest.<br>&#8211; <strong>Init<\/strong>:<br>&#8211; <strong>m.fl.<\/strong>: Der skal implementeres nogen kald, som kun bruges af JMRI. M\u00e5ske er det de samme som WEB siden bruger, alts\u00e5 via AjaxHandler.<\/p>\n\n\n\n<p><strong>Klasse<\/strong>: Display<br><strong>Metoder<\/strong>: Init, NewLevel, AtLevel, Homing<br><strong>Semantik<\/strong>: Et simpelt interface til at styre displayet.<br>&#8211; <strong>Init<\/strong>: Initialiser display interfacet.<br>&#8211; <strong><strong>NewLevel<\/strong><\/strong>: Vis bev\u00e6gelsen fra en etage til en anden p\u00e5 displayet.<br>&#8211; <strong>AtLevel<\/strong>: Vis den etage, hvor elevatoren st\u00e5r, p\u00e5 displayet.<br>&#8211; <strong>Homing<\/strong>: Vis teksten &#8220;Homing..&#8221; p\u00e5 displayet.<\/p>\n\n\n\n<p><strong>Klasse<\/strong>: DccInterface<br><strong>Metoder<\/strong>: Init, Loop, Callback<br><strong>Semantik<\/strong>:<br>&#8211; <strong>Init<\/strong>: Initialiserer NmraDcc interfacet.<br>&#8211; <strong>Loop<\/strong>: Kalder videre ind i NmraDcc for at holde det i live.<br>&#8211; <strong>Callback<\/strong>: Ikke en del af klassen. NmraDcc kr\u00e6ver, at det er en simpel funktion. Reagerer p\u00e5 de relevante sporskiftekommandoer ved at kalde ind i PosLogic.<\/p>\n\n\n\n<p>Desuden kan <strong>OTAHandler<\/strong> klassen fra havetoget genbruges. Den g\u00f8r det muligt at uploade en ny software version til ESP32 over WIFI.<\/p>\n\n\n\n<p>Mht. DCC interfacet, s\u00e5 kan ECOS styre en M\u00e4rklin 7686 drejeskive. Og en drejeskive og en elevator er begge noget, der kan flytte tog til en ud af flere mulige positioner. S\u00e5 det er t\u00e6t nok p\u00e5 til at v\u00e6re bedre end alt andet. Jeg har fundet en beskrivelse af, hvordan den drejeskive \u201cser ud\u201d p\u00e5 et DCC system:&nbsp;<a rel=\"noreferrer noopener\" href=\"http:\/\/members.ozemail.com.au\/~rossstew\/rms\/pdf\/7686_turntable_quick_start.pdf\" target=\"_blank\">7686_turntable_quick_start.pdf<\/a><\/p>\n\n\n\n<p>Det vil alts\u00e5 sige, at drejeskiven optr\u00e6der som et antal sporskifter. Jeg f\u00e5r kun brug for 6 sporskifter-definitioner, fordi elevatoren kun kan s\u00e6ttes i 12 forskellige stillinger:<\/p>\n\n\n\n<p>Etage 1: Sporskifte 229 r\u00f8d knap (close?)<br>Etage 2: Sporskifte 229 gr\u00f8n knap (throw?)<br>Etage 3: Sporskifte 230 r\u00f8d knap (close?)<br>Etage 4: Sporskifte 230 gr\u00f8n knap (throw?)<br>Etage 5: Sporskifte 231 r\u00f8d knap (close?)<br>osv. osv.<\/p>\n\n\n\n<p>Og s\u00e5 m\u00e5 b\u00e5de JMRI og elevatorens DCC interface bare rette ind efter ECOS\u2019 muligheder. Jeg har fundet et par Arduino DCC drejeskive dekodere til inspiration:&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/peteGSX-Projects\/programmable-dcc-turntable\" target=\"_blank\">Pete GSX <\/a>og&nbsp;&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/tkoning\/dcc-turntable\" target=\"_blank\">T Koning<\/a> Se ogs\u00e5 <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/lucadentella\/arduino-dccshield\" target=\"_blank\">https:\/\/github.com\/lucadentella\/arduino-dccshield<\/a> og <a rel=\"noreferrer noopener\" href=\"https:\/\/mrrwa.org\/dcc-decoder-interface\/\" target=\"_blank\">hardware diagrammet her<\/a>. Kun input delen er n\u00f8dvendig. Her beh\u00f8ves ingen CV programmering. <a rel=\"noreferrer noopener\" href=\"https:\/\/electronics-diy.com\/arduino-dcc-decoder.php\" target=\"_blank\">Alternativ (n\u00e6sten identisk) hardware her<\/a>.<\/p>\n\n\n\n<p>Dvs., s\u00e5dan havde jeg f\u00f8rst lavet det. Men dern\u00e6st besluttede jeg at bruge 12 adresser i stedet for. Stadigv\u00e6k med 229 som start-adresse (som etage 1). Men nu s\u00e5dan, at nu er det udelukkende adressen (og ikke throw\/close), der bestemmer etagen. Det h\u00e6nger sammen med, at jeg i ECOS&#8217;en har lavet en side med en repr\u00e6sentation af hver af de 12 etager som et signal. Dvs. uanset status af signalet, s\u00e5 vil et tryk p\u00e5 den f\u00e5 elevatoren til at bev\u00e6ge sig til p\u00e5g\u00e6ldende etage.<\/p>\n\n\n\n<p>Med hensyn til displayet er der en artikel at komme i gang p\u00e5 her:&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/randomnerdtutorials.com\/esp32-ssd1306-oled-display-arduino-ide\/\" target=\"_blank\">I2C OLED display<\/a>. Vha. artiklens link til en stump kode, der l\u00e6ser adressen p\u00e5 forbundne I2C devices, fandt jeg ud af, at mit display har adresse 0x3C. <\/p>\n\n\n\n<p>Og da jeg igen begyndte at \u201clege\u201d ESP32, havde jeg glemt, at <strong><span style=\"text-decoration: underline;\">n\u00e5r en ESP32 skal have downloadet en ny software, skal man trykke \u201cenable\u201d knappen<\/span><\/strong> (den til h\u00f8jre, n\u00e5r USB stikket vender hen mod en) ned, n\u00e5r Arduino IDE er n\u00e6sten f\u00e6rdig med at kompilere, og dern\u00e6st holde den nede indtil der ikke l\u00e6ngere tegnes prikker efter \u201cconnecting\u201d ordet i output vinduet. Husk endvidere, at serial monitor skal \u00e5bnes via Arduino IDE menuen. Det er ikke det samme som output vinduet.<\/p>\n\n\n\n<p>Til motorstyringen ser det ud til, at AccelStepper er et godt bud:&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/waspinator\/AccelStepper\" target=\"_blank\">AccelStepper p\u00e5 GitHub<\/a>&nbsp;hhv.&nbsp;<a rel=\"noreferrer noopener\" href=\"http:\/\/www.airspayce.com\/mikem\/arduino\/AccelStepper\/index.html\" target=\"_blank\">AccelStepper hjemmeside<\/a> &#8211; dog med det lille problem, at man kan v\u00e6lge enten at synkronisere flere motorer eller at have styr p\u00e5 acceleration og deceleration. Jeg har behov for begge dele p\u00e5 samme tid.<\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/kjlisby\/train_elevator\" target=\"_blank\">Koden kan findes her.<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Design af WEB siden:<\/h4>\n\n\n\n<p>I f\u00f8rste omgang er det OK med en helt tekstbaseret side. Grafik kan altid tilf\u00f8jes.<\/p>\n\n\n\n<p>Til drift af elevatoren skal der v\u00e6re f\u00f8lgende:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Knapper til at v\u00e6lge, hvilken etage, der skal flyttes til<\/li>\n\n\n\n<li>De samme status informationer, som vises p\u00e5 OLED displayet<\/li>\n\n\n\n<li>M\u00e5ske noget debuginformation &#8211; en log eller lignende<\/li>\n<\/ul>\n\n\n\n<p>Og til kalibreringen skal der v\u00e6re:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Et antal rubrikker med hver sin kalibreringsparameter:\n<ul class=\"wp-block-list\">\n<li>      \u00d8jeblikkelig v\u00e6rdi<\/li>\n\n\n\n<li>      +\/- knapper til at \u00e6ndre v\u00e6rdien<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Det ser s\u00e5dan ud i virkeligheden (screenshot fra den &#8220;tykke&#8221; UI n\u00e6vnt l\u00e6ngere nede, men samme princip i HTML udgaven):<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"http:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/10\/screenshot.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"620\" src=\"http:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/10\/screenshot-1024x620.jpg\" alt=\"\" class=\"wp-image-2965\" srcset=\"https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/10\/screenshot-1024x620.jpg 1024w, https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/10\/screenshot-300x182.jpg 300w, https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/10\/screenshot-768x465.jpg 768w, https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/10\/screenshot-1536x930.jpg 1536w, https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/10\/screenshot.jpg 1854w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Mht. kalibrering: <\/p>\n\n\n\n<p>Der er 100 mm eller 50 spindel-omdrejninger a 200 steps = 10.000 steps mellem to etager. Dvs.: <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Etage 1 og 2 er 0 steps<\/li>\n\n\n\n<li>Etage 3 og 4 er 10.000 steps<\/li>\n\n\n\n<li>Etage 5 og 6 er 20.000 steps<\/li>\n\n\n\n<li>Etage 7 og 8 er 30.000 steps<\/li>\n\n\n\n<li>Etage 9 og 10 er 40.000 steps<\/li>\n\n\n\n<li>Etage 11 og 12 er 50.000 steps<\/li>\n<\/ul>\n\n\n\n<p>Disse tal skal kunne kalibreres for hver side. Og skulle det vise sig, at der er forskelle p\u00e5 opadg\u00e5ende retning og nedadg\u00e5ende retning, s\u00e5 m\u00e5 PosLogic laves, s\u00e5 der altid positioneres ved at stoppe lidt for lavt, og dern\u00e6st k\u00f8re langsomt op til den kalibrerede position. Dvs., at der skal kalibreres p\u00e5 samme m\u00e5de.<\/p>\n\n\n\n<p>Det skal v\u00e6re s\u00e5dan, at der f\u00f8rst v\u00e6lges en etage, hvorefter elevatoren bev\u00e6ger sig hen til den etage, ud fra den kalibrering, der allerede findes, hvorefter kun de to relevante  kalibrerings-paramtere (dvs. h\u00f8jre og venstre) kan \u00e6ndres. Resten skal v\u00e6re disablede. <\/p>\n\n\n\n<p>Og s\u00e5 snart en parameter \u00e6ndres, skal den p\u00e5g\u00e6ldende stepper motor bev\u00e6ge sig tilsvarende.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">12. oktober 2023<\/h4>\n\n\n\n<p>Software\u2019n fungerer i store tr\u00e6k. Men det g\u00f8r ESP32 WIFI forbindelsen ikke. Den er s\u00e5 svag, at jeg stort set ikke kan f\u00e5 den til at connecte. Og selv n\u00e5r forbindelsen kommer op, vil den ikke rigtigt blive oppe. M\u00e5ske kan det fikses med et WIFI access point lige ved siden af elevatoren. Eller en bedre antenne p\u00e5 ESP32. Der kan loddes en ekstern antenne p\u00e5. Eller det kan l\u00f8ses med en ESP32 med Ethernet port. De findes.<\/p>\n\n\n\n<p>Men jeg overvejer i stedet at flytte WEB serveren over p\u00e5 PC\u2019en. F.eks. implementeret vha. Flask. Og s\u00e5 ellers bruge Serial forbindelsen i ESP32 til at kommunikere mellem PC og ESP32. Og <a href=\"https:\/\/developer.chrome.com\/articles\/serial\/\">Web Serial API<\/a> i JavaScript koden i browseren for at f\u00e5 fat i USB porten i PC enden. <\/p>\n\n\n\n<p>Eller jeg kunne lave det som en gammeldags applikation med et user interface. For at holde mig til noget, der delvis kan genbruges inde fra JMRI, bliver det nok en kombination af Python, PySerial og TkInter. <a rel=\"noreferrer noopener\" href=\"http:\/\/robotic-controls.com\/learn\/python-guis\/tkinter-serial\" target=\"_blank\">Som her.<\/a> <\/p>\n\n\n\n<p>S\u00e5 m\u00e5 jeg senere bestemme mig for, om jeg ogs\u00e5 bruger PySerial fra JMRI, eller om jeg bruger <a rel=\"noreferrer noopener\" href=\"https:\/\/www.jmri.org\/jython\/serialinput\/SerialPortDevice.py\" target=\"_blank\">den serielle kommunikation<\/a> fra Java \/ Jython. <\/p>\n\n\n\n<p>Ved at g\u00e5 Web server vejen vil jeg kunne have b\u00e5de stand-alone applikationen (i det tilf\u00e6lde browseren) og JMRI til at kommunikere med elevatoren samtidig. Det vil jeg ikke kunne med den \u201ctykke\u201d applikation, idet b\u00e5de JMRI og applikationen skal bruge samme COM\/USB port i PC\u2019en. Alts\u00e5 med mindre JMRI i stedet kommunikerer igennem min applikation. Eller med mindre jeg udstyrer ESP32 med et ekstra USB interface. Det kan man sagtens. Men jeg ser ikke det behov. Lad os se p\u00e5 use cases:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ved automatisk togdrift har jeg ikke brug for stand-alone applikationen. Jeg kan holde \u00f8je med elevatoren b\u00e5de p\u00e5 det fysiske display og i JMRI.<\/li>\n\n\n\n<li>Ved kalibrering har jeg ikke brug for JMRI. Den funktionalitet har jeg kun t\u00e6nkt mig at implementere i stand-alone applikationen. JMRI skal kun skulle skifte etage og m\u00e5ske vise status.<\/li>\n\n\n\n<li>N\u00e5r jeg bare vil k\u00f8re tog direkte fra ECOS, kan jeg styre elevatoren derfra. Eller fra enten stand-alone applikationen eller JMRI.<\/li>\n<\/ul>\n\n\n\n<p>Jeg tror ikke n\u00f8dvendigvis, at det er super sv\u00e6rt. I grove tr\u00e6k handler det om at fjerne SDWebServer, OTAHandler og AjaxHandler. Og til geng\u00e6ld indf\u00f8re en AjaxOverSerial i b\u00e5de ESP32 enden og browser \/ JavaScript \/ Python \/ JMRI \/ Jython enden. Jeg kunne ogs\u00e5 fjerne SD kortet og i stedet gemme kalibreringsdata p\u00e5 PC\u2019en. Men derved ville elevatoren ikke kunne fungere uden PC, s\u00e5 det ville v\u00e6re en d\u00e5rlig ide. Men eftersom  SD kortet kun ville komme til at indeholde en enkelt fil med i alt 24 long integers, s\u00e5 vil jeg nu nok fjerne den alligevel og i stedet bruge <a rel=\"noreferrer noopener\" href=\"https:\/\/randomnerdtutorials.com\/esp32-save-data-permanently-preferences\/\" target=\"_blank\">Preferences biblioteket<\/a> og den indbyggede flash memory.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Definition af den serielle kommunikation<\/h4>\n\n\n\n<p>Alle kommandoer og svar er en linie tekst.<\/p>\n\n\n\n<p>Kommandoer:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>get status (returnerer statusinformation som defineret nedenfor)<\/li>\n\n\n\n<li>get calibration &lt;etage&gt; (returnerer kalibrerede data for etagen)<\/li>\n\n\n\n<li>get position &lt;etage&gt; (returnerer status og position for steppere og end-stop switche)<\/li>\n\n\n\n<li>get lock (returnerer l\u00e5sestatus)<\/li>\n\n\n\n<li>set calibration &lt;etage&gt; &lt;venstre&gt; &lt;h\u00f8jre&gt; (s\u00e6tter og persisterer kalibreringsdata for etagen)<\/li>\n\n\n\n<li>set level &lt;etage&gt; (flytter elevatoren til den angivne etage)<\/li>\n\n\n\n<li>set levelfromcalibration &lt;etage&gt; &lt;venstre&gt; &lt;h\u00f8jre&gt; (flytter elevatoren til de angivne stepper positioner)<\/li>\n\n\n\n<li>set lock &lt;ja\/nej&gt; (s\u00e6tter l\u00e5sestatus)<\/li>\n\n\n\n<li>move &lt;left\/right\/both&gt; &lt;steps&gt; (flytter den ene (eller begge) stepper(e) som angivet)<\/li>\n\n\n\n<li>reset (annullerer homing, s\u00e5 dette gentages ved n\u00e6ste \u201cset level\u2019) <\/li>\n<\/ul>\n\n\n\n<p>Svar:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CALIBRATION &lt;etage&gt; &lt;venstre&gt; &lt;h\u00f8jre&gt;<\/li>\n\n\n\n<li>LOCKED &lt;ja\/nej&gt;<\/li>\n\n\n\n<li>STATUS &lt;statusinformation&gt;<\/li>\n<\/ul>\n\n\n\n<p>Parametre:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&lt;etage&gt;: et tal mellem 1 og 12<\/li>\n\n\n\n<li>&lt;venstre&gt;: antal steps for venstre motor, der svarer til etagen<\/li>\n\n\n\n<li>&lt;h\u00f8jre&gt;: antal steps for h\u00f8jre motor, der svarer til etagen<\/li>\n\n\n\n<li>&lt;ja\/nej&gt;: enten YES eller NO<\/li>\n\n\n\n<li>&lt;left\/right\/both&gt; enten \u201cleft\u201d eller \u201cright\u201d eller &#8220;both&#8221;<\/li>\n\n\n\n<li>&lt;steps&gt; ved angivelse af fortegn (f.eks. +14 eller -14) menes et relativt antal steps. Uden fortegn flyttes til den absolutte position.<\/li>\n\n\n\n<li>&lt;statusinformation&gt;, som er en af f\u00f8lgende:\n<ul class=\"wp-block-list\">\n<li>BLOCKED       Noget blokerer lyset for en af IR sensorerne.<\/li>\n\n\n\n<li>HOMING 1     Elevatoren homer. P\u00e5 vej ned til endestop.<\/li>\n\n\n\n<li>HOMING 2     Elevatoren homer. Leder efter det sted, hvor endestop deaktiveres.<\/li>\n\n\n\n<li>HOMING 3     Elevatoren homer. P\u00e5 vej lidt h\u00f8jere end 1. etage.<\/li>\n\n\n\n<li>HOMING 4     Elevatoren homer. P\u00e5 vej ned til etage 1.<\/li>\n\n\n\n<li>MOVING &lt;fra&gt; &lt;til&gt;<\/li>\n\n\n\n<li>IDLE &lt;etage&gt;<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>STATUS svaret bliver ogs\u00e5 sendt som event, n\u00e5r der sker en \u00e6ndring, Dvs. n\u00e5r status skifter, n\u00e5r enten der bliver sendt kommandoer via DCC eller n\u00e5r en etage\u00e6ndring er udf\u00f8rt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">19. oktober &#8211; Initialisering<\/h4>\n\n\n\n<p>Efter at jeg har pr\u00f8vet at forbinde mit Python UI til elevatoren, har jeg opdaget, at ESP32 genstarter hver gang jeg genstarter UI\u2019et (dvs. formentlig hver gang UI\u2019et forbinder til ESP32). Det har f\u00e5et mig ind p\u00e5 den tanke, at homing ikke er noget man selv skal styre og ej heller noget, der kun sker lige efter opstart. Det skal v\u00e6re just-in-time, dvs., n\u00e5r der bliver bedt om at skifte etage. Og selvf\u00f8lgelig kun, hvis det ikke allerede er gjort.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">20. oktober 2023 &#8211; N\u00e6sten alt fungerer<\/h4>\n\n\n\n<p>Nu er det hele implementeret. Og kun JMRI delen er helt utestet. Desuden er homing funktionen ikke fuldt testbar, f\u00f8r elevatoren findes i virkeligheden. Men motorerne k\u00f8rer skam jvf. ovenst\u00e5ende.<\/p>\n\n\n\n<p>I dag har jeg b\u00e5de testet DCC interfacet og skrevet (men alts\u00e5 ikke testet) JMRI interfacet.<\/p>\n\n\n\n<p>DCC interfacet havde et par fejl. For det f\u00f8rste havde jeg ikke forbundet optokobleren rigtigt. Og for det andet kan jeg ikke bruge M\u00e4rklin drejeskive definitionen i ECOS. Den kommunikerer naturligvis ikke via DCC. S\u00e5 i stedet har jeg nu defineret tre signaler med hver fire aspekter. Og det fungerer fint. 7 minutter inde i denne video bruges der dog en anden ops\u00e6tning af ECOS, som nok er lidt smartere: <a href=\"https:\/\/youtu.be\/sEMklCIiHEo?si=Sb-RR_vqEFoCq4I6\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/youtu.be\/sEMklCIiHEo?si=Sb-RR_vqEFoCq4I6<\/a> Og det samme her: <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/jvstrn\/DCC-Controlled-Kato-Turntable\" target=\"_blank\">https:\/\/github.com\/jvstrn\/DCC-Controlled-Kato-Turntable<\/a><\/p>\n\n\n\n<p>JMRI interfacet har jeg implementeret som en udvidelse af mit script til automatisk drift via warrants. Ogs\u00e5 dette har jeg lagt p\u00e5 GitHub til almindelig afbenyttelse.<\/p>\n\n\n\n<p>Udvidelsen best\u00e5r af <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/kjlisby\/train_elevator\/blob\/main\/serial_elevator\/JMRI\/JMRI_Interface.py\" target=\"_blank\">denne klasse<\/a>, som kun instantieres i et eksemplar (i sin egen tr\u00e5d), og som kommunikerer med RunTrain tr\u00e5dene vha. nogen Jython Queue k\u00f8er. Se definitionen af interfacet samt selve implementeringen i ovenst\u00e5ende link.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">16\/9-2024: Rel\u00e6modul tilf\u00f8jet<\/h4>\n\n\n\n<p>Jeg har besluttet at erstatte noget mekanik med noget elektronik og noget software. Og det er allerede gjort. Det handler om str\u00f8m til skinnerne, hvor jeg er g\u00e5et v\u00e6k fra mekaniske kontakter og over til rel\u00e6moduler koblet til ESP32\u2019eren vha. en MCP23017. Opdateringen kan ses p\u00e5 <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/kjlisby\/train_elevator\" target=\"_blank\">GitHub<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">28\/9: IR sensorer tilf\u00f8jet<\/h4>\n\n\n\n<p>Jeg besluttede mig for at d\u00f8mme elevatoren blokeret indtil 20 sekunder efter, at noget er detekteret i bare en af de fire portaler.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">4\/10-2024: IR modtager tilf\u00f8jet<\/h4>\n\n\n\n<p>Ved hj\u00e6lp af Arduino biblioteket IRremote (den som shirriff har lavet), har jeg tilf\u00f8jet yderligere en m\u00e5de at f\u00e5 elevatoren til at bev\u00e6ge sig til et nyt niveau, nemlig vha. fjernbetjeningen til mit TV. S\u00e5 nu er der disse muligheder:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>DCC<\/li>\n\n\n\n<li>JMRI (via mit script)<\/li>\n\n\n\n<li>USB \/ min serielle protokol fra min Python GUI<\/li>\n\n\n\n<li>USB \/ min serielle protokol fra fra Arduino IDE\u2019en<\/li>\n\n\n\n<li>USB \/ min serielle protokol fra JMRI scripting vinduet<\/li>\n\n\n\n<li>USB \/ min serielle protokol fra en terminal emulator eller lignende (ikke testet)<\/li>\n\n\n\n<li>TV\u2019ets fjernbetjening<\/li>\n\n\n\n<li>WIFI \/ HTML siden (ikke f\u00e6rdigudviklet, og bliver det heller ikke)<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">19\/10-2024: Testet med n\u00e6sten samlet elevator<\/h4>\n\n\n\n<p>Det var med noget b\u00e6ven, at jeg t\u00e6ndte for str\u00f8mmen til stepperne efter at have samlet hele mekanikken. For motorerne er muligvis st\u00e6rke nok til at \u00f8del\u00e6gge mekanikken, hvis den er gal med software\u2019n. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/09\/55F188F8-2537-485D-A209-B24943D5942D-scaled.jpeg\"><img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"1024\" src=\"https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/09\/55F188F8-2537-485D-A209-B24943D5942D-768x1024.jpeg\" alt=\"\" class=\"wp-image-3892\" srcset=\"https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/09\/55F188F8-2537-485D-A209-B24943D5942D-768x1024.jpeg 768w, https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/09\/55F188F8-2537-485D-A209-B24943D5942D-225x300.jpeg 225w, https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/09\/55F188F8-2537-485D-A209-B24943D5942D-1152x1536.jpeg 1152w, https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/09\/55F188F8-2537-485D-A209-B24943D5942D-1536x2048.jpeg 1536w, https:\/\/lisby.dk\/wordpress\/wp-content\/uploads\/2023\/09\/55F188F8-2537-485D-A209-B24943D5942D-scaled.jpeg 1920w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/a><\/figure>\n\n\n\n<p>Jeg begyndte forsigtigt med at granske PosLogic koden omkring homing. Hvor der da ogs\u00e5 var adskillige fejl.<\/p>\n\n\n\n<p>Desuden implementerede jeg et par kommandoer p\u00e5 den serielle konsol til at bev\u00e6ge en motor samt til at afl\u00e6se nuv\u00e6rende position og status p\u00e5 stepperne og end-stop switche. Derved kunne jeg teste, at motorerne k\u00f8rte den rigtige vej, og at der ikke var byttet rundt p\u00e5 h\u00f8jre og venstre.<\/p>\n\n\n\n<p>Men til slut m\u00e5tte jeg til det og trykkede 1 p\u00e5 fjernbetjeningen. Det virkede skidt. Meget skidt. <\/p>\n\n\n\n<p>I starten bev\u00e6gede elevatoren sig meget lidt. Det viste sig at v\u00e6re nogen DIP switche p\u00e5 stepper driverne, der var sat til at k\u00f8re 8 microsteps pr. step. S\u00e5 det var nemt at l\u00f8se. Men derefter k\u00f8rte det for hurtigt. Jeg havde konfigureret AccelStepper librariet til at k\u00f8re med en maksimal hastighed p\u00e5 1500 steps pr. sekund. Det satte jeg f\u00f8rst ned til 100, dern\u00e6st 200, s\u00e5 jeg kunne teste videre uden at smadre alting.<\/p>\n\n\n\n<p>P\u00e5 et tidspunkt kom der meget grimme lyde og det hele satte sig fast, fordi motorerne ikke bev\u00e6gede sig synkront og trak hele elevatoren sk\u00e6v.<\/p>\n\n\n\n<p>Udover mine egne kodefejl, k\u00e6mpede jeg l\u00e6nge med, at efter at homing funktionen havde bev\u00e6get motorerne ganske forsigtigt og fundet det eksakte sted, hvor endestop switchene deaktiveres, s\u00e5 flyttede den ene eller begge motorer pludselig elevatoren en centimeter eller to. \u00d8v!<\/p>\n\n\n\n<p>Det lod til, at AccelStepper librariet blev forvirret over, at jeg gentagne gange beder motorerne om at flytte 1\/10 omdrejning (20 steps), samtidig med at der skal accelereres op og ned. Jeg endte med at initialisere AccelStepper librariet til at s\u00e6tte hastigheden p\u00e5 motorerne til 600 steps (svarende til tre omdrejninger eller 6 mm) pr. sekund og accelerationen til et meget h\u00f8jt tal (50.000 steps pr. sekund pr. sekund), s\u00e5 der i praksis startes og stoppes s\u00e5 abrupt, som hardwaren fysisk er i stand til. Det betyder, at motorerne nu stopper, hvor jeg beder dem om at stoppe.<\/p>\n\n\n\n<p>Og det betyder, at det tager et sekund at bev\u00e6ge elevatoren seks millimeter. Dvs. 90 mm \/ 6 mm\/s = 15 sekunder at bev\u00e6ge elevatoren fra en etage til den n\u00e6ste. Og det passer meget godt i praksis. Jeg har m\u00e5lt det med et stopur. Der er i \u00f8vrigt kun 5 etager (eller 5&#215;15 = 75 sekunder) fra top til bund af elevatoren.<\/p>\n\n\n\n<p>Sluttelig har jeg rettet homing logikken og groft rekalibreret elevatoren, idet der kun er 90 mm (og dermed 9000 steps) og ikke 100 mm \/ 10000 steps pr. etage og idet etage 1 og 2 ligger p\u00e5 -2500 steps, fordi det svarer til, at endestop switchene er 25 mm inde p\u00e5 switch aktuatorerne.<\/p>\n\n\n\n<p><strong>20\/10-2024:<\/strong> UP\/DOWN knapperne p\u00e5 TV fjernbetjeningen implementeret.<\/p>\n\n\n\n<p><strong>28\/1-2025:<\/strong> Reset kommandoen tilf\u00f8jet den serielle protokol.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Software er som s\u00e6dvanlig det der usynlige, der bringer det hele til live, binder alle komponenter sammen og f\u00e5r det hele til at fungere. Desuden skal det indeholde en WEB server, s\u00e5 man fra en PC eller en tablet kan styre elevatoren og se samme information som p\u00e5 displayet. Kravspecifikationen: Design: For at implementere disse &hellip; <a href=\"https:\/\/lisby.dk\/wordpress\/?p=2812\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Elevatordesign &#8211; software<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2812","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/2812"}],"collection":[{"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2812"}],"version-history":[{"count":15,"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/2812\/revisions"}],"predecessor-version":[{"id":4435,"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/2812\/revisions\/4435"}],"wp:attachment":[{"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2812"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2812"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lisby.dk\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2812"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}