Plotter / Schrittmotoren

Hallo da draussen,
die letzten Tage habe ich damit verbracht einen Plotter zum beschriften von Stiften und ähnlichen runden Objekten zu bauen.
Die Machnik ist soweit fertig und Funktioniert auch schon Testweise.
Nun bin ich bei der Steuerung des Ganzen angelangt und bin bei der Suche nach einem Lösungsansatzes auf einen Bausatz von Makeblock gestossen welcher einen “Egg Plotter” beinhaltet.
https://eckstein-shop.de/Makeblock-mDrawbot-Kits
Erstaunlicherweise ist die Machanik garnicht so unterschiedlich. Das beste ist jedoch die Ansteuerung mit"mDraw".
Bei einem ersten Versuch habe ich zumindestens den Servo(z.Axe) korrekt zum laufen gebracht. Leider werden die Schrittmotoren offensichtlich seriell angesteuert.
Ich habe aber zwei kleine SM aus den Starterkit’s verwendet.

Meine Frage ist nun wie ich die trotzdem verwenden kann?
Ich hätte evtl. gedacht die Seriellen Informationen an einen zweiten UNO oder Mini zu leiten und diese dann in an die benötigten vier Ausgänge zu leiten und somit die SM anzutreiben.
Hat jemand ne Idee???

hier noch ein Bild vom Anschlusscontroller. Die SM werden an 1 und 2 angeschlossen.

Makeblock_Orion_Pin_large.png

Bilder sind wenig hilfreich, Schaltpläne schon eher. Dann wüßte man auch, ob die Motor-Treiber schon auf dem Board drauf sind.

Ob die Schrittmotoren ausreichen, mußt Du selbst wissen, das kommt drauf an was sie antreiben müssen.

Wenn ich das richtig verstanden habe wird bei diesem System ein Adaptershield für den vereinfachten Aufbau mit RJ45 Steckern aufgesteckt. Am Port 1 & 2 können dann je 1 SM Treberplatienen angesteckt werden. Diese werden dann mittels I2C angesteuert. Die passenden SM haben 4 Kabel. Die von mir verbauten 5. Wenn die Treiberplatiene auch meine SM antreiben könnte währe mein Problem schon gelöst. Leider habe ich keine Dokumentation gefunden. Deswegen hätte ich gedacht irgendwie den Datenstrom ab zu fangen und dann diese umzuwandeln.

PS: die SM arbeiten zufriedenstellend

Hast Du den Code für diese Steuerung?

Hier der Code:

#include <MeOrion.h>
#include <EEPROM.h>
#include <SoftwareSerial.h>
#include <Wire.h>

// data stored in eeprom
union{
    struct{
      char name[8];
      unsigned char motoADir;
      unsigned char motoBDir;
      int speed;
      int penUpPos;
      int penDownPos;
    }data;
    char buf[64];
}roboSetup;

// arduino only handle A,B step mapping
float curSpd,tarSpd; // speed profile
float curX,curY,curZ;
float tarX,tarY,tarZ; // target xyz position
// step value
int tarA,tarB,posA,posB; // target stepper position
int8_t motorAfw,motorAbk;
int8_t motorBfw,motorBbk;

MePort stpA(PORT_1);
MePort stpB(PORT_2);
MePort ylimit(PORT_3);
int ylimit_pin1 = ylimit.pin1();
int ylimit_pin2 = ylimit.pin2();
MePort xlimit(PORT_6);
int xlimit_pin1 = xlimit.pin1();
int xlimit_pin2 = xlimit.pin2();
MeDCMotor laser(M2);
MePort servoPort(PORT_7);
int servopin =  servoPort.pin2();
Servo servoPen;

/************** motor movements ******************/
void stepperMoveA(int dir)
{
//  Serial.printf("stepper A %d\n",dir);
  if(dir>0){
    stpA.dWrite1(LOW);
  }else{
    stpA.dWrite1(HIGH);
  }
  stpA.dWrite2(HIGH);
  stpA.dWrite2(LOW);
}

void stepperMoveB(int dir)
{
//  Serial.printf("stepper B %d\n",dir);
  if(dir>0){
    stpB.dWrite1(LOW);
  }else{
    stpB.dWrite1(HIGH);
  }
  stpB.dWrite2(HIGH);
  stpB.dWrite2(LOW);
}


/************** calculate movements ******************/
//#define STEPDELAY_MIN 200 // micro second
//#define STEPDELAY_MAX 1000
long stepAuxDelay=0;
int stepdelay_min=500;
int stepdelay_max=2000;
#define YRATIO 5
#define ACCELERATION 2 // mm/s^2 don't get inertia exceed motor could handle
#define SEGMENT_DISTANCE 10 // 1 mm for each segment
#define SPEED_STEP 1

void doMove()
{
  long mDelay=stepdelay_max;
  int speedDiff = -SPEED_STEP;
  int dA,dB,maxD;
  float stepA,stepB,cntA=0,cntB=0;
  int d;
  dA = tarA - posA;
  dB = tarB - posB;
  maxD = max(abs(dA),abs(dB));
  stepA = (float)abs(dA)/(float)maxD;
  stepB = (float)abs(dB)/(float)maxD;
  //Serial.printf("target: %d %d\n",tarA,tarB);
  //Serial.printf("move: max:%d da:%d db:%d\n",maxD,dA,dB);
  //Serial.print(stepA);Serial.print(' ');Serial.println(stepB);
  for(int i=0;(posA!=tarA)||(posB!=tarB);i++){                         // Robbo1 2015/6/8 Changed - change loop terminate test to test for moving not finished rather than a preset amount of moves
    //Serial.printf("step %d A:%d B;%d tar:%d %d\n",i,posA,posB,tarA,tarB);
    // move A
    if(posA!=tarA){
      cntA+=stepA;
      if(cntA>=1){
        d = dA>0?motorAfw:motorAbk;
        posA+=(dA>0?1:-1);
        stepperMoveA(d);
        cntA-=1;
      }
    }
    // move B
    if(posB!=tarB){
      cntB+=stepB;
      if(cntB>=1){
        d = dB>0?motorBfw:motorBbk;
        posB+=(dB>0?1:-1);
        stepperMoveB(d);
        cntB-=1;
      }
    }
    mDelay=constrain(mDelay+speedDiff,stepdelay_min,stepdelay_max)+stepAuxDelay;
    if(mDelay > 10000)
    {
      delay(mDelay/1000);
      delayMicroseconds(mDelay%1000);
    }
    else
    {
      delayMicroseconds(mDelay);
    }
    if((maxD-i)<((stepdelay_max-stepdelay_min)/SPEED_STEP)){
      speedDiff=SPEED_STEP;
    }
  }
  //Serial.printf("finally %d A:%d B;%d\n",maxD,posA,posB);
  posA = tarA;
  posB = tarB;
}

/******** mapping xy position to steps ******/
#define STEPS_PER_CIRCLE 3200.0f
void prepareMove()
{
  int maxD;
  unsigned long t0,t1;
  float dx = tarX - curX;
  float dy = tarY - curY;
  float distance = sqrt(dx*dx+dy*dy);
  float distanceMoved=0,distanceLast=0;
  //Serial.print("distance=");Serial.println(distance);
  if (distance < 0.001)
    return;
  tarA = tarX*STEPS_PER_CIRCLE/360;
  tarB = tarY*STEPS_PER_CIRCLE/360*YRATIO;
  
  doMove();
  curX = tarX;
  curY = tarY;
}

void initPosition()
{
  curX=0; curY=60;
  posA = 0;
  posB = (STEPS_PER_CIRCLE*curY/360*YRATIO);
}

/************** calculate movements ******************/
void parseCordinate(char * cmd)
{
  char * tmp;
  char * str;

  tarX = curX;
  tarY = curY;
  str = strtok_r(cmd, " ", &tmp);             // Robbo1 2015/6/8 comment - this removes the G code token from the input string - potential for future errors if method of processing G codes changes
  while((str=strtok_r(0, " ", &tmp))!=NULL){  // Robbo1 2015/6/8 changed - placed strtok_r into loop test so that the pointer tested is the one used in the current loop
    //str = strtok_r(0, " ", &tmp);           // Robbo1 2015/6/8 removed - removed from here and place in the while loop test

    //Serial.printf("%s;",str);
    if(str[0]=='X'){
      tarX = atof(str+1);
      //Serial.print("tarX ");Serial.print(tarX);
    }else if(str[0]=='Y'){
      tarY = atof(str+1);
      //Serial.print("tarY ");Serial.print(tarY);
    }else if(str[0]=='Z'){
      tarZ = atof(str+1);
    }else if(str[0]=='F'){
      float speed = atof(str+1);
      tarSpd = speed/60; // mm/min -> mm/s
    }else if(str[0]=='A'){
      stepAuxDelay = atol(str+1);
    }
  }
  //Serial.print("G1 ");Serial.print(tarX);Serial.print(" ");Serial.println(tarY);
  prepareMove();
}


void parseGcode(char * cmd)
{
  int code;
  code = atoi(cmd);
  switch(code){
    case 1: // xyz move
      parseCordinate(cmd);
      break;
    case 28: // home
      tarX=0; tarY=60;
      prepareMove();
      break; 
  }
}


// local data
void initRobotSetup()
{
  int i;
  //Serial.println("read eeprom");
  for(i=0;i<64;i++){
    roboSetup.buf[i] = EEPROM.read(i);
    //Serial.print(roboSetup.buf[i],16);Serial.print(' ');
  }
  //Serial.println();
  if(strncmp(roboSetup.data.name,"EGG3",4)!=0){
    Serial.println("set to default setup");
    // set to default setup
    memset(roboSetup.buf,0,64);
    memcpy(roboSetup.data.name,"EGG3",4);
    roboSetup.data.motoADir = 0;
    roboSetup.data.motoBDir = 0;
    syncRobotSetup();
  }
  if(roboSetup.data.motoADir==0){
    motorAfw=1;motorAbk=-1;
  }else{
    motorAfw=-1;motorAbk=1;
  }
  if(roboSetup.data.motoBDir==0){
    motorBfw=-1;motorBbk=1;
  }else{
    motorBfw=1;motorBbk=-1;
  }
}



/************** arduino ******************/
void setup() {
  Serial.begin(115200);
  initRobotSetup();
  initPosition();
  servoPen.attach(servopin);
  servoPen.write(0);
}

char buf[64];
char bufindex;
char buf2[64];
char bufindex2;

void loop() {
  if(Serial.available()){
    char c = Serial.read();
    //buf[bufindex++]=c;                 // Robbo1 2015/6/8 Removed - Do not store the \n
    if(c=='\n'){
      buf[bufindex++]='\0';              // Robbo1 2015/6/8 Add     - Null terminate the string - Essential for first use of 'buf' and good programming practice
      parseCmd(buf);
      memset(buf,0,64);
      bufindex = 0;
    }else if(bufindex<64){               // Robbo1 2015/6/8 Add     - Only add char to string if the string can fit it and still be null terminated 
      buf[bufindex++]=c;                 // Robbo1 2015/6/8 Moved   - Store the character here now
 }
  }
}

Leider musste ich einige Zeilen entfernen da sonst der Post zu gross wäre.
Für mich sind das überwiegend noch Böhmische Dörfer.

Habe noch ein wenig gegoogelt und folgendes herrausgefunden:
Zur Zeit verwend ich einen unipolaren SM. Dieser kann aber auch, wie benötigt, als bipolarer Motor verwendet werden. Das bedeuteet für mich einen Plan B.
Dennoch würde mich eine Softwarelösung mehr interessieren um auch ein wenig über den I2C zu lehrnen.

Wenn ich mir stepperMoveA() so anschaue, dann werden da ganz normale Schrittmotor-Signale erzeugt, eins für die Richtung (dWrite1), das andere für einen Schritt (dWrite2).

Jetzt könntest Du diese beiden Funktionen (A/B) durch eigene ersetzen, die irgendwelche Daten übertragen.

Oder Du klinkst Dich in doMove() ein, und ersetzst dort die for Schleife - vorausgesetzt stepperMoveA/B wird sonst nirgends mehr verwendet. Dann mußt Du aber aufpassen, daß schräge Linien auch schräg bleiben, und nicht eine Richtung schneller fertig wird als die andere.

Mir deucht, Du mußt bei diesem Projekt erst einiges über die synchrone Steuerung von Schrittmotoren lernen, bevor Du überhaupt zu I2C kommen kannst. Sonst ist es ein ziemlicher Overkill, für jeden Schritt eines Motors mindestens 2 Bytes I2C zu übertragen, als einen einfachen Impuls.

DrDiettrich:
Mir deucht, Du mußt bei diesem Projekt erst einiges über die synchrone Steuerung von Schrittmotoren lernen, bevor Du überhaupt zu I2C kommen kannst.

Mich deucht noch viel mehr.
Mittlerweile habe ich mich von der Vorstellung getrennt eine Softwarelösung herbei zu führen.
Habe jetzt drei “A4988 StepStick Compatible Stepper Motor Driver” bestellt und die passenden Motoren.
Leider habe ich da noch ein eine Frage zum anschluss des Treibers.
In der Schematischen Darstellung für den Treiber werden nur vier Aschlüsse gezeigt die vom UNO zum Treiber gehen.
VDD
GND
Step(SCL)TAKT
Dir(SDA)DATEN
Dies sollte klar sein.
Zum selektieren des Ports gibt es dann noch 10~ und 11~ (so nehme ich an). Da am Treiber eine Verbindung zwischen Reset- und Sleep- eingezeichnet ist vermute ich das diese miteinander verbunden werden müssen.
Aber wie ist hier meine Frage.