Binary rest jump

Is there a way to prevent a binary sequence recycle jump ?

I have some absolute linear encoder scales I want to combine for a DRO application. They are coded using a 3 track, pure binary system. The output position word, as far as I can tell, is a combination of the 8 bit Coarse track combined with the 9 bit Fine track for a 17 bit position word. The offset Mid track being just for noise correction of the other 2.

Here's the problem, if the output is treated as a unsigned value, the position word jumps from 131072 to 0 if the scale contains the Coarse track recycle point (goes from 255 back to 0).
If the position word is treated as a signed value, the same happens at the Coarse track mid-point where the value goes from positive to negative ( or reverse for other direction of travel) when Coarse track goes from 127 to 128.

My problem comes from the fact that I have both of these transition points (one on each of 2 different scales) that I'm trying to combine. They are not manufactured anymore so getting another scale isn't an option.

Please post a program that illustrates the problem.

Jumping from -128 to +127 seems like it could be avoided. That is the change from 0b11111111 to 0b01111111 What about you invert all the bits of Coarse before adding to Fine?

 total = (~Coarse)<<9 + Fine;

I have some absolute linear encoder scales.

Please explain what these are.

They are coded using a 3 track, pure binary system.

Please explain what this means.

8 bit Coarse track combined with the 9 bit Fine track for a 17 bit position word

Just checking, you have 17 output wires, 9 of which represent a 9 bit word indicating fine changes and 8 of which an 8 bit word, indicating course changes of position? Is this correct? If not, please clarify. A diagram of some kind might be helpful.

Does it work like this:
8 bit word goes from 0x00 to 0xff, then when it rolls over to 0x00 the 9 bit word goes from 0x000 to 0x001. Is that correct?

I suggest you put the 8 bit word into a uint8_t and the 9 bit word into a uint16_t and print both of them to the serial monitor one after the other as they change and see what happens.

The linear encoders are iGaging Absolute Origin DRO scales.
The encoded scale tape is a capacitive style that's incremented with 3 distinct tracks that the readhead detects and forms the position output Word which is a 52 bit word transmitted LSB first.

When formatted with MSB first, there are 16 unused leading '1' bits followed by 25 bits of the position (8-bit Coarse track, 8-bit Mid track, & 9-bit Fine track) and then 4 more unused '0' bits. The 16 leading and 4 lagging bits never change.

Each track is coded using a pure binary sequence with 1 complete cycle of the Fine track for a change of 1 in the Coarse track resulting in 131,072 unique position ID's over the max possible length of a scale, hence the "Absolute". One Mid track cycle covers the same distance as 16 Fine track cycles and is used for noise correction only.

The problem results from the mass production where the scale tape is a repeating full length binary sequence over and over. The tape is attached to the backing and cut to whatever length is desired.
For instance, one of my longer scales has a Coarse track that starts around 205, goes up through the recycle point of 255, and continues out to around 30.

If this was for a single scale, the answer would be easy by handling the integers as either signed or unsigned. My problem stem from needing to read 3 scales at the same time via a controller that transmits the position of each of the 3 scales to an App (Touch DRO) that uses these position inputs for Digital Read-out functions.
With one scale having a Coarse track recycle transition point and another having a Coarse track mid-point transition, one scale always has a "Jump" in position output when the transition is crossed.

For example, with the sketch coded to treat the track integers as signed, the scale with the recycle point outputs a linear position trend as it becomes less and less negative up to the transition where it goes through '0' and then positive.
At the same time, the scale with the Coarse track mid-point being treated as signed integers will output a larger value up to the mid-track transition where it goes from max positive value to the max negative value (+65535 to -65536 or vice versa depending on direction of travel) resulting in a large position jump.

I've been trying to figure out if it's possible to code each scale independently to treat the track integers as signed or unsigned based on a variable within a sketch, but haven't found a way, if it's even possible to do.

That's a better explanation, I am, however, still struggling to understand it.

How is the data communicated? Not on the multiple wires I suggested I think, but how?

It would help if you could do as I suggested and print all 3 (including the error correction data) and show us the results.

A photo of the device, including this track of which you speak, and your code (don't forget code tags).

I can't imaging that using signed variables is appropriate for what you are doing.

ikn2:
When formatted with MSB first, there are 16 unused leading '0' bits followed by 25 bits of the position (8-bit Coarse track, 8-bit Mid track, & 9-bit Fine track) and then 4 more unused '0' bits. The 16 leading and 4 lagging bits never change.

Each track is coded using a pure binary sequence with 1 complete cycle of the Fine track for a change of 1 in the Coarse track resulting in 131,072 unique position ID's over the max possible length of a scale, hence the "Absolute". One Mid track cycle covers the same distance as 16 Fine track cycles and is used for noise correction only.

I must be misunderstanding something because based on that it seems like you should separate the 8, 8 and 9 bits into three separate numbers and then they won't have to interfere with each other.

...R

I'm assuming you've read https://www.gammon.com.au/millis which explains how unsigned mathematics works and how to completely ignore the rollover from maximum to zero? If you haven't, then read it. It is vital to understand how unsigned long variables are used.

With that as a given, you could left-justify the 17 bit data in a 32-bit unsigned long. Bit-shift everything to the left by enough to fill all the leftmost digits of the 32-bits. Then use the current - initial construction to get the position relative to an initial start point, being the smallest end of the available travel.

MorganS:
I'm assuming you've read Gammon Forum : Electronics : Microprocessors : millis() overflow ... a bad thing? which explains how unsigned mathematics works and how to completely ignore the rollover from maximum to zero? If you haven't, then read it. It is vital to understand how unsigned long variables are used.

With that as a given, you could left-justify the 17 bit data in a 32-bit unsigned long. Bit-shift everything to the left by enough to fill all the leftmost digits of the 32-bits. Then use the current - initial construction to get the position relative to an initial start point, being the smallest end of the available travel.

You don't even need to left justify the data. Just put it into the 17 LSBs of a uint32_t with 0s in the upper 17 bits. Then, do the [b]current - initial[/b] subtraction. Finally mask (logical 'AND') the result with [b]0x1FF[/b].

The communication is via a 4-wire mini USB connection (VDD, Gnd, Clk, Data).
The readhead passes over the scale tape reading the 3 tracks on a 10 Hz frequency and combines them into a 52-bit output Word transmitted LSB first. The OEM display processor would then take that data, do the bit-jitsu, and output a decimal position. The overflow isn't really a true overflow condition. Each of the 3 tracks are coded using a binary number sequence.

From O-scope testing, we determined the 3 tracks (referred to as Coarse, Mid, & Fine) were as follows:
Fine track - a 9-bit binary sequence, each increment being 0.01 mm long or 5.12 mm for a full cycle.
Mid track - an 8-bit binary sequence, each cycle being 16 cycles of the Fine track or 81.92 mm.
Coarse track - also an 8-bit binary sequence, each cycle being 16 Mid track cycles or 512 Fine track cycles with a maximum length of 131,072 mm in length. Any longer and the sequence would repeat and it would no longer be an Absolute scale.

Both the Coarse and Fine tracks are in sync, starting out at zero with the transitions aligning, hence when the Fine track goes from 111111111 to 000000000 (511 to 0), the Coarse track goes from 00000000 to 00000001 (0 to 1).
The Mid track, however, has its transitions offset from the other two tracks. We’ve concluded the Mid track is just used for noise correction of the other two tracks and is offset so all three tracks don't hit their transitions at the same time. The output position being a corrected combination of the Coarse and Fine tracks.
This is what gives each position a unique identifier over the max possible length that any one scale could be of 1,310.72 meters as any longer would result in a repeat and wouldn’t be unique.

The manufacturer cut the scales into various lengths less than the longest possible length (I think the longest sold was 34” or 36” long) so not all start with the Coarse and Fine tracks at zero. The OEM display had a function where you could set the “Absolute Zero” position anywhere along the length of the scale. It would just store the unique ID when you hit the button and then display the delta between the current position and the Absolute Zero position.

We’ve pretty much decoded everything except how the OEM displays handle the binary Coarse track jump. As stated before, if the track integers are handled as Unsigned, the position will jump when the Coarse track hits the recycle point (11111111 to 00000000). If integers are handled as Signed, the same happens at the Coarse track mid-point (01111111 to 10000000) where it goes from max positive to max negative (+65535 to -65536).
Since these are Chinese manufactured scales, it’s possible that the OEM displays were coded differently depending on if the scale contained either of these points. If it was cut short enough and the tape didn’t contain either of these points, it doesn’t matter how the integer is handled (signed or unsigned) as the output is linear. It’s only an issue if the tape contains one of these points. Here’s where I assume that no scale was cut that contained both of these points. The only way to confirm if they used different code handling for scales containing either of these points would be to have two scale of the same version (they made two, v3.1 & v4.3) each containing one of the points and swapping out the OEM displays and then seeing if a position jump occurred.

What we’re attempting to do is code an Arduino based controller that takes the output of 3 scales and transmits them to an App based DRO display called Touch DRO.
The problem arose when I discovered one of my scales contained the mid-point and another contained the recycle point. Worse was that they were different versions so the OEM displays were incompatible to the other scale (different resolutions), thus, I couldn’t confirm or disprove the use of different coding in the OEM displays. I'll post couple pic’s of the readheads and O-scope signal along with the coding in different posts as size is too big for single post.

Entire sketch is too big to post. Here's how the track numbers are handled:

iGaging Absolute Scale Controller
v0.0 1/21/19 Brian Quinn
// Main loop here
void loop(){
if (ReadyFlags & XFlag){ // Data is in, calculate the position
CalcPos(XFine, XMid, XCoarse, XPos, XFlag);}
if (ReadyFlags & YFlag){
CalcPos(YFine, YMid, YCoarse, YPos, YFlag);}
if (ReadyFlags & ZFlag){
CalcPos(ZFine, ZMid, ZCoarse, ZPos, ZFlag);}
if (ReadyFlags & 0xF0){ // Position(s) calculated, send them all out.
//This section recoded per Yuriy's suggestion to be faster and more memory efficient
//I'm not using the Flash memory storage macro, so the actual chars will be using SRAM
Serial.print("X");
Serial.print((long)XPos);
Serial.print(";Y");
Serial.print((long)YPos);
Serial.print(";Z");
Serial.print((long)ZPos);
Serial.print(";");
ReadyFlags &= byte(0x0F); // clear the high nibble, preserve the low nibble
}
}

//Turn noisy scale data into a good absolute position
inline void CalcPos(unsigned int &Fine, unsigned int &Mid, int &Coarse, long &Position, const byte &Flag)
{
byte Mask = 0;
Mask = (Fine & 0x1E0) >> 5; // get the top 4 bits of Fine, shift into place
Mid += 50; // phase shift Mid. Must be between 48 and 56
do { // noise correct the mid track
Mid++;
} while ((Mid & 0x0F) != Mask);
Mid = (Mid & 0xF0) >> 4; // only keep the top 4 bits of the corrected value and shift right 4 places
if (Coarse & 0x80){Coarse |= 0xFF00;} // sign the Coarse value, if required
Coarse -= 3; // phase shift the Coarse track. At least 3, no more than 8
do { // noise correct the Coarse track
Coarse++;
} while ((Coarse & 0x0F) != Mid);
Position = (Coarse << 9) | (Fine & 0x1FF); // put all the bits in the right place. Note: this loses the MSB from Coarse!
if (Coarse & 0x80){Position |= 0xFFFF0000;} // sign the output value & recover MSB from Coarse, if required
Fine ^= Fine; // clear the old data
Mid ^= Mid;
Coarse ^= Coarse;
ReadyFlags &= byte(~Flag); // Reset data-in flag (low nibble)
ReadyFlags |= (Flag << 4); // Set position-ready-to-send flag (high nibble)
}

Here's the pictures:

Ikn2
Thank you for the additional information. I think you have an interesting project and an interesting problem. This is the kind of thing that were it for a friend, especially a friend who can be relied upon to supply beer and curry, I'd probably get deeply involved in. However, to do this remotely is beyond my ability to help any further, sorry. Hopefully someone else can be more helpful. ++Karma; for tackling this.

In the mean time, please edit reply #10 and put your code in code tags, and reply #11 to show the photos in the post. You read about code tags and posting images when you read 'how to use this forum - please read', obviously you have forgotten what it said :confused: