/* BALANCE.CC Controls the balancing pendulum robot, Ballybot. Alistair Sutherland suthe-aj@ee.uwa.edu.au CIIPS, 2003 */ // Test Gyroscope output #include #include #include "eyebot.h" #include "../a-gyro/gyro.h" #include "motors.h" // was 40 3.3 3.4 0.6 before the robot was cut in half #define K1 39.0 #define K2 3.5 #define K3 3.4 #define K4 0.6 #define MAX_STATES_STORED 25 #define SAMPLE_INTERVAL 3 // Prototypes void SampleState(); void *memset( void *dest, int c, size_t count ); // Global variables (needs to be shared with timer handler) struct { float fAngle; float fAngVel; float fX; float fXVel; int iTime; } g_StateHistory[MAX_STATES_STORED] = {0}; int g_iSampleCount; int g_iFirstSample; int g_iHasBeeped; int g_iLastTimeStamp; float g_fLastDisplacement; // The gyroscope ... CGyro * g_pGyro; // The motors ... CMotors * g_pMotors; int g_iMotorsOn; int main( ) { int iKey; TimerHandle hGyroTimer; // Create the motors g_pMotors = new CMotors; // Init variables iKey = 0; g_iSampleCount = 0; g_iFirstSample = 1; // True initially g_iLastTimeStamp = 0; g_fLastDisplacement = 0; g_iMotorsOn = 1; g_iHasBeeped = 0; // Create the gyroscope (use GYRO_ONLY_MODE if there is no inclinometer) // g_pGyro = new CGyro(NORMAL_MODE); g_pGyro = new CGyro(GYRO_ONLY_MODE); // Recalibrate gyro g_pGyro->Recalibrate(); LCDClear(); // Initialise distance to zero, and get start time g_pMotors->Reset(); memset(&g_StateHistory, 0, sizeof(g_StateHistory)); g_StateHistory[0].iTime = OSGetCount(); // Start timer to handle samples hGyroTimer = OSAttachTimer(SAMPLE_INTERVAL, (TimerFnc) (SampleState)); // Now take samples until whenever... while ( g_iMotorsOn == 1 && iKey != KEY4) { // Check for commands: iKey = KEYRead(); if (iKey == KEY4) { // Stop recording gyro measurments! g_pGyro->StopRecording(); // Motors off!.. g_iMotorsOn = 0; g_pMotors->SetForce(0, 0); // stop timer OSDetachTimer( hGyroTimer ); OSWait(2); // Make sure motors are off!.. g_iMotorsOn = 0; g_pMotors->Reset(); // download data (only does something if the gyro was created in DEBUG_ONLINE_MODE mode) g_pGyro->DownloadData(); // you could add code here to transmit the g_StateHistory buffer } } // destroy the gyroscope & motors delete g_pGyro; delete g_pMotors; return 0; } ////////////////////////////////////////////////////////// // // SAMPLE STATE // // Read gyroscope and odometers to get state estimates & // make control decision // void SampleState() { float fForce; // Get time ... g_StateHistory[g_iSampleCount].iTime = OSGetCount(); // Get current state: g_StateHistory[g_iSampleCount].fAngle = g_pGyro->GetAngle(); g_StateHistory[g_iSampleCount].fAngVel = g_pGyro->GetAngularVel(); g_StateHistory[g_iSampleCount].fX = g_pMotors->GetDistance(); if (g_iFirstSample) { g_StateHistory[g_iSampleCount].fXVel = 0.0; g_iFirstSample = 0; } else { g_StateHistory[g_iSampleCount].fXVel = (g_StateHistory[g_iSampleCount].fX - g_fLastDisplacement ) / (g_StateHistory[g_iSampleCount].iTime - g_iLastTimeStamp); } g_iLastTimeStamp = g_StateHistory[g_iSampleCount].iTime; g_fLastDisplacement = g_StateHistory[g_iSampleCount].fX; // Calculate desired force... fForce = g_StateHistory[g_iSampleCount].fAngle * K1 + g_StateHistory[g_iSampleCount].fAngVel * K2 + g_StateHistory[g_iSampleCount].fX * K3 + g_StateHistory[g_iSampleCount].fXVel * K4; // Set force... if (g_iMotorsOn == 1) g_pMotors->SetForce(fForce, g_StateHistory[g_iSampleCount].fXVel); else g_pMotors->SetForce(0, 0); g_iSampleCount++; if (g_iSampleCount >= MAX_STATES_STORED) { g_iSampleCount = 0; } }