Arduino Motor Fokus Teil2

#1
Hallo,

für ein neues Projekt habe ich die SW meines Motor Fokus komplett neu, in Arduino Umgebung geschrieben. Ich mache dazu mal hier einen neuen Thread auf (hier der alte Thread).

Die Software ist natürlich wieder frei verwendbar und kann beliebig verändert werden.

Gesteuert wird das ganze über die RoboFokus Software und ist somit auch wieder ASCOM kompatibel.

Neu hinzugekommen ist:
Die Software ist nun komplett in Arduino (statt in Bascom) geschrieben.
Ein Temperatursensor, ein AD22100, ist hinzugekommen.
Die Anzahl der max. Schritte sind auf 999999 erweitert.
Wenn man außerdem kurz hintereinander auf IN oder OUT klickt, wird jeweils eine weitere Schrittlänge verfahren. Wenn man ständig klickt, kann man so kontinuierlich verfahren. Das ist praktisch, wenn man mit dem Fokus weit daneben ist und lange Wege fahren muss.
Außerdem sind die 4 „User-Buttoms“ verwendbar, um z.B. die Taukappenheizungen zu schalten.

Eine Handsteuerung ist allerdings immer noch nicht implementiert. Vielleicht hat jemand Zeit/Lust, das nachzurüsten. Da ich ausschließlich fotografiere, brauche ich das nicht.
Endlagenschalter werde ich evtl. später noch hinzufügen.

Es gibt zwei Besonderheiten in den RoboFokus Einstellmenüs:
In der „Motor-Configuration“ kann man mit StepSize 1..5 den Mikroschrittbetrieb von 2..32-fach einstellen. Stellt man größere Werte als 5 ein, bleibt es bei 32 Mikroschritten (der DRV8825 kann nur 32 Schritte, was aber eh mehr als genug ist).
Stellt man Duty-Cycle kleiner als 50 ein, wird der Motor nach dem Verfahren ausgeschaltet - wenn der Wert größer/gleich 50 ist, bleibt er an und erzeugt so ein Haltemoment (das dürfte die sinnvollere Betriebsart sein). Normalerweise kann man mit Duty-Cycle den Haltestrom stufenlos von 0-100% einstellen. Das kann aber leider der DRV8825 nicht.

Vor dem Kompilieren muss man die TimerOne Library einbinden: Hier das Zip runterladen und in der Arduino IDE, unter Sketch > Library importieren > Add Library und dann auf das Zip File zeigen.

Ein Freund von Arduino bin ich trotzdem nicht geworden. RoboFokus wird komplett verwirrt, wenn sich nach dem Öffnen des USB Ports plötzlich der Bootloader meldet.
Dem kann man abhelfen, indem man, nach dem Upload der Firmware, den Reset Kondensator aus dem Nano-Board entfernt. Ein erneuter Upload funktioniert danach allerdings nur noch mit Hilfe des Reset Taster (nach dem klicken auf Upload den Reset Taster kurz drücken).

Bevor man den Motor anschließt, sollte man an dem Poti des DRV8825 einen sinnvollen Motorstrom einstellen. Die Messspannung an dem Messpunkt (s. Anhang) mal 2 ergibt den eingestellten Motorstrom (0,25V am Messpunkt entspricht also 0,5A Motorstrom).

Den Temperatursensor werde ich noch mit Wärmeleitkleber in der Flachfräsung einkleben. Dann misst er die Temperatur des Alu Gehäuses. Die Lufttemperatur wäre evtl. durch die Abwärme des Motors verfälscht.

Auf der 12V Versorgungsleitung sollte man noch einen fetten Elko (so 47µF/63V), zum Abblocken von Spikes, vorsehen.

Die Baudrate muss in RoboFokus auf 19200, 8Bit, non parity, 1 Stop Bits eingestellt werden.
Den richtigen COM Port erfährt man im Fenster Windows > Startmenü > Geräte und Drucker: Wenn man den Arduino-Nano einsteckt, poppt ein neues „Gerät“ auf. Mit Doppelklick darauf wird im Reiter Hardware der neu vergebene COM Port angezeigt (falls man Win7 User ist...)


Code:
// MotorFok2 Arduino Version
// ohne Enlagenschalter, ohne Handsteuerung von Edgar99
// General Public, kann beliebig verbreitet und verändert werden



#include <TimerOne.h>
#include <EEPROM.h>

unsigned long StepDelayFaktor = 1000;			// 1 StepDelay = 1000 µs



//********************************************
//************ define I/O pins ***************
//********************************************

// pins for Arduino Nano // pins for Arduino Pro Micro

int led = 13;					//for test only

int tempSensor = A7;	//A3		// temperature sensor

int Mot_dir		= 10;	//9;		//Portb.2 Direction		1 = move out
int Mot_stp		=  9;	//8;		//Portb.1 Step			on rising edge     
int Mot_sleep	=  8;	//7;		//Portb.0 Sleep			L = Sleep
int Mot_reset	=  7;	//6;		//Portd.7 Reset			L = RESET
int Mot_m3		=  6;	//5;		//Portd.6 µ-Step		Bit2
int Mot_m2		=  5;	//4;		//Portd.5 µ-Step		Bit1
int Mot_m1		=  4;	//3;		//Portd.4 µ-Step		Bit0
int Mot_en		=  3;	//2;		//Portd.3 Enable		L = Enable
int Pwr_1		= A2;	//A2		// power switch 1
int Pwr_2		= A3;	//A1		// power switch 2
int Pwr_3		= A4;	//A0		// power switch 3
int Pwr_4		= A5;	//10		// power switch 4




//************ define serial strings ***************

unsigned long serialValue;
char serialBuffer[10];

char versionStr[10]			= "FV003.14";		// response string for firmware version
char actualPositionStr[10]	= "FD000000";		// response string for actual Position
char maxTravelStr[10]		= "FL000000";		// response string for max. travel
char backlashStr[10]		= "FBN00000";		// response string for backlash
char configStr[10]			= "FC000000";		// response string for config
char tempStr[10]			= "FT00NNNN";		// response string for temperature
char powerStr[10]			= "FP00NNNN";		// response string for power switches


//****** define EEPROM map **********

struct param_t {
byte test;
unsigned long MaxTravel;	
unsigned int Backlash;					
unsigned int BacklashDir;	
unsigned int DutyCycle;		
unsigned int StepDelay;	
unsigned int StepSize;		
}param = {			// default values
	0,				// dummy = 0
	999999,			// max. travel range 0..999.999
	20,				// Backlash 0..255
	2,				// BacklashDir 2 = add to IN; 3 = add to OUT
	55,				// DutyCycle < 50: motor power turn OFF; >= 50: motor power remains ON after movements
	1,				// StepDelay 1..20 (1 = max Speed)
	7,				// StepSize 1..7 (microsteps)	
};


//******* default motor params

unsigned int ActualDir		= 0;				// 0 = Non; 2 = IN; 3 = OUT
unsigned long ActualMovement= 0;				// 0..999999
unsigned long ActualPosition= 500000;			// 0 = inward, 999999 = outward
float Temperature	= 586.3;					// 0..1024 represents 0..512 Kelvin
unsigned long PowerSwitch = 0;					// status of power switches

unsigned long MoveCNT		= 0;				// motor step counter


//********** Flags *****************

byte MotorRun				= 0;
byte MotorRequ				= 0;
byte MotorBacklash			= 0;
byte PositionRefresh		= 0; 
byte MotorDir				= 0;





//***********************************************
//************ Timer1 interrupt *****************
//********* moves motor by one step *************
//***********************************************
void Timer1Int() {
	
	if (MoveCNT == 0){
	MotorRun = 0;								// movement finished
	}
	else {
		digitalWrite(Mot_stp, HIGH);			// motor step	
		MoveCNT--;								// dec step CNT
			if (MotorDir == 2){ActualPosition--;}
			else {ActualPosition++;}				
		digitalWrite(Mot_stp, LOW);				// minimum H time is 1.9µs !!			
	}
}

//***********************************************
// ***********	 abort motor	   **************
//***********************************************
void abortMotor(){
	MoveCNT = 0;									// motor stop
	MotorRun = 0;
	MotorRequ = 0;
	MotorBacklash = 0;
//	Timer1.stop();															
}

//***********************************************
// *********** calculate check sum **************
//***********************************************
char calcCheckSum(char Buffer[]){

	char checkSum = '\0'; 

	for (int i = 0; i < 8; i++){
		checkSum = checkSum + Buffer[i];
	}
	
return checkSum;
}

//************************************************
// ******** check serialBuffer == "..000.." ****** 
//************************************************
int zeroStr(int start, int end){

	for (int i = start; i <= end; i++){
		if (serialBuffer[i] != '0'){
			return 0;			
		}
	}
	return 1;
}


//****************************************************************
// ******* convert unsigned long to ASCII incl. leading '0' ******
//****************************************************************																
void uitoa(char Buffer[], int start, int end, unsigned long intValue) {

	for (int i = 0; i < (end - start); i++){
		Buffer[end - 1 - i] = 48 + (intValue % 10);
		intValue = intValue / 10;
	}
}

//************************************************
// ******* convert ASCII to unsigned long ********
//************************************************

// Buffer kann serialBuffer sein ??

unsigned long atoui(char Buffer[], int start, int end){
	Buffer[end + 1] = '\0';
	return atol(&Buffer[start]);
}

//************************************************
// ********     sent actual position      ********
//************************************************
void sentActualPosition(){						
	uitoa(actualPositionStr, 2, 8, ActualPosition);			// write ASCII value to string
	actualPositionStr[8] = calcCheckSum(actualPositionStr);	// add check sum
	Serial.write(actualPositionStr);	
}

//************************************************
// ********       sent max. travel        ********
//************************************************
void sentMaxTravel(){
	uitoa(maxTravelStr, 2, 8, param.MaxTravel);				// write ASCII value to string
	maxTravelStr[8] = calcCheckSum(maxTravelStr);			// add check sum
	Serial.write(maxTravelStr);	
}

//************************************************
// ********       sent backlash           ********
//************************************************
void sentBacklash(){
	uitoa(backlashStr, 3, 8, param.Backlash);				// write ASCII value to string
	backlashStr[2] = char(param.BacklashDir + 48);
	backlashStr[8] = calcCheckSum(backlashStr);				// add check sum
	Serial.write(backlashStr);	
}

//************************************************
// ********         sent config           ********
//************************************************			
void sentConfig(){
	configStr[2] = char(param.DutyCycle);					// Error in Robofocus specs !!
	configStr[3] = char(param.StepDelay);					// Error in Robofocus specs !!
	configStr[4] = char(param.StepSize);					// Error in Robofocus specs !!
	configStr[8] = calcCheckSum(configStr);					// add check sum
	Serial.write(configStr);	
}

//************************************************
// ********      sent temperature         ********
//************************************************
void sentTemp(){
	Temperature = analogRead(tempSensor)/2.304 + 424.078;
	uitoa(tempStr, 4, 8, int(Temperature));	
	tempStr[8] = calcCheckSum(tempStr);						// add check sum
	Serial.write(tempStr);	
}

//************************************************
// ********     sent power switches       ********
//************************************************
void sentPowerSwitch(){
    uitoa(powerStr, 4, 8, PowerSwitch);						// write ASCII value to string
	powerStr[8] = calcCheckSum(powerStr);					// add check sum
	Serial.write(powerStr);	
	
	if (powerStr[4] == '2'){digitalWrite(Pwr_1, HIGH);} else {digitalWrite(Pwr_1, LOW);}	// set power switches
	if (powerStr[5] == '2'){digitalWrite(Pwr_2, HIGH);} else {digitalWrite(Pwr_2, LOW);}
	if (powerStr[6] == '2'){digitalWrite(Pwr_3, HIGH);} else {digitalWrite(Pwr_3, LOW);}
	if (powerStr[7] == '2'){digitalWrite(Pwr_4, HIGH);} else {digitalWrite(Pwr_4, LOW);}
//	if (powerStr[7] == '2'){digitalWrite(led, HIGH);} else {digitalWrite(led, LOW);}	// Test
}

//************************************************
// ********     set motor StepSize        ********
//************************************************	
void setStepSize(){
	if (param.StepSize > 7){param.StepSize = 7;}				
	if (bitRead(param.StepSize, 0)){digitalWrite(Mot_m1, HIGH);} 
		else {digitalWrite(Mot_m1, LOW);}
	if (bitRead(param.StepSize, 1)){digitalWrite(Mot_m2, HIGH);} 
		else {digitalWrite(Mot_m2, LOW);}		
	if (bitRead(param.StepSize, 2)){digitalWrite(Mot_m3, HIGH);} 
		else {digitalWrite(Mot_m3, LOW);}		
}

//************************************************
// ********        write EEPROM           ********
//************************************************
void writeEEprom(struct param_t * value, unsigned int size){
	for (unsigned int i = 0; i < size; i++){
		EEPROM.write(i, *((char*)value + i)); 	
	}
}


//************************************************
// ********        read EEPROM            ********
//************************************************	
void readEEprom(struct param_t * value, unsigned int size){
	for (unsigned int i = 0; i < size; i++){
		*((char*)value + i) = EEPROM.read(i); 		
	}
}


//***********************************************	
//****************** setup **********************
//***********************************************
		
void setup() {  
	
	pinMode(led, OUTPUT); 
	pinMode(Mot_dir, OUTPUT); 
	pinMode(Mot_stp, OUTPUT); 
	pinMode(Mot_sleep, OUTPUT); 
	pinMode(Mot_reset, OUTPUT); 
	pinMode(Mot_m3, OUTPUT); 
	pinMode(Mot_m2, OUTPUT); 
	pinMode(Mot_m1, OUTPUT); 
	pinMode(Mot_en, OUTPUT); 
	pinMode(Pwr_1, OUTPUT); 
	pinMode(Pwr_2, OUTPUT);
	pinMode(Pwr_3, OUTPUT);
	pinMode(Pwr_4, OUTPUT);
	
	digitalWrite(Mot_dir, LOW); 
	digitalWrite(Mot_stp, LOW);	
	digitalWrite(Mot_sleep, HIGH);		// awake motor 
	digitalWrite(Mot_reset, LOW);		// reset
	digitalWrite(Mot_m3, LOW); 
	digitalWrite(Mot_m2, LOW);	
	digitalWrite(Mot_m1, LOW);
	digitalWrite(Mot_en, HIGH);			// motor disable
	
	digitalWrite(Mot_reset, HIGH);		// non reset
	
	analogReference(DEFAULT);
	
	if (EEPROM.read(0) == param.test){			// if EEPROM values are valid
		readEEprom(&param, sizeof(param));		// read EEPROM values
	}
	 
	setStepSize();	
	
	Serial.setTimeout(500);      
	Serial.begin(19200, SERIAL_8N1);		// 19200Baud, 8Bit, non parity, 1 Stop
	while (!Serial) {}					// wait for serial port to connect (needed for Leonardo only)
}
  


//***********************************************	
//****************** Loop  **********************
//***********************************************

void loop() {

// Handsteuerung fehlt


//*********** sent actual position until motor is running ***********

	if (PositionRefresh){
			Serial.flush(); 
			sentActualPosition();					// sent actual position							
	}

	if (!MotorRun && !MotorBacklash && PositionRefresh){		 
			PositionRefresh = 0;					// reset position refresh						
	}


//*********** read serial interface *************

	if (Serial.available() > 0) {								
		if (Serial.readBytes(serialBuffer, 9) == 9) {
			if (serialBuffer[0] == 'F') {
				if (serialBuffer[8] == calcCheckSum(serialBuffer)){
						
					switch (serialBuffer[1]) {
					
						case 'V':												// CMD = request firmware version
						versionStr[8] = calcCheckSum(versionStr);				// add check sum
						Serial.write(versionStr);					
						break;
					
					
						case 'G':												// CMD = goto command
						if (zeroStr(2, 7)){
							sentActualPosition();								// if "0" sent actual Position
							break;
						}
							
						serialValue = atoui(serialBuffer, 2, 7);				// read serial value
							if (serialValue <= ActualPosition) {
								ActualMovement = ActualPosition - serialValue;
								ActualDir = 2;									// move in
							}
							else {
								ActualMovement = serialValue - ActualPosition;
								ActualDir = 3;									// move out
							}
							MotorRequ = 1;										// Start move
						break;
						
						
						case 'I':												// CMD = move in
						ActualMovement = atoui(serialBuffer, 3, 7);					
						ActualDir = 2;	
						MotorRequ = 1;											// Start move
						break;
						
						
						case 'O':												// CMD = move out
						ActualMovement = atoui(serialBuffer, 3, 7);	
						ActualDir = 3;
						MotorRequ = 1;											// Start move
						break;
			
						
						case 'S':												// CMD = set current position
						if (zeroStr(2, 7)){
							sentActualPosition();								// if "0" sent actual Position
							break;
						}
						abortMotor();											// motor stop
						ActualPosition = atoui(serialBuffer, 2, 7);
						break;
						
						
						case 'L':												// CMD = set maximum travel
						if (zeroStr(2, 7)){
							sentMaxTravel();									// if "0" sent travel range
							break;
						}
						abortMotor();											// motor stop
						param.MaxTravel = atoui(serialBuffer, 2, 7);
						sentMaxTravel();
						writeEEprom(&param, sizeof(param));						// save to EEprom	
						break;
						
						
						case 'P':												// CMD = power switch
						if (zeroStr(4, 7)){
							sentPowerSwitch();									// if "0" sent power switches
							break;
						}														// CMD = set remote power module
						PowerSwitch = atoui(serialBuffer, 4, 7);
						sentPowerSwitch();
						break;
						
						
						case 'B':												// CMD = backlash compensation
						if (zeroStr(2, 7)){
							sentBacklash();										// if "0" sent backlash
							break;
						}
						abortMotor();											// motor stop
						param.BacklashDir = int(serialBuffer[2] - 48);
						param.Backlash = atoui(serialBuffer, 3, 7);
						sentBacklash();
						writeEEprom(&param, sizeof(param));						// save to EEprom	
						break;
						
						
						case 'C':												// CMD = set configuration
						if (zeroStr(2, 7)){
							sentConfig();										// if "0" sent Config
							break;
						}
						param.DutyCycle = serialBuffer[2];
						param.StepDelay = serialBuffer[3];	
						param.StepSize = serialBuffer[4];
						abortMotor();											// motor stop
						writeEEprom(&param, sizeof(param));						// save to EEprom	
						setStepSize();									
						sentConfig();
						break;
						
						
						case 'T':
						sentTemp();												// CMD = temperature reading
						break;
						
						
							
					}
				}
			}
				else {
					if (serialBuffer[0] == 'V') {
					abortMotor();	
					PositionRefresh = 0;
					}
				}		
		}
	}



//*********************************************
//********* state machine to move motor *******
//*********************************************


//************* Start Motor *******************

if (!MotorRun && MotorRequ && !MotorBacklash){							
	
	MotorRun = 1;
	MotorRequ = 0;
	
	MotorDir = ActualDir;
	PositionRefresh = 1;
		
	if (param.BacklashDir == ActualDir){
		MotorBacklash = 1;									// add Backlash
		MoveCNT = param.Backlash + ActualMovement;
	} 
		else {
		MotorBacklash = 0;
		MoveCNT = ActualMovement;	
		}
	
	if (MotorDir == 2){digitalWrite(Mot_dir, LOW);}	
		else {digitalWrite(Mot_dir, HIGH);}					// set Motor Dir 
			
	digitalWrite(Mot_en, LOW);								// motor Enable	
	
	Timer1.initialize(StepDelayFaktor * param.StepDelay);	// set motor speed
	Timer1.attachInterrupt(Timer1Int);						// interrupt enable
}


//************* Backlash *******************

if (!MotorRun && MotorBacklash){			// TEST !MotorRequ &&

	MotorRun = 1;
	//MotorRequ = 0;
	MotorBacklash = 0;
	
	if (MotorDir == 2){								// reverse direction
		MotorDir = 3;
		digitalWrite(Mot_dir, HIGH);
	}
	else {
		MotorDir = 2;
		digitalWrite(Mot_dir, LOW);
	}	
	MoveCNT = param.Backlash;						// init counter	
}


//************* Motor finish *******************

if (!MotorRun && !MotorRequ && !MotorBacklash){		 
	Timer1.stop();
	if (param.DutyCycle < 50){
		digitalWrite(Mot_en, HIGH);					// motor disable	
	}	
	else {
		digitalWrite(Mot_en, LOW);					// motor enable
	}
								
}

}
 

Anhänge

#2
Hallo Edgar,

sehr schön!
Das "Autoreset" Problem ist aber anders lösbar.
Entweder ein 10uf Kondensator zwischen Reset und Ground
oder
ein 120 Ohm wiederstand zwischen reset und 5V

Dann kann man sich das destruktives vorgen sparen.

Ich benutze den Wiederstand an meine arduino 2009. ich habe es einsteckbar gemacht..

Gruß
Igor
 
#3
Hi Edgar,

herzlichen Dank für deine Arbeit!

Ich schreibe mir das mal auf einen kleinen 5V-Motor (28BYJ-48) und die Standard-Stepper-Library um. Da der Motor noch ein Vorgetriebe hat, müsste es auch ohne Microstep gehen - dann spart man sich den Haltestrom. Ich hoffe mal, man kann "setStepSize" entsprechend ignorieren?

Noch eine Frage: Ich bin neu in dem Thema und hätte fast angefangen, das ganze von Anfang an selbst zu programmieren. Dabei hätte ich für die erste Version weniger Wert auf einen Temperatur-Sensor gelegt, dafür aber zumindest 1 Endkontakt vorgesehen, den ich in einer Initialisierungs-Routine anfahre. Hältst Du das für sinnfrei?

Gruß
Klaus

 
#4
Hallo Klaus,

eine Initialisierung und Endschalter hatte ich mir auch mal angedacht. In der Praxis kann man den OAZ aber auch per Hand ganz reindrehen, bevor man den Motor Fokus einschaltet. Dann hat man auch den Nullpunkt.
Den Endpunkt (den max. Verfahrweg) kann man in RoboFokus einstellen.
Das geht irgendwie schneller.

Der Motor, den du ausgesucht hast, scheint mir ein wenig schwach.
Meiner hat 0,12 Nm, und mit der 1:3 Untersetzung liegen dann max. 0,36 Nm an der OAZ Achse an. Da ich aber den max. Motorstrom nicht ganz ausnutze, sind es vielleicht so 0,3 Nm. Das ist eigentlich gerade ausreichend.
Dein Motor hat nur 0,035 Nm, also nur etwa 1/10 der Kraft. Das könnte evtl. zu wenig sein.

@Igor
guter Tipp :super:
Das Problem scheint also auch bei anderen Anwendungen aufzutauchen? Ich dachte, dass sich nur RoboFokus da ein bisschen zickig zeigt...
 
#5
Hi Edgar,

der Grund, warum ich diesen kleinen Motor benutzen möchte, ist

a) dass ich so keine extra Stromversorgung brauche, sondern Motor und Arduino über USB versorgen kann.

b) dass ich eine Menge Optiken fokussieren will

und wenn man das Ganze noch ausreichend untersetzt, klappt es auch mit dem Drehmoment :/

Die erste Adaption - für den TS APO65Q - ist auch schon fertig:



Die beiden Zahnräder ergeben nochmal eine Untersetzung von 1:9. Ich habe einfach mal meine Kamera inkl. Filterrad (und nur für's Gewicht ein Objektiv, das normalerweise natürlich nicht dahin gehört) auf den OAZ gestellt (zusammen ca. 3kg):



Und siehe da - es bewegt sich. Absolut zuverlässig...

http://www.watchgear.de/jwplayer/RF-Belastet.mp4

Unterm Strich komme ich auf theoretische 0,7µm/Step (ohne Fehlerbalken für die selbstgedruckten Zahnräder :D). Das sollte auch genau genug sein.


Das Programm habe ich schon entsprechend angepasst und das funktioniert auch schon prima. Ich muss nur noch die Motorabschaltung realisieren.

Und die nächste Adaption - für das ganz übel zu fokussierende Canon 50/1,8II - ist schon auf dem Drucker.

Gruß
Klaus

P.S. Habe den Kondensator auch ausgelötet. Mich stört es nicht, vor dem Upload kurz Reset zu drücken...
 
#6
Hallo,

hier mal mein Nachbau, wobei ich anfangs auf kleinere Probleme gestossen bin. Den Arduino Nano hatte ich noch in meinem Sammelsurium, wie auch den Motortreiber. Also hab ich die Firmware auf den Arduino gebrannt und erst mal die Kommunikation mit Robofocus getestet. Dabeisind dann auch die Anfangs beschriebenen Probleme aufgetreten. Der Grund dafür ist, das der Arduino kein Original ist, sondern ein so ein China-Klon. Dieser verwendet nicht den FT232 sondern einen CP340. Dieser wird leider von Robofocus nicht erkannt und somit kann der COM-Port nicht geöffnet werden, bzw. läuft Robofocus schon beim Start auf einen Fehler.
Auf der Suche nach einer Lösung, bin ich recht schnell fündig geworden. Das Problem konnte ganz einfach mit einem USB-UART gelöst werden. Entweder mit dem FT232 oder, wie in meinem Fall ein CP102. Da ist dann eine zusätzliche Platine mit dazu gekommen, der Vorteil liegt aber darin, das statt der USB-UART, auch eine "Bluetooth-UART" mit FT232 eingesetzt werden kann und Robofocus dann ganz komfortabel per Bluetooth gesteuert werden kann.
Einfach von der UART die 5V und GND an die entsprechenden Pins vom Arduino. Dann RX der UART an TX vom Arduino und TX der UART an RX vom Arduino...fertig.
Als Gehäuse hab ich ein 35x35mm Alu-Profil aus dem Baumarkt genutzt. Die NEMA11 passen da fast saugend rein, nur müssen die Anschlußkabel etwas verlegt werden.
Die drei Platinen sind auf einem Stück Lochraster-Leiterplatte gelötet und dann das komplette Paket auf einem Streifen 3mm Kunststoff-Träger.
Hier dann ein paar Bilder von meinem Nachbau. Dieser ist mittlerweile schon eine ganze Zeit Störungsfrei im Einsatz und ich möchte diesen nicht mehr missen.

An dich Edgar, recht herzlichen Dank für deine Unterstützung und guten Tipp's.

Anbei noch ein paar Bilder. Eine komplette Bilderserie vom Umbau stelle ich noch ein...
 

Anhänge

Neustes Astronomie Foto

Diese Seite empfehlen

Oben