RLS Orbis - encoder

Hi,

Anyone tried to implement this type of encoder? I tried but only get rubbish data.

https://www.rls.si/eng/fileuploader/download/download/?d=1&id=171&title=Data+Sheet%3A+Orbis™+true+absolute+rotary+encoder+(BRD01)

// Delay (us) after CS gets low and SPI communication starts
#define RLS_ORBIS_CS_DELAY 3

unsigned int readEncoderPos()
{
    SPI.beginTransaction(SPISettings(1'000'000, MSBFIRST, SPI_MODE0));

    digitalWrite(chip_select_pin, LOW);

    // wait at least 2.5us, as per datasheet.
    delayMicroseconds(RLS_ORBIS_CS_DELAY);

    unsigned int reading = SPI.transfer16(0x3300);  // 0x3300, since we're sending MSB first.

    digitalWrite(chip_select_pin, HIGH);

    // not needed if you moved SPI.beginTransaction() to setup. 
    SPI.endTransaction();

    Serial.print("reading: ");
    Serial.println(reading);

    // shift out the 2 status bits
    return reading >> 2;
}

Thanks!

I’ve had a quick scan of datasheet. 0x33 is a command for usart but you are using spi, so that is not a valid command.

I expect the following applies:

If command byte does not match any of listed commands, encoder will send only Position, Status, CRC data. If additional data is 
not required, MOSI line of the encoder should be tied to GND.

I think crc+status+position might be 5bytes long so you might need 5x spi.transfer(0x0).

Or you could try a valid cmd e.g temp which i think means you want spi.transfer(0x74) + 6x spi.transfer(0x00) as i think that is a 7 byte command

Hi Owen,

I try read 5 bytes but data looks wierd, always different without touching the motor shaft, encoder also light green = encoder position is valid, I tried also different speeds and modes.

 FF FF FF FF 1
 FF FF FF FF FF
 FF FF F8 0 1
 FF FF FF FF FF
 FF FF FF FF F8
 FF FF FF FF 80
 FF FF FF FF 0
 FF FF FF 80 0
 FF FF 0 0 0
 C0 0 0 0 0
uint8_t buffer[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t encoder_buffer_size = 5;

unsigned int readEncoderPos()
{
    // Setting speed to 1MHz, but the encoder can probably do better

    SPI.beginTransaction(SPISettings(1'500'000, MSBFIRST, SPI_MODE0));

    digitalWrite(chip_select_pin, LOW);

    // wait at least 2.5us, as per datasheet.
    delayMicroseconds(3);

    for (uint8_t n = 0; n < encoder_buffer_size; ++n)
    {
      buffer[n] = SPI.transfer(0x0);
    }
    digitalWrite(chip_select_pin, HIGH);

    // not needed if you moved SPI.beginTransaction() to setup. 
    SPI.endTransaction();

    // shift out the 2 status bits
    return 0.0;
}

for (uint8_t n = 0; n < encoder_buffer_size; ++n)
{
  Serial.print(" ");
  Serial.print(buffer[n], HEX);
}
Serial.println("");

Couple of things to try/check.

1.The datasheet calls for a pause time of 20us before pulling chip select high
2. Some beginTransaction, endTransaction implementations do the chipselect high/low themselves if you’ve passed in an optional pin select pin. Might be worth stepping through to see if chip select is happening earlier than you think.
3. It looks like you print outs are ‘slipping’ to right which might suggest the output is 6 or 7 bytes. Maybe try using a known command e.g temp which has a documented length

1 Like

Hi,

I manage to get the data output correct when put little higher delay between readings and constant read 6 bytes, Thanks!

But something is going on with sensor.update() without it the output is stable and return correct angle all the time.

2.45
2.45
2.45
2.45
2.45
2.45

But once I call sensor.update() before it start to jump between correct value (2.45) to 12.05, why is this?

2.45
12.05
2.45
2.45
12.05
2.45
2.45
2.45
2.45
2.45
2.45

That is odd. Probably need to see more of your code. Does your loop look something like this?

void loop() {
  sensor.update();
  Serial.println(sensor.getAngle());
}

Maybe you can put some addional logging in the sensor.update() function.
The sensor.getAngle() returns a cached value that is created during the sensor.update(); function (which calls your getSensorAngle() function). Perhaps there is some bug with the way full_rotations is being worked out?

Hi,

You are right, using getAngle() the value looks correct, do you know how to verify the crc from encoder? I notice that sometimes it stop running and maybe that is because encoder return wrong position sometimes?

Not done much with CRCs but you could use the arduino CRC library.

I asked gpt4 how it might be used in your context and here is some code it created (the 0x97 magic number is mentioned in datasheet)

#include <CRC.h>

void setup() {
  Serial.begin(9600);
  // Wait for the serial connection to initialize
  while (!Serial) {}

  // Your data here (excluding the CRC byte)
  uint8_t data[5] = {0x01, 0x02, 0x03, 0x04, 0x05};

  // Initialize CRC8 with your specific parameters
  // Polynomial: 0x97, Initial value: 0xFF, XOR out: 0xFF (inversion), both reversals set to false based on your earlier message
  CRC8 crc(0x97, 0xFF, 0xFF, false, false);

  // Add your data to the CRC calculation
  crc.add(data, sizeof(data));

  // Calculate the CRC
  uint8_t crcResult = crc.calc();

  // Output the calculated CRC
  Serial.print("Calculated CRC: 0x");
  Serial.println(crcResult, HEX);
}

void loop() {
  // put your main code here, to run repeatedly:

}

I’ve not read through the code at all so ‘buyer beware’!

It there are CRC problems then something isn’t right with SPI, e.g. interference, wrong mode, timing, etc, so I wouldn’t want to live with spotting and ignoring CRC errors but would want to get to root cause.

1 Like

I integrated this encoder, it’s pretty nice. I even coded all the calibration routines and zero offset stuff. It is very fast and accurate. I can post up the code tomorrow if you want - FYI I did a table lookup for the crc checks

2 Likes

Hi Chris!

That would be awesome :ok_hand:

Thanks