예제 #1
0
def test_sensor_port_in_use(meta: client.SensorInfo) -> None:
    """Using an unavailable port will not throw."""
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('localhost', 0))
    _, port = sock.getsockname()
    with closing(sock):
        with closing(client.Sensor("os.invalid", port, metadata=meta)):
            pass

        with closing(client.Sensor("os.invalid", 0, port, metadata=meta)):
            pass
예제 #2
0
def test_sensor_port_in_use(default_meta: client.SensorInfo) -> None:
    """Instantiating clients listening to the same port does not fail."""
    with closing(client.Sensor("", 0, 0, metadata=default_meta)) as s1:
        with closing(
                client.Sensor("",
                              s1._cli.lidar_port,
                              s1._cli.imu_port,
                              metadata=default_meta)) as s2:
            assert s2._cli.lidar_port != 0
            assert s2._cli.imu_port != 0
            assert s2._cli.lidar_port == s1._cli.lidar_port
            assert s2._cli.imu_port == s1._cli.imu_port
예제 #3
0
def fetch_metadata(hostname: str) -> None:
    """Fetch metadata from a sensor and write it to disk.

    Accurately reconstructing point clouds from a sensor data stream
    requires access to sensor calibration and per-run configuration
    like the operating mode and azimuth window.

    The client API makes it easy to read metadata and write it to disk
    for use with recorded data streams.

    Args:
        hostname: hostname of the sensor
    """
    # [doc-stag-fetch-metadata]
    with closing(client.Sensor(hostname)) as source:
        # print some useful info from
        print("Retrieved metadata:")
        print(f"  serial no:        {source.metadata.sn}")
        print(f"  firmware version: {source.metadata.fw_rev}")
        print(f"  product line:     {source.metadata.prod_line}")
        print(f"  lidar mode:       {source.metadata.mode}")
        print(f"Writing to: {hostname}.json")

        # write metadata to disk
        source.write_metadata(f"{hostname}.json")
예제 #4
0
def test_scans_closed(meta: client.SensorInfo) -> None:
    """Check reading from closed scans raises an exception."""
    with closing(client.Sensor("os.invalid", 0, 0, metadata=meta)) as source:
        scans = client.Scans(source)
        scans.close()
        with pytest.raises(ValueError):
            next(iter(scans))
예제 #5
0
def configure_dual_returns(hostname: str) -> None:
    """Configure sensor to use dual returns profile given hostname

    Args:
        hostname: hostname of the sensor
    """
    config = client.get_config(hostname)
    if (config.lidar_mode == client.LidarMode.MODE_2048x10) or (
            config.lidar_mode == client.LidarMode.MODE_1024x20):
        print(
            f"Changing lidar_mode from {str(config.lidar_mode)} to 1024x10 to"
            "  enable to dual returns. Will not persist change.")
        config.lidar_mode = client.LidarMode.MODE_1024x10

    # [doc-stag-config-udp-profile]
    config.udp_profile_lidar = client.UDPProfileLidar.PROFILE_LIDAR_RNG19_RFL8_SIG16_NIR16_DUAL
    # [doc-etag-config-udp-profile]

    try:
        client.set_config(hostname, config, persist=False, udp_dest_auto=False)
    except ValueError:
        print("error: Your sensor does not support dual returns. Please"
              " check the hardware revision and firmware version vs release"
              " notes.")
        return

    print("Retrieving sensor metadata..")
    with closing(client.Sensor(hostname)) as source:
        # print some useful info from
        print(
            f"udp profile lidar: {str(source.metadata.format.udp_profile_lidar)}"
        )
예제 #6
0
def test_sensor_packet_bad_size(default_meta: client.SensorInfo) -> None:
    """Check that the client will ignore improperly-sized packets."""
    with closing(
            client.Sensor("",
                          0,
                          0,
                          metadata=default_meta,
                          timeout=1.0,
                          _flush_before_read=False)) as source:
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.sendto(b"hello", ("localhost", source._cli.lidar_port))
        with pytest.raises(client.ClientTimeout):
            next(iter(source))
예제 #7
0
def test_sensor_packet(default_meta: client.SensorInfo) -> None:
    """Check that the client will read single properly-sized LEGACY packet."""
    with closing(
            client.Sensor("",
                          0,
                          0,
                          metadata=default_meta,
                          timeout=5.0,
                          _flush_before_read=False)) as source:
        data = np.random.randint(255,
                                 size=source._pf.lidar_packet_size,
                                 dtype=np.uint8)
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.sendto(data.tobytes(), ("localhost", source._cli.lidar_port))
        packet = next(iter(source))
        assert (packet._data == data).all()
예제 #8
0
def record_pcap(hostname: str,
                lidar_port: int = 7502,
                imu_port: int = 7503,
                n_seconds: int = 10) -> None:
    """Record data from live sensor to pcap file.

    Note that pcap files recorded this way only preserve the UDP data stream and
    not networking information, unlike capturing packets directly from a network
    interface with tools like tcpdump or wireshark.

    See the API docs of :py:func:`.pcap.record` for additional options for
    writing pcap files.

    Args:
        hostname: hostname of the sensor
        lidar_port: UDP port to listen on for lidar data
        imu_port: UDP port to listen on for imu data
        n_seconds: max seconds of time to record. (Ctrl-Z correctly closes
                   streams)
    """
    import ouster.pcap as pcap
    from datetime import datetime

    # [doc-stag-pcap-record]
    from more_itertools import time_limited
    # connect to sensor and record lidar/imu packets
    with closing(client.Sensor(hostname, lidar_port, imu_port,
                               buf_size=640)) as source:

        # make a descriptive filename for metadata/pcap files
        time_part = datetime.now().strftime("%Y%m%d_%H%M%S")
        meta = source.metadata
        fname_base = f"{meta.prod_line}_{meta.sn}_{meta.mode}_{time_part}"

        print(f"Saving sensor metadata to: {fname_base}.json")
        source.write_metadata(f"{fname_base}.json")

        print(f"Writing to: {fname_base}.pcap (Ctrl-C to stop early)")
        source_it = time_limited(n_seconds, source)
        n_packets = pcap.record(source_it, f"{fname_base}.pcap")

        print(f"Captured {n_packets} packets")
예제 #9
0
def plot_imu_z_accel(hostname: str,
                     lidar_port: int = 7502,
                     imu_port: int = 7503,
                     n_seconds: int = 5) -> None:
    """Plot the z acceleration from the IMU over time

    Args:
        hostname: hostname of the sensor
        imu_port: UDP port to listen on for imu data
        n_seconds: seconds of time to take a sample over
    """
    import matplotlib.pyplot as plt  # type: ignore

    # [doc-stag-imu-z-accel]
    from more_itertools import time_limited
    # connect to sensor and get imu packets within n_seconds
    source = client.Sensor(hostname, lidar_port, imu_port, buf_size=640)
    with closing(source):
        ts, z_accel = zip(*[(p.sys_ts, p.accel[2])
                            for p in time_limited(n_seconds, source)
                            if isinstance(p, client.ImuPacket)])
    # initialize plot
    fig, ax = plt.subplots(figsize=(12.0, 2))
    ax.plot(ts, z_accel)
    # [doc-etag-imu-z-accel]

    plt.title("Z Accel from IMU over {} Seconds".format(n_seconds))
    ax.set_xticks(np.arange(min(ts), max(ts), step=((max(ts) - min(ts)) / 5)))
    # add end ticker to x axis
    ax.set_xticks(list(ax.get_xticks()) + [max(ts)])

    ax.set_xlim([min(ts), max(ts)])
    ax.set_ylabel("z accel")
    ax.set_xlabel("timestamp (ns)")

    ax.ticklabel_format(useOffset=False, style="plain")
    plt.show()
예제 #10
0
def test_sensor_timeout(meta: client.SensorInfo) -> None:
    """Setting a zero timeout reliably raises an exception."""
    with closing(client.Sensor("os.invalid", 0, 0, metadata=meta,
                               timeout=0.0)) as source:
        with pytest.raises(client.ClientTimeout):
            next(iter(source))
예제 #11
0
def test_sensor_init(meta: client.SensorInfo) -> None:
    """Initializing a data stream with metadata makes no network calls."""
    with closing(client.Sensor("os.invalid", 0, 0, metadata=meta)):
        pass
예제 #12
0
def test_sensor_closed(default_meta: client.SensorInfo) -> None:
    """Check reading from a closed source raises an exception."""
    with closing(client.Sensor("", 0, 0, metadata=default_meta)) as source:
        source.close()
        with pytest.raises(ValueError):
            next(iter(source))
예제 #13
0
def test_sensor_init(default_meta: client.SensorInfo) -> None:
    """Initializing a data stream with metadata makes no network calls."""
    with closing(client.Sensor("", 0, 0, metadata=default_meta)) as source:
        assert source._cli.lidar_port != 0
        assert source._cli.imu_port != 0