home
erste Version am 10.10.2021
letzte Änderung am 11.11.2021
MausBeweger
Das Ziel dieses Projekts ist eine aktive Abstellfläche für
die Maus. Sobald eine Maus darauf abgestellt wird, bekommt sie
regelmäßig einen virtuellen Stubs und simuliert somit
Anwesenheit am Rechner.
Der Einsatzweck dafür ist das HomeOffice, in dem parallel an zwei
Rechnern gearbeitet wird.
Auf dem Firmen-Laptop läuft üblicherweise der ganze
Kommunikations-Kram bzw. speziell das Chat-Tool.
Die eigentliche Arbeit wird jedoch gerne mal an einem anderen
-angenehmeren- Rechner (mit FullSize-Tastatur und größerem Monitor)
via ssh oder ssh-X-Forwarding erledigt.
Weil die Maus am Firmen-Laptop bei dieser Konstellation jedoch
längere Zeit unbewegt bleibt, schaltet das Chat-Tool seinen Status
ständig von anwesend auf abwesend um. Echt lästig...
Sicher könnte man das Problem auch komplett in Software
lösen - jedoch wäre diese Software dann sicher ständig aktiv und
würde nerven, wenn man dann tatsächlich doch mal am Laptop zugange
wäre.
Bei der angedachten mechanischen Lösung kann/muss die Maus
bei Bedarf auf eine spezielle Park-Position geschoben werden, um per
Chat erreichbar zu bleiben.
Es gibt durchaus fertige Lösungen für diese Aufgabe. Deren
Werbebilder sind jedoch gelegentlich ziemlich grenzwertig: immer
wieder chillende Yuppies mit Mops und Apple-Device (alias
Super-Checker), die dank MausBeweger grinsend und
tiefenentspannt Kaffee schlüfen können (während der Chef mit
Stasi-Mentalität dann wohl annimmt, sie würden arbeiten).
Lustigerweise zeugen die
Amazon-Bewertungen oft von ungenügender Qualität dieser Devices.
Ich hoffe doch mal, dass jeder, der überhaupt auf meiner Seite
landet, Spaß am Gerät hat, gerne das tut, was er tut ....
und den Maus-Beweger eben nicht dazu einsetzt, derart
erbärmlichen Arbeitszeit-Betrug zu begehen.
Andererseits wirds bei dieser Anti-Zielgruppe wahrscheinlich sowieso
daran scheitern, dass ihnen Gerätschaften und/oder Fähigkeiten
fehlen, die zum Nachbau unabdingbar sind.
Als da wären: Verfügbarkeit und Bedienkenntnisse für 3D-Drucker,
Arduino/ATmega328-Programmierumgebung, Lötkolben (Achtung! Schmerzhaft...zumindest bei 430°C) .
Inhaltsverzeichnis
Vorüberlegungen
Erste Tests
Und schon funktioniert es
Das Unterteil
Die Firmware (für den ATmega328)
Alles beisammen
Verlötung der
Lochrasterplatte
Neues Oberteil
Vorüberlegungen
Die
Maus soll real nicht bewegt werden. Vielmehr soll der Boden unter
dem optischen Sensor bewegt werden.
Zwei relativ kostengünstige Optionen fallen mir ein (und eine
dritte, die aber schnell wieder verworfen wurde):
- ) per 5V-Steppermotor (28byj48) eine Stroboskop-Scheibe drehen
lassen oder
- ) per 5V-Modellbau-Servo einen weissen Arm vor einem
schwarzen Hintergrund bewegen oder
- ) per geplustem LED- oder Laser-Gegenlicht....oder auch
nicht....wegen
dem hier....ist mir viel zu kompliziert.
Weil der Maus-Cursor nicht konstant in eine Richtung wandern soll,
ist eine Drehscheibe (bei Variante 1.) dann doch keine so gute Idee.
Variante 2. würde weniger Platz beanspruchen, Variante 1. wäre
voraussichtlich etwas billiger.
Der Stepper braucht vier Pins zur Ansteuerung, der Servo nur einen.
Die bevorzugte CPU ist ein ATtiny85 - also Pin-Knappheit.
Denkbar wäre nämlich auch noch eine Art Einschalter - also sodass
nur bei erkannter Maus-Lagerung etwas passiert.
Andererseits wird es vollkommen reichen, wenn einmal pro Minute
Maus-Wackeln erfolgt. Also Strom-technisch egal. Aber vielleicht
Lärm-technisch doch sinnvoll....wir werden sehen.
Das Gehäuse wird aus dem 3D-Drucker kommen und keilförmig sein. Ein
30°-Winkel vielleicht.
Unterschiedliche Maus-Abmessungen und Sensor-Positionen könnten eine
Herausforderung werden.
Unter der Annahme, dass der Sensor immer mittig zum Maus-Chassis
sitzen wird, wäre eine simulierte Seitwärtsbewegung geschickter.
Und an der tieferen Kante bräuchte es ein einzeln druckbares
Maus-Ausrichtungs-Element. Damit müsste höchstens dieses Teil neu
entworfen und gedruckt werden, wenn eine Maus mit anderen
Abmessungen zum Einsatz kommen sollte.
Oder die Maus steht waagerecht auf der Fläche. Das wäre
wahrscheinlich einfacher bzw. leichter für unterschiedliche
Maus-Modelle nutzbar.
Die Höhe wäre dann mindestens 35mm (MicroServo) oder 32mm
(28byj48-Stepper).
Erste Tests
Nun habe ich erste Tests mit einem MicroServo und der Servo-Library gemacht. Tatsächlich lautlos
wird der Servo erst nach einem servo.detach().
Und zu allem Übel steht hier noch, dass die Library nicht am ATtiny85
funktioniert.
Den 28byj48-Stepper per ATtiny85 ansteuern, kann ich
schon.
Jedoch habe ich gerade eine Seite mit Doku gefunden, wie es ganz ohne
Library funktioniert. Das klappt sehr schön an einem ArduinoUNO.
Damit ist der Servo raus: der Stepper ist leiser, billiger, flacher
und einfacher ansteuerbar.
Dann stellt sich noch die Frage, ob es einen Ausrichtungs-Modus
braucht. Schließlich reagieren diverse Programme auf
MouseOver-Events mit PopUp-Fenstern - oder Schlimmerem. Daher ist
die Idee, die Maus zunächst in einen diesbezüglich unkritischen
Bereich des Bildschirms zu fahren, bevor sie auf den MausBeweger
gesetzt wird. Dort soll sie nur noch kleine Hin- und Her-Bewegungen
ausführen, um im unkritischen Bereich zu bleiben.
Dort abgesetzt, möchte man wahrscheinlich zeitnah wissen, ob sie
korrekt über dem bewegten Bereich steht. Bei nur einem kleinen
Ruckler pro Minute, wird das aber nix mit zeitnah. Es
bräuchte entweder eine Erkennung von "Maus wurde bewegt" oder einen
Taster zum Ankündigen der Ausrichtungs-Wunsches.
Oder wieder zurück zu der Idee vom keilförmigen Gehäuse: ein
justierbares Maus-Ausrichtungs-Element. Das ist wohl einfacher -
speziell bei der späteren Nutzung.
Der erste Gehäuse-Entwurf sieht erstmal so aus .... noch ohne
Maus-Ausrichtungs-Element:
In ABS gedruckt soll das 1:18 Stunden dauern und 19g Filament
benötigen.
Das ist zwar hart an der Schmerzgrenze für einen Test-Druck, aber
vielleicht braucht es dann nur noch ein passend hohes Unterteil ....
und das Gehäuse wäre durch.
Auf jeden Fall wird sich damit testen lassen, ob es grundsätzlich
funktioniert.
Und schon funktioniert
es
Wie geil. Klappt auf Anhieb. Noch ohne Unterteil und mit ArduinoUNO
- aber klappt.
Die Maus wandert per Magie ca. 1/10-Bildschirmbreite von
links nach rechts ... und wieder zurück.
Wenn man sich einmal gemerkt hat, wie die Maus auf dem MausBeweger
abgestellt werden muss, braucht es auch kein
Maus-Ausrichtungs-Element mehr.
Nun fehlt nur noch der Gehäuse-Boden, die Umstellung auf den
ATtiny85 und eine Stromversorgung per USB.
Sobald das Gehäuse final ist, werde ich es auf Thingiverse hochladen
und das Thing hier verlinken.
Das Unterteil
Im Unterteil braucht es mindestens einen USB-Anschluß zur
Stromversorgung.
Vielleicht auch eine Power-LED und vielleicht sogar noch einen
Taster für den Ausrichtungstest ... und bei langem Druck zum
Abschalten.
Damit würden dann sechs steuerbare Pins benötigt werden.
Hmmmm..... und wie leitet man dann eine Re-Programmierung des Chips
ein!?
Laut Datasheet vom ATtiny85 gilt für den Reset-Pin
(1) "can also be used as a (weak) I/O pin".
Bei Heise heisst es hingegen: "Neben GND und
Spannungsversorgung ist Pin 1 als Reset-Pin für den Flash-Vorgang
reserviert. Fünf GPIO-Pins (also als Ein- oder Ausgang) bleiben für
eigene Anwendungen übrig."
Irgendwie geht es wohl. Aber in die Fuse-Abgründe wollte
ich eigentlich nicht eintauchen.
Daher nehme ich vielleicht lieber einen ATtiny861, von dem ich vor Urzeiten (Jan.
2018) fünf Exemplare gekauft habe.
Oder auch nicht. Der Nullkraft-Sockel des Diamex kann den nicht.
Dann war das offenbar ein Fehlkauf. Auf sowas hier habe ich keinen Bock mehr...
Somit bliebe mir nur noch der ATmega328 (samt Quarz - weil der
OptiFix-Bootloader den braucht), wenn ich nicht auf eine Lieferung
von Reichelt warten will.
Auch doof. Weil Overkill.
Die LED könnte parallel zu einer Stepper-Spule geschaltet werden.
Wäre aber Stromverschwendung und vielleicht auch ungesund für den
Stepper.
Oder ein 74HC795-Schieberegister vor Stepper und LED. Damit hätte
ich dann aus drei ATtiny85-Pins acht Ausgangs-Pins gemacht.
Ach was solls. Dann wird eben ein weiteres Exemplar meines großen
ATmega328-Vorrats eine Bestimmung bekommen.
Die Firmware (für den ATmega328)
Drei Komponenten müssen gesteuert / abgefragt werden.
- ) der Stepper
- ) die LED
- ) der Taster
Sobald Saft via USB da ist, leuchtet die LED. Bei aktivem Stepper
blinkt die LED schnell. Im Schlafmodus blinkt die LED im
Sekundentakt - oder ist aus...mal schauen.
Wird der Taster kurz betätigt, läuft der Stepper an und führt drei
Hin-/Her-Bewegungen aus. Wird er mindestens eine Sekunde lang
gedrückt gehalten, wechselt das Gerät in den Schlafmodus.
Der Stepper ist an oder aus und führt, wenn an, immer gleich weite
Hin-/Her-Bewegungen aus.
Sodele...das hier erfüllt diese Vorgaben:
/*
* MausBeweger
*
* Stepper-Ansteuerung inspiriert von: https://elektro.turanis.de/html/prj143/index.html
*
* D.Ahlgrimm 15.10.2021
*/
#include <TimerOne.h> // https://www.arduino.cc/reference/en/libraries/timerone/
#define PIN_COIL_IN1 8 // Spule blue
#define PIN_COIL_IN2 9 // Spule pink
#define PIN_COIL_IN3 10 // Spule yellow
#define PIN_COIL_IN4 11 // Spule orange
#define PIN_BUTTON 3 // Taster
#define PIN_LED 13 // LED
#define MOTOR_SPEED 10 // in Millisekunden
#define BUTTON_OPEN 0
#define BUTTON_PRESSED_SHORT 1
#define BUTTON_PRESSED_LONG 2
#define BUTTON_RELEASED_SHORT 3
#define BUTTON_RELEASED_LONG 4
volatile byte button=BUTTON_OPEN; // aktueller Zustand des Tasters
#define LED_OFF 0 // nicht verwendet
#define LED_ON 1 // Geraet an - aber Stepper gerade inaktiv
#define LED_BLINK_FAST 2 // Stepper aktiv
#define LED_BLINK_SLOW 3 // Schlafmodus
volatile byte led_preset=LED_ON; // aktueller LED-Modus
#define DEBUG false
const byte coil_pin[4] = { PIN_COIL_IN1, PIN_COIL_IN2, PIN_COIL_IN3, PIN_COIL_IN4 };
const bool coil_pwr[9][4] = { // Soll-Zustaende der Spulen am Stepper
{ LOW, LOW, LOW, HIGH },
{ LOW, LOW, HIGH, HIGH },
{ LOW, LOW, HIGH, LOW },
{ LOW, HIGH, HIGH, LOW },
{ LOW, HIGH, LOW, LOW },
{ HIGH, HIGH, LOW, LOW },
{ HIGH, LOW, LOW, LOW },
{ HIGH, LOW, LOW, HIGH },
{ LOW, LOW, LOW, LOW } // Stepper = aus
};
volatile bool stepper_on=true; // steuert den Ein/Aus-Zustand des Steppers
volatile byte stepper_force_cnt=0; // fuer Stepper 3x Hin-/Her nach kurzem Betaetigen des Tasters
// --------------------------------------------------------------------------------
// Wird einmal pro Millisekunde aufgerufen.
void per_ms(void) {
static bool led_state; // An/Aus-Zustand der LED
static bool led_slow_on=true; // zum asynchronen Blinkverhaeltnis beim langsamen Blinken
static int led_slow_on_cnt; // Zaehler fuer das asynchrone Blinkverhaeltnis
static byte but_last=1; // Aenderungserkennung beim Taster
static byte but_state=HIGH; // Zustand des Tasters, HIGH=offen, LOW=gedrueckt
static unsigned long button_pressed=0L; // Timeout-Wert fuer den Taster (Erkennung fuer "lange gedrueckt")
// - - - - - - - - - - - - - - - - - - - - -
// LED-Steuerung
// - - - - - - - - - - - - - - - - - - - - -
switch(led_preset) {
case LED_OFF:
led_state=LOW;
break;
case LED_ON:
led_state=HIGH;
break;
case LED_BLINK_FAST:
if(millis()%50==0) {
led_state=!led_state; // schnelles Flackern
}
break;
case LED_BLINK_SLOW:
if(millis()%3000==0) {
led_slow_on=!led_slow_on; // asynchrone Blinken (alle drei Sekunden kurz aufblinken)
if(led_slow_on) {
led_slow_on_cnt=0;
led_state=HIGH;
} else {
led_state=LOW;
}
}
break;
}
if(led_preset==LED_BLINK_SLOW && led_slow_on) {
led_slow_on_cnt++;
if(led_slow_on_cnt>30) { // beim asynchronen Blinken wird die An-Phase nach 30ms...
led_state=LOW; // ...beendet.
}
}
digitalWrite(PIN_LED, led_state);
// - - - - - - - - - - - - - - - - - - - - -
// Abfrage und Verarbeitung des Tasters
// - - - - - - - - - - - - - - - - - - - - -
but_state=digitalRead(PIN_BUTTON);
if(but_state==LOW && button==BUTTON_PRESSED_SHORT) { // wenn der Taster gedrueckt ist und davor auch schon gedrueckt war...
if(button_pressed>0L && millis()>button_pressed) { // ...und der Taster bereits seit einer Sekunde gedrueckt gehalten wird...
button=BUTTON_PRESSED_LONG; // ...diesen Umstand vermerken...
button_pressed=0L;
#if DEBUG
Serial.println("long detected");
#endif
}
}
if(but_state!=but_last) { // wenn sich der Status am Taster geaendert hat...
but_last=but_state;
#if DEBUG
Serial.println("but changed");
#endif
switch(button) {
case BUTTON_OPEN: // wenn der Taster nicht betaetigt war und jetzt betaetigt wurde...
button=BUTTON_PRESSED_SHORT; // ...merken (erstmal als "kurz gedrueckt")...
button_pressed=millis()+1000; // ...und die Lang-Drueck-Erkennung aufsetzen
break;
case BUTTON_PRESSED_SHORT: // wenn der Taster kurz betaetigt war und jetzt losgelassen wurde...
button=BUTTON_RELEASED_SHORT; // ...mal kurz merken... wird nach Verarbeitung auf BUTTON_OPEN gesetzt
break;
case BUTTON_PRESSED_LONG: // wenn der Taster lange betaetigt war und jetzt losgelassen wurde...
button=BUTTON_RELEASED_LONG; // ...wie zuvor
break;
}
}
if(button==BUTTON_RELEASED_SHORT) { // wenn der Taster kurz betaetigt war und jetzt wieder losgelassen wurde...
#if DEBUG
Serial.println("BUTTON_RELEASED_SHORT");
#endif
stepper_on=true; // ...Stepper einschalten
stepper_force_cnt=3;
led_preset=LED_BLINK_FAST;
button=BUTTON_OPEN;
} else if(button==BUTTON_RELEASED_LONG) { // wenn der Taster lange betaetigt war und jetzt wieder losgelassen wurde...
#if DEBUG
Serial.println("BUTTON_RELEASED_LONG");
#endif
stepper_on=false; // Stepper aus und "Schlafmodus" einleiten
led_preset=LED_BLINK_SLOW;
button=BUTTON_OPEN;
} else if(button==BUTTON_PRESSED_LONG) { // wenn der Taster jetzt eine Sekunde lang betaetigt wurde...
if(stepper_on) { // ...und der Stepper grade an ist - sofort ausschalten
stepper_on=false;
led_preset=LED_BLINK_SLOW;
}
}
}
// --------------------------------------------------------------------------------
// Init.
void setup() {
for(int c=0; c<4; c++) {
pinMode(coil_pin[c], OUTPUT);
}
pinMode(PIN_BUTTON, INPUT_PULLUP);
pinMode(PIN_LED, OUTPUT);
Timer1.initialize(1000); // 1x pro Millisekunde
Timer1.attachInterrupt(per_ms);
#if DEBUG
Serial.begin(115200);
#endif
}
// --------------------------------------------------------------------------------
// Mainloop.
void loop() {
static int i;
static bool stepper_last=true; // Aenderungserkennung am Stepper
if(stepper_on) {
moveMouse();
for(i=0; i<3000 && stepper_on && stepper_force_cnt==0; i++) { // 3000*10ms = 30 Sekunden Pause
delay(10);
}
if(stepper_force_cnt>0) {
stepper_force_cnt--;
#if DEBUG
Serial.print("stepper_force_cnt=");
Serial.println(stepper_force_cnt);
#endif
}
} else {
if(stepper_last!=stepper_on) {
stepper_last=stepper_on;
stopMotor();
#if DEBUG
Serial.println("stopMotor()");
#endif
}
}
delay(10);
}
// --------------------------------------------------------------------------------
// Einen Hin-/Her-Dreher ausfuehren.
void moveMouse(void) {
led_preset=LED_BLINK_FAST;
for(int i=0; i<50; i++) { // Drehung rechts
rotateRight();
}
led_preset=LED_ON;
stopMotor(); // Strom sparen
delay(100);
led_preset=LED_BLINK_FAST;
for(int i=0; i<50; i++) { // Drehung links
rotateLeft();
}
led_preset=LED_ON;
stopMotor(); // Strom sparen
}
// --------------------------------------------------------------------------------
// Acht Stepper-Schritte nach links.
void rotateRight(void) {
if(!stepper_on) { return; }
for(int c=0; c<8; c++) {
//setMotor(coil_pwr[c]);
setMotor(coil_pwr[c][0], coil_pwr[c][1], coil_pwr[c][2], coil_pwr[c][3]);
}
}
// --------------------------------------------------------------------------------
// Acht Stepper-Schritte nach rechts.
void rotateLeft(void) {
if(!stepper_on) { return; }
for(int c=7; c>=0; c--) {
//setMotor(coil_pwr[c]);
setMotor(coil_pwr[c][0], coil_pwr[c][1], coil_pwr[c][2], coil_pwr[c][3]);
}
}
// --------------------------------------------------------------------------------
// Die Stepper-Spulen stromlos machen.
void stopMotor() {
//setMotor(coil_pwr[8]);
setMotor(coil_pwr[8][0], coil_pwr[8][1], coil_pwr[8][2], coil_pwr[8][3]);
}
// --------------------------------------------------------------------------------
// Einen Stepper-Schritt ausfuehren.
// ...funktioniert...liefert aber Warnings.
void setMotor_alt(bool *coil_num) {
for(int c=0; c<4; c++) {
digitalWrite(coil_pin[c], coil_num[c]);
}
delay(MOTOR_SPEED);
}
// --------------------------------------------------------------------------------
// Einen Stepper-Schritt ausfuehren.
void setMotor(bool in1, bool in2, bool in3, bool in4) {
digitalWrite(PIN_COIL_IN1, in1);
digitalWrite(PIN_COIL_IN2, in2);
digitalWrite(PIN_COIL_IN3, in3);
digitalWrite(PIN_COIL_IN4, in4);
delay(MOTOR_SPEED);
}
Die IDE meldet dafür:
Der Sketch verwendet 2202 Bytes (6%) des
Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 64 Bytes (3%) des dynamischen
Speichers, 1984 Bytes für lokale Variablen verbleiben. Das
Maximum sind 2048 Bytes.
|
Alles beisammen
Nun brauchts das Unterteil und Rumgelöte. Mal schauen, wann ich mich
dazu motivieren kann.....Morgen vielleicht.
Oder auch nicht...
Ein Wochenende später habe ich das Unterteil entworfen und gedruckt.
Ärgerlicherweise hatte ich offenbar zwischendurch am Radius der
Gehäuse-Kanten rumgespielt.
Jedenfalls hatten Ober- und Unterteil unterschiedliche Radien.
Außerdem war die Verbindung der beiden Teile unzureichend.
Ergo: beide Teile sind als Testdruck zu betrachten. Locker drei
Stunden Druck-Dauer und 40g Filament für die Pütz.
Heute habe ich beide Teile um-designed. Nebenbei wurden aus
den Radien simple 45°-Winkel...mal schauen, ob sich das besser (mit
weniger Warping) in ABS drucken lässt.
Sieht nun so aus (Anklicken für volle Größe):
Im Gehäuse-Unterteil befindet sich eine Halterung/Führung für die
CPU-Leiterplatte. Diese muss dazu die Abmessungen 56x30mm einhalten.
Das größere Loch ist für eine 5mm LED samt Halterung vorgesehen.
Das kleinere Loch für den Taster hat einen Durchmesser von ~5mm.
Eine URL habe ich dafür nicht, weil der Taster aus der Grabbelkiste
stammt. Zu lang sollte er nicht sein. Meiner ragt samt Kontakten
13mm ins Gehäuse rein. Das passt noch problemlos vor die
Leiterplatte.
Weiterhin gibts jetzt auch schon einen Schaltplan:
Wann auch immer ich das dann verlöte. (wahrscheinlich ohne die
Strippen an AREF und AVCC)
Den 3D-Druck habe ich dann doch noch am Sonntagabend angeschmissen.
Und.... Ja wie geil...der Druck ist perfekt! Zumindest für meine
Verhältnisse/Ansprüche. Beide Teile lassen sich stramm verbinden,
aber auch problemlos wieder auseinandernehmen.
Nebenbei auch kein Warping mehr. Vielleicht lags an meinen
Änderungen am Modell - vielleicht auch einfach nur daran, dass es
diesmal 30 Lines Brim statt vorher 20 Lines waren.
Eigentlich hasse ich Cura ja zutiefst....aber manchmal...ganz
manchmal...macht es auch genau das Richtige.
Normalerweise immer wieder diese vermeintlich sinnlosen Wege - quer
über die vorher sauber gedruckten Flächen.
Mit viel gutem Willen sind die Bewegungen möglicherweise
jedoch tatsächlich extra zum Abkühlen eingebaut worden.
Man weiss es nicht.
Magie! ...Quasi. ....Darf man nicht hinterfragen.....
Hauptsache es passt am Ende.
Weil ich ziemlich zuversichtlich bin, dass das Gehäuse nun final
ist, hier der Link zum Design auf Thingiverse. Und hier das SCAD-File.
Die USB-A-Buchse ist übrigens diese hier. Sie sitzt sehr stabil im Gehäuse
und wird schon dann nicht mehr von einem abgezogenen USB-Stecker
rausgerissen, wenn die beiden Blech-Nasen um 90° umgebogen sind.
Final verlöte ich die vier Kontakte noch mit einem kleinen Stückchen
Leiterplatte, das etwas breiter als die Buchse ist. Dann sollte das
Teil endgültig und zuverlässig -auch bei Trampeltier-Bedienung- an
Ort und Stelle bleiben.
Auf den äußeren Kontakten liegt VBus und GND. Laut dem hier sollte GND (bei meiner Einbau-Lage)
an der Innenseite liegen - aber ich werde das vor der Verdrahtung
natürlich nochmal per Messung verifizieren.
Wichtig ist die Verfügbarkeit so eines USB-Kabels. Also A-Stecker auf
A-Stecker.
Da hat man gefühlte 100 USB-Kabel... aber soeins fehlt dann
natürlich. Derzeit nutze ich ein Y-Kabel, das bei einer
USB-HDD dabei war und zwei A-Stecker auf einen Mini-B-Stecker
schaltet - weil die HDD wohl mehr als die für USB2.0 spezifizierten
500mA zieht.
Gerade habe ich mir das Kabel bei Reichelt bestellt und ebenfalls
fünf ATtiny4313 mit den in Warenkorb gelegt. Mal schauen. Vielleicht
wirds dann auch der (ohne Quarz).
Jedoch mag der Compiler die TimerOne-Library nicht. Also müsste ich
erstmal alles deutlich umbauen.
Verlötung der
Lochrasterplatte
Wieder mal Sonntag. Gestern habe ich das Gehäuse-Unterteil verlötet.
Heute kam dann die Bestückung und Verlötung der Leiterplatte hinzu.
Es ist dann doch der ATmega328 samt Quarz geworden, weil
1.) die Bauteilkosten nur ein/zwei Euro höher als beim ATtiny4313
sind und
2.) der ArduinoUNO als Programmiergerät für den ATmega328 genutzt
werden kann.
Vier Kontakte werden benötigt, um das Gehäuse-Unterteil mit der
Leiterplatte zu verbinden. (ich hatte aber nur ein fünfpoliges
Pärchen aus Stecker und Buchse)
Bei dieser Nummerierung (das Foto stammt aus einem anderen
Projekt):

...gilt jetzt:
Pin
|
Belegung
|
Pin@ATmega328
|
1
|
frei
|
-
|
2
|
Taster
|
5
|
3
|
+5V
|
7
|
4
|
LED
|
19 (via 220
Ω) |
5
|
GND
|
8, 22
|
Der erste Test erfolgte gerade ohne die Strippen zur
StepperDriver-Leiterplatte.
Aber LED und Taster tun bereits fleissig das, was sie tun sollen.
AREF und AVCC hängen abweichend zum Schaltplan in der Luft und statt
des
22µF ist jetzt ein 10µF TantalElko verbaut.
Zuerst kam mir das Flackern der LED etwas zu hektisch (und zu lange)
vor. Jedoch liegt das wohl einfach nur daran, dass es vorher diese
onboard-mini-LED des ArduinoUNO war ... und eine 5mm LED deutlich
wahrnehmbarer ist.
Eben weil es mir komisch vorkam, habe ich die Pause zwischen
den Flacker-Phasen mittels online Stopuhr vermessen und bin auf 29.96
Sekunden gekommen.
Ergo: das passt exakt zum Programmcode (und ich habe offenbar
unglaublich genau gemessen) :-)
Der Schlafmodus funktioniert ebenfalls. Aber unschön - zumindest
dann, wenn man den Taster während einer Flacker-Phase eine
Sekunde lang gedrückt hält.
Da muss ich nochmal ran, damit die LED immer in dem Moment
abgeschaltet wird, wenn die eine Sekunde Druck-Dauer erreicht ist.
An die sechs Kontakte der StepperDriver-Leiterplatte habe ich (auf
der Leiterbahn-Seite) kurze Strippen angelötet. Und deren Gegenseite
werde ich wohl -schlicht und ergreifend- direkt in meine
Lochrasterplatte löten - also ohne Molex-Kupplung dazwischen. Weil:
achtpolig wäre das Nächstpassende, was ich da hätte.
Und...gesagt...getan....klappt. Grundsätzlich zumindest. Also die
Elektronik.
Aber diesem blöden Gehäuse-Oberteil fehlen jetzt etwa ein/zwei
Millimeter Höhe.
So ein Dreck.
Fürs Erste ist das Ding trotzdem so schon nutzbar.
Neues Oberteil
In der SCAD-Datei
reicht ein "+5" beim Z-Parameter in sechs Zeilen. Der Druck soll
1:30 Stunden dauern und 22g Filament benötigen.
Mal schauen, ob ich das heute noch drucke.
Hat dann wieder ein paar Tage gedauert....
Zwischenzeitlich hatte ich nämlich noch die Idee, zwei oder vier Nasen
am neuen Oberteil anzubringen, in die ein Maus-Ausrichtungs-Aufsatz
eingesnappt werden könnte.
Aber...nö...geht auch ohne.
Denn: heute musste der Drucker sowieso angeheizt werden, um ein
gestorbenes Haushaltsteil neu zu drucken.
Diesmal dann in ABS statt PLA+ (hoffentlich hält es damit jetzt
etwas länger als 16 Monate).
Und weil der Drucker nun schon mal auf Temperatur und mit
ABS-Filament bestückt war, habe ich gleich das veränderte
Mausbeweger-Oberteil als nächsten Job geladen.
Derzeit ist der Drucker bei Ebene 5 von 80. Ab dem nächsten Layer
gehts schneller voran.
80[Layer] * 0.25[Layerhöhe in mm] = 20mm. Also ist das Ding jetzt
20mm hoch.
Zusammen mit dem 22mm hohen Unterteil also 42mm in Summe.
Eine sehr gute Zahl :-) Google bzw. Wikipedia sagt dazu
"Antwort". Sollte man wissen!
Fertig. Sieht nun so aus:
Und im Einsatz so:
Oder auch so:
Nun könnte alles schön sein.
Tja....wäre unser Tool nicht "Teams". In Falle für uns Entwickler
konkret Teams for Linux.
Was für ein unglaublich minderwertiger Schrott.
Heute wieder: ich spreche gerade im Gruppenchat und die Webcam
streamt zusätzlich noch mein edles Antlitz in den Chat.
Trotzdem werde ich als "Offline" angezeigt.....dann mal als
"Abwesend"...vielleicht auch kurz "Anwesend" oder "im Call"...und
dann wieder "Offline".
Einfach Random!
Sechs!
Setzen!
Wie sehr ich M$-Produkte hasse.
Und deswegen werde ich die oben angedachten Änderungen an der
Firmware auch nicht mehr vornehmen. Schließlich ist eh alles für
die Katz.