Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid response checksum when attempting to adjust sample rate #120

Open
tyler124 opened this issue Aug 23, 2017 · 5 comments
Open

Invalid response checksum when attempting to adjust sample rate #120

tyler124 opened this issue Aug 23, 2017 · 5 comments

Comments

@tyler124
Copy link

tyler124 commented Aug 23, 2017

Hello,

I'm creating a C++ class that uses the libsweep low level API and also includes some additional error checking and functionality like automatically disabling scanning before attempting to set a new sample rate. I have a unit test that does things like set sample rates, sets sample rates while scanning, and stops scanning. Sometimes my unit tests run as expected and pass, other times it hangs or I get a "Invalid response checksum" error.

Here's the code i'm working with:

SweepLidar.hpp

#ifndef SWEEP_LIDAR_H
#define SWEEP_LIDAR_H

#include <stdint.h>
#include <iostream>

#include "sweep/sweep.hpp"

class SweepLidar
{

public:
    SweepLidar(const char* inputPort) : device(new sweep::sweep(inputPort)), currentlyScanning(false)
    { }
    int32_t setSampleRate(int32_t rate);
    void startScanning();
    void stopScanning();

private:
    std::unique_ptr<sweep::sweep> device;
    bool currentlyScanning;
};

#endif

SweepLidar.cpp

#include <stdio.h>
#include <stdint.h>
#include <iostream>
#include "SweepLidar.hpp"
#include "errorCodes.hpp"

int32_t SweepLidar::setSampleRate(int32_t rate)
{
    int32_t status = ERROR;

    //Save the current state of the device, so that we can return the device to that state once we're finished
    bool deviceOriginallyScanning = currentlyScanning;
    if (rate == 500 || rate == 750 || rate == 1000)
    {
        if (currentlyScanning)
        {
            std::cout << "Disengaging scanning while sample rate is adjusted." << std::endl;
            stopScanning();
        }
        device->set_sample_rate(rate);

        //Verify that the sample rate we now retrieve is the new sample rate
        int32_t currentSampleRate = device->get_sample_rate();
        if (currentSampleRate == rate)
        {
            status = SUCCESS;
            std::cout << "Successfully set LIDAR sample rate to: " << currentSampleRate << "hz" << std::endl;
        }

        //Return the device to its original state
        if (deviceOriginallyScanning)
        {
            std::cout << "Reengaging scanning." << std::endl;
            startScanning();
        }
    }
    else
    {
        status = INVALID_SAMPLE_RATE;
        std::cerr << "Error: sample rate of " << rate << "Hz not available. Options: 500Hz, 750Hz, 1000Hz." << std::endl;
    }
    return status;
}

void SweepLidar::startScanning()
{
    std::cout << "Starting data capture..." << std::endl;
    device->start_scanning();
    currentlyScanning = true;
}

void SweepLidar::stopScanning()
{
    std::cout << "Stopping data capture..." << std::endl;
    device->stop_scanning();
    currentlyScanning = false;
}

main.cpp

#include <iostream>
#include "SweepLidar.hpp"
#include "errorCodes.hpp"

using namespace std;


static void lidarSetSampleRateUnitTest() {
    int cases = 0;
    int failures = 0;
    int32_t status = ERROR;


    SweepLidar lidar("/dev/ttyUSB0");
    cases++;
    status = lidar.setSampleRate(500);
    if (status != SUCCESS)
    {
        failures++;
    }

    cases++;
    status = lidar.setSampleRate(1000);
    if (status != SUCCESS)
    {
        failures++;
    }

    cases++;
    status = lidar.setSampleRate(550);
    if (status != INVALID_SAMPLE_RATE)
    {
        failures++;
    }

    cases++;
    lidar.startScanning();
    status = lidar.setSampleRate(750);
    lidar.stopScanning();
    if (status != SUCCESS)
    {
        failures++;
    }

    cases++;
    lidar.startScanning();
    status = lidar.setSampleRate(1000);
    lidar.stopScanning();
    if (status != SUCCESS)
    {
        failures++;
    }

    cout << "Test cases:" << cases << endl;
    cout << "Failed:" << failures << endl;

}

int main()
{
    lidarSetSampleRateUnitTest();
    return 0;
}

Around 80% of the time, the tests successfully runs with the following output:

Creating sweep lidar...
Successfully set LIDAR sample rate to: 500hz
Successfully set LIDAR sample rate to: 1000hz
Error: sample rate of 550Hz not available. Options: 500Hz, 750Hz, 1000Hz.
Starting data capture...
Disengaging scanning while sample rate is adjusted.
Stopping data capture...
Successfully set LIDAR sample rate to: 750hz
Reengaging scanning.
Starting data capture...
Stopping data capture...
Starting data capture...
Disengaging scanning while sample rate is adjusted.
Stopping data capture...
Successfully set LIDAR sample rate to: 1000hz
Reengaging scanning.
Starting data capture...
Stopping data capture...
Test cases:5
Failed:0

Around 20% of the time, the unit test will fail by either hanging when attempting to stop the in-progress scan to adjust the sample rate, or fail by throwing an "Invalid response checksum" error also when attempting to stop an in-progress scan to adjust the sample rate:

> Creating sweep lidar...
> Successfully set LIDAR sample rate to: 500hz
> Successfully set LIDAR sample rate to: 1000hz
> Error: sample rate of 550Hz not available. Options: 500Hz, 750Hz, 1000Hz.
> Starting data capture...
> Disengaging scanning while sample rate is adjusted.
> Stopping data capture...
> (hangs here)
Creating sweep lidar...
Successfully set LIDAR sample rate to: 500hz
Successfully set LIDAR sample rate to: 1000hz
Error: sample rate of 550Hz not available. Options: 500Hz, 750Hz, 1000Hz.
Starting data capture...
Disengaging scanning while sample rate is adjusted.
Stopping data capture...
Successfully set LIDAR sample rate to: 750hz
Reengaging scanning.
Starting data capture...
Stopping data capture...
Starting data capture...
Disengaging scanning while sample rate is adjusted.
Stopping data capture...
terminate called after throwing an instance of 'sweep::device_error'
  what():  invalid response header checksum
Aborted

Process returned 134 (0x86)   execution time : 0.258 s
Press ENTER to continue.

sweep firmware version

v1.4

libsweep version + affected bindings

v1.2.3

operating system

Raspbian

Platform/Hardware Setup

USB connection to Raspberry Pi 3B

Description:

@dcyoung
Copy link

dcyoung commented Aug 29, 2017

Please try upgrading your firmware to the latest (v1.4) and see if the issue persists.

@tyler124
Copy link
Author

Sorry, I mistakenly looked at the protocol version instead of the firmware version when I originally listed it. Fixed now. My firmware has always been at v1.4

image

@dcyoung
Copy link

dcyoung commented Aug 31, 2017

Hmmm. Alright.

So the program is hanging sometime after printing "Stopping data capture...". Can you debug the program (or even just add some additional print statements) to tell which call is hanging... ie: on device->stop_scanning(), device->set_sample_rate(rate), or device->get_sample_rate() etc. We might be able to narrow down the issue from there.

I believe all necessary blocks were added to libsweep, but can you try adding pauses between the different libsweep function calls just in case. This really shouldn't be necessary, but I'm interested to see if it affects the behavior. Try placing an unnecessarily large pause (25-50ms) after any library method such as device->stop_scanning() etc.

@tyler124
Copy link
Author

tyler124 commented Sep 6, 2017

Sorry for the delay, I've been busy with work but finally got to run some more tests tonight.

The first set of tests I ran had a very long pause of 2000 milliseconds after I call device->stop_scanning(), see below:

SweepLidar.cpp

#include <stdio.h>
#include <stdint.h>
#include <iostream>
#include "SweepLidar.hpp"
#include "ErrorCodes.hpp"

#include <chrono>
#include <thread>

int32_t SweepLidar::test()
{
    device->set_motor_speed(0);
    return SUCCESS;
}


int32_t SweepLidar::setSampleRate(int32_t rate)
{
    int32_t status = ERROR;

    //Save the current state of the device, so that we can return the device to that state once we're finished
    bool deviceOriginallyScanning = currentlyScanning;
    if (rate == 500 || rate == 750 || rate == 1000)
    {
        if (currentlyScanning)
        {
            std::cout << "Disengaging scanning while sample rate is adjusted." << std::endl;
            stopScanning();
        }
        device->set_sample_rate(rate);

        //Verify that the sample rate we now retrieve is the new sample rate
        int32_t currentSampleRate = device->get_sample_rate();
        if (currentSampleRate == rate)
        {
            status = SUCCESS;
            std::cout << "Successfully set LIDAR sample rate to: " << currentSampleRate << "hz" << std::endl;
        }

        //Return the device to its original state
        if (deviceOriginallyScanning)
        {
            std::cout << "Reengaging scanning." << std::endl;
            startScanning();
        }
    }
    else
    {
        status = INVALID_SAMPLE_RATE;
        std::cerr << "Error: sample rate of " << rate << "Hz not available. Options: 500Hz, 750Hz, 1000Hz." << std::endl;
    }
    return status;
}

int32_t SweepLidar::getSampleRate()
{
    int32_t rate = ERROR;

    //Save the current state of the device, so that we can return the device to that state once we're finished
    bool deviceOriginallyScanning = currentlyScanning;
    if (currentlyScanning)
    {
        std::cout << "Disengaging scanning while sample rate is adjusted." << std::endl;
        stopScanning();
    }
    rate = device->get_sample_rate();
    //Return the device to its original state
    if (deviceOriginallyScanning)
    {
        std::cout << "Reengaging scanning." << std::endl;
        startScanning();
    }

    return rate;
}

void SweepLidar::startScanning()
{
    std::cout << "Starting data capture..." << std::endl;
    device->start_scanning();

    currentlyScanning = true;
}

void SweepLidar::stopScanning()
{
    std::cout << "Stopping data capture..." << std::endl;
    device->stop_scanning();

    //Debug: pause the thread for 2000ms to give the device time to fully stop
    std::cout << "Pausing for 2000ms..." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));

    currentlyScanning = false;
}

This change seems to have had a general positive effect, I ran the lidarSetSampleRateUnitTest() seen in Main.cpp above ~30 times and all runs besides two were successful. I never got the "Invalid response checksum" error that I was seeing before, but with the above changes I still had two runs which got hung up in the stop_scanning() function, see console output below:

Successfully set LIDAR sample rate to: 500hz
Successfully set LIDAR sample rate to: 1000hz
Error: sample rate of 550Hz not available. Options: 500Hz, 750Hz, 1000Hz.
Starting data capture...
Disengaging scanning while sample rate is adjusted.
Stopping data capture...
Pausing for 2000ms...
Successfully set LIDAR sample rate to: 750hz
Reengaging scanning.
Starting data capture...
Stopping data capture...
Pausing for 2000ms...
Starting data capture...
Disengaging scanning while sample rate is adjusted.
Stopping data capture...
Pausing for 2000ms...
Successfully set LIDAR sample rate to: 1000hz
Reengaging scanning.
Starting data capture...
Stopping data capture...
(hung here)

I also performed tests with 50ms pauses after device->start_scanning() and device->stop_scanning() calls, see below:

#include <stdio.h>
#include <stdint.h>
#include <iostream>
#include "SweepLidar.hpp"
#include "ErrorCodes.hpp"

#include <chrono>
#include <thread>

int32_t SweepLidar::test()
{
    device->set_motor_speed(0);
    return SUCCESS;
}


int32_t SweepLidar::setSampleRate(int32_t rate)
{
    int32_t status = ERROR;

    //Save the current state of the device, so that we can return the device to that state once we're finished
    bool deviceOriginallyScanning = currentlyScanning;
    if (rate == 500 || rate == 750 || rate == 1000)
    {
        if (currentlyScanning)
        {
            std::cout << "Disengaging scanning while sample rate is adjusted." << std::endl;
            stopScanning();
        }
        device->set_sample_rate(rate);

        //Verify that the sample rate we now retrieve is the new sample rate
        int32_t currentSampleRate = device->get_sample_rate();
        if (currentSampleRate == rate)
        {
            status = SUCCESS;
            std::cout << "Successfully set LIDAR sample rate to: " << currentSampleRate << "hz" << std::endl;
        }

        //Return the device to its original state
        if (deviceOriginallyScanning)
        {
            std::cout << "Reengaging scanning." << std::endl;
            startScanning();
        }
    }
    else
    {
        status = INVALID_SAMPLE_RATE;
        std::cerr << "Error: sample rate of " << rate << "Hz not available. Options: 500Hz, 750Hz, 1000Hz." << std::endl;
    }
    return status;
}

int32_t SweepLidar::getSampleRate()
{
    int32_t rate = ERROR;

    //Save the current state of the device, so that we can return the device to that state once we're finished
    bool deviceOriginallyScanning = currentlyScanning;
    if (currentlyScanning)
    {
        std::cout << "Disengaging scanning while sample rate is adjusted." << std::endl;
        stopScanning();
    }
    rate = device->get_sample_rate();
    //Return the device to its original state
    if (deviceOriginallyScanning)
    {
        std::cout << "Reengaging scanning." << std::endl;
        startScanning();
    }

    return rate;
}

void SweepLidar::startScanning()
{
    std::cout << "Starting data capture..." << std::endl;
    device->start_scanning();
    
    //Debug: pause the thread for 50ms to give the device time to fully start
    std::cout << "Pausing for 50ms..." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    
    currentlyScanning = true;
}

void SweepLidar::stopScanning()
{
    std::cout << "Stopping data capture..." << std::endl;
    device->stop_scanning();

    //Debug: pause the thread for 50ms to give the device time to fully stop
    std::cout << "Pausing for 50ms..." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    currentlyScanning = false;
}

This seems to have had a neutral or potentially negative effect, with failures around 1/6 time I run the test function. This includes "Invalid response checksum" errors:

Successfully set LIDAR sample rate to: 500hz
Successfully set LIDAR sample rate to: 1000hz
Error: sample rate of 550Hz not available. Options: 500Hz, 750Hz, 1000Hz.
Starting data capture...
Pausing for 50ms...
Disengaging scanning while sample rate is adjusted.
Stopping data capture...
terminate called after throwing an instance of 'sweep::device_error'
  what():  invalid response header checksum
Aborted

Process returned 134 (0x86)   execution time : 0.179 s
Press ENTER to continue.

And now sometimes hangs when starting scanning, which I don't think I saw before:

Successfully set LIDAR sample rate to: 500hz
Successfully set LIDAR sample rate to: 1000hz
Error: sample rate of 550Hz not available. Options: 500Hz, 750Hz, 1000Hz.
Starting data capture...
(hung here)

My application is currently single-threaded by the way. Seems like the library may be prematurely exiting the start_scanning() or stop_scanning() functions before they are truly stable/complete.

@dcyoung
Copy link

dcyoung commented Sep 8, 2017

Have you ever seen the LED on the face of the device flash red?

Can you use the Visualizer desktop application to note the Rotation Time Dump and Error Count Dump for your sweep, and report back. Both commands should be selectable from the "Transmit Command" dropdown in the "Command Controls" panel on the "Device" tab.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants