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):
  1. ) per 5V-Steppermotor (28byj48) eine Stroboskop-Scheibe drehen lassen    oder
  2. ) per 5V-Modellbau-Servo einen weissen Arm vor einem schwarzen Hintergrund bewegen   oder
  3. ) 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:
Screenshot aus
        openSCAD      Entwurf mit Maus

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.
  1. ) der Stepper
  2. ) die LED
  3. ) 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):

zweiter Entwurf oben     zweiter Entwurf unten

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:
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):
Foto: wo sitzt
      Pin 1
...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.

Foto vom
        Mausbeweger...schließt nicht
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:
Gehäuse -offen-

Und im Einsatz so:
der Mausbeweger im
        Einsatz

Oder auch so:
ohne Maus

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.