@ 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.