Communicating with Peter Norburg Stepper Board

Hi All,

This is the first project that I've had to communicate between a separate board and and Arduino via TTL. I'm building a little CNC bed for a sculpture that uses a Peter Norburg SD4D stepper controller card and two bipolar 3A stepper motors. The Norburg card is nice for this, as you can throw it commands and it will automatically sync the motors, plus automatically calculate arcs and circles for the bed. The board I'm using is below:

The Norburg card sends an "" charachter after its completed a move to tell you that its ready for the next command. So, for instance, if I wanted my bed to move 1000 steps in the X direction, I would first send it "1000X", wait for the "" response, then send it "G", which tells it to go. After the motors complete this movement, it responds with a "*" again. I have the RX (pin 0) connected to the SO (Serial Out) and TX(pin 1) to SI(Serial In) on the Norburg. The stepper board comes with a Simple Serial program where you can issue line commands via USB. I've done this and can get both motors to follow simple X & Y commands, so I know the connection between the stepper board, stepper drivers and motors is working fine.

So, I've searched the internets for some code to poll for the "*" and found the following. This works, but its patchy. Say, it may get through 70% of the commands, but then just hangs. I've got a few things that I'm unfamiliar with or have reoccuring problems:

  1. I/O & USB problems at Upload: I seem to keep getting "avrdude: stk500_getsync(): not in sync: resp=0x00" message when I try up upload new code when my IO wires are connected. Any way around this?

2)Serial Monitor vs I/O: Whats the different between Serial.print and Serial.write? If I'm using Serial.Print to show whats up on the Serial Monitor, are these also getting sent to the stepper controller? Or, is it only when Serial.write is used that data is sent via the I/O pins? Because when I'm just printing my operations via Serial.Print at the beginning of my code, the motors seem to be freaking out a little bit. Actually, just opening or closing the Serial Monitor window seems to have an effect on my code. If I comment out the Serial.Print commands, the motors seems to stay idle.

  1. As I mentioned above this code gets part way through the command list, but then just hangs. The Serial Monitor shows that "*" charachters are being returned. But for some reason it just balls up. Any ideas on how to debug this so that I can see if what commands are being issued to the stepper board?
/*
CNC Bed Sketch 

This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
 
 
*/

//******************Constants***********
char* stepCommand[] = {    //Load up CNC Patterns into string array
  "1000X",
  "G", 
  "-1000X",
  "G",
  "0X",
  "G",
  "1000Y",
  "G",
  "-1000Y",
  "G",
  "0Y",
  "G"
  };
  
 const int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size
 

//******************Variables***********
String readString;
String writeString;
int commandNumber = 0;
//****************Function Prototypes******


//***************Setup******************************
void setup() {
  Serial.begin(9600);    //Begin serial communication at 9600
  pinMode(0, INPUT);      //0 Pin is RX
  pinMode(1, OUTPUT);    //1 Pin is TX
  
  //Serial.write ("200R");                //Set Run Rate to 200 steps/sec
  //Serial.write("-12?");              //This line returns SD4D firmware version. Uses to check polling code below
 
  Serial.println("Starting Serial"); //Signal start of communication
 
  Serial.print("String Array Size = ");
  Serial.println(numCommands);
  
  Serial.println("<<<<<Commands Below>>>>>>");    //This just prints the given string commands to see if they are being sent correctly
  for (int i = 0; i < numCommands; i++){
   Serial.println(stepCommand[i]);
   delay(500);
   }
  Serial.print("<<<<<Commands Above>>>>>");
  
  delay(1000);
}

//*************Main Program Loop************************
void loop() {
    while(Serial.available() > 0){
      delay(100);
      char c = Serial.read();   //get one byte from buffer
      readString += c;
      if(c== '*'){
        Serial.write(stepCommand[commandNumber]);
        commandNumber++;
          if(commandNumber == numCommands){    //if the max number of commands is reached...
            commandNumber = 0;                //reset command number back to zero
          }
        //delay(500);
        break;
      }  
    }
    if(readString.length() > 0){
      Serial.println(readString);
      readString = "";  //clears variable for new input
   }
}
//*********************FUNCTIONS***************************

//**************************************************************************

This is what comes up on my Serial Monitor:

h1000X (The "h" command isn't in the above code. I added that and its a status ping for the stepper board)
I4* (the I4 is the status return)
G
*
-1000X
*
G
*
0X
*
G
*
1000Y
*
G
*
-1000Y

I deleted a LOT of carriage returns from the Serial Monitor. The carriage returns increase as the commands are issued. By the time I get to where the code balls up, its all carriage returns. I don't know what that means.

Thanks for any help! Let me know if I'm leaving out any info....
--. Karl

Your primary problem is with your calculation of the size of your Command array.

stepCommand is essentially a 2d array (and a jagged one at that).
This: char* stepCommand[] is the same as this: char stepCommand[][]
Your calculation of the number of elements in this array is incorrect. It's basically returning the total number of characters in the array, not the number of full command strings. The way you're defining the array, there's no easy way to calculate the number of commands in the array. Best to just handle that semi-manually, either with a #define or a const param. I would include this value in the declaration of your array as well, like:

char* stepCommand[numCommands]

Doing so will cause a compile error if your param does not agree with your array (if you add another command to the array and forget to update numCommands value, it won't compile)

Beyond that, you'll likely run into problems with your String objects as well. Best just not to use them. They thrash memory pretty hard.
And while this probably isn't exhibiting itself as any sort of problem, there's no reason to have a delay between Serial.available() and Serial.read().

Thanks for the help! I'm going to try your suggestions. A couple clarification questions:

Your calculation of the number of elements in this array is incorrect. It's basically returning the total number of characters in the array, not the number of full command strings. The way you're defining the array, there's no easy way to calculate the number of commands in the array. Best to just handle that semi-manually, either with a #define or a const param.

const int numCommands = (sizeof(stepCommand)/sizeof(char*));
This line of code gives me a value of 12, which seems to be right to me. Maybe even though I have 12 commands, this isn't the correct array size? I'm going to try your method, just trying to figure out why this doesn't work so I can understand what going on here.

Beyond that, you'll likely run into problems with your String objects as well. Best just not to use them. They thrash memory pretty hard.

The stepper board is controlled with commands like "1000X" which is a string, right? How would I get around using string objects?

Thanks a ton,
-->K

AXNRXN:
const int numCommands = (sizeof(stepCommand)/sizeof(char*));
This line of code gives me a value of 12, which seems to be right to me. Maybe even though I have 12 commands, this isn't the correct array size? I'm going to try your method, just trying to figure out why this doesn't work so I can understand what going on here.

Hmm, apparently I have misunderstood how sizeof() works in that situation. If it's returning the correct array size, then ignore my comments, they're apparently incorrect.

On the String objects though, your commands are stored in C strings, which are just arrays of chars. The String objects I'm referring to are

String readString;
String writeString;

Those are String objects. The String class isn't working properly in the current version of Arduino and causes memory leaks over time. Switch them to C strings as well.

As for your other questions...

1: You cannot have multiple devices connected to the serial port at the same time. If your stepper controller is connected to the serial port, then you can't connect to it with your PC (the usb port ties into that serial port. The Uno only has the 1 hardware uart). You could move the stepper controller to a softwareserial port on any of the other pins, allowing you to communicate with the Uno with the computer via USB while it's connected to the stepper controller.

2: Serial.print(100) will send the string "100" out the serial port as 3 bytes of data corresponding the characters 1, 0, and 0. It converts data to human readable ascii. Serial.write(100) sends the numeric value of 100 out the serial port as a single byte of data. When transmitting char data the output is the same either way. In general though, if the intent is to transmit human readable text, use print/println.

Okay. I think I understand what going on a little more. Thanks for your help!

Now, I've dicked around with the code and found that the Serial.print command is what screwing everything up. I commented out all the lines of code that I intended to print to the Serial Monitor and the bed is moving as expected. How can I separate the instructions for the stepper board from the data I'd like to print on the Serial Monitor. Is software.serial the solution here?

/*
CNC Bed Sketch 

This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
 
 
*/

//******************Constants***********

const int numCommands = 12;
char* stepCommand[numCommands] = {    //Load up CNC Patterns into string array
  "1000X",
  "G", 
  "-1000X",
  "G",
  "0X",
  "G",
  "1000Y",
  "G",
  "-1000Y",
  "G",
  "0Y",
  "G"
  };
 

//******************Variables***********
String readString;
String writeString;
int commandNumber = 0;
//****************Function Prototypes******


//***************Setup******************************
void setup() {
  Serial.begin(9600);    //Begin serial communication at 9600
  pinMode(0, INPUT);      //0 Pin is RX
  pinMode(1, OUTPUT);    //1 Pin is TX
  
  Serial.write("*");      //send initial "*" to start Stepperboard
 /*
  Serial.println("Starting Serial"); //Signal start of communication
 
  Serial.print("String Array Size = ");
  Serial.println(numCommands);
  
  Serial.println("<<<<<Commands Below>>>>>>");    //This just prints the given string commands to see if they are being sent correctly
  for (int i = 0; i < numCommands; i++){
   Serial.println(stepCommand[i]);
   delay(500);
   }
  Serial.print("<<<<<Commands Above>>>>>");
  */
  delay(1000);
}

//*************Main Program Loop************************
void loop() {
    while(Serial.available() > 0){
      delay(100);                //Wait for buffer to fill
      char c = Serial.read();   //get one byte from buffer
      readString += c;
      if(c== '*'){
        Serial.write(stepCommand[commandNumber]);
        commandNumber++;
          if(commandNumber == numCommands){    //if the max number of commands is reached...
            commandNumber = 0;                //reset command number back to zero
          }
        //delay(500);
        break;
      }  
    }
    //if(readString.length() > 0){
    //  Serial.println(readString);
     // readString = "";  //clears variable for new input
  // }
}
//*********************FUNCTIONS***************************

//**************************************************************************

And while this probably isn't exhibiting itself as any sort of problem, there's no reason to have a delay between Serial.available() and Serial.read().

FYI. I tried taking out the delay here and the while loop just runs through. There needs to be a slight delay in order for the buffer to load in a character, it seems.

About the Strings Objects:
You recommend dealing with collecting the incoming characters in an array rather than the string object? Like how I loaded all my command strings into the char* stepCommand[ ] array?

Using SoftwareSerial:
If I move the stepperboard IO to two other pins, will that send all Serial.println commands ONLY to the serial monitor and my Serial.write commands ONLY to my stepperboard? I'm trying to figure how I can print debug data to the serial monitor without freaking out the stepperboard.

Thanks a lot for your help. I'm psyched that I have this thing moving around now. Cool shit.

--> Karl

FYI. I tried taking out the delay here and the while loop just runs through. There needs to be a slight delay in order for the buffer to load in a character, it seems.

Serial.available() returns the number of characters currently in the buffer. If it returns a value greater than zero, then there are that many characters in the buffer right then and there. If removing the delay() caused your code not to work the way you want, then that's symptomatic of another problem.

You recommend dealing with collecting the incoming characters in an array rather than the string object?

Yes.

Like how I loaded all my command strings into the char* stepCommand[ ] array?

Sorta. Working with C strings requires more effort than working with String objects, which is why most people are so fond of using Strings. If you aren't very familiar with manipulating C strings, googling C string tutorial should provide plenty of guidance. There are a lot of C library functions for handling all the heavy lifting, so it's not all that much more effort than using a String class. It's just not all wrapped up in a nice package for you.

If I move the stepperboard IO to two other pins, will that send all Serial.println commands ONLY to the serial monitor and my Serial.write commands ONLY to my stepperboard? I'm trying to figure how I can print debug data to the serial monitor without freaking out the stepperboard.

If you use the software serial class to communicate with the stepperboard, you'll create a new serial object associated with those pins and use that object to communicate with the board, not Serial. Something like...

SoftwareSerial StepperSerial(RXpin, TXpin);

//Send command to stepper board
StepperSerial.write(Command);

//Send message to Serial Monitor
Serial.println("Message out.");

There are plenty of examples out there using the SoftwareSerial library as well.

Alright, I have the software.serial stuff working pretty well. My stepper commands are coming from pins 2 & 3 and don't interfere with the serial.print commands that I send to the serial monitor. There is something goofy going on with trying to receive the data from the stepper board and then print it to the monitor. This could be from some sort of interference between the serial and software.serial commands running at the same time, or like you said, maybe how I'm trying to read the string.

Serial.available() returns the number of characters currently in the buffer. If it returns a value greater than zero, then there are that many characters in the buffer right then and there. If removing the delay() caused your code not to work the way you want, then that's symptomatic of another problem.

I see what you're saying. I tried again without the delay and it seems to work now. Maybe it was just buggy before I tried the software.serial method.

/*
CNC Bed Sketch 

This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
 
 
*/

//******************Constants***********
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX

char* stepCommand[] = {    //Load up CNC Patterns into string array
  "10000X",
  "G", 
  "-10000X",
  "G",
  "0X",
  "G",
  "10000Y",
  "G",
  "-10000Y",
  "G",
  "0Y",
  "G"
  };
 
const int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size

//******************Variables***********
String readString;
int commandNumber = 0;
//****************Function Prototypes******


//***************Setup******************************
void setup() {
  Serial.begin(9600);    //Begin serial communication at 9600
  
  mySerial.begin(9600);  //Set software serial baud rate
  
  mySerial.write("!");      //reset Stepper Board
  delay(50);
  mySerial.write("1500R");  //Set Run Rate
  delay(50);
  mySerial.write("800P");  //Set Ramp Rate
  delay(50);
 
  Serial.println("Starting Serial"); //Signal start of communication
 
  Serial.print("String Array Size = ");
  Serial.println(numCommands);
  
  Serial.println("<<<<<Commands Below>>>>>>");    //This just prints the given string commands to see if they are being sent correctly
  for (int i = 0; i < numCommands; i++){
   Serial.println(stepCommand[i]);
   }
   
  Serial.print("<<<<<Commands Above>>>>>");
  
  delay(1000);
}

//*************Main Program Loop************************
void loop() {
    while(mySerial.available()){
      //delay(100);                //Wait for buffer to fill
      char c = mySerial.read();   //get one byte from buffer
      readString += c;
      if(c== '*'){
        mySerial.write(stepCommand[commandNumber]);
        Serial.println(stepCommand[commandNumber]);
        commandNumber++;
          if(commandNumber == numCommands){    //if the max number of commands is reached...
            commandNumber = 0;                //reset command number back to zero
          }  
        break;
      }  
    }
    if(readString.length() > 0){
      Serial.println(readString);
      readString = "";  //clears variable for new input
   }
}
//*********************FUNCTIONS***************************

//**************************************************************************

This is the output from the serial monitor. You can see that the list of commands print to the monitor fine. But, the strings put together by the "readString" object come out all jumbled. My cut-n-paste doesn't show it, but add hieroglyphic symbols appear where a blank space is shown below. Even though this comes out with weird charachters, my motors are moving according to plan. I've seen this before with mismatched baud rates, but everything here is 9600. It doesn't seem to affect the operation of the CNC bed, so I guess its no big deal.

Starting Serial
String Array Size = 12
<<<<>>>>>
10000X
G
-10000X
G
0X
G
10000Y
G
-10000Y
G
0Y
G
<<<<>>>>10000X

M1,-12
SD4DNCRouter 4.3 Oct 3, 2011
o?
*
G
?
*
-10000X
?
*
G
?
G3*
0X
?
*
G
?
G2*
10000Y
?
*
G
?
G1*
-10000Y
?
*
G
?
G0*
?
?

0Y
G0*

Thanks for your help. Much appreciated. I'll review C strings and see if I can make all that work.

Hi There! I'm back with another question. I have my system running pretty good. I've been having trouble communicating with the stepper controller board with respect to reading limit switches when they are triggered on the ends on my CNC bed. So, my code just issues a simple back-and-forth command for the X-axis stepper motor. While this is in motion, I trigger the +X limit switch and try to record the response. The data coming from the stepper board load up into a String object. I know I should change this to an C string array, but its just easier for me at the moment to work with the Objects. Once I have a better handle on it, I'll try to convert my readString object to a character array. Anywho, if I poll the stepper board with an "L" character, it responds with info on what going on with the limit switches. It so happens that "L,16392" corresponds to the +X limit switch getting tripped. I compare my readString to this string value with an IF statement, but even though the output on the Serial Monitor seems to look the same, the code does not consider them equal. I tried if(readString == String("L,16392")) as well, but that just has the same results. Any ideas? Code and Serial Monitor output below:

/*
CNC Bed Sketch 

This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
 
 
*/

//******************Constants***********
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX

char homePosition[5] = "0XYG";



//******************Variables***********

String readString;
int commandNumber = 0;
int numCommands = 0;


//****************Function Prototypes******
long convertToSteps(int inches);

//***************Setup******************************
void setup() {
  delay(1000);
  
  Serial.begin(9600);    //Begin serial communication at 9600
  mySerial.begin(9600);  //Set software serial baud rate
  
  randomSeed(analogRead(0)); 
  
  // Initialize Stepperboard Values
  mySerial.write("!");      //reset Stepper Board
  delay(50);
  mySerial.write("1500R");  //Set Run Rate
  delay(50);
  mySerial.write("800P");  //Set Ramp Rate
  delay(1000);
}

//*************Main Program Loop************************
void loop() {
 
 
 char* stepCommand[] = {    //Load up CNC Patterns into string array
 "30000XG", 
 "-30000XG"
  }; 
 
 int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size

 while(mySerial.available()){
   char c = mySerial.read();   //get one byte from buffer
   readString += c;
   if(c== '*'){
     mySerial.write(stepCommand[commandNumber]);
     Serial.print(stepCommand[commandNumber]);
     Serial.println(" --> IF LOOP");
     commandNumber++;
     if(commandNumber == numCommands){    //if the max number of commands is reached...
        commandNumber = 0;                //reset command number back to zero
     }  
     break;
   } 
 }

 mySerial.write("L");
  
 if(readString.length() > 0){
   Serial.println(readString + " --> ReadString"); 
   if(readString == "L,16392"){
     Serial.println("Write Q Here");
   }
   else{
     Serial.println("Strings not Egual");
   }
   readString = "";  //clears variable for new input
   }
}
//*********************FUNCTIONS***************************
long convertToSteps(int inches){
  long steps = 130435 * inches;  //there are 130435 steps in 1-inch
  return(steps);
}
//**************************************************************************

L,0

  • --> ReadString
    Strings not Egual
    -30000XG IF LOOP
    ?
    ?
    ?
    L,0
  • --> ReadString
    Strings not Egual
    30000XG IF LOOP
    ?
    ?
    ?
    L,16392
  • --> ReadString
    Strings not Egual
    -30000XG IF LOOP
    ?
    ?
    ?
    L,16392
  • --> ReadString
    Strings not Egual
    30000XG IF LOOP