Top
Gesamtindex → STM32  →  

Motor Midi

 

 
Inhaltsverzeichnis

Die Evolution der Idee

Mein Bruder baut Musikinstrumente aus allem, was Geräusch gibt. Eine seiner Ideen ist, Gegenstände durch Motoren angeschlagen zum Klingen zu bringen, und im zweiten Schritt die Motoren durch Kontakte aus einem Kinderpiano anzusteuern.

Mehr oder weniger enttäuschend. Das Klingen der Gegenstände wird vom Schlagen des Motors gestört.

 

Wie wäre es, die Motorgeräusche selber zu nutzen? Der Motor hat eine nominelle Drehzahl von 3000 U/min, was einem doch recht tiefen G1 entspricht. Als erstes wäre also die Schlagfrequenz zu erhöhen, z.B. durch eine Scheibe mit acht Nylonschnüren. Das bringt schon mal höhere Töne zustande. Die Schnüre werden sich im Lauf der Zeit abnutzen, so dass ein fertig aufgebautes Instrument permanente Pflege erforderte.
Eine Scheibe mit aufgeklebten Magneten koppelt die Drehung des Motors berührungslos und damit verschleißfrei aus.

 

Ansteuerung über Tasten

Ursprünglich sollten die Töne von den Gegenständen stammen, die Motoren also nur an oder aus geschaltet sein. Jetzt gilt es, die Motordrehzahl je nach gewünschtem Ton einzustellen. Dafür sorgt eine digitale Ansteuerung, die den Motor mit unterschiedlichen Spannungen betreibt, je nach gedrückter Taste.
Der folgende Aufbau verwendet eine kleine Konservendose als Membran, weshalb höhe Töne unverhältnismäßig laut klingen.

Magnetrad

Das Magnetrad koppelt das Drehen des Motors verschleißfrei auf einen mit einer akustische Membran (hier ein Dosendeckel) verbundenen Stabmagneten. Die Magnetscheiben sind aus auf der Straße gefundenen Zigarettenpapierpackungen recykelt. Beim Aufkleben stören die doch deutlichen Kräfte zwischen den Scheiben. Mein Ausweg:
- einen guten Tropfen Sekundenkleber auf das Holzrad setzen
- Magnetscheibe auf den vorgesehenen Platz drücken
- auf den vorgequollenen Sekundenkleber Natron streuen, was diesen schnell aushärten lässt
- zur weiteren Verstärkung einmal Epoxidharzkleber rundum auftragen
- während das Epoxidharz aushärtet, den Motor langsam (!) drehen lassen, damit sich keine Tropfnasen bilden.
Ein Stück Fahrradschlauch soll Kräfte auf die Klebung bei evtl. Kollisionen dämpfen.

 

Verbesserungen

1. Die Lautstärke steigt mit der Umdrehungszahl, tiefen Tönen fehlt der "Bass". Hilfreich wäre eine größere Membran, die schnellen Bewegungen nicht mehr so gut folgen kann. Vermutlich wird die Resonanzfrewuenz dann zum ´Problem.

2. Die Motoransteuerung kann den Motor nicht aktiv bremsen. Besonders auffällig wird das in Pausen nach hohen Tönen, bei denen der Motor abheult (als Gegenteil zu Aufheulen). Vorgemerkt für Version 2.

3. Der Treiber für den BUK545 ist ein Inverter. Das ist nur wegen der Kompatibilität zu einem Steckbrettaufbau mit einem bedrahteten TCA4426 microchip.com ⇗. Problem: auch wenn das Compare Register des Timers auf 0xFFFF gesetzt ist, geht der Ausgang für einen Takt auf 0, entsprechend erhält das Gate einen kurzen On-Puls. Keine Ahnung, ob sich das per Registereinstellungen ändern lässt. Am einfachsten nicht invertiert ansteuern.

 

Die Elektronik

sn74ahct1g00   ti.com ⇗
BUK545   alldatasheet.com ⇗


Stromversorgung

Zuerst verwendete ich ein chinesisches LM2596 Modul, auf 5V eingestellt, zur direkten Versorgung der Schaltung. Just vor einer geplanten Vorführung des Aufbaus fiel dann das Prozessorboard aus, beim Anstecken der 24V. Als Ursache vermute ich eine Überhöhung der Ausgansspannung beim irgendwie ungünstigen Anlegen der 24V. Siehe Messungen dazu: LM2596.
In der Schaltung übernimmt jetzt ein analoger Regler die Erzeugung der 5V. Das DCDC Modul erzeugt dessen Eingangsspannung von 8V, damit dieser nur ca. 150mW Leistung verbraten muß.

Encoder

Pin Farbe Belegung
1 gelb Anode LED (120R nach +5V)
2 grau Versorgung +5V
3 weiß Kanal B
4 grün Kanal A
5 braun GND

Die verwendete Scheibe liefert 120 Pulse / Umdrehung.

Optokoppler

Es war kein (schneller) 6N138S zur Hand, der normalerweise zur galvanischen Trennung von MIDI verwendet wird. Ein TLP281-Modul erwies sich als zu träge. Verkleinerung einer der Arbeitswiderstände auf 560+150 = 710R konnte dessen Übertragungsgeschwindigkeit soweit erhöhen, dass die 31,25kBaud Kommunikation möglich wurde.
Was zunächst als vorläufige Lösung gedacht war, ist weiterhin im fertigen Gerät enthalten.

Eine Sache hielt mich ungebührlich lange auf: der Ausgang des TLP281-Moduls ist gegenüber einem 6N138S invertiert!
Ein kleiner Single-Gate Inverter liegt daher vor dem RX-Eingang der BluePill. A10 ist 5V tolerant, daher ist die Speisung des Inverters mit 5V kein Problem.

Pinbelegung BluPill

gewählt Port Pin   Pin   Port gewählt
Out B12 28       GND  
In mit Pullup, zur Auswahl
des MIDI-Steuergeräts
B13 29       GND  
  B14 30       3V3  
  B15 31       RST  
  A8 8   27 B11    
  A9 9   26 B10    
RX: Midi Input A10 10   17 B1    
  A11 11   16 B0    
  A12 12   7 A7    
  A15 15   6 A6    
Encoder weiß B3 19   5 A5    
Encoder grün EXTI4 B4 20   4 A4    
  B5 21   3 A3    
  B6 22   2 A2    
  B7 23   1 A1    
  B8 24   0 A0 ADC1 opt. Poti für Parametereingaben
~ Motor PWM B9 25   34 C15    
  5V     33 C14   =1 wenn Interrupt aktiv
  GND     32 C13 LED  
  3V3         VBAT  

5V tolerant  BluePill 

 

Software

Arduino-IDE: 1.8.5. mit der Anpassung von rogerclarkmelbourne  Installation ⇗

MotorMidi.ino   Pitches.h

Midi

Das icon iKeyboard erzeugt MIDI-Nachrichten mit Pitches von 36..96 (61 Tasten), beginnend mit C

NOTE_ON. channel: 1, controller #36, value = 106
NOTE_ON. channel: 1, controller #36, value = 0
NOTE_ON. channel: 1, controller #96, value = 94
NOTE_ON. channel: 1, controller #96, value = 0

Das MotorPiano hat 44 Tasten, es meldet Pitches von 16 .. 59 (44 Tasten), beginnend mit C.
Das ist keine Übereinstimmung. Mist.

Ein Jumper muß über die Einstellung eintscheiden. Durch Verwendung zweier nebeneinander liegender GPIOs bleibt der Verdrahtungsaufwand  minimal, nämlich 0.

Mit dem iKeyboard erzeuge ich C2 (65Hz, linke Taste) bis  E5 (659Hz).
Für den Index in m_tones[] ziehe ich beim iKeyboard 23 von contoller ab (damit stimmen Tastenwert und Note überein). Die linke Taste sendet 36, 23 abgezogen gibt 13, m_tones[13] = C2.
Für das Motorpiano darf ich also nur 3 abziehen.

 

 

Interrupts & Timer

nested Interrupts

Takt, Überlauf Prio intern extern Pin
Timer4 24MHz, 1024     CH4: MotorPWM PB9
      CH3: opt. analoger Ausgang   PB8
  - ohne angeschlossene Interruptroutine    
Timer3 1MHz, 1000 14 Überlauf alle 1ms:
- g_millisec inkrementieren
- Regelroutine
- -
    microsec() nutzt den Zählerstand    
Timer2 1MHz,  65535 3 Überlauf: Motor dreht zu langsam.
zählt die µs ab Encoderflanke.
  -
EXTI4 5 Encoder. max. alle 100µs   PB4

 

Ermittlung der Drehzahl

Tachometer: Encoderscheibe.
Die resourcensparendste Lösung wäre wohl, einen Timer duirch einen externes Signal automatisch die Zeit zwischen (acht) Encoderflanken messen zu lassen. Die programmiertechnisch einfacher implementierbare Lösung war, Timer2 im Encoderinterrupt auszulesen und neu zu starten:

void encoder () {
    static uint32_t encCnt = 0;
    encCnt += 1;
    if ( encCnt >= 15) {
        uint32_t et = Timer2.getCount(); // Timer auslesen
        Timer2.setCount( 0);             // und neu starten
        g_encoderPps = 5000000 / et ;
        if ( g_tim2Overflow) {
            g_encoderPps = 0;
        }
        encCnt = 0;
    }
}

wobei g_tim2Overflow im Timer2 Überlaufinterrupt gesetzt wird. Das Aufsummieren von Encoderperioden erhöht die Genauigkeit, vor allem bei hohen Drehzahlen. 15 Encoderperioden ist die Zeit zwischen zwei Polpulsen (120 / 8 = 15).

Im ersten Ansatz verwendete ich micros() zur Bestimmung der verstrichenen Zeit. Es gab jedoch in den Messergebnissen immer wieder Ausreißer. Der Tiefpass vor PB4 brachte keine Verbesserung. Die Ursache liegt offenbar darin, dass micros() Zählerüberläufe nicht mitbekam, was vermutlich an der Verwendung von micros() innerhalb der Interruptroutine liegt. Nicht erschöpfend untersucht.

Problem: abgelaufene Mikrosekunden bestimmen. Beim Bestimmen der Rotationsgeschwindigkeit mit Strompulsen lief das, jetzt habe ich wieder Ausreißer. Urggh.

Was hilft: die Prio des 1ms Interrupts über die der Encoderroutine setzen - dadurch geht der Überlauf des Zählers garantiert in die g_millisec ein.
Jedoch erledigt der 1ms Interrupt auch die Regelung, welche potentiell so lange dauert, dass Encoderinterrupts verloren gehen!

Aus der Interrupttabelle für die BluePill entnehme ich: Prio SysTick = 6. Ich setze Encoderprio = 7, Regelungsprio = 10 und verwende micros(), d.h. den Arduino µs Timer, von dem ich vermute, dass er mit SysTick läuft.
Weiterhin Ausreißer.

Kann der Interrupt seine Prio dynamisch verringern?

Idee: mit EXTI4 den Timer2 resetten. Beim nächsten EXTI4 dessen Stand auslesen.
µs, über 8 Flanken aufsummieren. 65536  wird bei 1U/s erreicht.
Bei 3000U/min geht der Zähler noch bis auf 1333 - das erscheint mir ausreichende Auflösung.

deepbluembedded.com verwendet InputCapture: liest bei beiden Flanken den Timerstand und bildet die Differenz, berücksichtigt die zwischendurch aufgelaufenen Overflow Interrupts.
Leider komme ich mit dem RCM Beispiel nicht klar: wie ordne ich den Eingang zu, wie setze ich den Prescaler auf 8 events?


STM32 Timer Tutorial  deepbluembedded.com ⇗  führt auf:

Interrupt/DMA generation on the following events:
– Update: counter overflow/underflow, counter initialization (by software or internal/external trigger)

 

Regelung

PI-Regler.

 

Dokumentenhistorie

Datum Änderung
2024-04-16 angelegt, als Ableger von Motor-tachless

In Motor tachless bestimme ich die Drehzahl eines Motors anhand seiner Strompulse, um damit eine Regelung aufzubauen. Um die Regelung erstmal stabil aufzusetzen, schob ich eine Drehzahlmessung mit Encoderscheibe ein. Die damit erzielte Regelung war super.
Mit dieser Schaltung möchte ich Albrecht einen Motor zur Verfügung stellen, der die Drehzahl eines Motors durch Midi gesteuert einstellt.

2024-04-18 die Mikrosekunden ohne Slip ermitteln.  Ich verwende Timer2
2024-04-21 veröffentlicht
2024-04-26 aufklappbares Inhaltsverzeichnis