Access Ping360 data for post processing, Python

Hi @Winter, welcome to the forum :slight_smile:

I’d recommend you instead use/refer to the decode_sensor_binary_log.py file from our Ping Viewer repository, since it actually gets updated. I believe the one you linked to was originally a one-off example - not sure where you found that link, but if it’s on our forums or in our documentation then please let me know so I can update it :slight_smile:

The .bin files produced by Ping Viewer are described in the Ping Viewer documentation, as:

The relevant data message specification for the ping360 is device_data, in the Ping Protocol docs.

The decode_sensor_binary_log.py script parses a binary log file into PingMessage instances (using/from the bluerobotics-ping library), and filters them into only the messages containing scan data. For the Ping360 that’s the device_data message, which has a data attribute that is a bytearray of the intensity values returned by the sonar. You can index into that directly if you want to (e.g. decoded_message.data[0] for the first intensity value), but for processing purposes I’d recommend converting the data to a numpy array instead (e.g. np.frombuffer(decoded_message.data, np.uint8)).

You can look at the message specification for the other available attributes, but of particular note are the angle (for direction) and sample_period (used to determine distance).

A few gotchas:

  1. the ping angles are measured in gradians, so the angle attribute is a value from 0 to 399
  2. the ping360 zero angle is at the back where the penetrator is, so ‘forwards’ (the direction of the arrow on the bottom of the Ping360) is at angle 200 gradians
  3. Sonar (and all time of flight sensors) measure the time it takes for the pulse to return, so while d_{sound} = v_{sound} * t_{sample}, the target is half of that: d_{target} = \frac{d_{sound}}{2}

The following function can be used to determine the target distance per sample:

def meters_per_sample(ping_message, v_sound=1500):
    """ Returns the target distance per sample, in meters. 
    
    'ping_message' is the message being analysed.
    'v_sound' is the operating speed of sound [m/s]. Default 1500.

    """
    # sample_period is in 25ns increments
    # time of flight includes there and back, so divide by 2
    return v_sound * ping_message.sample_period * 12.5e-9

If you have the sample index (from within the data array) the distance at the start of the sample time is just

sample_start_distance = sample_index * meters_per_sample(ping_message, v_sound)

(i.e. the first sample (index 0) has distance 0m).
Alternatively, you can get the distance to the middle of the sample time with

sample_average_distance = (sample_index + 0.5) * meters_per_sample(ping_message, v_sound)

We’re currently looking to add some more thorough examples of using our ping libraries - is there anything in particular you’d be interested in? :slight_smile:

1 Like