I tried unsuccessfully to use a binary communication scheme and ended up switching to ASCII and upping the speed to 115200 bauds. The Arduino code now uses the Messenger library which works quite well.
Here is a really ugly picture of the assembly: (stepper not included in picture)
Here is the Arduino sketch:
#includeMessenger message = Messenger(); ////// ED_v4 Step Mode Chart ////// // // // MS1 MS2 Resolution // // L L Full step (2 phase) // // H L Half step // // L H Quarter step // // H H Eighth step // // // //////////////////////////////////// const int DIR_PIN = 3; // PIN 3 = DIR const int STEP_PIN = 2; // PIN 2 = STEP const int MS1_PIN = 12; // PIN 13 = MS const int MS2_PIN = 9; // PIN 9 = MS2 const int SLEEP_PIN = 11; // PIN 12 = SLP const int LED_ERR = 7; unsigned int DIV=8; unsigned int DELAY=1600/DIV; int POSITION=0; int TARGET=0; int QUANTA = 10; int DIR=1; int MOVING=0; boolean bEnabled=false; int iPos=0; int iWait=0; void SetDivider( int div ); void SendSteps( int nb=1); void SetDirection( int dir ); void setup() { pinMode(DIR_PIN, OUTPUT); // set pin 3 to output pinMode(STEP_PIN, OUTPUT); // set pin 2 to output pinMode(MS1_PIN, OUTPUT); // set pin 13 to output pinMode(MS2_PIN, OUTPUT); // set pin 9 to output pinMode(SLEEP_PIN, OUTPUT); // set pin 12 to output pinMode(LED_ERR, OUTPUT); DIV=8; DELAY=1600/DIV; SetDivider( DIV ); Serial.begin(115200); // open the serial connection at 9600bps message.attach(messageCompleted); } void loop() { // The following line is the most effective way of // feeding the serial data to Messenger while ( Serial.available() ) { message.process( Serial.read() ); } MoveQuanta(); } void SendSteps( int nb) { for( int i=0; i<nb; ++i ) { // This LOW to HIGH change is what creates the.. digitalWrite(STEP_PIN, LOW); // .."Rising Edge" so the easydriver knows to when to step. digitalWrite(STEP_PIN, HIGH); delayMicroseconds(DELAY); } } void SetDirection( int dir ) { if( dir>0 ) { // CLOCKWISE DIR=1; digitalWrite(DIR_PIN, LOW); } else { // COUNTER-CLOCKWISE DIR=-1; digitalWrite(DIR_PIN, HIGH); } } void SetDivider( int div ) { switch( div ) { case 1: digitalWrite(MS1_PIN, LOW); digitalWrite(MS2_PIN, LOW); break; case 2: digitalWrite(MS1_PIN, HIGH); digitalWrite(MS2_PIN, LOW); break; case 4: digitalWrite(MS1_PIN, LOW); digitalWrite(MS2_PIN, HIGH); break; case 8: digitalWrite(MS1_PIN, HIGH); digitalWrite(MS2_PIN, HIGH); break; } } void MoveQuanta() { if( bEnabled ) { if( TARGET > POSITION ) { MOVING=1; SetDirection( 1 ); int steps = min(TARGET-POSITION, QUANTA); SendSteps( steps ); POSITION += steps; } else if( TARGET < POSITION ) { MOVING=1; SetDirection( -1 ); int steps = min(POSITION-TARGET, QUANTA); SendSteps( steps ); POSITION -= steps; } else { MOVING=0; } } } // Define messenger function void messageCompleted() { // commands: // e Enable Drives // d Disable Drives // sd999 Set Divider <int> // sw999 Set Wait <int> // gp Get Position // gd Get Divider // gw Get Wait // ma999 Move Absolute <int> // mr999 Move Relative <int> // rp Reset Position // x Stop All Movements if ( message.checkString("e") ) { /////////////////////////////////////// Enable digitalWrite(SLEEP_PIN, HIGH); bEnabled=true; } else if ( message.checkString("d") ) { /////////////////////////////////////// Disable digitalWrite(SLEEP_PIN, LOW); bEnabled=false; } if ( message.checkString("sd") ) { /////////////////////////////////////// Set Div int div = message.readInt(); if( div == 1 || div == 2 || div == 4 || div == 8 ) { DIV=div; SetDivider( DIV ); } } else if ( message.checkString("sw") ) { /////////////////////////////////////// Set Wait DELAY = message.readInt(); } else if ( message.checkString("sq") ) { /////////////////////////////////////// Set Quanta QUANTA = message.readInt(); } if ( message.checkString("im") ) { /////////////////////////////////////// Is Moving Serial.println( MOVING, DEC ); } if ( message.checkString("gd") ) { /////////////////////////////////////// Get Div Serial.println( DIV, DEC ); } else if ( message.checkString("gw") ) { /////////////////////////////////////// Get Wait Serial.println( DELAY, DEC ); } else if ( message.checkString("gp") ) { /////////////////////////////////////// Get Position Serial.println( POSITION, DEC ); } else if ( message.checkString("gq") ) { /////////////////////////////////////// Get Quanta Serial.println( QUANTA, DEC ); } else if ( message.checkString("gt") ) { /////////////////////////////////////// Get Target Serial.println( TARGET, DEC ); } if ( message.checkString("ma") ) { /////////////////////////////////////// Move Absolute if( bEnabled ) { int pos = message.readInt(); TARGET = pos; } } else if ( message.checkString("mr") ) { /////////////////////////////////////// Move Relative if( bEnabled ) { int pos = message.readInt(); TARGET += pos; } } else if ( message.checkString("rp") ) { /////////////////////////////////////// Reset Position POSITION=0; TARGET=0; } else if ( message.checkString("x") ) { /////////////////////////////////////// STOP! // stop on next MoveQuanta TARGET=POSITION; } else { digitalWrite( LED_ERR, HIGH ); } }
And here is the Python Stepper class:
# -*- coding: utf-8 -*- import serial import time ## The arduino can be reset by putting the DTR pin high, then low. ## This is normally done on connection by the PySerial module (on windows). ## This means that everytime a connection is made to the arduino, a reset is sent ## and about 5 seconds are necessary before sending commands. To prevent this, the ## line 61 in C:\Python26\Lib\site-packages\serial\serialwin32.py must be changed ## from: ## self._dtrState = win32file.DTR_CONTROL_ENABLE ## to: ## self._dtrState = win32file.DTR_CONTROL_DISABLE class Stepper: def __init__( self, COMPort ): self.COMMAND_ENABLE = "e" # no parameters self.COMMAND_DISABLE = "d" # no parameters self.COMMAND_SET_DIV = "sd " # <int> self.COMMAND_SET_WAIT= "sw " # <int> self.COMMAND_SET_QUANTA= "sq " # <int> self.COMMAND_GET_DIV = "gd" # no parameters self.COMMAND_GET_WAIT = "gw" # no parameters self.COMMAND_GET_QUANTA = "gq" # no parameters self.COMMAND_GET_TARGET = "gt" # no parameters self.COMMAND_GET_POSITION = "gp" # no parameters self.COMMAND_MOVE_ABS = "ma " # <int> self.COMMAND_MOVE_REL = "mr " # <int> self.COMMAND_RESET_POSITION = "rp" # no parameters self.COMMAND_STOP = "x" # no parameters self.COMMAND_IS_MOVING = "im" # no parameters self.Arduino = serial.Serial(COMPort, 115200, 8, 'N', 1 ) self.Arduino.open() def __del__(self): pass self.Disable() #self.Arduino.close() def _SendCommmand(self, command ): self.Arduino.write( command + "\r" ) def Enable(self): self._SendCommmand( self.COMMAND_ENABLE ) def Disable(self): self._SendCommmand( self.COMMAND_DISABLE ) def SetDiv(self, div): if div in [1,2,4,8]: self._SendCommmand( self.COMMAND_SET_DIV + str( div ) ) def GetDiv(self): self._SendCommmand( self.COMMAND_GET_DIV ) ret = self.Arduino.readline() return int(ret) def SetWait(self, wait): self._SendCommmand( self.COMMAND_SET_WAIT + str( wait ) ) def GetWait(self): self._SendCommmand( self.COMMAND_GET_WAIT ) ret = self.Arduino.readline() return int(ret) def SetQuanta(self, wait): self._SendCommmand( self.COMMAND_SET_QUANTA + str( wait ) ) def GetQuanta(self): self._SendCommmand( self.COMMAND_GET_QUANTA ) ret = self.Arduino.readline() return int(ret) def GetTarget(self): self._SendCommmand( self.COMMAND_GET_TARGET ) ret = self.Arduino.readline() return int(ret) def MoveRel(self, position): self._SendCommmand( self.COMMAND_MOVE_REL + str( position ) ) def MoveAbs(self, position): self._SendCommmand( self.COMMAND_MOVE_ABS + str( position ) ) def GetPosition(self): self._SendCommmand( self.COMMAND_GET_POSITION ) ret = self.Arduino.readline() return int(ret) def ResetPosition(self): self._SendCommmand( self.COMMAND_RESET_POSITION ) def Stop(self): self._SendCommmand( self.COMMAND_STOP ) def IsMoving(self): self._SendCommmand( self.COMMAND_IS_MOVING ) ret = self.Arduino.readline() return int(ret) == 1 def Reset(self): self.Arduino.setDTR( True ) self.Arduino.setDTR( False ) #should wait a few seconds after this! time.sleep(2)