Example/test programs for my BNO080 driver.

Dependencies:   BNO080

BNO080 Driver Examples

These examples show how to use some of the functionality on my BNO080 driver. To get started with MBed CLI:

Build Instructions

$ hg clone https://MultipleMonomials@os.mbed.com/users/MultipleMonomials/code/BNO080-Examples/
$ cd BNO080-Examples
$ mbed deploy
$ mbed compile

BNOTestSuite.cpp

Committer:
MultipleMonomials
Date:
2020-05-04
Revision:
3:f72d98d0095e
Parent:
1:14c135ea7134
Child:
4:85b98cc04a0a

File content as of revision 3:f72d98d0095e:

/* 
	USC RPL HAMSTER v2.3
	Contributors: Lauren Potterat 
*/


#include "BNOTestSuite.h"

#include <cinttypes>

#define RAD_TO_DEG (180.0/M_PI)

void BNOTestSuite::test_printInfo()
{
	pc.printf("BNO080 reports as SW version %" PRIu8 ".%" PRIu8 ".%" PRIu16", build %" PRIu32 ", part no. %" PRIu32"\n",
			imu.majorSoftwareVersion, imu.minorSoftwareVersion, imu.patchSoftwareVersion,
			imu.buildNumber, imu.partNumber);
}


void BNOTestSuite::test_readRotationVector()
{
	const size_t update_rate_ms = 200;

	imu.enableReport(BNO080::ROTATION, update_rate_ms);

	while (true)
	{
        // note: for some reason it seems like wait() here waits 10x the time you tell it to
        // not sure what's causing this behavior, and I don't see it with mbed os 2
        ThisThread::sleep_for(update_rate_ms);

        if(imu.updateData())
		{
        	TVector3 eulerRadians = imu.rotationVector.euler();
        	TVector3 eulerDegrees = eulerRadians * RAD_TO_DEG;

			pc.printf("IMU Rotation Euler: Roll: %f deg, Pitch: %f deg, Yaw: %f deg \r\n",
					  eulerDegrees[0], eulerDegrees[1], eulerDegrees[2]);

        	pc.printf(", Accuracy: %.02f", (imu.rotationAccuracy * RAD_TO_DEG));

        	pc.printf(", Status: %s\n", imu.getReportStatusString(BNO080::ROTATION));
		}
		else
		{
			pc.printf("IMU was not ready with data packet!\r\n");
		}
    }
}

void BNOTestSuite::test_readRotationAcceleration()
{
	imu.enableReport(BNO080::ROTATION, 1000);
	imu.enableReport(BNO080::TOTAL_ACCELERATION, 500);

	while (true)
	{
        ThisThread::sleep_for(1);

		if(imu.updateData())
		{
			if (imu.hasNewData(BNO080::ROTATION))
			{
				pc.printf("IMU Rotation Euler: ");
				TVector3 eulerRadians = imu.rotationVector.euler();
				TVector3 eulerDegrees = eulerRadians * (180.0 / M_PI);
				eulerDegrees.print(pc, true);
				pc.printf("\n");
			}
			if (imu.hasNewData(BNO080::TOTAL_ACCELERATION))
			{
				pc.printf("IMU Total Acceleration: ");
				imu.totalAcceleration.print(pc, true);
				pc.printf("\n");
			}
		}
	}
}

void BNOTestSuite::test_tapDetector()
{
	imu.enableReport(BNO080::TAP_DETECTOR, 10);
	pc.printf("Listening for taps...\n");

	while(true)
	{
		if(imu.updateData())
		{
			if(imu.tapDetected)
			{
				pc.printf("Tap detected!\n");
				imu.tapDetected = false;
			}
		}
	}
}

void BNOTestSuite::test_gameRotationVector()
{
	const size_t update_rate_ms = 200;

	imu.enableReport(BNO080::GAME_ROTATION, update_rate_ms);

	while (true)
	{
		// note: for some reason it seems like wait() here waits 10x the time you tell it to
        // not sure what's causing this behavior, and I don't see it with mbed os 2
        ThisThread::sleep_for(update_rate_ms);

		if(imu.updateData())
		{
			pc.printf("IMU Game Rotation Euler: [");
			TVector3 eulerRadians = imu.gameRotationVector.euler();
			TVector3 eulerDegrees = eulerRadians * RAD_TO_DEG;
			eulerDegrees.print(pc, true);

			pc.printf("], Status: %s\n", imu.getReportStatusString(BNO080::GAME_ROTATION));
		}
		else
		{
			pc.printf("IMU was not ready with data packet!\r\n");
		}
	}
}

void BNOTestSuite::test_tare()
{
	const size_t update_rate_ms = 100;
	imu.enableReport(BNO080::ROTATION, update_rate_ms);

	Timer runningTime;
	runningTime.start();

	bool sentTareCmd = false;

	while (true)
	{
        ThisThread::sleep_for(update_rate_ms);

		if(imu.updateData())
		{
			pc.printf("IMU Rotation Euler: [");
			TVector3 eulerRadians = imu.rotationVector.euler();
			TVector3 eulerDegrees = eulerRadians * RAD_TO_DEG;
			eulerDegrees.print(pc, true);

			pc.printf("], Status: %s\n", imu.getReportStatusString(BNO080::ROTATION));
		}
		else
		{
			pc.printf("IMU was not ready with data packet!\r\n");
		}

		if(runningTime.read() > 2 && !sentTareCmd)
		{
			pc.printf("2 seconds have passed, sending tare command...\n");
			imu.tare();
			sentTareCmd = true;
		}
	}
}

void BNOTestSuite::test_magCalibration()
{
	// enable calibration for the magnetometer
	bool success = imu.enableCalibration(false, false, true);

	const size_t update_rate_ms = 200;
	imu.enableReport(BNO080::GAME_ROTATION, update_rate_ms);
	imu.enableReport(BNO080::MAG_FIELD, update_rate_ms);
	imu.enableReport(BNO080::MAG_FIELD_UNCALIBRATED, update_rate_ms);

	if(success)
	{
		pc.printf("Calibration mode was successfully enabled!\n");
	}
	else
	{
		pc.printf("Calibration mode failed to enable!\n");
		while(true){}
	}

	while (true)
	{
		// note: for some reason it seems like wait() here waits 10x the time you tell it to
        // not sure what's causing this behavior, and I don't see it with mbed os 2
        ThisThread::sleep_for(update_rate_ms);

		if(imu.updateData())
		{
			pc.printf("IMU Magnetic Field: [");
			imu.magFieldUncalibrated.print(pc, true);

			pc.printf("] uTesla, Status: %hhu (should be 2-3 when calibration is complete), ", imu.getReportStatus(BNO080::MAG_FIELD));

			pc.printf("Hard iron offsets: [");
			imu.hardIronOffset.print(pc, true);

			pc.printf("]\n");

		}
		else
		{
			pc.printf("IMU was not ready with data packet!\r\n");
		}
	}

}

void BNOTestSuite::test_stabilityClassifier()
{
	imu.enableReport(BNO080::STABILITY_CLASSIFIER, 200);

	while (true)
	{
        ThisThread::sleep_for(1);

		if(imu.updateData())
		{
			if (imu.hasNewData(BNO080::STABILITY_CLASSIFIER))
			{
				pc.printf("Stability: ");

				switch(imu.stability)
				{
					case BNO080::UNKNOWN:
						pc.printf("Unknown\n");
						break;
					case BNO080::ON_TABLE:
						pc.printf("On Table\n");
						break;
					case BNO080::STATIONARY:
						pc.printf("Stationary\n");
						break;
					case BNO080::STABLE:
						pc.printf("Stable\n");
						break;
					case BNO080::MOTION:
						pc.printf("Motion\n");
						break;
				}
			}
		}
	}

}

void BNOTestSuite::test_metadata()
{
	pc.printf("Printing metadata for Linear Acceleration:\r\n");
	imu.printMetadataSummary(BNO080::LINEAR_ACCELERATION);

	pc.printf("Printing metadata for Rotation Vector:\r\n");
	imu.printMetadataSummary(BNO080::ROTATION);

	pc.printf("Printing metadata for Magnetic Field:\r\n");
	imu.printMetadataSummary(BNO080::MAG_FIELD);

	pc.printf("Printing metadata for Tap Detector:\r\n");
	imu.printMetadataSummary(BNO080::TAP_DETECTOR);

}

void BNOTestSuite::test_orientation()
{
	const size_t update_rate_ms = 200;
	imu.enableReport(BNO080::TOTAL_ACCELERATION, update_rate_ms);
	imu.enableReport(BNO080::ROTATION, update_rate_ms);

	Timer runningTime;
	runningTime.start();

	bool setOrientation = false;

	while (true)
	{
        ThisThread::sleep_for(update_rate_ms);

		if(imu.updateData())
		{
			if (imu.hasNewData(BNO080::ROTATION))
			{
				pc.printf("IMU Rotation Euler: ");
				TVector3 eulerRadians = imu.rotationVector.euler();
				TVector3 eulerDegrees = eulerRadians * (180.0 / M_PI);
				eulerDegrees.print(pc, true);
				pc.printf("\n");
			}
			if (imu.hasNewData(BNO080::TOTAL_ACCELERATION))
			{
				pc.printf("IMU Total Acceleration: ");
				imu.totalAcceleration.print(pc, true);
				pc.printf("\n");
			}
		}

		if(runningTime.read() > 2 && !setOrientation)
		{
			pc.printf("2 seconds have passed, sending set orientation command...\n");
			setOrientation = true;

			// rotate sensor about the Y axis, so Z points down and X points west.
			// (values from BNO datasheet page 41)
			imu.setSensorOrientation(Quaternion(0, -1, 0, 0));
		}
	}
}

void BNOTestSuite::test_permanentOrientation()
{
	pc.printf("Setting permanent sensor orientation...\n");
	Timer orientationTimer;
	orientationTimer.start();

	// rotate sensor 90 degrees CCW about the Y axis, so X points up, Y points back, and Z points out
	// (values from BNO datasheet page 41)
	// imu.setPermanentOrientation(Quaternion(1.0f/SQRT_2, -1.0f/SQRT_2, 0, 0));

	// rotate sensor 180 degrees about Y axis
	//with these quaternion values x axis is oriented to point toward BRB, Z points up and Y points out towards you when you face the unit
	// see page 5 and 11 of hillcrestlabs FSM30X datasheet
	imu.setPermanentOrientation(Quaternion(0,-1, 0, 0)); 
	
	// reset to default orientation
	//imu.setPermanentOrientation(Quaternion(0, 0, 0, 0));

	orientationTimer.stop();
	pc.printf("Done setting orientation (took %.03f seconds)\r\n", orientationTimer.read());

}

void BNOTestSuite::test_disable()
{
	const size_t update_rate_ms = 200;
	imu.enableReport(BNO080::TOTAL_ACCELERATION, update_rate_ms);
	imu.enableReport(BNO080::ROTATION, update_rate_ms);

	Timer runningTime;
	runningTime.start();

	bool disabledRotation = false;

	while (true)
	{
        ThisThread::sleep_for(update_rate_ms);

		if(imu.updateData())
		{
			if (imu.hasNewData(BNO080::ROTATION))
			{
				pc.printf("IMU Rotation Euler: ");
				TVector3 eulerRadians = imu.rotationVector.euler();
				TVector3 eulerDegrees = eulerRadians * (180.0 / M_PI);
				eulerDegrees.print(pc, true);
				pc.printf("\n");
			}
			if (imu.hasNewData(BNO080::TOTAL_ACCELERATION))
			{
				pc.printf("IMU Total Acceleration: ");
				imu.totalAcceleration.print(pc, true);
				pc.printf("\n");
			}
		}

		if(runningTime.read() > 2 && !disabledRotation)
		{
			pc.printf("2 seconds have passed, disabling rotation report...\n");
			disabledRotation = true;

			imu.disableReport(BNO080::ROTATION);
		}
	}
}

int main()
{
	pc.baud(115200);

	pc.printf("============================================================\n");


	// reset and connect to IMU
	while(!imu.begin())
	{
		pc.printf("Failed to connect to IMU!\r\n");
        ThisThread::sleep_for(500);
	}

	//Declare test harness
	BNOTestSuite harness;

	int test = -1;
	pc.printf("\r\n\nHamster BNO Test Suite:\r\n");

	//MENU. ADD OPTION PER EACH TEST
	pc.printf("Select a test: \n\r");
	pc.printf("1. Print chip info\r\n");
	pc.printf("2. Display rotation vector\r\n");
	pc.printf("3. Display rotation and acceleration\r\n");
	pc.printf("4. Run tap detector\r\n");
	pc.printf("5. Display game rotation vector\r\n");
	pc.printf("6. Test tare function\r\n");
	pc.printf("7. Run magnetometer calibration\r\n");
	pc.printf("8. Test stability classifier\r\n");
	pc.printf("9. Test metadata reading (requires BNO_DEBUG = 1)\r\n");
	pc.printf("10. Test set orientation\r\n");
	pc.printf("11. Test set permanent orientation\r\n");
	pc.printf("12. Test disabling reports\r\n");
	pc.printf("13. Exit test suite\r\n");

	pc.scanf("%d", &test);
	pc.printf("Running test %d:\r\n\n", test);


	//SWITCH. ADD CASE PER EACH TEST
	switch(test){
		case 1:
			harness.test_printInfo();
			break;
		case 2:
			harness.test_readRotationVector();
			break;
		case 3:
			harness.test_readRotationAcceleration();
			break;
		case 4:
			harness.test_tapDetector();
			break;
		case 5:
			harness.test_gameRotationVector();
			break;
		case 6:
			harness.test_tare();
			break;
		case 7:
			harness.test_magCalibration();
			break;
		case 8:
			harness.test_stabilityClassifier();
			break;
		case 9:
			harness.test_metadata();
			break;
		case 10:
			harness.test_orientation();
			break;
		case 11:
			harness.test_permanentOrientation();
			break;
		case 12:
			harness.test_disable();
			break;
		case 13:
			pc.printf("Exiting test suite.\r\n");
			return 0;
		default:
			printf("Invalid test number. Please run again.\r\n");
			return 1;
	}

	pc.printf("Done!\r\n");
	return 0;

}