diff --git a/src/drivers/optical_flow/pmw3901/PMW3901.cpp b/src/drivers/optical_flow/pmw3901/PMW3901.cpp index b4df95cb3e..1bdc45cd2e 100644 --- a/src/drivers/optical_flow/pmw3901/PMW3901.cpp +++ b/src/drivers/optical_flow/pmw3901/PMW3901.cpp @@ -314,8 +314,12 @@ PMW3901::Run() readMotionCount(delta_x_raw, delta_y_raw, qual); - _flow_sum_x += delta_x_raw; - _flow_sum_y += delta_y_raw; + if (qual > 0) { + _flow_sum_x += delta_x_raw; + _flow_sum_y += delta_y_raw; + _flow_sample_counter ++; + _flow_quality_sum += qual; + } // returns if the collect time has not been reached if (_flow_dt_sum_usec < _collect_time) { @@ -336,19 +340,12 @@ PMW3901::Run() rotate_3f(_yaw_rotation, report.pixel_flow_x_integral, report.pixel_flow_y_integral, zeroval); rotate_3f(_yaw_rotation, report.gyro_x_rate_integral, report.gyro_y_rate_integral, report.gyro_z_rate_integral); - report.frame_count_since_last_readout = 4; // microseconds + report.frame_count_since_last_readout = _flow_sample_counter; // number of frames report.integration_timespan = _flow_dt_sum_usec; // microseconds report.sensor_id = 0; + report.quality = _flow_sample_counter > 0 ? _flow_quality_sum / _flow_sample_counter : 0; - // This sensor doesn't provide any quality metric. However if the sensor is unable to calculate the optical flow it will - // output 0 for the delta. Hence, we set the measurement to "invalid" (quality = 0) if the values are smaller than FLT_EPSILON - if (fabsf(report.pixel_flow_x_integral) < FLT_EPSILON && fabsf(report.pixel_flow_y_integral) < FLT_EPSILON) { - report.quality = 0; - - } else { - report.quality = qual; - } /* No gyro on this board */ report.gyro_x_rate_integral = NAN; @@ -363,6 +360,8 @@ PMW3901::Run() _flow_dt_sum_usec = 0; _flow_sum_x = 0; _flow_sum_y = 0; + _flow_sample_counter = 0; + _flow_quality_sum = 0; _optical_flow_pub.publish(report); @@ -379,6 +378,7 @@ PMW3901::readMotionCount(int16_t &deltaX, int16_t &deltaY, uint8_t &qual) int ret = transfer(&data[0], &data[0], 12); if (OK != ret) { + qual = 0; perf_count(_comms_errors); DEVICE_LOG("spi::transfer returned %d", ret); return ret; @@ -386,7 +386,14 @@ PMW3901::readMotionCount(int16_t &deltaX, int16_t &deltaY, uint8_t &qual) deltaX = ((int16_t)data[5] << 8) | data[3]; deltaY = ((int16_t)data[9] << 8) | data[7]; - qual = data[11]; + + // If the reported flow is impossibly large, we just got garbage from the SPI + if (deltaX > 240 || deltaY > 240 || deltaX < -240 || deltaY < -240) { + qual = 0; + + } else { + qual = data[11]; + } ret = OK; diff --git a/src/drivers/optical_flow/pmw3901/PMW3901.hpp b/src/drivers/optical_flow/pmw3901/PMW3901.hpp index 09d5768bae..942495d401 100644 --- a/src/drivers/optical_flow/pmw3901/PMW3901.hpp +++ b/src/drivers/optical_flow/pmw3901/PMW3901.hpp @@ -103,7 +103,7 @@ protected: private: - const uint64_t _collect_time{15000}; // usecs, optical flow data publish rate + const uint64_t _collect_time{15000}; // usecs, ensures flow data is published every second iteration of Run() (100Hz -> 50Hz) uORB::PublicationMulti _optical_flow_pub{ORB_ID(optical_flow)}; @@ -117,6 +117,8 @@ private: int _flow_sum_x{0}; int _flow_sum_y{0}; uint64_t _flow_dt_sum_usec{0}; + uint16_t _flow_quality_sum{0}; + uint8_t _flow_sample_counter{0}; /** * Initialise the automatic measurement state machine and start it.