Home-Run mit einem MoToStepper und einem analogen Endlagenschalter

Hallo Leute,

ich verwende einen Arduino Mega 2560.
Nei meinem letzten Thema Home-Run mit einem AccelStepper habe ich die Motor-Bibliothek gewechselt und verwende nun den "MoToStepper".
In der Zwischenzeit hat mein Gerät einen zweiten Motor bekommen und eigentlich läuft alles prima.
Der zweite Motor hat wegen Platzproblemen einen analogen Endlagenschalter, der Code zur Ansteuerung sieht wie folgt aus:

bool isAtEndPositionZ()
{
	int value = analogIn(MOTOR_IN_Z);
	return value > 620;
}


Folgendes passiert: Lese ich den Endlagenschalter über einen separaten Befehl aus, bekomme ich ordentliche Werte, wie oben die Schwelle 620.

Fahre ich ein Home-Run wie im verlinkten Thema, kommt beim Analogschalter keine Änderung an, ich muss das Home-Run hart abbrechen.

Fahre ich ein Home-Run unter Verwendung des digitalen Schalters (manuell ausgelöst), funktioniert das Home-Run wie er soll.

Frage:
Ist jemandem ein solches Verhalten bekannt?
Kann man da etwas tun oder ist die Verwendung eines digitalen Endlagenschalters notwendig?

Ich habe Ihr Thema aus einer englischsprachigen Kategorie in die Kategorie International > Deutsch des Forums verschoben @RodFromGermany.

Bitte posten Sie zukünftig jeweils in der Kategorie, die der von Ihnen verwendeten Sprache entspricht. Dies ist ein wesentlicher Teil des verantwortungsvollen Umgangs im Forum, wie es auch in der Anleitung "Wie man dieses Forum benutzt" erläutert wird. Diese Anleitung beinhaltet viele weitere nützliche Informationen. Bitte unbedingt lesen!

Vielen Dank im Voraus für Ihre Mitarbeit!

Es wäre sinnvoll, wenn Du uns den aktuellen kompletten Sketch zeigen würdest.

Gruß Tommy

Und wer garantiert dir, dass die Werte nicht immer <=620 oder >620 sind?

Dass man analoge Pins auch digital betreiben kann weißt du?

Was genau verstehst du unter einem "analogen Endlagenschalter" ?
Die üblichen Endlagenschalter sind normal digital, die können nur EIN oder AUS, 1 oder 0.

Aber evtl. verwendest du etwas, was mir bisher unbekannt ist.

Nicht nur Dir, mir auch.
Grüße Uwe

Und wenn der TO uns das jetzt noch erklärt, lernen wir sogar noch etwas dazu. :sweat_smile:

@ Tommy56 Die Homerun-Prozedur und Co sollten genügen, das andere steht im verwiesenen Thread:

/* ====== minimumStepper =======================================
*  Bare minimum to get a stepper with step/dir driver turning
*/
#include <MobaTools.h>
#include <MemoryFree.h>

// Lichtschranke, Referenzpunktschalter
const byte ReferenceX = A0;
const byte ReferenceZ = A1;

// Stepper connections - Please adapt to your own needs.
const byte PinStepX = 2;
const byte PinDirX = 3;

const byte PinStepZ = 6;
const byte PinDirZ = 7;

// Steps per revolution - may need to be adjusted
const int stepsPerRevX = 600;
const int stepsPerRevZ = 600;

// Analogwert der z-Endlage
// 2,9 ... 3,3 V
// frei:		~570 digit
// geschaltet:	~650 digit
const int EndPositionZ = 620;

// 60 rev/min (if stepsPerRev is set correctly)
const int SpeedX = 600;
const int SpeedZ = 600;

// maximale Anzahl zu empfangender Zeichen pro Befehl
const byte maxChars = 32;

// Puffer für vom USB-Port empfangene Zeichen
char recievedChars[maxChars];
// Flag, dass neue Daten vom USB empfangen wurden
bool newData = false;
// Flag, dass Datenempfang innerhalb der Start- und Endmarker aktiv ist
bool recieveInProgress = false;
// Puffer für den Namen des Befehls
char cmdName[maxChars];
// wenn gesendet: Befehlsparameter, ansonsten 0
long cmdValue;

MoToStepper stepperX(stepsPerRevX, STEPDIR);	// create a stepper instance
MoToStepper stepperZ(stepsPerRevZ, STEPDIR);	// create a stepper instance

void setup()
{
	Serial.begin(115200);

	stepperX.attach(PinStepX, PinDirX);
	stepperX.setSpeed(SpeedX);				// 60 rev/min (if stepsPerRev is set correctly)
	stepperX.setRampLen(stepsPerRevX / 3);	// Ramp length is 1/2 revolution
	stepperX.attachEnable(100);				// if you want to switch off power when stepper reached position

	stepperZ.attach(PinStepZ, PinDirZ);
	stepperZ.setSpeed(SpeedZ);				// 60 rev/min (if stepsPerRev is set correctly)
	stepperZ.setRampLen(stepsPerRevZ / 3);	// Ramp length is 1/2 revolution
	stepperZ.attachEnable(100);				// if you want to switch off power when stepper reached position
}

void loop()
{
	recieveCommand();

	if (newData)
	{
		size_t pos = strcspn(recievedChars, " ");
		if (pos < strlen(recievedChars))
		{
			// Leerzeichen zwischen Befehl und Wert
			strncpy(cmdName, recievedChars, pos);
			cmdName[pos] = 0;	// Kennung String-Ende
			cmdValue = atol(&recievedChars[pos + 1]);
		}
		else
		{
			// Nur Befehl, kein Wert
			strncpy(cmdName, recievedChars, maxChars);
			cmdValue = 0;
		}

		newData = false;

		if (strcmp(cmdName, "Name") == 0)
		{
			sendAcknowledgeString(cmdName, "SersStepper");
		}
		else if (strcmp(cmdName, "HomeRunX") == 0)
		{
			// Durchführen einer Referenzfahrt,
			// lässt sich leider nicht anhalten
			homeRun(true, cmdValue);
		}
		else if (strcmp(cmdName, "HomeRunZ") == 0)
		{
			// Durchführen einer Referenzfahrt,
			// lässt sich leider nicht anhalten
			homeRun(false, cmdValue);
		}
		else if (strcmp(cmdName, "GetReferenceX") == 0)
		{
			int val = isAtEndPosition(true);
			sendAcknowledgeValue(recievedChars, val);
		}
		else if (strcmp(cmdName, "GetReferenceZ") == 0)
		{
			int val = isAtEndPosition(false);
			sendAcknowledgeValue(recievedChars, val);
		}
		else if (strcmp(cmdName, "GetReferenceValueZ") == 0)
		{
			int val = analogRead(ReferenceZ);
			sendAcknowledgeValue(recievedChars, val);
		}
		else
		{
			Serial.print("<ERR> ");
			Serial.print("Unknown command: \"");
			Serial.print(cmdName);
			Serial.println("\"");
		}
	}
}

/// <summary>
/// Senden einer Antwort mit einem numerischen Wert
/// </summary>
/// <param name="cmd">der Befehl</param>
/// <param name="value">der numerische Wert</param>
void sendAcknowledgeValue(char* cmd, long value)
{
	Serial.print("<ACK> ");
	Serial.print(cmd);
	Serial.print(" => ");
	Serial.println(value);
}

/// <summary>
/// Senden einer Fehlermeldung
/// </summary>
/// <param name="message"></param>
void sendAcknowledgeError(const char* message)
{
	Serial.print("<ERR> ");
	Serial.println(message);
}

/// <summary>
/// Fahren in die Endlage und ein Stück zurück
/// </summary>
/// <param name="x">Auswahl des Motors</param>
/// <param name="direction">initiale Fahrtrichtung</param>
void homeRun(bool x, int direction)
{
	// wir nehmen mal an, dass sich der Motor
	// nicht in der mechanischen Endlage befindet
	bool moving = true;
	long position = GetStepper(x)->currentPosition();

	if (direction >= 0)
	{
		// == 0 ist die Default-Richtung
		direction = 1;
		sendAcknowledgeString((char*)"HomeRun 1", "Start");
	}
	else
	{
		direction = -1;
		sendAcknowledgeString((char*)"HomeRun -1", "Start");
	}

	if (isAtEndPosition(x))
	{
		// aus der Endlage herausfahren
		GetStepper(x)->rotate(-direction);
		while (isAtEndPosition(x) && stepperMoving(x, position, &moving));
	}

	if (!isAtEndPosition(x))
	{
		// in die Endlage hineinfahren
		GetStepper(x)->rotate(direction);
		while (!isAtEndPosition(x) && stepperMoving(x, position, &moving));
	}

	if (!isAtEndPosition(x) && !moving)
	{
		// TODO: Nicht getestet
		// ohne Rampe anhalten
		GetStepper(x)->stop();
		sendAcknowledgeError("HomeRun not finished, motor stopped");
		return;
	}

	// Refschalter erreicht, anhalten
	GetStepper(x)->rotate(0);
	while (GetStepper(x)->moving());     // Bremsrampe abwarten;

	// Langsam und ohne Rampe zurück zum Schaltpunkt des Refpunktes fahren
	GetStepper(x)->setSpeedSteps(1000);
	GetStepper(x)->setRampLen(0);

	GetStepper(x)->rotate(-direction);
	while (isAtEndPosition(x) && stepperMoving(x, position, &moving));

	if (isAtEndPosition(x) && !moving)
	{
		// TODO: Nicht getestet
		// ohne Rampe anhalten
		GetStepper(x)->stop();
		sendAcknowledgeError("HomeRun not finished, motor stopped");
		return;
	}

	// Refschalter frei, mit Rampe anhalten
	GetStepper(x)->rotate(0);
	while (GetStepper(x)->moving());     // Bremsrampe abwarten;

	// Nullen der aktuellen Position
	GetStepper(x)->setZero();

	// Geschwindigkeit, Beschleunigung
	if (x)
	{
		stepperX.setSpeed(SpeedX);
		stepperX.setRampLen(stepsPerRevX / 3); // Ramp length is 1/2 revolution
	}
	else
	{
		stepperZ.setSpeed(SpeedZ);
		stepperZ.setRampLen(stepsPerRevZ / 3); // Ramp length is 1/2 revolution
	}

	sendAcknowledgeString((char*)"HomeRun finished", "");
}

/// <summary>
/// Auslesen des Endlagenschalters
/// </summary>
/// <returns>in Endlage</returns>
bool isAtEndPosition(bool x)
{
	if (x)
	{
		// Referenz X: digital
		return digitalRead(ReferenceX);
	}

	// Referenz Z: analog
	int val = analogRead(ReferenceZ);
	return val > EndPositionZ;
}

/// <summary>
/// Test, ob sich der Motor bewegt
/// </summary>
/// <param name="lastPos">[in,out] die letzte Position</param>
/// <param name="moving">Bewegungsflag</param>
/// <returns>in Bewegung</returns>
bool stepperMoving(bool x, long& lastPos, bool* moving)
{
	long position = GetStepper(x)->currentPosition();
	if (position != lastPos)
	{
		*moving = true;
		lastPos = position;
		return true;
	}

	// TODO: ggf. optimieren
	delay(100);

	position = GetStepper(x)->currentPosition();
	*moving = position != lastPos;
	lastPos = position;
	return moving;
}

/// <summary>
/// Auswahl des angesprochenen Steppers
/// </summary>
/// <param name="x">x- oder z-Achse</param>
/// <returns>die Stepper-Instanz</returns>
MoToStepper* GetStepper(bool x)
{
	return x ? &stepperX : &stepperZ;
}

@ zwieblum

// Analogwert der z-Endlage
// 2,9 ... 3,3 V
// frei:		~570 digit
// geschaltet:	~650 digit

@ wwerner Ja, kein Erfolg, auch nicht mit pinMode(ReferenceZ, INPUT_PULLUP);.

@ HotSystems @ uwefed Wir verwenden optische Schalter, bei denen ein Lichtstrahl endlichen Durchmessers von einer Fahne abgedunkelt wird. Bei einer endlichen Fahrgeschwindigkeit kommt es zu einem allmählichen Übergang zwischen den genannten Spannungen bzw. Digits.

Dann zeig uns doch mal einen Link des verwendeten "Schalters". Dann haben wir evtl. auch den Wissenstand, um da zu helfen.
Warum immer so geheimnisvoll ?

Also ist das ein LDR?

@ fony LDR ???

@ HotSystems Ich mache die Software, nicht die Elektronik.
Das ist ein alter DDR-Schalter, da haben wir noch ein paar von in der Kiste;

http://www.hellsoft.cz/ok1ike/soubory/ddr/index.htm

nach "MB123" suchen und drauf klicken, da kommt eine GIF mit den Informationen.

Dennoch muss alles zusammen passen. Und wenns mit dem einen Teil nicht geht, muss was anderes her.

Aber mit der Gabellichtschranke (MB123) sollte das schon funktionieren.
Aber da wir deinen Hardware-Aufbau nicht kennen, ist das hier nur eine Raterei.

Die elektrische Logik funktioniert, wenn ich ein "manuelles Home Run" durchführe:
(MoveRel(entsprechende Distanz))
und per Timer den Schalter überwache und beim Auslösen den Motor stoppe.

Bei der im Quelltext geposteten Home Run-Prozedur funktioniert das mit dieser Elektronik nicht.

Die KI meint dazu, dass der AD-Wandler ggf. zu langsam ist, was zu dem Versagen führt.

Kann es sein, dass Du eine Klammer falsch gesetzt hast?