Search code examples
pythonc++bit-manipulationserial-communication

Python bit manipulation to get usable data out of a lidar sensor


I am trying to write a python driver for a lidar sensor that only has a package for robot OS.

I was able to get the communication working on a Raspberry Pi and I am getting the data that I need.

I never really worked with bytearrays before and even python is pretty new to me.

The received data looks like this (png), but you can take a look at the documentation (pdf) as well.

So if I'm not mistaken, I have to combine three bits into two like this:

[0x5D, 0xC7, 0xD0] => [0x5DC, 0x7D0]

I think the aforementioned robot OS library does this here, but my c++ is even worse than my python :)

After I have the correct data I want to sort it into a 2D array but that's not a problem.

Can you point me in the right direction, or just suggest how to search for a solution?

Thank you for your help


Solution

  • So here's one solution (maybe not the cleanest but it's bit-manipulation so...):

    arr = [0x5D, 0xC7, 0xD0]
    byte_0 = arr[0] << 4 | (arr[1] >> 4)
    byte_1 = (arr[1] & 0xF) << 8 | arr[2]
    

    I'll try to go over this step by step. The three bytes are, in binary representation:

    0b0101_1101
    0b1100_0111
    0b1101_0000
    

    The << operator is the shift-operator. It moves the bits to the left the specified amount. Applying this to the first byte yields: 0b0101_1101 << 4 = 0b0101_1101_0000, effectively appending four zero's at the end. The >> operator is basically equivalent to the << operator, just shifting it the other way round. It discards bits when they would go below position 0: 0b1100_0111 >> 4 = 0b1100 Finally, the | operator is the logical 'or' operator. It performs a bit-wise or operation where each result bit is '1' if one or both of the initial bits is '1'. It is only '0' when both bits are '0'. We can make use of this to 'override' the contents of the lower four bits of our result so far. Note that I have omitted leading zero's for simplicity, but here are the numbers padded with zeroes 0b0101_1101_0000 | 0b0000_0000_1100 = 0b0101_1101_1100. And there you have your first number. Now note that this is not a byte, rather you now need 12 bits to represent the number.

    The same is done with the second byte. The only thing new here is the logical and operator (&). This operator yields '1' only if both bits are '1'. We can use this to mask out a part of interest of the byte: 0b1100_0111 & 0x1111 = 0b0111