Please help in creating programming Arduino for 3D scanning rotary table.

I own a structured light 3D scanner and I'm interested in building a rotary table controlled by the scanner's software. I couldn't find anything similar on this forum.

The commands sent and received over USB by the software follow this protocol:

General Rotary Communication Protocol

All commands sent to the rotary table are in simple character format including the motor numbers. Only the parts marked as xxx are passed to the table as byte data. For example, if you want table 1 to rotate 4 steps, instead of passing "I1M004" you pass "I1M" + (char)0 + (char)0 + (char)4 In general all commands get a reply in the form of ^XXXXXX.

Commands

V

Request the status of the rotary table. Usual reply would be ^R1R2R3R4 indicating rotary 1 ready, rotary 2 ready, etc. ^B1xxxR2R3R4 means rotary 1 is busy where xxx are 3 bytes indicates how many steps the rotary still has to perform.

SmMxxx

Sets the speed of the motor m to xxx, where xxx is a 3 bytes of data indicating the speed. Example code: port.Write("S1M" + (char)0 + (char)6 + (char)255); // set motor 1 to speed 1791. The standard speed range of our rotary table is: 0x000001 to 0x0012FF (1 to 4863). Controller will respond with ^mxx mirroring the motor number and 2 last bytes of speed setting.

ImMxxx

Turns motor m xxx number of steps. Controller will acknowledge with ^Bmxxx.

DmCWLO

Set motor number m to rotate clockwise. Each consecutive command to rotate the motor m will rotate it clockwise.

DmCWHi

Sets rotary m to rotate counterclockwise.

EmHALT

Rotary m stop.

Rotary Sample Command Sequence

Motor numbers are passed as characters but the number of steps and speed are passed as 3 bytes of binary for simplicity.

send: V reply: ^R1R2R3R4 send: S1M1791 reply: ^191 send: D1CWLO reply: ^ send: I1M100 reply: ^B1100

Thank you.

That sounds like it should be perfectly feasible. But I don't see any specific question in your post.

If you are wondering how the Arduino will take in the commands from the scanner the examples in serial input basics should be helpful

However, there may be a fly in the soup ....

When you say "The commands sent and received over USB" do mean that they are sent over a USB connection between the scanner and your PC?

How would you get the PC to pass on the commands to the Arduino?

...R

Robin2: That sounds like it should be perfectly feasible. But I don't see any specific question in your post.

If you are wondering how the Arduino will take in the commands from the scanner the examples in serial input basics should be helpful

However, there may be a fly in the soup ....

When you say "The commands sent and received over USB" do mean that they are sent over a USB connection between the scanner and your PC?

How would you get the PC to pass on the commands to the Arduino?

...R

Hello Robin2, and thanks for your prompt response.

The software that controls the scanner, Flexscan3D, is already installed in the computer and controls the scanner, which is nothing more than a projector and two inspection cameras. The projector connects to the DVI port on the computer, and the cameras connect to USB ports. The rotary table in this case, would be a stepper motor controlled by the arduino, which would respond to the commands sent to it by the software following the protocol mentioned earlier.

I have used the Device Monitoring Studio to monitor the COM port where the Arduino is connected (COM9) in this case and the Arduino is receiving the initial V command. In this particular command, the Arduino should interpret the command and respond with ^R1R2R3R4.

So basically, all the functions are controlled by the Flexscan3D software. On another Arduino loaded with GRBL and a Python script in the computer, I have been able to run a rotary by using the scripting feature on the Flexscan3D software, but since this is an external script, the Flexscan3D is no able to measure how much the object was rotated, therefore the alignment process of the scans is not performed correctly.

I will keep studying the serial input basics and posting any possible results on this section of the forum. Your help would be greatly appreciated.

Thanks again.

OK. Maybe I had things back-to-front in my mind. From your earlier description I thought the commands that you list were being RECEIVED by the PC over a USB link to the scanner.

But, if I interpret you recent Post correctly, all of the commands, for the scanner AND for the Arduino are geing generated within the PC.

Presumably you can tell the PC software to send the commands for the rotary table to the serial port/USB connection to the Arduino. Perhaps you can confirm that I now have the correct understanding?

My guess (but no more than that) is that each set of commands from the PC is terminated with CF/LF and if so CR could be used as the terminating character in the second example in serial input basics - recvWithEndMarker(). That would allow it to receive any command and your Arduino code could then look through the received data to decide what needs to happen.

For example (very crude example)

if (receivedChars[0] == 'V') {
   Serial.println("^R1R2R3R4");
}

...R

Robin2: OK. Maybe I had things back-to-front in my mind. From your earlier description I thought the commands that you list were being RECEIVED by the PC over a USB link to the scanner.

But, if I interpret you recent Post correctly, all of the commands, for the scanner AND for the Arduino are geing generated within the PC.

Presumably you can tell the PC software to send the commands for the rotary table to the serial port/USB connection to the Arduino. Perhaps you can confirm that I now have the correct understanding?

My guess (but no more than that) is that each set of commands from the PC is terminated with CF/LF and if so CR could be used as the terminating character in the second example in serial input basics - recvWithEndMarker(). That would allow it to receive any command and your Arduino code could then look through the received data to decide what needs to happen.

For example (very crude example)

if (receivedChars[0] == 'V') {
   Serial.println("^R1R2R3R4");
}

...R

Yes, Robin2. This is exactly the idea.

I was able to implement your code snippet into a sketch. Now the Flexscan3D software is detecting the rotary by running the sketch in the Arduino. Although this code allows only this (the rotary being detected), I still have to use the external script to run the actual stepper with another Arduino. Now I need to program the arduino to return the number of steps the stepper motor turned back to the software. If you have any suggestions I'm open to them since right now I have two Arduinos working, one for returning the motors ready response = ^R1R2R3R4, and another for actually turning the rotary.

Be aware that these are the only two commands I'm really interested in running:

• V: For the software to detect the rotary, and • S1M1791: For moving the rotary and responding with the amount of steps the motor moved.

I am really not interested in changing the direction of the motor.

Even if I had to keep using two Arduinos wouldn't be a problem. As long as the one used to respond keeps returning the motors ready response and an arbitrary number of steps back to the PC and Flexscan software. I could then adjust the number of steps necessary for the rotary table to rotate the required distance to match the angle specified by the software.

In other words, as a workaround, I could use a "dummy" Arduino to respond to the software and an active one, loaded with GRBL to move the stepper. I could do this until I learn how to actually create the program and embed it into a single Arduino.

Sorry if this sound confusing, I think I've had too much coffee today.

Thanks

seasicksinbad: Sorry if this sound confusing, I think I've had too much coffee today.

Yes, it is. Mainly because it is hard to follow multiple trains of thought at the slow speed of the Forum.

I suggest you do things step by step. The first thing I would suggest is to write an Arduino program that can construct the various replies from data in variables. Just put fixed values in the variables at this stage. Later you can update the variables from data gathered. Also just write the replies to the Serial Monitor.

You aim should be to create a series of functions that produce the appropriate replies in response to the different commands that are received. This is a very crude illustration of what I have in mind (just pseudo code)

void loop() receiveData(); if (command == 'V') doTheVstuff() respondToV() if (command == 'S') doTheSstuff() respondToS()

The functions respondToX() would be the ones to produce and send the replies

...R

This is what I got so far. Using the examples shown in serial input basics and Robin2 advice. I will keep posting as works progresses.

char receivedChar; boolean newData = false;

void setup() { Serial.begin(9600); }

void loop() { recvOneChar(); showNewData(); }

void recvOneChar() { if (Serial.available() > 0) { receivedChar = Serial.read(); newData = true; } }

void showNewData() { if (newData == true && receivedChar == 'V') { Serial.println("^R1R2R3R4"); newData = false; } }

To follow what I suggested earlier, change the name of the function showNewData() to

void checkForV() {
    if (newData == true &&
           receivedChar == 'V')
    {
    Serial.println("^R1R2R3R4");
          newData = false;
     }
}

And then you can develop similar functions for the other commands.

But the other commands have more than a single character so you will need to use recvWithEndMarker().

...R

I found this sketch which could be easily adapted to my purpose since it breaks down the commands into single components.

However, by analizing the commands Flexscan3D is sending to the Arduino, I realized there are no end markers, it just jumps from one command to the next. So I am thinking some kind of limit of characters (in this case, 6 is the max amount of characters sent by Flexscan) could be used.

The sketch below, replies back nicely using the serial monitor when it's set to Newline, but does nothing when set to No Line Ending. Any suggestions? Tank you beforehand.

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the incloming string is complete

float kp = 10;     //sample parameter 1
float kd = 5;      //sample parameter 2
float ki = 2;      //sample parameter 3


void setup() 
{
Serial.begin(9600);          //Start serial communication  
inputString.reserve(200);      //Reserves 200 bytes for the string
}

void loop()
{
//This becomes true when the serial port receives a "\n" character (end of line)
if (stringComplete)            
{
  SerialProc();                //the function which runs when a full line is received
  inputString = "";            //once processed, the string is cleared
  stringComplete = false;      //set flag to false to indicate there is nothing in the buffer waiting
}
}

void serialEvent()              //This serial event runs between each loop cycles
{
while (Serial.available())    //if there is anything in the incoming buffer this while loop runs
{
  // get the next new byte:
  char inChar = (char)Serial.read(); 
  // add it to the inputString:
  inputString += inChar;
  // if the incoming character is a newline, set a flag
  // so the main loop can do something about it:
  if (inChar == '\n') 
  {
    stringComplete = true;    //This indicates the line is complete, and the main program can process it
  } 
}
}

void SerialProc()  //the function which processes the incoming commands. It needs to be modified to your needs
{
 //first is the first character of the incoming string / line
 String first = inputString.substring(0,1);  //first  character in incoming string specifies the command
 
 //cmd is the first three characters of the incoming string / line
 String cmd = inputString.substring(0,3);  //first three characters in incoming string specifies the command

 //param is the rest of the string to the end of the line (excluding the first three characters)
 String param = inputString.substring(3, inputString.length());  //rest of incoming string is making up the parameter

 //creating a buffer as an array of characters, same size as the length of the parameters string
 char buf[param.length()];
 //moving the parameters from string to the char array
 param.toCharArray(buf,param.length());

 //the above string to char array conversion is required for the string to float 
 //conversion below (atof)

 //the below part is the command execution. Could have used a switch below, but the series of ifs
 //just did the trick

  if (first == "V")
    SendReply();
  if (cmd == "S1M")
    SendComment();                    //Executing command 1
  else if (cmd == "S2M")
    kp = atof(buf);                   //executing command 2 (setting parameter kp)
  else if (cmd == "I1M")
    kd = atof(buf);                   //executing command 3 (setting parameter kd)
  else if (cmd == "I2M")
    ki = atof(buf);                   //executing command 4 (setting parameter ki)
    if (param == "000")
    SendComment();
}

void SendReply()
{
//This is called from the SerialProc function when the V command is received
//After the last parameter (TimeDelay) it sends the carrige return characters via the Serial.println
Serial.println("^R1R2R3R4");
}
void SendComment()
{
//This is called from the SerialProc function when the S1M command is received
//After the last parameter (TimeDelay) it sends the carrige return characters via the Serial.println
Serial.println("Comment");
}

(Code Tags Please!)

seasicksinbad: However, by analizing the commands Flexscan3D is sending to the Arduino, I realized there are no end markers, it just jumps from one command to the next. So I am thinking some kind of limit of characters (in this case, 6 is the max amount of characters sent by Flexscan) could be used.

Is there a start marker? Is there a distinct time interval between messages? Even if all the commands are the same length it would be almost impossible to guarantee reliable reception without some form of marker.

Can you post an example of a succession of (say) 6 commands from Flexscan.

...R

Hello Robin2. These are examples of some of the commands Flexscan3D send to the arduino.

And this is the list of commands for calibrating the scanner in .txt format

data.txt (86.6 KB)

I see what you mean by time interval between commands, but I don't see how this can help.

Here’s a clearer representation in PDF

data.pdf (367 KB)

I can't make sense of the data links. The JPGs look like they are photos from a book. My text editor can't see anything in data.txt and the PDF has a long list without any explanation.

What I had in mind was that you would have used your Arduino to collect data without making any attempt to interpret it so that you could show a list of all the characters that the Arduino could see - including linfeeeds and such like.

An oscillocope could be very useful if you have one or can borrow one.

If there is no simpler option then it will be necessary to use the gap between messages to identify when a new message starts. This is something similar to what was eventually figured out in this long Thread to which (I think) I made a useful input.

Have you any data about how long (in millisecs) is the minimum gap?

...R

It seems like the Flexscan software does not have any type of end markers, apparently it works by sending packets with buffer sizes of 0x3 and 0x6 bytes. Could this be possible? If so, is there a way the Arduino could handle incoming data by packet size?

Also, there's an interval of .109 milliseconds between each command.

seasicksinbad:
Also, there’s an interval of .109 milliseconds between each command.

I have been looking back through your posts but the only baudrate I can see mentioned is 9600 baud. At that rate there would about 1 millisec (i.e. 10 times your number) between CHARACTERS).

If the data really is coming in so fast that there really is a delay of only 109 microsecs between messages it will be more difficult to decode - but probably possible.

Where did you get the figure of 109 usecs from?

Is there a Flexscan user manual?

Have you tried capturing a sample of the data so that you can post it here?

…R

Progress