Hüftknochen-Einschlagapparat

Eine Apparatur zum Erlernen des richtigen Hammerschlags bei Operationen an (künstlichen) Hüftgelenken. Eingebettet in einer AR-Anwendung, an deren Entwicklung ich nicht beteiligt war.

Doch dazu kam ich nur scheibchenweise, um schließlich doch alles machen zu müssen. Abgesehen von der Mechanik.

Linak-Servo

Irgendwas aus Dänemark mit Absolutwertgeber, was mir hier vorgesetzt wird.

Linear-Servomotor und Steuerung im Versuchsaufbau

Gegenstand

Das Bedienteil will irgendetwas standardisiertes sein, tatsächlich entpuppt sich die Parametrierungsschnittstelle als closed-source sowie (absichtlich?) falsch dokumentiert: Die im Datenblatt angegebene Baudrate stimmt nicht.

Anschlüsse des Bedienteils (roter MicroMatch-Stecker)
NummerNameRichtungFunktion
1+5VBedienteilSpannung 5 V
20VkeineBezugspotenzial 0 V
3IND (sic)SteuerteilInterrupt (Unterbrechungsanforderung) negiert
4RxBedienteilEmpfangsdaten TTL
5TxSteuerteilSendedaten TTL
6--nicht belegt (von wegen!)

Bastelauftrag

Ziel ist es, das Bedienteil durch eine PC-Software zu ersetzen, um die Parametrierung durch Software erledigen zu können. Im Blick ist dabei LabVIEW.

Dazu muss das Protokoll erschnüffelt werden. In diesem Fall steht sigrok/PulseView sowie ein preisgünstiges CY7C68013A-Entwicklungsboard aus China zur Verfügung.

Screenshots beim „Wert abfragen“, als Tabelle burst1 und burst2

Gleich zu Anfang stellt sich heraus:

Der „burst1“ erschließt sich durch scharfes Hingucken. Dabei ist [0A] die String-Länge. Das [0B] vermutlich die Paket-Länge; hier nur 1 Sub-Item. Die anderen Konstanten werden wohl nicht entzifferbar (= bedeutungslos) bleiben. Unklar ist noch, warum der burst1 mit einem unbeantworteten [01] endet. Könnte sein dass das bereits zum burst2 gehört.

Der „burst2“ ist ebenfalls entziffert. Darin ist vermerkt, wieviele Parameter und Werte es gibt, und welche 8 Bit und welche 16 Bit breit sind. Daraus ergibt sich die Einschränkung, dass 16-Bit-Parameter stets hinter allen 8-Bit-Parametern angeordnet sein müssen; das gleiche für die Werte. Und dass es maximal 79 (Parameter + Werte) geben kann, da Parameter 1 auf „Adresse“ 21 und Folgebytes von Mehrbyte-Werten auf „Adresse“ 100 (jeweils dezimal) abgefragt werden.

Da auf dem Zielrechner das LabVIEW streikt, wurde kurzerhand das Programm in C++ in Visual Studio 6 erstellt. Alle Werte werden korrekt angezeigt. Die Zeilentitel können vom Anwender geändert werden und werden persistent je nach angeschlossener Steuerung (Name als Referenz) in der Registrierung gespeichert. Die Parameter können vom Anwender zwar editiert werden, werden jedoch noch nicht zur Steuerung zurückgeschrieben. Ein Tastaturinterface zum Umbenennen der Zeile bzw. zur Wertänderung ist (seitens Windows) nicht vorhanden, wird wohl noch mit F2 bzw. F3 realisiert (Explorer-kompatibel).

Screenshot des Test- und Überwachungsprogramms

Das gesamte Teilprojekt, den Linak-Servo zu „reverse-engineeren“ erwies sich nachfolgend als hinfällig, da die entscheidende Steuerungsgröße Kraft nicht verfügbar ist und die Alternative Weg nur per Analogwert vorgebbar ist.

Gesamtlösung

Nun kommt die Katze aus dem Sack: Der Linak-Servo dient dazu, eine Fahrradbremse anzuziehen. Da sich alles bloß nicht die Stellkraft und die Position des Servos digital einstellen lässt, müssen mechanisch federnde Elemente dazwischen (Hebel, Bowdenzug) die Proportionalität von Weg und Kraft herstellen und ein Analogwert legt die Position fest. Der FT232R-Adapter wird wieder frei und durch die Firmware des Arduino(?) ersetzt. Zum Einsatz kam schließlich ein Board mit STM32F103. Und eine Firmware mit WebUSB für die Funktionsdarstellung im Browser.

Hinfällig: Da dies nicht ohne Bauchschmerzen mit einem Arduino Uno geht, tendiere ich umgehend zu meinem Liebling Arduino Leonardo mit nativem USB-Interface. Das Computerprogramm soll in LabVIEW laufen und mit dem Versuchsaufbau über USB (genau 1 Kabel) kommunizieren.

Zusätzlich soll noch eine mit einem Hammer einwirkende Kraft gemessen werden. Im Vorversuch wurde eine Abtastrate von 20 kSa/s als geradeso ausreichend festgelegt, um den Kraftstoß zu erfassen. Eine geeignete Kraftmessdose mit Dehnmessstreifen wurde konstruiert, aufgebaut und eingebaut. Zur Erfassung des Kraftstoßes fallen die üblichen Wägezellenverstärker mit Sigma-Delta-Umsetzer aus; diese sind viel zu langsam.

Und ein Verschiebeweg wird mit einem digitalen Messschieber aufgenommen. Der misst nur langsam; die Position vor und nach dem Hammerschlag genügt. Die üblichen Messchieber haben 1/100 mm = 10 µm Auflösung. Siehe auch caliper2pc.

Schließlich soll die Festhaltekraft (Bremskraft) außer durch das Computerprogramm auch analog an einem Potenziometer eingestellt werden können.

Die Linak-Steuerung benötigt zudem ein Netzteil mit 24 V und 2,2 A. Dass diese ihrerseits 5 V liefern kann wird hier nur genutzt, um der Steuerung einen Analogwert vorzugeben.

Gesamtschaltung mit Entwicklungsboard basierend auf STM32F103C8T6

Der allfällige Vorverstärker für die Kraftmessdose mit OPA2376 verstärkt das Brückenausgangssignal um den Faktor 300, allein mit R4 einstellbar. R2 dient zum Brückenabgleich. Durch die Gegenkopplung des OPV arbeitet die Brücke im Kurzschlussbetrieb, und es wird effektiv der Diagonalstrom in eine Spannung gewandelt.

Hinfällig: Die Variante mit dem teureren und größeren Arduino Micro verwendet den differenziellen A/D-Wandler mit umschaltbaren Verstärkungen (×1, ×10, ×40 und ×200), um verschieden starke Schläge angemessen erfassen zu können. Leider bleiben dann nur 8 Bit Auflösung laut Datenblatt übrig, und man muss die Schlagstärke a priori kennen.

Die Variante mit dem chinesischen Pro Micro verwendet einen Instrumentationsverstärker und muss asymmetrisch messen, da bei diesem weder ADC0 noch ADC1 (noch AREF) herausgeführt ist. Dafür gibt es 10 Bit Auflösung.

ATmegas sind für die Abtastung des Kraftstoßes etwas überfordert. Externe A/D-Wandler erscheinen Overkill. Daher tendiere ich nun eher zur Verwendung eines STM32F103C8T6 auf einem Bluepill-Board. (Liegt schon zu Hause herum.) Den fälligen USB-Seriell-Konverter, den man leider zum Betanken dieses Boards benötigt, gewinne ich vom FT232R-Adapter für den Linak-Servo.

Der 12-bit-A/D-Wandler schafft 1 MSa/s, und es sind zwei davon drin. Leider nicht differenziell, daher Single-Ended-Konvertierung mit OPA2376 + INA155 (liegen herum, waren wohl kostenlose TI-Muster gewesen). Das USB-Interface wird wieder als WebUSB implementiert. Um Betriebsspannungskollisionen auszuschließen liefert der Linak-Servo die 5 V für den Verstärker vom PWM-Ausgang: Die Linak-Steuerung bekommt einen Analogwert nur dann, wenn diese auch 5 V liefert, also eingeschaltet ist. So kommt die gesamte Schaltung ohne wacklige 5 V vom USB aus, sondern vom 3,3-V-Festspannungsregler auf dem BlackPill-Board.

Die verwendeten Analogschaltkreise:

Blaue Pille, Schwarze Pille

Hoppla, ich hatte wohl die schwarze und nicht die blaue Pille genommen! Da unterscheidet sich die Pinbelegung ganz erheblich! Die Pin-1-Festlegung der Stiftleisten erscheint willkürlich, ich habe es hier wie bei DIL-Schaltkreisen umlaufend nummeriert.

 
Blue Pill und (von mir so genannt) Black Pill im Vergleich

Zur besseren Übersicht über herausgeführte Pins und deren Sonderfunktionen diese sortierbare Tabelle — Angaben ohne Gewähr:

Pinzuordnung STM32C8T6 vs. BluePill-40 / BlackPill-34. Graue Funktionen bei Pin-Remap
LQFP48SonderfunktionPortpin5V?UARTI²C/SPIPWMADCBluePill-40LabelBlackPill-34
1UBAT1VB-
2Tamper-RTCPC13n2, Blaue LED nach UDDC134
3Osc32 InPC14n3, Quarz 32 KHzC14Quarz 32 KHz
4Osc32 OutPC15n4, Quarz 32 KHzC15Quarz 32 KHz
5Osc InPD0nQuarz 8 MHz
6Osc OutPD1nQuarz 8 MHz
7Resetn17R5
8GNDA19, 20, 39G1
9UDDA18, 403V333
10WakeUpPA0nCts2T2C1ETR05A06
11PA1nRts2T2C216A17
12PA2nTx2T2C327A28
13PA3nRx2T2C438A39
14PA4nCk2SS149A410
15PA5nSCK1510A511
16PA6nMISO1T3C1/T1BKI611A612
17PA7nMOSI1T3C2/T1C1712A713
18PB0nT3C3/T1C2813B014
19PB1nT3C4/T1C3914B115
20Boot1PB2n
21PB10jTx3SCL2T2C315B1016
22PB11jRx3SDA2T2C416B1117
23GND19, 20, 39G1
24UDD18, 403V333
25PB12jCk3SS2/SMBAI2T1BKI21B1218, LED nach UDD
26PB13jCts3SCK2T1C122B1319
27PB14jRts3MISO2T1C223B1420
28PB15jMOSI2T1C324B1521
29MCOPA8jCk1T1C125A822
30PA9jTx1T1C226A923
31PA10jRx1T1C327A1024
32USBD-PA11jCts1T1C428, USBA1125, USB
33USBD+PA12jRts1T1ETR29, USBA1226, USB
34TMSPA13jX4-2DIOX4-3
35GND19, 20, 39G1
36UDD18, 403V333
37TCKPA14jX4-3SCKX4-2
38TDIPA15jSS1T2C1ETR30A1527
39TDOPB3jSCK1T2C231B328
40RSTPB4jMISO1T3C132B429
41PB5nSMBAI1/MOSI1T3C233B530
42PB6jTx1SCL1T4C134B631
43PB7jRx1SDA1T4C235B732
44Boot0n
45CANRXPB8jSCL1T4C336B82
46CANTXPB9jSDA1T4C437B93
47GND19, 20, 39G1
48UDD18, 403V333
5P38, USB5V34,USB
Hinfällig: Um sich den Analogvergleicher zu sparen (leider ist keiner drin) erfolgt die Pegelkonvertierung vom Messschieber mittels A/D-Wandler. Der ist mit seinen 1 MSa/s eh' schnell genug.

Urschleim: Der Urlader

Der STM32F103 kommt leider ohne USB-Urlader ab Werk. Und leider ist das Angebot von Urladern aus der Arduino-Szene ungenügend. Der beste zu findende ist ein HID-Urlader von serasidis.gr (aus Griechenland) mit 2 KiByte Platzbedarf, leider per Jumper BOOT1 zu starten: Zu umständlich. Eine Neukompilierung ohne Interrupts und ohne angezogene Handbremse (hier: USB-FIFO-Größe von 8 auf 64 Byte geändert) ist nun so gestaltet, dass man mit der Reset-Taste zum Urlader kommt; alle anderen Reset-Ursachen (bspw. Strom weg) führen zum Anwendungsprogramm, für das noch 62 KiByte Flash-Platz übrig bleibt. (Auf 1 KiByte ist der Urlader wohl nur mit ARM-Assembler hinzubekommen, wenn überhaupt. Wenn man bedenkt, dass der „Original“-Arduino-Urlader schlappe 20 KiByte wegschnappt, ist das schon ganz gut.) Zudem waren die Programme für seriellen Zugriff (stm32flash.exe) und HID-Zugriff (hid-flash.exe) viel zu groß; wurden mit MSVC6 auf 1/4 der ursprünglichen Größe eingedampft, ohne den Quelltext auszulichten. Bei „hid-flash“ ging mir der Zwang zum COM-Port (!) auf den Keks, dieses ist jetzt allenfalls optional, da eine Steuerung von BOOT1 nun nicht mehr erforderlich ist.

Hier ist alles dokumentiert und herunterladbar.

Implementierung

Auf einem für mich neuen Mikrocontroller etwas zu implementieren, was auch noch an die Grenzen des Machbaren geht, ist ein Weg mit vielen 🪨 Stolpersteinen.

USB

Das WebUSB-Interface war, ausgehend vom Urlader, recht schnurstracks hinzubekommen. Man muss allerdings aufpassen, dass der Controller nicht in Interruptroutinen erstickt! Im Gegensatz zum AVR, wo bei 100 % Interruptlast das Hauptprogramm mit wenigstens 1 Instruktion pro Interrupt vorankommt (also im 🐌 Schneckentempo), geht beim STM32F103 „dank“ Interruptverkettung (tail chaining) gar nichts mehr! 🛑 Man sagt, die Hauptschleife verhungert. Und so suchte ich den Fehler prompt an der falschen Stelle.

Messschieber

Bei der Entscheidung, den Analogvergleicher LM393 wegzulassen und stattdessen den A/D-Wandler zu benutzen hatte ich mich wohl 🐎 vergaloppiert! Denn das Taktsignal des Messschiebers kommt mit immerhin 80 kHz, man muss es mit 200 kSa/s abtasten. Das passt gerade so ins Taktregime, wenn man die 4 A/D-Eingänge zyklisch abtastet, mit minimaler Abtastzeit: Der A/D-Wandler, der mit 12 MHz getaktet wird, benötigt 14 Takte pro Kanal, das ergibt eine Kanalabtastrate von 12 MHz/14/4 = 214 kSa/s. Aber eine Flankendetektierung pro Abtastwert geht nicht, der Controller stirbt an Interrupt-Überlast. Vorbereitung: Das Taktregime gewissenhaft kontrollieren, dass der Controller, der A/D-Wandler und die übrige Peripherie tatsächlich mit dem maximal möglichen Durchsatz läuft. Die Lösung: Die Wandlerdaten werden en bloc von bspw. 16 Quadrupeln eingesammelt und in einer Schleife deserialisiert. Das senkt die Interruptfrequenz und damit die Last. Das verlustfreie Abholen der Daten erfolgt per DMA und Interrupts bei halbem und vollem Puffer; die jeweils inaktive Pufferhälfte wird verarbeitet. Der Messschieber verwendet ein 2 × 24-Bit-Binärprotokoll, von dem nur der 2. Block ausgewertet wird. Ein Skalierungsfaktor wird dann im WebUSB per JavaScript angerechnet. Die Ausgabe erfolgt auf 1/100 mm.

Schließlich wurde doch noch ein LM393 spendiert, in invertierender Beschaltung, und das Ganze an SPI1 zu betreiben. Der Pferdefuß steckt im Detail: Wie empfängt man mit dem Mikrocontroller 49 Bit? Die einzige Möglichkeit, die 49. Taktflanke zu verschlucken (= Rücksetzen des internen Bitzählers) besteht mit der Steuerung von Slave-Select. Aus- und Einschalten des SPI-Moduls tut's nicht!!

Kraftsensor

Im Prinzip ist eine Art Einstrahl-Oszilloskop gefragt, bei dem 100 kSa/s genügen. Durch den Messschieber kommen ohnehin bereits reichlich 200 kSa/s an. Die Triggerbedingung in Software zu realisieren führte erneut zum Verhungern der Hauptschleife, auch wenn man größere Blöcke verarbeitet. Daher wurde kurzerhand das Regime so geändert, dass der DMA-Puffer riesig ist und die Triggerbedingung per ADC-Watchdog 🐕 läuft. Da dazu zeitraubende Fallunterscheidungen nötig sind, wurde das Problem dadurch gelöst, die Interruptvektortabelle in den RAM zu verlegen und den Vektor bedarfsgerecht umzustellen. Das funktioniert nun am Fallbeispiel einer steigenden Flanke so:

  1. Für die Prätrigger-Zeit wird nichts gemacht. Dazu wird der Timer3 im Einzelschuss-Modus gestartet.
  2. Mit der Timer3-ISR wird die Trigger-Vorbedingung am A/D-Wandler gesetzt: Der A/D-Wert muss sich unterhalb der unteren Triggerschwelle befinden. Der Timer3 wird deaktiviert oder zur Auto-Triggerung verwendet.
  3. Mit dem nächsten Interrupt vom A/D-Wandler, der nur vom Watchdog kommen kann (die Werte werden unabhängig davon per DMA abgeholt) wird die Trigger-Hauptbedingung am A/D-Wandler gesetzt: Der A/D-Wert muss sich oberhalb der oberen Triggerschwelle befinden. Dazu wird die Interruptroutine für den A/D-Wandler umgebogen.
  4. Mit dem nächsten Interrupt vom A/D-Wandler, der nur vom Watchdog kommen kann, wird der Watchdog deaktiviert (simplerweise durch Laden von 0xFFF in HTR) und der Timer3 mit der Post-Trigger-Zeit im Einzelschussmodus gestartet. Dazu wird die Interruptroutine für den Timer3 umgebogen.
  5. Mit dem Eintreffen des Timer3-Interrupts befinden sich alle gewünschten Sampledaten im DMA-Puffer. Allerdings nicht in der passenden Reihenfolge; der Schnitt ist irgendwo mittendrin: Die Position des DMA-Schreibzeigers bekommt man durch Auswerten von CNDTR. Diese müssen nun (leider nur per Software) aus dem Puffer herauskopiert werden, während der DMA-Controller weitere neue Werte hineinschreibt. Deshalb dimensioniert man den DMA-Puffer ein bisschen größer und beginnt beim Herauskopieren mit dem ältesten Wert.
    Alternativ könnte man mit 2 DMA-Puffern arbeiten, aber da diese viel Platz fressen, ist das nicht so toll.
  6. Mit dem erneuten Scharfmachen des Triggers muss man wiederum die Prätrigger-Zeit abwarten, sonst kann es passieren, dass ein Signalverlaufsabschnitt mehrfach angezeigt wird. Daher wird wieder Timer3 im Einzelschussmodus gestartet, und es geht wieder von vorn los. Damit kein Ergebnispuffer verloren geht, bevor sie zum USB gehen, gibt es mehrere davon in einem weiteren Ringpuffer.
Es hat sich gezeigt, dass ein Hammerschlag mehrere Triggerereignisse generiert, er prellt also wie jede Computertaste auch. Deshalb erscheint die Pufferung wichtig.

Wegpotenziometer

Späterhin fiel die Entscheidung, zusätzlich oder an Stelle des Messschiebers (mit 10 µm Auflösung) einen Absolut-Wegsensor einzubauen. Am einfachsten ein Potenziometer. Denn ein inkrementeller Wegsensor, hier der Messschieber kann beim schnellen Versetzen (per Hammerschlag) springen oder (wahrscheinlicher) Striche verschlucken. In Verbindung mit dem internen 12-Bit-A/D-Wandler wird eine Auflösung von 60 mm / 4096 = 20 µm erreicht, mit Rauschanteil verlässlich 0,1 mm, das reicht.

Damit kann man nun durch Erweiterung der Oszi-Funktion auf „Zweistrahlbetrieb“ Kraftstoß und Verschiebung gleichzeitig messen und verfolgen. Die dazu notwendige Halbierung der Einzelabtastrate auf ca. 400 kSa/s ist vertretbar. Gefordert sind gar nur 200 kSa/s, sodass sogar Drei- und Vierkanalbetrieb offen steht.

D/A-Wandler

Zunächst wurde die Schaltung so aufgebaut, dass der eingebaute D/A-Wandler genutzt und das Ausgangssignal auf 5 V verstärkt wird. Aber Pustekuchen! Das STM32F103-Datenblatt ist dazu gemacht, zigtausendfache Umweltsünden zu begehen!! Man muss es nämlich ausdrucken und alle nichtzutreffenden Passagen durchstreichen! Das sind sehr, sehr viele. Dann bleibt gar nicht mehr so viel übrig (und wichtige Seiten über den Interruptcontroller fehlen noch), und das D/A-Wandlerkapitel entfällt ganz! Ist also gar keiner drin. Also das übliche: Mit PWM. (Ein echter D/A-Wandler stand schwachsinnigerweise im Pflichtenheft.) Als AVR-Verwöhnter hat man es mit STM32F103 echt schwer. Ein zutreffend gefiltertes Datenblatt ist man auch von 8-Bit-PICs sowie EZUSB gewöhnt. Hingegen kenne ich keinen 16- oder 32-Bit-Controller mit zutreffendem Datenblatt, vom C167 vielleicht abgesehen.

Brems-Potenziometer

Das Brems-Potenziometer braucht nur gelegentlich abgefragt zu werden. Da das eine lückenlose Erfassung des Kraftsensors behindert, wurde es trotzdem in das 200-kSa/s-Regime hineingepresst. Mit dem zweiten A/D-Wandler sollte es möglich sein, das Potenziometer und auch die Chiptemperatur nach dem Telegramm vom Messschieber abzufragen; die Pause ist ziemlich lang. Dazu muss der Kraftsensor vom ADC2 angefragt werden, der dann durchlaufen muss. Das Datenblatt schweigt sich IMHO aus, was passiert, wenn ADC1 lange (17,1 µs vorgeschrieben für Temperatursensor) abtastet und ADC2 währrenddessen laufend neue A/D-Werte produziert. Und wie sich das Ganze resynchronisiert. Günstig erscheint es für diesen Ansatz, die 3 langsamen Werte (Potenziometer, Temperatur, Referenzspannung) per „eingespritzten“ (injected) Wandlungsprozess in die laufende Erfassung der Takt- und Datenleitung vom Messschieber einzuschieben.

Die Verwendung von ADC2 für die Oszilloskopfunktion des Kraftsensors ermöglicht es, den Analog-Watchdog des ADC1 für die Erkennung von Taktimpulsen zu verwenden. Damit kann man die Interruptlast für den Messschieber dramatisch senken.

Der durchgestrichene Text ist hinfällig, weil der Messschieber nicht mehr per A/D-Wandler sondern per Pegelwandler und SPI abgefragt wird. Dadurch kann sich ADC1 um die Oszilloskopfunktion mit Trigger kümmern, und ADC2 kümmert sich um alles andere. Temperaturmessung fällt dadurch flach, weil diese nur an ADC1 möglich ist und der Hardware-Trigger (notwendig für das Oszi) ebenfalls an ADC1 hängt.

Linak-Servo

Der wichtigste Teil der Servosteuerung ist der D/A-Wandler. Alle anderen Parmeter des Servos werden über die serielle Schnittstelle des STM32F103 vermittelt. Das erspart einen gesonderten USB-RS232-Umsetzer, hält einen USB-Port frei und die Apparatur kompakt.
TODO: Noch zu implementieren

Das letztendliche Problem ist eine verbleibende Diskrepanz zur Praxis, weil während des Einschlagimpulses der Widerstand nicht zunimmt wie beim kegelförmigen Formstück (echtes Implantat) sondern nach Überwindung der Haftreibung in etwa konstant bleibt. Ein dem echten Einschlag entsprechenden Widerstand könnte man durch kegelförmige Gleitflächen erreichen (dann fixer Zusammenhang zwischen Weg und Kraftzunahme in Verbindung mit den Federkonstanten des Zustellsystems) oder durch eine schnellwirkende Wegmessung und Bremskraftveränderung, die dann in Mikrosekunden (!) reagieren müsste. Was an Railguns erinnert: Schneller als Körperschall zu sein. Angemerkt , recht spät für so ein Projekt!

Mechanischer Aufbau

Das Ganze ist eine „Brettschaltung“, die schließlich auf einen stabilen Tisch montiert wird. In der Mitte befindet sich der Linearmotor, der über ein raumgreifendes Hebelgestänge und einen Bowdenzug eine Fahrradbremse betätigt, die den (zunehmenden) Widerstand beim Einschlagen simuliert. Im linken Teil befinden sich Netzteil, Linak-Steuerung sowie die via USB angeschlossene Gesamtsteuerung mit STM32F103-Mikrocontroller und analoger Außenbeschaltung. Auf der rechten Seite befindet sich der Hüftknochen-Simulator, in den ein stangenförmiges Gebilde mit Schlagkopf eingeführt wird, welches dem medizinischen Gerät einigermaßen nachgebildet sein soll. Es besteht nicht aus teurem Medizin-Edelmetall.

Aufbau-Foto

Firmware für STM32F103 — siehe Makefile zum Bau und Flashen

WebUSB-Äpp — Zugriff auf das Gerät über das WebUSB-Interface

WebHID-Äpp — Zugriff auf das Gerät über das HID-Interface

DLL 32+64 Bit mit Test-🦎Echse und ⛲Quelle

Messwerte

Kraftvorgabe in kNGemittelter DigitalwertSteilheit in 1/kN
0720-
10148076
40306058,5
Kalibrierung

Damit passt die Dimensionierung der Verstärkerschaltung zum Problem. Der Jumper JP1 ist nicht gesteckt. Die Linearität lässt zu wünschen übrig. (Die Steilheit sollte gleich sein.) Ob die Firmware oder die PC-Software die Linearisierung vornehmen soll ist noch unklar.

Reinfälle

Oszillogramm der Tracedatenübertragung: Zunächst 19 Pakete via Interrupt-In an HID, danach 19 Pakete via Bulk-In an WebUSB

Potimechanik

Foto und 3D-Aufbau

Irgendwie wird der Kraftsensor überhaupt nicht mehr ausgereizt, die maximal erreichbaren Kraftwerte liegen bei 4 kN (400 kp). Also nur bei 10 % vom Endwert. Dabei ist der gesamte Kraftstoß etwa 1 ms breit, während sich die Potimechanik rund um das Wegmesssystem eher 4 ms Zeit lässt, bei straffer Bremse. Ob das jetzt die gebremste Masse oder aber die Seilkonstruktion um die Potiachse ist lässt sich nicht ohne weiteres feststellen. Mit einer High-Speed-Kamera vielleicht. Der ermittelte Kraftstoß liegt so bei Werten um 20 (nach der Division mit dem 1-ms-Integrationsintervall). Und die Maximalkraft bei reichlich 100. Wohlgemerkt, bei einem 12-Bit-A/D-Wandler. Alles in allem eine schlechte Dimensionierung. Aber für's Prinzip reicht es jetzt: Es kommen für unterschiedlich starke Schläge unterschiedlich starke Impulse, Kraft-Maxima und Verschiebewege. Die AC-Triggerung ist hinreichend empfindlich. Das Ergebnis bei poll() kommt sehr schnell, innerhalb von 30 ms. Das ist IMHO der größte Vorteil der Umgestaltung. Weiterhin stimmt der Weg-Wert immer (weil Absolutwertgeber), der Messschieber springt gelegentlich. Werte vom Messschieber werden von der DLL nicht mehr geliefert. Die DLL braucht das Oszillogramm nicht (wie bisher) auszuwerten, das macht jetzt die Firmware. Die Firmware ist nunmehr als ein bis-zu-4-Kanal-Oszilloskop ausgelegt. Die Triggerquellenumschaltung funktioniert jedoch nicht so recht. Die Voreinstellung in der Firmware ist 2 Kanäle (ADC8+ADC9), 4 ms Samplezeit, Triggerhysterese +50, Triggerquelle ADC8, AC-Kopplung, kurzer Prätrigger. Die Voreinstellung wird nach Reset wirksam, daher hilft beim irrtümlichen Verstellen das Ab- und Anstecken. Allerdings kann man nicht ohne Neuübersetzung andere Voreinstellungen (bei geänderten Aufbau­parametern, bspw. mehr Rauschen, was mehr Hysterese erfordert) festlegen. Mit den 4 ms ist der RAM des STM32F103 nahezu erschöpft, das sind knapp 2 K Samples pro Kanal. Für mehr Zeit müsste man die Summenabtastrate heruntersetzen. Strukturell steht eine DMA-Pufferumschaltung bei Triggerereignis an. Das erspart die murksig erscheinenden memcpy()-Aufrufe. Für die nächste Firmware-Überarbeitung …