Macroschlitten

Crystal Clear action run.png
Macroschlitten

Status: stable

Beschreibung
Autor: ptflea
Version 0.5
Flattr Flattr Macroschlitten
PayPal Spenden für Macroschlitten

Stepper läuft mit 12V

Ardunio-Code

  1 #include <AFMotor.h>
  2 #include <AccelStepper.h>
  3 
  4 // Connect a stepper motor with 48 steps per revolution (7.5 degree)
  5 // to motor port #2 (M3 and M4)
  6 int incomingByte;  
  7 char Data[8];
  8 int i;
  9 unsigned long Zeit;
 10 int bewegung;
 11 int schritte;
 12 
 13 int motorStepsPerRev = 200;
 14 float currentMaxSpeed = 1200.0;
 15 float currentAcceleration = 300.0;
 16 const int stepType = INTERLEAVE;
 17 
 18 AF_Stepper motor1(motorStepsPerRev, 2);
 19 AF_Stepper motor2(motorStepsPerRev, 1);
 20 
 21 
 22 void forwarda() {  
 23   motor1.onestep(FORWARD, stepType);
 24 }
 25 void backwarda() {  
 26   motor1.onestep(BACKWARD, stepType);
 27 }
 28 
 29 AccelStepper accelA(forwarda, backwarda);
 30 
 31 
 32 void forwardb() {  
 33   motor2.onestep(FORWARD, stepType);
 34 }
 35 void backwardb() {  
 36   motor2.onestep(BACKWARD, stepType);
 37 }
 38 
 39 AccelStepper accelB(forwardb, backwardb);
 40 
 41 int range_in;
 42 int byte_in[2];         // variable to store the VALID data from the port
 43 char nextMsg;
 44 
 45 
 46 void setup(){
 47  
 48   motor1.setSpeed(50);  // in rpm 
 49   motor2.setSpeed(50);  // in rpm
 50   
 51   //Accelstepper Setup
 52   accelA.setMaxSpeed(currentMaxSpeed);
 53   accelA.setAcceleration(currentAcceleration);  
 54   accelB.setMaxSpeed(currentMaxSpeed);
 55   accelB.setAcceleration(currentAcceleration);
 56   
 57   accelA.setMinPulseWidth(10);
 58   accelB.setMinPulseWidth(10);
 59   
 60   
 61   Serial.begin(9600);
 62   digitalWrite(13, HIGH); //turn on LED to indicate program has started
 63 }
 64 
 65 void loop(){
 66   
 67 
 68    do {
 69      // Wenn Daten verfügbar Zeichen in Data schreiben bis 4 Zeichen erreicht oder 0,5 Sekunden Warten nach dem ersten übertragenen byte
 70      if (Serial.available()) {
 71 	if (i == 0)
 72             {
 73               bewegung = Serial.read();
 74             }
 75             else
 76             {
 77              Data[i-1] = Serial.read();
 78          }
 79 	 i++;
 80 	 }    
 81      if(i<1)Zeit = millis();
 82      } while (i<4&&(millis()-Zeit) < 500); //nach i< kommt die Anzahl der Zeichen
 83     // Serial.flush(); //empty serial buffer
 84        // Abschließende Null für gültigen String
 85      Data[i-1] = 0;    
 86     
 87      schritte = atof(Data);  // Wert von String zu Zahl wandeln wenn gewünscht
 88      i=0;
 89      decodeMessage(bewegung, schritte); 
 90      
 91 }
 92 
 93 void decodeMessage(int msg, int range){
 94   int faktor = 5;
 95   //check command type and command value
 96   if(bitRead(msg, 0) == 1){
 97     //Bit 1 = High   DOWN (1)
 98    // motor1.step(faktor, FORWARD, INTERLEAVE); 
 99     	accelA.move(-range);
100 	accelA.runToPosition();
101   }
102   if(bitRead(msg, 1) == 1){
103     //Bit 2 = High   UP (2)
104     //motor1.step(faktor, BACKWARD, INTERLEAVE); 
105 	accelA.move(range);
106 	accelA.runToPosition(); 
107   }
108   if(bitRead(msg, 2) == 1){
109     //Bit 3 = High   LEFT (4)
110     motor1.step(faktor, FORWARD, INTERLEAVE); 
111   }
112   if(bitRead(msg, 3) == 1){
113     //Bit 4 = High   RIGHT (8)
114     motor1.step(faktor, BACKWARD, INTERLEAVE); 
115 
116   }
117   if((msg & 15) == 0){
118     //Bit 1-4 = Low
119     //sendMsg(000); //send a message back for testing purposes
120   }
121   sendMsg(msg, range);
122 }
123 
124 
125 
126 void sendMsg(int msg, int range){
127   /* Processing uses Serial.buffer(4) to read the messages it receives,
128    * meaning that messages of 4 bytes long should be sent.
129    * Arduino sends integers as Strings, so to ensure 4 characters are sent
130    * for each message, I check the size of the integer to send and add zeroes
131    * as needed (zeroes ensure that the received message can easily be cast
132    * to an integer by Processing, which would not be the case with other, non-numerical, characters)
133    */
134   //if(Serial.available() > 0) Serial.flush();
135 //  if(msg < 1000) Serial.print(0);
136 //  if(msg < 100) Serial.print(0);
137 //  if(msg < 10) Serial.print(0);
138   //delay(1000); 
139   
140   Serial.print(range); //...send a confirmation
141   Serial.println(msg);
142  
143 }

Processing-Code

  1 import processing.serial.*;
  2 
  3 Serial myPort;
  4 PFont font;
  5 
  6 String Schritte = "333";
  7 int msgQueue[]; //the message queue
  8 boolean msgLock; //message lock, active until last message is confirmed
  9 int lstMsg; //last message sent
 10 int schritt = 125;
 11 
 12 void setup(){
 13   size(400, 300);
 14   background(0);
 15   font = createFont("Verdana", 14);
 16   
 17   msgQueue = new int[0];
 18   
 19   
 20   println(Serial.list());
 21  myPort = new Serial(this, Serial.list()[Serial.list().length - 1], 9600); //the highest connected COM port is always my Arduino
 22   //myPort.buffer(4); //buffer 4 bytes of data before calling serialEvent()
 23   myPort.bufferUntil('\n');
 24 
 25 }
 26 
 27 void draw(){
 28   background(0);
 29   textFont(font, 14);
 30   text("Taste 8: vorwärts\nTaste 7: weit vorwärts\n\nTaste 2: zurück\nTaste 1: weit zurück\n\n9 -> Schritt erhöhen\n3 -> Schritt verkleinern", 25, 25);
 31   text("Schritte: " + schritt, 25, 230);
 32   parseQueue();
 33 }
 34 
 35 void keyPressed(){
 36   if(int(key) == 50){// Taste 2 DOWN
 37     queueMessage(2); //
 38     //Schritte = Integer.toString(schritt);
 39     queueMessage(schritt);
 40   }
 41     if(int(key) == 56){// Taste 8 UP
 42     queueMessage(1); // 
 43     //Schritte = Integer.toString(schritt);
 44      queueMessage(schritt);
 45   }
 46     if(int(key) == 51){// Taste 3 Schritt verkleinern
 47     schritt = schritt - 5;
 48   }
 49     if(int(key) == 57){// Taste 9 Schritt erhöhen
 50     schritt = schritt + 5;
 51   }
 52     if(int(key) == 55){ //Taste 7 Grosser Schritt UP
 53     queueMessage(1); // 
 54     queueMessage(600);
 55   }
 56     if(int(key) == 49){ //Taste 1 Grosser Schritt DOWN
 57     queueMessage(2); // 
 58     queueMessage(600);
 59   }
 60 }
 61 
 62 /* serialEvent(Serial myPort)
 63  * called when the amount of bytes specified in myPort.buffer()
 64  * have been transmitted, converts serial message to integer,
 65  * then sets this value in the chair object
 66  */
 67 void serialEvent(Serial myPort){
 68   if(myPort.available() > 0){
 69     
 70     String message = myPort.readString(); //read serial buffer
 71     int msg = int(message); //convert message to integer
 72     println(msgQueue.length);
 73     myPort.clear(); //clear whatever might be left in the serial buffer
 74     //msgLock = false;
 75      if(msg == 0){
 76       println("Anweisung durchgeführt");
 77       msgLock = false;
 78     }
 79   }
 80 }
 81 
 82 private void writeSerial(int msg){
 83   if(myPort.available() > 0) myPort.clear(); //empty serial buffer before sending
 84   myPort.write(msg);
 85 }
 86 
 87 public void queueMessage(int msg){
 88   msgQueue = append(msgQueue, msg);
 89 }
 90 
 91 private void parseQueue(){
 92   
 93     if(msgQueue.length > 0 && !msgLock) {
 94       msgLock = true; //lock queue, preventing new messages from being sent
 95       lstMsg = msgQueue[0]; //queue the first message on the stack
 96       writeSerial(lstMsg); // sende richtungsbefehl
 97       println("writing Richtung: " + lstMsg);
 98             
 99       msgQueue = subset(msgQueue, 1); // letzten befehl löschen
100       
101       lstMsg = msgQueue[0]; //queue the first message on the stack
102       Schritte = Integer.toString(lstMsg);
103       myPort.clear();
104       myPort.write(Schritte);// sende Schrittzahl
105       println("writing Schritte: " + lstMsg);
106       
107       msgQueue = subset(msgQueue, 1); // letzten befehl löschen
108     }
109 
110 }


Knitty: passap Firmware

//////////////////////////////////////////////////////////////////////////////
// Knitty Project
//
// Author: ptflea, schinken
//

//Servo
#include <Servo.h> 

Servo servoColour12;  // create servo object to control a servo 
Servo servoColour34;

#define INT_ENCODER 0
#define INT_IFDR    1

//////////////////////////////////////////////////////////////////////////////
// General purpose definitions

#define PIN_IFDR      3         // Green
#define PIN_CSENSE    2         // Yellow
#define PIN_CREF      4         // White
#define PIN_NEEDLE_RTL    5         // Blue,  Pattern RTL
#define PIN_NEEDLE_LTR    6         // ,  Pattern LTR
#define PIN_BUTTON_1  7         // Button_1 (activate colour change)
#define BUTTONDELAY   20        // delay for Button_1 
// PIN 8 and 9 are for the color change servos
#define PIN_Eyelet_1  10        // Eyelet_1 status
#define Eyelet_1_DELAY   100
#define PIN_Eyelet_2  11        // Eyelet_2 status
#define PIN_Eyelet_3  12        // Eyelet_3 status
#define PIN_Eyelet_4  13        // Eyelet_4 status


long buttonLastChecked = 0; // variable to limit the button getting checked every cycle
int button_1_State = 0;     // status of button_1
int button_1_Hold = 0; // toggle state of Button_1

long eyelet_1_LastChecked = 0;
int eyelet_1_State = 0;
int eyelet_1_Hold = 0;

#define DIRECTION_UNKNOWN       0
#define DIRECTION_LEFT_RIGHT   -1
#define DIRECTION_RIGHT_LEFT    1

char currentDirection = DIRECTION_UNKNOWN;
char lastDirection = DIRECTION_UNKNOWN;

signed int currentCursorPosition = 0;
signed int lastCursorPosition = 0;
signed int leftEndCursorPosition = 0;
unsigned int currentPatternIndex = 0;
signed int firstNeedle = 0;
signed int offsetCarriage_RTL = 52;
signed int offsetCarriage_LTR = 46;


volatile unsigned char knitPattern[255] = {
  0};
bool isKnitting = false;

//////////////////////////////////////////////////////////////////////////////
// Knitty Serial Protocol

// Receive commands
#define COM_CMD_PATTERN      'P'
#define COM_CMD_PATTERN_END  'E'
#define COM_CMD_CURSOR       'C'
#define COM_CMD_IFDR         'I'
#define COM_CMD_RESPONSE     'R'
#define COM_CMD_DIRECTION    'D'
#define COM_CMD_DEBUG        'V'
#define COM_CMD_NEW_PATTERN  'N'
#define COM_CMD_FIRST_NEEDLE 'F'  //first needle of pattern from right
#define COM_CMD_SEPERATOR    ':'

#define COM_CMD_SERVO        'S'

#define COM_CMD_PLOAD_END    '\n'

// Parser states
#define COM_PARSE_CMD      0x01
#define COM_PARSE_SEP      0x02
#define COM_PARSE_PLOAD    0x03


unsigned char parserState = COM_PARSE_CMD;

unsigned char parserReceivedCommand = 0;
String parserReceivedPayload = "";

unsigned char patternLength = 0;

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

  // Button Input
  pinMode(PIN_BUTTON_1, INPUT);

  //Eylet Input
  pinMode(PIN_Eyelet_1, INPUT);


  // Setup PHOTO SENSOR pin change interrupt
  pinMode(PIN_CSENSE, INPUT);
  pinMode(PIN_CREF, INPUT);
  attachInterrupt(INT_ENCODER, interruptPinChangeEncoder, CHANGE);

  // Setup IFDR pin change interrupt
  pinMode(PIN_IFDR, INPUT);
  attachInterrupt(INT_IFDR, interruptPinChangeIfdr, FALLING);

  // Setup Needles
  pinMode(PIN_NEEDLE_RTL, OUTPUT);
  digitalWrite(PIN_NEEDLE_RTL, HIGH);
  pinMode(PIN_NEEDLE_LTR, OUTPUT);
  digitalWrite(PIN_NEEDLE_LTR, HIGH);

}

void executeCommand(unsigned char cmd, String payload) {

  switch(cmd) {
  case COM_CMD_PATTERN:

    patternLength = payload.length();
    for(unsigned char i = 0; i < patternLength; i++) {
      knitPattern[i] = (payload.charAt(i) == '1')? 1 : 0;
    }

    break;

  case COM_CMD_CURSOR:
    currentCursorPosition = payload.toInt();
    break;

  case COM_CMD_FIRST_NEEDLE:
    firstNeedle = payload.toInt()*2-2;
    break;

  case COM_CMD_SERVO:

    switch(payload.toInt()) {
    case 0: //no colour selected
      servoColour12.write(90);
      servoColour34.write(90);
      break;
    case 1: //Color 1
      servoColour12.write(70);    
      servoColour34.write(90);
      break;    
    case 2: //Color 2
      servoColour12.write(115);
      servoColour34.write(90);
      break; 
    case 3: //Color 3
      servoColour12.write(90);    
      servoColour34.write(70);
      break;    
    case 4: //Color 4
      servoColour12.write(90);
      servoColour34.write(115);
      break; 
    case 5: //Servo off
      servoColour12.detach();
      servoColour34.detach();
      break; 
    case 6: //Servo on
      servoColour12.attach(8);
      servoColour34.attach(9);
      break; 
    }

    break;


  }
}

void sendCommand(unsigned char cmd, String payload) {
  Serial.write(cmd);
  Serial.write(COM_CMD_SEPERATOR);
  Serial.print(payload);
  Serial.write("\n");
}

void parserSerialStream() {

  if (Serial.available() == 0) {
    return;
  }

  char buffer = Serial.read();

  switch(parserState) {

  case COM_PARSE_CMD:
    parserState = COM_PARSE_SEP;
    parserReceivedCommand = buffer;
    parserReceivedPayload = "";
    break;

  case COM_PARSE_SEP:

    // We're awaiting a seperator here, if not, back to cmd
    if(buffer == COM_CMD_SEPERATOR) {
      parserState = COM_PARSE_PLOAD;
      break;
    }

    parserState = COM_PARSE_CMD;
    break;

  case COM_PARSE_PLOAD:

    if(buffer == COM_CMD_PLOAD_END) {

      executeCommand(parserReceivedCommand, parserReceivedPayload);
      parserState = COM_PARSE_CMD;

      sendCommand(COM_CMD_RESPONSE, "OK");
      break;
    }

    parserReceivedPayload += buffer;
    break;
  }
}

void loop() {
  parserSerialStream();

  //check if button for colour change ist activated and send response to processing
  button_1_State = digitalRead(PIN_BUTTON_1);

  if( buttonLastChecked == 0 ) // see if this is the first time checking the buttons
    buttonLastChecked = millis()+BUTTONDELAY;  // force a check this cycle
  if( millis() - buttonLastChecked > BUTTONDELAY ) { // make sure a reasonable delay passed
    if (button_1_State == HIGH) {    
      if (button_1_Hold == HIGH) { 
        // Send   
        sendCommand(COM_CMD_RESPONSE, "ON"); 
        button_1_Hold = LOW;
      }
    }
    else {
      if (button_1_Hold == LOW) { 
        // Send   
        sendCommand(COM_CMD_RESPONSE, "OFF"); 
        button_1_Hold = HIGH;
      }
    }
    buttonLastChecked = millis(); // reset the lastChecked value
  }



  //check Eyelets
  eyelet_1_State = digitalRead(PIN_Eyelet_1);

  if( eyelet_1_LastChecked == 0 ) // see if this is the first time checking the buttons
    eyelet_1_LastChecked = millis()+Eyelet_1_DELAY;  // force a check this cycle
  if( millis() - eyelet_1_LastChecked > Eyelet_1_DELAY ) { // make sure a reasonable delay passed
    if (eyelet_1_State == HIGH) {    
      if (eyelet_1_Hold == HIGH) { 
        // Send   
        sendCommand(COM_CMD_RESPONSE, "Eyelet 1 OUT"); 
        eyelet_1_Hold = LOW;
      }
    }
    else {
      if (eyelet_1_Hold == LOW) { 
        // Send   
        sendCommand(COM_CMD_RESPONSE, "Eyelet 1 IN"); 
        eyelet_1_Hold = HIGH;
      }
    }
    eyelet_1_LastChecked = millis(); // reset the lastChecked value
  }
}




void setNeedleByCursor(char cursorPosition) {

  // Just to be sure that we never exceed the pattern
  if(cursorPosition > patternLength-1 || cursorPosition < 0) {
    return;
  }

  if(currentDirection == DIRECTION_LEFT_RIGHT) {
    setNeedle_LTR(knitPattern[cursorPosition]);
  } 
  else if(currentDirection == DIRECTION_RIGHT_LEFT) {
    setNeedle_RTL(knitPattern[patternLength-cursorPosition-1]);
  }
}



void setNeedle_RTL(char state) {
  //change state because the E6000 sets needle by 0
  if(state==1){
    state = 0;
  }
  else
  {
    state = 1;
  }
  digitalWrite(PIN_NEEDLE_RTL, state);
}

void setNeedle_LTR(char state) {
  //change state because the E6000 sets needle by 0
  if(state==1){
    state = 0;
  }
  else
  {
    state = 1;
  }
  digitalWrite(PIN_NEEDLE_LTR, state);
}


void interruptPinChangeEncoder() {

  char currentPinChangeValue = digitalRead(PIN_CSENSE);
  char currentPinChangeOppositeValue = digitalRead(PIN_CREF);

  // Determine direction
  if(currentPinChangeValue == currentPinChangeOppositeValue) {
    currentDirection = DIRECTION_LEFT_RIGHT;
  } 
  else {
    currentDirection = DIRECTION_RIGHT_LEFT;
  }

  // RTL = 1, LTR = -1
  currentCursorPosition += currentDirection; 

  //store last position
  lastCursorPosition = currentCursorPosition;


  //debug cursorposition
  //sendCommand(COM_CMD_RESPONSE, String(currentCursorPosition));

  // Check if we're in range of our needles
  if((currentDirection == DIRECTION_RIGHT_LEFT && currentCursorPosition > offsetCarriage_RTL + firstNeedle) ||
    (currentDirection == DIRECTION_LEFT_RIGHT && currentCursorPosition - offsetCarriage_LTR  <= patternLength + firstNeedle)) {

    if(currentPatternIndex > patternLength) {

      setNeedle_RTL(0);
      setNeedle_LTR(0);
      currentPatternIndex = 0;
      isKnitting = false;

      sendCommand(COM_CMD_PATTERN_END, "1");


    } 
    else {

      if(isKnitting == true) {
        // React on FALLING Edge 
        if(currentPinChangeValue == 1)  {
          setNeedleByCursor(currentPatternIndex);
          currentPatternIndex++;
        }
      }

    }
  }

  if(lastDirection != currentDirection) {
    lastDirection = currentDirection;
    currentPatternIndex = 0;
    isKnitting = true;
    if(currentDirection == DIRECTION_RIGHT_LEFT) {
      sendCommand(COM_CMD_DIRECTION, "RTL");
    } 
    else {
      sendCommand(COM_CMD_DIRECTION, "LTR");
    }
  }
}

// We only use the IFDR to determine if we can send the pattern
// for the next line.
void interruptPinChangeIfdr() {
  if(isKnitting == false) {
    sendCommand(COM_CMD_IFDR, "1");
  }
}


Knitty passap 26.09.2014

//////////////////////////////////////////////////////////////////////////////
// Knitty Project
//
// Author: ptflea, schinken, 
//

//Servo
#include <Servo.h>

Servo servoColour12;  // create servo object to control a servo
Servo servoColour34;

#define INT_ENCODER 0


//////////////////////////////////////////////////////////////////////////////
// General purpose definitions

//Pin 3 unused
#define PIN_CSENSE    2         // Yellow
#define PIN_CREF      4         // White
#define PIN_NEEDLE_RTL    5         // Blue,  Pattern RTL
#define PIN_NEEDLE_LTR    6         // ,  Pattern LTR
#define PIN_BUTTON_1  7         // Button_1 (activate colour change)
#define BUTTONDELAY   20        // delay for Button_1
// PIN 8 and 9 are for the color change servos
#define PIN_Eyelet_1  10        // Eyelet_1 status
#define Eyelet_1_DELAY   100
#define PIN_Eyelet_2  11        // Eyelet_2 status
#define PIN_Eyelet_3  12        // Eyelet_3 status
#define PIN_Eyelet_4  13        // Eyelet_4 status


long buttonLastChecked = 0; // variable to limit the button getting checked every cycle
int button_1_State = 0;     // status of button_1
int button_1_Hold = 0; // toggle state of Button_1

long eyelet_1_LastChecked = 0;
int eyelet_1_State = 0;
int eyelet_1_Hold = 0;

#define DIRECTION_UNKNOWN       0
#define DIRECTION_LEFT_RIGHT   -1
#define DIRECTION_RIGHT_LEFT    1

char currentDirection = DIRECTION_UNKNOWN;
char lastDirection = DIRECTION_UNKNOWN;

signed int currentCursorPosition = 0;
unsigned long lastCursorChange = 0;
unsigned int currentPatternIndex = 0;
signed int firstNeedle = 0;
signed int offsetCarriage_RTL = 52;
signed int offsetCarriage_LTR = 30;


volatile unsigned char knitPattern[255] = {
  0};
bool isKnitting = false;

volatile unsigned char passapCalibrateArray[8] = { 
  0 };
signed int  passapCalibratePointer = 0;
static unsigned char passaptestpatter[8] = {
  1, 1, 0, 1, 1, 0, 0, 0};


//////////////////////////////////////////////////////////////////////////////
// Knitty Serial Protocol

// Receive commands
#define COM_CMD_PATTERN      'P'
#define COM_CMD_PATTERN_END  'E'
#define COM_CMD_CURSOR       'C'
#define COM_CMD_RESPONSE     'R'
#define COM_CMD_DIRECTION    'D'
#define COM_CMD_DEBUG        'V'
#define COM_CMD_NEW_PATTERN  'N'
#define COM_CMD_FIRST_NEEDLE 'F'  //first needle of pattern from right
#define COM_CMD_SEPERATOR    ':'

#define COM_CMD_SERVO        'S'

#define COM_CMD_PLOAD_END    '\n'

// Parser states
#define COM_PARSE_CMD      0x01
#define COM_PARSE_SEP      0x02
#define COM_PARSE_PLOAD    0x03


unsigned char parserState = COM_PARSE_CMD;

unsigned char parserReceivedCommand = 0;
String parserReceivedPayload = "";
unsigned char patternLength = 0;

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

  // Button Input
  pinMode(PIN_BUTTON_1, INPUT);

  //Eylet Input
  pinMode(PIN_Eyelet_1, INPUT);


  // Setup PHOTO SENSOR pin change interrupt
  pinMode(PIN_CSENSE, INPUT);
  digitalWrite(PIN_CSENSE, HIGH);  //activate PullUp
  pinMode(PIN_CREF, INPUT);
  digitalWrite(PIN_CREF, HIGH);  //activate PullUp
  attachInterrupt(INT_ENCODER, interruptPinChangeEncoder, CHANGE);

  // Setup Needles
  pinMode(PIN_NEEDLE_RTL, OUTPUT);
  digitalWrite(PIN_NEEDLE_RTL, HIGH);
  pinMode(PIN_NEEDLE_LTR, OUTPUT);
  digitalWrite(PIN_NEEDLE_LTR, HIGH);

}

void executeCommand(unsigned char cmd, String payload) {

  switch(cmd) {
  case COM_CMD_PATTERN:
    //Serial.print("P ");
    //Serial.println(patternLength);
    sendCommand(COM_CMD_RESPONSE, "PatternLength: " + String(patternLength));
    break;

  case COM_CMD_CURSOR:
    currentCursorPosition = payload.toInt();
    break;

  case COM_CMD_FIRST_NEEDLE:
    firstNeedle = payload.toInt()*2-2;
    sendCommand(COM_CMD_RESPONSE, "FirstNeedle: " + String(firstNeedle));
    break;

  case COM_CMD_SERVO:

    switch(payload.toInt()) {
    case 0: //no colour selected
      servoColour12.write(90);
      servoColour34.write(90);
      break;
    case 1: //Color 1
      servoColour12.write(70);
      servoColour34.write(90);
      break;
    case 2: //Color 2
      servoColour12.write(115);
      servoColour34.write(90);
      break;
    case 3: //Color 3
      servoColour12.write(90);
      servoColour34.write(70);
      break;
    case 4: //Color 4
      servoColour12.write(90);
      servoColour34.write(115);
      break;
    case 5: //Servo off
      servoColour12.detach();
      servoColour34.detach();
      break;
    case 6: //Servo on
      servoColour12.attach(8);
      servoColour34.attach(9);
      break;
    }

    break;


  }
}

void sendCommand(unsigned char cmd, String payload) {
  Serial.write(cmd);
  Serial.write(COM_CMD_SEPERATOR);
  Serial.print(payload);
  Serial.write("\n");
}

void parserSerialStream() {

  if (Serial.available() == 0) {
    return;
  }

  char buffer = Serial.read();

  switch(parserState) {

  case COM_PARSE_CMD:
    parserState = COM_PARSE_SEP;
    parserReceivedCommand = buffer;
    parserReceivedPayload = "";
    if (buffer == COM_CMD_PATTERN) {
      patternLength = 0;
    }
    break;

  case COM_PARSE_SEP:

    // We're awaiting a seperator here, if not, back to cmd
    if(buffer == COM_CMD_SEPERATOR) {
      parserState = COM_PARSE_PLOAD;
      break;
    }

    parserState = COM_PARSE_CMD;
    break;

  case COM_PARSE_PLOAD:

    if(buffer == COM_CMD_PLOAD_END) {

      executeCommand(parserReceivedCommand, parserReceivedPayload);
      parserState = COM_PARSE_CMD;

      sendCommand(COM_CMD_RESPONSE, "Recieved");
      break;
    }

    if (parserReceivedCommand == COM_CMD_PATTERN) {
      knitPattern[patternLength] = (buffer == '1')? 1 : 0;
      patternLength += 1;
    } 
    else {
      parserReceivedPayload += buffer;
    }
    break;
  }
}

void loop() {
  parserSerialStream();

  //check if button for colour change ist activated and send response to processing
  button_1_State = digitalRead(PIN_BUTTON_1);

  if( buttonLastChecked == 0 ) // see if this is the first time checking the buttons
    buttonLastChecked = millis()+BUTTONDELAY;  // force a check this cycle
  if( millis() - buttonLastChecked > BUTTONDELAY ) { // make sure a reasonable delay passed
    if (button_1_State == HIGH) {
      if (button_1_Hold == HIGH) {
        // Send
        sendCommand(COM_CMD_RESPONSE, "ColourChanger ON");
        button_1_Hold = LOW;
      }
    } 
    else if (button_1_Hold == LOW) {
      // Send
      sendCommand(COM_CMD_RESPONSE, "ColourChanger OFF");
      button_1_Hold = HIGH;
    }
    buttonLastChecked = millis(); // reset the lastChecked value
  }



  //  //check Eyelets
  //  eyelet_1_State = digitalRead(PIN_Eyelet_1);
  //
  //  if( eyelet_1_LastChecked == 0 ) // see if this is the first time checking the buttons
  //    eyelet_1_LastChecked = millis()+Eyelet_1_DELAY;  // force a check this cycle
  //  if( millis() - eyelet_1_LastChecked > Eyelet_1_DELAY ) { // make sure a reasonable delay passed
  //    if (eyelet_1_State == HIGH) {
  //      if (eyelet_1_Hold == HIGH) {
  //        // Send
  //        sendCommand(COM_CMD_RESPONSE, "Eyelet 1 OUT");
  //        eyelet_1_Hold = LOW;
  //      }
  //    }
  //    else {
  //      if (eyelet_1_Hold == LOW) {
  //        // Send
  //        sendCommand(COM_CMD_RESPONSE, "Eyelet 1 IN");
  //        eyelet_1_Hold = HIGH;
  //      }
  //    }
  //    eyelet_1_LastChecked = millis(); // reset the lastChecked value
  //  }

}




void setNeedleByCursor(int cursorPosition) {

  // Just to be sure that we never exceed the pattern
  //  if(cursorPosition > patternLength-1 || cursorPosition < 0) {
  //    return;
  //  }

  if(currentDirection == DIRECTION_LEFT_RIGHT) {
    setNeedle_LTR(knitPattern[cursorPosition]);
  }
  else if(currentDirection == DIRECTION_RIGHT_LEFT) {
    setNeedle_RTL(knitPattern[patternLength-cursorPosition-1]);
  }
}



void setNeedle_RTL(char state) {
  //change state because the E6000 sets needle by 0
//  Serial.print("-");
//  Serial.print(String(0+state));
  if(state==1){
    state = 0;
  } 
  else {
    state = 1;
  }
  digitalWrite(PIN_NEEDLE_RTL, state);
}

void setNeedle_LTR(char state) {
  //change state because the E6000 sets needle by 0
//  Serial.print("-");
//  Serial.print(String(0+state));
  if(state==1){
    state = 0;
  }
  else
  {
    state = 1;
  }
  digitalWrite(PIN_NEEDLE_LTR, state);
}


void interruptPinChangeEncoder() {

  unsigned long now = micros();
  if (now - lastCursorChange < 1000) {
    lastCursorChange = now;
    return;
  }
  lastCursorChange = now;

  char currentPinChangeValue = digitalRead(PIN_CSENSE);
  char currentPinChangeOppositeValue = digitalRead(PIN_CREF);



  // Determine direction
  if(currentPinChangeValue == currentPinChangeOppositeValue) {
    currentDirection = DIRECTION_LEFT_RIGHT;
  } 
  else {
    currentDirection = DIRECTION_RIGHT_LEFT;
  }

  // RTL = 1, LTR = -1
  currentCursorPosition += currentDirection; 

//  Serial.print(String(currentPatternIndex));
//  Serial.print("-");
//  Serial.print(String(currentCursorPosition));



  //debug cursorposition
  //  if(currentCursorPosition==0){
  //  sendCommand(COM_CMD_RESPONSE, String(currentCursorPosition));
  ////sendCommand(COM_CMD_RESPONSE, String(firstNeedle));
  //  }


  if (currentCursorPosition >20 && currentCursorPosition < 420  ){   // Check if we're in range of our needles
    if((currentDirection == DIRECTION_RIGHT_LEFT && currentCursorPosition > offsetCarriage_RTL + firstNeedle) ||
      (currentDirection == DIRECTION_LEFT_RIGHT && currentCursorPosition - offsetCarriage_LTR  <= patternLength*2 + firstNeedle)) {
      //sendCommand(COM_CMD_RESPONSE, String(currentPatternIndex));
      if(currentPatternIndex > patternLength) {

        setNeedle_RTL(0);
        setNeedle_LTR(0);
        currentPatternIndex = 0;
        isKnitting = false;

        sendCommand(COM_CMD_PATTERN_END, "1");
      } 
      else if(isKnitting == true) {
        //        Serial.print(String(1+currentDirection));
        //        Serial.print("-");
        //        Serial.print(String(currentCursorPosition));
        //        Serial.print("-");
        //        Serial.println(String(offsetCarriage_RTL + firstNeedle));


        // React on FALLING Edge
        if(currentPinChangeValue == 1)  {
          setNeedleByCursor(currentPatternIndex);
          currentPatternIndex++;
        }
      }
    }
  }

 // Serial.println();

  if (currentCursorPosition >30 && currentCursorPosition < 420  ){ //don't check if not in needle range
    if(lastDirection != currentDirection) {
      lastDirection = currentDirection;
      currentPatternIndex = 0;
      isKnitting = true;
      if(currentDirection == DIRECTION_RIGHT_LEFT) {
        sendCommand(COM_CMD_DIRECTION, "RTL");
      } 
      else {
        sendCommand(COM_CMD_DIRECTION, "LTR");
      }
    }
  }

  //AutoCalibrate
  passapCalibrateArray[passapCalibratePointer & 0x07] = currentPinChangeValue;
  passapCalibrateArray[(passapCalibratePointer+1) & 0x07] = currentPinChangeOppositeValue;

  if (passapCalibratePointer > 8){ // 16
    // read last 16 digits of passapCalibrateArray
    int found = 1;
    for (int i=0; i<8; i++){
      if (passapCalibrateArray[(passapCalibratePointer-i+2) & 0x07] !=
        passaptestpatter[i]) {
        found = 0;
        break;
      }
    }
    if (found){
     sendCommand(COM_CMD_RESPONSE, "Calibrate");
      //calibrate
      currentCursorPosition = 0;
      passapCalibratePointer = 0;
    }
  }
  passapCalibratePointer = passapCalibratePointer +2;
}

Knitty passap Doppelbett 01.09.2014

//////////////////////////////////////////////////////////////////////////////
// Knitty Project
//
// Author: ptflea, schinken, 
//

//Servo
#include <Servo.h>

Servo servoColour12;  // create servo object to control a servo
Servo servoColour34;

//define interupts for CSENSE
#define INT_ENCODER 0   
#define INT_ENCODER_BACK 1


//////////////////////////////////////////////////////////////////////////////
// General purpose definitions

//front carriage
#define PIN_CSENSE  2         // Yellow
#define PIN_CREF    4         // White
#define PIN_NEEDLE_RTL 5      // Blue,  Pattern RTL
#define PIN_NEEDLE_LTR 6      // ,  Pattern LTR
//back carriage
#define PIN_CSENSE_BACK   3         // 
#define PIN_CREF_BACK    12         // 
#define PIN_NEEDLE_RTL_BACK 11      //   Pattern RTL
#define PIN_NEEDLE_LTR_BACK 10      //   Pattern LTR


#define PIN_BUTTON_1 13// 7         // Button_1 (activate colour change)
#define BUTTONDELAY   20        // delay for Button_1
// PIN 8 and 9 are for the color change servos
#define PIN_Eyelet_1  10        // Eyelet_1 status
#define Eyelet_1_DELAY   100
#define PIN_Eyelet_2  11        // Eyelet_2 status
#define PIN_Eyelet_3  12        // Eyelet_3 status
#define PIN_Eyelet_4  13        // Eyelet_4 status


long buttonLastChecked = 0; // variable to limit the button getting checked every cycle
int button_1_State = 0;     // status of button_1
int button_1_Hold = 0; // toggle state of Button_1

long eyelet_1_LastChecked = 0;
int eyelet_1_State = 0;
int eyelet_1_Hold = 0;

#define DIRECTION_UNKNOWN       0
#define DIRECTION_LEFT_RIGHT   -1
#define DIRECTION_RIGHT_LEFT    1

#define DIRECTION_UNKNOWN_BACK       0
#define DIRECTION_LEFT_RIGHT_BACK   -1
#define DIRECTION_RIGHT_LEFT_BACK    1


char currentDirection = DIRECTION_UNKNOWN;
char lastDirection = DIRECTION_UNKNOWN;
char currentDirection_back = DIRECTION_UNKNOWN;
char lastDirection_back = DIRECTION_UNKNOWN;

//signed int reactOnEdge_back = 1; 

signed int currentCursorPosition = 0;
unsigned long lastCursorChange = 0;
unsigned int currentPatternIndex = 0;
signed int firstNeedle = 0;
signed int offsetCarriage_RTL = 52;
signed int offsetCarriage_LTR = 30;

signed int currentCursorPosition_back = 0;
unsigned long lastCursorChange_back = 0;
unsigned int currentPatternIndex_back = 0;
signed int firstNeedle_back = 0;
signed int offsetCarriage_RTL_back = 52;
signed int offsetCarriage_LTR_back = 31;

volatile unsigned char knitPattern[255] = { 
  0 };
volatile unsigned char knitPattern_back[255] = { 
  0 };

bool isKnitting = false;

volatile unsigned char passapCalibrateArray[8] = { 
  0 };
signed int  passapCalibratePointer = 0;
static unsigned char passaptestpatter[8] = { 1, 1, 0, 1, 1, 0, 0, 0};

volatile unsigned char passapCalibrateArray_back[8] = { 
  0 };
signed int  passapCalibratePointer_back = 0;
//static unsigned char passaptestpatter_back[8] = { 1, 1, 0, 1, 1, 0, 0, 0};
static unsigned char passaptestpatter_back[8] = { 1, 0, 0, 1, 1, 1, 0, 1};
//static unsigned char passaptestpatter_back[8] = {  0, 0, 1, 1, 0, 1, 1, 1};



//////////////////////////////////////////////////////////////////////////////
// Knitty Serial Protocol

// Receive commands
#define COM_CMD_PATTERN      'P'
#define COM_CMD_PATTERN_END  'E'
#define COM_CMD_CURSOR       'C'
#define COM_CMD_RESPONSE     'R'
#define COM_CMD_DIRECTION    'D'
#define COM_CMD_DEBUG        'V'
#define COM_CMD_NEW_PATTERN  'N'
#define COM_CMD_FIRST_NEEDLE 'F'  //first needle of pattern from right
#define COM_CMD_SEPERATOR    ':'

#define COM_CMD_SERVO        'S'

#define COM_CMD_PLOAD_END    '\n'

// Parser states
#define COM_PARSE_CMD      0x01
#define COM_PARSE_SEP      0x02
#define COM_PARSE_PLOAD    0x03


unsigned char parserState = COM_PARSE_CMD;

unsigned char parserReceivedCommand = 0;
String parserReceivedPayload = "";
unsigned char patternLength = 0;

void setup() {
  Serial.begin(115200);
  sendCommand(COM_CMD_RESPONSE, "up and running");

  // Button Input
  pinMode(PIN_BUTTON_1, INPUT);

  //Eylet Input
  pinMode(PIN_Eyelet_1, INPUT);


  // Setup PHOTO SENSOR pin change interrupt
  pinMode(PIN_CSENSE, INPUT_PULLUP);
  pinMode(PIN_CSENSE_BACK, INPUT_PULLUP);

  pinMode(PIN_CREF,  INPUT_PULLUP);
  pinMode(PIN_CREF_BACK,  INPUT_PULLUP);

  attachInterrupt(INT_ENCODER, interruptPinChangeEncoder, CHANGE);
  attachInterrupt(INT_ENCODER_BACK, interruptPinChangeEncoder_back, CHANGE);

  // Setup Needles
  pinMode(PIN_NEEDLE_RTL, OUTPUT);
  digitalWrite(PIN_NEEDLE_RTL, HIGH);
  pinMode(PIN_NEEDLE_LTR, OUTPUT);
  digitalWrite(PIN_NEEDLE_LTR, HIGH);

  pinMode(PIN_NEEDLE_RTL_BACK, OUTPUT);
  digitalWrite(PIN_NEEDLE_RTL_BACK, HIGH);
  pinMode(PIN_NEEDLE_LTR_BACK, OUTPUT);
  digitalWrite(PIN_NEEDLE_LTR_BACK, HIGH);
}

void executeCommand(unsigned char cmd, String payload) {

  switch(cmd) {
  case COM_CMD_PATTERN:
    //Serial.print("P ");
    //Serial.println(patternLength);
    //sendCommand(COM_CMD_RESPONSE, "PatternLength: " + String(patternLength));
    break;

  case COM_CMD_CURSOR:
    currentCursorPosition = payload.toInt();
    break;

  case COM_CMD_FIRST_NEEDLE:
    firstNeedle = payload.toInt()*2-2;
    sendCommand(COM_CMD_RESPONSE, "FirstNeedle: " + String(firstNeedle));
    break;

  case COM_CMD_SERVO:

    switch(payload.toInt()) {
    case 0: //no colour selected
      servoColour12.write(90);
      servoColour34.write(90);
      break;
    case 1: //Color 1
      servoColour12.write(70);
      servoColour34.write(90);
      break;
    case 2: //Color 2
      servoColour12.write(115);
      servoColour34.write(90);
      break;
    case 3: //Color 3
      servoColour12.write(90);
      servoColour34.write(70);
      break;
    case 4: //Color 4
      servoColour12.write(90);
      servoColour34.write(115);
      break;
    case 5: //Servo off
      servoColour12.detach();
      servoColour34.detach();
      break;
    case 6: //Servo on
      servoColour12.attach(8);
      servoColour34.attach(9);
      break;
    }

    break;


  }
}

void sendCommand(unsigned char cmd, String payload) {
  Serial.write(cmd);
  Serial.write(COM_CMD_SEPERATOR);
  Serial.print(payload);
  Serial.write("\n");
}

void parserSerialStream() {

  if (Serial.available() == 0) {
    return;
  }

  char buffer = Serial.read();

  switch(parserState) {

  case COM_PARSE_CMD:
    parserState = COM_PARSE_SEP;
    parserReceivedCommand = buffer;
    parserReceivedPayload = "";
    if (buffer == COM_CMD_PATTERN) {
      patternLength = 0;
    }
    break;

  case COM_PARSE_SEP:

    // We're awaiting a seperator here, if not, back to cmd
    if(buffer == COM_CMD_SEPERATOR) {
      parserState = COM_PARSE_PLOAD;
      break;
    }

    parserState = COM_PARSE_CMD;
    break;

  case COM_PARSE_PLOAD:

    if(buffer == COM_CMD_PLOAD_END) {

      executeCommand(parserReceivedCommand, parserReceivedPayload);
      parserState = COM_PARSE_CMD;

      sendCommand(COM_CMD_RESPONSE, "Recieved");
      break;
    }

    if (parserReceivedCommand == COM_CMD_PATTERN) {
      //Change state because the E6000 set the needle at '0'
      knitPattern[patternLength] = (buffer == '0')? 1 : 0;
      knitPattern_back[patternLength] = (buffer == '1')? 1 : 0;
      
     // Serial.println(String(knitPattern_back[patternLength])+String(patternLength));
      patternLength += 1;
    } 
    else {
      parserReceivedPayload += buffer;
    }
    break;
  }
}


void loop() {
  parserSerialStream();
}


void setNeedleByCursor(int currentPatternIndexSet) {

  if(currentDirection == DIRECTION_LEFT_RIGHT) {
        if (patternLength <= currentPatternIndexSet){
         setNeedle_LTR(1);
       //  Serial.println("StateLTR:lastNeedle");
        }
         else {
      //  Serial.println("StateLTR:"+String(knitPattern_back[currentPatternIndexSet_back])+"-"+String(currentPatternIndexSet_back));
        setNeedle_LTR(knitPattern[currentPatternIndexSet]);
         }
  }
  else if(currentDirection == DIRECTION_RIGHT_LEFT) {
        if (patternLength-currentPatternIndexSet-1 < 0){
              setNeedle_RTL(1);
        // Serial.println("StateRTL:lastNeedle");
        }
       else{ 
       // Serial.println("StateRTL:"+String(knitPattern_back[patternLength-currentPatternIndexSet_back-1])+"-"+String(patternLength-currentPatternIndexSet_back-1));
        setNeedle_RTL(knitPattern[patternLength-currentPatternIndexSet-1]);
       }
  }
//  if(currentDirection == DIRECTION_LEFT_RIGHT) {
//    setNeedle_LTR(knitPattern[currentPatternIndexSet]);
//  }
//  else if(currentDirection == DIRECTION_RIGHT_LEFT) {
//    setNeedle_RTL(knitPattern[patternLength-currentPatternIndexSet-1]);
//  }
}

void setNeedleByCursor_back(int currentPatternIndexSet_back) {

  // Just to be sure that we never exceed the pattern
  //  if(cursorPosition > patternLength-1 || cursorPosition < 0) {
  //    return;
  //  }

  if(currentDirection_back == DIRECTION_LEFT_RIGHT) {
        if (patternLength <= currentPatternIndexSet_back){
         setNeedle_LTR_back(1);
       //  Serial.println("StateLTR:lastNeedle");
        }
         else {
      //  Serial.println("StateLTR:"+String(knitPattern_back[currentPatternIndexSet_back])+"-"+String(currentPatternIndexSet_back));
        setNeedle_LTR_back(knitPattern_back[currentPatternIndexSet_back]);
         }
  }
  else if(currentDirection_back == DIRECTION_RIGHT_LEFT) {
        if (patternLength-currentPatternIndexSet_back-1 < 0){
              setNeedle_RTL_back(1);
        // Serial.println("StateRTL:lastNeedle");
        }
       else{ 
       // Serial.println("StateRTL:"+String(knitPattern_back[patternLength-currentPatternIndexSet_back-1])+"-"+String(patternLength-currentPatternIndexSet_back-1));
        setNeedle_RTL_back(knitPattern_back[patternLength-currentPatternIndexSet_back-1]);
       }
  }
}


void setNeedle_RTL(char state) {
  //change state because the E6000 sets needle by 0
  //  Serial.print("-");
  //  Serial.print(String(0+state));
//  if(state==1){
//    state = 0;
//  } 
//  else {
//    state = 1;
//  }
  digitalWrite(PIN_NEEDLE_RTL, state);
}

void setNeedle_RTL_back(char state) {
  //change state because the E6000 sets needle by 0
//  if(state==1){
//    state = 0;
//  } 
//  else {
//    state = 1;
//  }
  digitalWrite(PIN_NEEDLE_RTL_BACK, state);
}

void setNeedle_LTR(char state) {
  //change state because the E6000 sets needle by 0
//  if(state==1){
//    state = 0;
//  }
//  else
//  {
//    state = 1;
//  }
  digitalWrite(PIN_NEEDLE_LTR, state);
}

void setNeedle_LTR_back(char state) {
  //change state because the E6000 sets needle by 0
//  if(state==1){
//    state = 0;
//  }
//  else
//  {
//    state = 1;
//  }
  digitalWrite(PIN_NEEDLE_LTR_BACK, state);
}


void interruptPinChangeEncoder() {

  unsigned long now = micros();
  if (now - lastCursorChange < 1000) {
    lastCursorChange = now;
    return;
  }
  lastCursorChange = now;

  char currentPinChangeValue = digitalRead(PIN_CSENSE);
  char currentPinChangeOppositeValue = digitalRead(PIN_CREF);

  //  Serial.print(String(0+currentPinChangeValue));
  //  Serial.print("-");
  //  Serial.println(String(0+currentPinChangeOppositeValue));

  // Determine direction
  if(currentPinChangeValue == currentPinChangeOppositeValue) {
    currentDirection = DIRECTION_LEFT_RIGHT;
  } 
  else {
    currentDirection = DIRECTION_RIGHT_LEFT;
  }

  // RTL = 1, LTR = -1
  currentCursorPosition += currentDirection; 

  // Serial.print(String(currentPatternIndex));
  // Serial.print("-");
  // Serial.print(String(currentCursorPosition));



  //debug cursorposition
  //  if(currentCursorPosition==0){
  //  sendCommand(COM_CMD_RESPONSE, String(currentCursorPosition));
  ////sendCommand(COM_CMD_RESPONSE, String(firstNeedle));
  //  }


  if (currentCursorPosition >20 && currentCursorPosition < 420  ){   // Check if we're in range of our needles
    if((currentDirection == DIRECTION_RIGHT_LEFT && currentCursorPosition > offsetCarriage_RTL + firstNeedle) ||
      (currentDirection == DIRECTION_LEFT_RIGHT && currentCursorPosition - offsetCarriage_LTR  <= patternLength*2 + firstNeedle)) {
      //sendCommand(COM_CMD_RESPONSE, String(currentPatternIndex));
      if(currentPatternIndex > patternLength) {

        //Set to '1' because the E6000 sets needle by 0
        setNeedle_RTL(1);
        setNeedle_LTR(1);
        currentPatternIndex = 0;
        isKnitting = false;
        
        sendCommand(COM_CMD_PATTERN_END, "1");
      } 
      else if(isKnitting == true) {
        //        Serial.print(String(1+currentDirection));
        //        Serial.print("-");
        //        Serial.print(String(currentCursorPosition));
        //        Serial.print("-");
        //        Serial.println(String(offsetCarriage_RTL + firstNeedle));


        // React on FALLING Edge     
        if(currentPinChangeValue == 1)  {
          setNeedleByCursor(currentPatternIndex);
          currentPatternIndex++;
        }
      }
    }
  }

  // Serial.println();

  if (currentCursorPosition >30 && currentCursorPosition < 420  ){ //don't check if not in needle range
    if(lastDirection != currentDirection) {
      lastDirection = currentDirection;
      currentPatternIndex = 0;
      isKnitting = true;
      if(currentDirection == DIRECTION_RIGHT_LEFT) {
        sendCommand(COM_CMD_DIRECTION, "RTL");
      } 
      else {
        sendCommand(COM_CMD_DIRECTION, "LTR");
      }
    }
  }

  //AutoCalibrate
  passapCalibrateArray[passapCalibratePointer & 0x07] = currentPinChangeValue;
  passapCalibrateArray[(passapCalibratePointer+1) & 0x07] = currentPinChangeOppositeValue;

  if (passapCalibratePointer > 8){ // 16
    // read last 16 digits of passapCalibrateArray
    int found = 1;
    for (int i=0; i<8; i++){
      if (passapCalibrateArray[(passapCalibratePointer-i+2) & 0x07] !=
        passaptestpatter[i]) {
        found = 0;
        break;
      }
    }
    if (found){
      //sendCommand(COM_CMD_RESPONSE, "Calibrate");
      //calibrate
      currentCursorPosition = -2;
      passapCalibratePointer = 0;
    }
  }
  passapCalibratePointer = passapCalibratePointer +2;
}



void interruptPinChangeEncoder_back() {

  unsigned long now = micros();
  if (now - lastCursorChange_back < 1000) {
    lastCursorChange_back = now;
    return;
  }
  lastCursorChange_back = now;

  char currentPinChangeValue_back = digitalRead(PIN_CSENSE_BACK);
  char currentPinChangeOppositeValue_back = digitalRead(PIN_CREF_BACK);

//    Serial.print(String(0+currentPinChangeValue_back));
//    Serial.print("-");
//    Serial.println(String(0+currentPinChangeOppositeValue_back));

  // Determine direction
  if(currentPinChangeValue_back == currentPinChangeOppositeValue_back) {
  //    currentDirection_back = DIRECTION_LEFT_RIGHT;
  currentDirection_back = DIRECTION_RIGHT_LEFT;
  } 
  else {
//      currentDirection_back = DIRECTION_RIGHT_LEFT;
    currentDirection_back = DIRECTION_LEFT_RIGHT;
  }

  // RTL = 1, LTR = -1
  currentCursorPosition_back += currentDirection_back; 

//   Serial.print(String(currentPatternIndex_back));
//   Serial.print("-");
//   Serial.print(String(currentCursorPosition_back));



  //debug cursorposition
  //  if(currentCursorPosition==0){
  //  sendCommand(COM_CMD_RESPONSE, String(currentCursorPosition));
  ////sendCommand(COM_CMD_RESPONSE, String(firstNeedle));
  //  }


  if (currentCursorPosition_back >20 && currentCursorPosition_back < 420  ){   // Check if we're in range of our needles
    if((currentDirection_back == DIRECTION_RIGHT_LEFT && currentCursorPosition_back > offsetCarriage_RTL_back + firstNeedle) ||
      (currentDirection_back == DIRECTION_LEFT_RIGHT && currentCursorPosition_back - offsetCarriage_LTR_back  <= patternLength*2 + firstNeedle)) {
      //Serial.println("CPI"+String(currentPatternIndex_back));
      if(currentPatternIndex_back > patternLength) {

        //Set to '1' because the E6000 sets needle by 0
        setNeedle_RTL_back(1);
        setNeedle_LTR_back(1);
        currentPatternIndex_back = 0;
        //isKnitting = false;

       // sendCommand(COM_CMD_PATTERN_END, "1");
      } 
      else if(isKnitting == true) {
//                Serial.print(String(1+currentDirection_back));
//                Serial.print("-");
//                Serial.print(String(currentCursorPosition_back));
//                Serial.print("-");
//                Serial.println(String(offsetCarriage_RTL_back + firstNeedle));


//        // React on FALLING/RAISING edge depending on direction  
//       if (currentDirection_back == DIRECTION_RIGHT_LEFT){
//       reactOnEdge_back = 1;
//       }
//       else{
//       reactOnEdge_back = 0;
//       }
       
        
        if(currentPinChangeValue_back == 1)  {
          setNeedleByCursor_back(currentPatternIndex_back);
         // Serial.println("PI: "+String(currentPatternIndex_back));
          currentPatternIndex_back++;
        }
      }
    }
  }

  // Serial.println();

  if (currentCursorPosition_back >30 && currentCursorPosition_back < 420  ){ //don't check if not in needle range
    if(lastDirection_back != currentDirection_back) {
      lastDirection_back = currentDirection_back;
      currentPatternIndex_back = 0;
      //isKnitting = true;
      if(currentDirection_back == DIRECTION_RIGHT_LEFT) {
        sendCommand(COM_CMD_DIRECTION, "RTL_back");
      } 
      else {
        sendCommand(COM_CMD_DIRECTION, "LTR_back");
      }
    }
  }

  //AutoCalibrate
  passapCalibrateArray_back[passapCalibratePointer_back & 0x07] = currentPinChangeValue_back;
  passapCalibrateArray_back[(passapCalibratePointer_back+1) & 0x07] = currentPinChangeOppositeValue_back;

  if (passapCalibratePointer_back > 8){ // 16
    // read last 16 digits of passapCalibrateArray
    int found = 1;
    for (int i=0; i<8; i++){
      if (passapCalibrateArray_back[(passapCalibratePointer_back-i+2) & 0x07] !=
        passaptestpatter_back[i]) {
        found = 0;
        break;
      }
    }
    if (found){
      //sendCommand(COM_CMD_RESPONSE, "Calibrate_back");
      //calibrate
      currentCursorPosition_back = 1;
      passapCalibratePointer_back = 0;
    }
  }
  passapCalibratePointer_back = passapCalibratePointer_back +2;
}