Track position of Zaber device while moving

242 views Asked by At

I am using a Zaber linear stage controlled by an Arduino using the Zaber shield. I try to do something similar to this question (Track position of a Zaber device as it moves), but using the Arduino language instead of Labview.

In the answer 3 options were provided: interpolate from the start and end points, poll the position using a timer, or turn on a device mode that reports the position every 250 ms.

The device mode does not seem to exist for my stage (X-LSQ-075B-E01) and I don't want to rely on interpolation. The stage is fitted with an encoder and I can easily get its readback for the exact position; I just don't know how to poll the stage while moving. I came up with the following code (a bit simplified), but it is relatively slow and only gives the readback from 1 stage (we are actually using 2) and sending the command to both does not really work.

#include <ZaberAscii.h>

ZaberShield shield(ZABERSHIELD_ADDRESS_AA);
ZaberAscii za(shield);

void setup() {
  shield.begin(115200);
  Serial.begin(115200);
  za.send(1, 1, "move rel", 20000);
  za.receive();

  while (za.isIdle(1) == false) {
    za.send(1, "get encoder.pos");
    ZaberAscii::reply reply = za.receive();
    if (!reply.isReply) {
      Serial.println("*** Received a non-reply message from device " + String(reply.deviceNumber) + ".");
    }
    else if (reply.isRejected) {
      Serial.println("*** A command was rejected by device " + String(reply.deviceNumber) + ".");
    }
    else {
      Serial.println( String(reply.deviceNumber) + ": " + String(reply.responseData));
    }
    delay(5);
  }

  za.pollUntilIdle(1);
  Serial.println("1 finished");
  za.send(2, 1, "move rel", 20000);

  while (za.isIdle(2) == false) {
    za.send(2, "get encoder.pos");
    Serial.println("Device 2 not idle");
    ZaberAscii::reply reply = za.receive();
    if (!reply.isReply) {
      Serial.println("*** Received a non-reply message from device " + String(reply.deviceNumber) + ".");
    }
    else if (reply.isRejected) {
      Serial.println("*** A command was rejected by device " + String(reply.deviceNumber) + ".");
    }
    else {
      Serial.println( String(reply.deviceNumber) + ": " + String(reply.responseData));
    }
    //delay(10);
  }
  Serial.println("2 finished");
}

void loop() {}
1

There are 1 answers

2
ZaberCS On BEST ANSWER

To have it work on both devices, you would need to send both movement commands before starting the while loop, and then for the while loop you would want the condition to repeat until both axes are idle. Within the while loop you would read the position of both axes.

On the timing, can you say approximately what frequency you're getting now? The timing per communication is typically about 5-10ms. With the current functions, the isIdle() call takes it's own command, so I'd expect the above loop to be about 20-40ms. You could cut it in half by pulling the .IsBusy information from the 'get encoder.pos' reply.

Mike McDonald [email protected]