Compass +GPS

Hi Folks,

I am writing a little program to display a graphical compass using opengl. The source data about headings etc comes from a library I am using which allows you to connect to a GPS.

I have two problems tho:

  1. The GPS I have can update the heading 5 times per second, yet the openGL can update at about 60 times a second. Whats a good way to avoid calling the GPS routine unnessecarily?

  2. In theory, the GPS could give a heading of say 050, then the next reading might be 065. To simulate a real world compass, and to look good, opengl wants to rotate smootly (albiet very fast) so I guess I need a if loop with roatate1 being the start value until hit reaches rotate2 and then rotate1 needs to take on the next compass reading and loop from rotate2 until it hits rotate1 value again?

Could someone please try to formalise this logic for me please?

Thanks heaps in advance,

-Al

  1. take a float variable(0.0f), and for each frame add the delta time to this variable(in seconds), then if the variable is above 0.2 then read the gps and subtract the variable with 0.2

  2. in this case you have to delay any reaction with 0.2 seconds.
    To do this, whenever you read a GPS heading then start moving the previous heading towards the new one at a rate that corresponds to 0.2 seconds.

It’s relativly easy to implement, but a bit hard to explain.

zeoverlord - you’re always helpful, and give great answers!!

How do I get delta time?

-Al

It depends on your platform, in most APIs there are some kind of timing functions, most give the time in milliseconds after the program was started.

In my own game engine i use this before every frame to get the delta time, it is based on the windows API.

tickCount = GetTickCount();
deltaTime = ((float)(tickCount - lastTickCount))/1000;
lastTickCount = tickCount;

This version is based on the SDL API (used in the new NeHe lessons).

m_currentTime = SDL_GetTicks();
delta = static_cast<float>(m_currentTime - m_lastTime) / 1000.0f;
m_lastTime = m_currentTime;

Unfortunatly i can’t tell you exactly how it should look like because i don’t know what API you are using, but i think you can figure it out.

About #1 - if you subtract 0.2 second every time you read gps you will get average delay of 0.2 seconds.
If you want to make sure that delay will be no less than 0.2s then instead of subtracting 0.2 just reset value to 0.0.

zeoverlord,

I have tried to impliment the solution, but somethnig is not quite right.

Please let me know if you spot something. The important parts are as below:

 
void GetGPSData()
{int Code;
 char *pend;
 
    // lock data buffer
    mgcLockData(1);
    // get timestamp
    Code = mgcGetData(GPRMC_COURSE,(LPSTR)DataBuffer);
	if(Code<0) ShowMGC32Error(Code);
 //   if(Code>0) course=(LPSTR)DataBuffer;
	course=strtod(DataBuffer, &pend);
    mgcLockData(0); // Lock Data Buffer
    Sleep(200);

	deltacourse=(course-lastcourse);
	lastcourse=course;

	courseincrement=(deltacourse/(1/deltaTime));
} /* end GetGPSData */

// EXTRACT FROM WINMAIN
	while(!done)									// Loop That Runs While done=FALSE
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?
		{
			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
			{
				done=TRUE;							// If So done=TRUE
			}
			else									// If Not, Deal With Window Messages
			{
				TranslateMessage(&msg);				// Translate The Message
				DispatchMessage(&msg);				// Dispatch The Message
			}
		}
		else										// If There Are No Messages
		{
			// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
			if (active)								// Program Active?
			{
				if (keys[VK_ESCAPE])				// Was ESC Pressed?
				{
					done=TRUE;						// ESC Signalled A Quit
				}
				else								// Not Time To Quit, Update Screen
				{	tickCount = GetTickCount();
					deltaTime = ((float)(tickCount - lastTickCount))/1000;
					lastTickCount = tickCount;

					timecounter=timecounter+deltaTime;

					if (timecounter>1.0)
					{
						GetGPSData();
						timecounter=0;
					}
					
					DrawGLScene();					// Draw The Scene
					SwapBuffers(hDC);				// Swap Buffers (Double Buffering)
					course=lastcourse+courseincrement;
				}
			}

			if (keys[VK_F1])						// Is F1 Being Pressed?
			{
				keys[VK_F1]=FALSE;					// If So Make Key FALSE
				KillGLWindow();						// Kill Our Current Window
				fullscreen=!fullscreen;				// Toggle Fullscreen / Windowed Mode
				// Recreate Our OpenGL Window
				if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))
				{
					return 0;						// Quit If Window Was Not Created
				}
			}
		}
	}

//EXTRACT FROM GLDRAWSCENE
	glPushMatrix();
	glRotatef(course,0.0f,0.0f,1.0f);
	glBegin(GL_LINES);							// LINES FORMING EDGE OF COMPASS ROSE
		for (deg=0;deg<360;deg+=10)
		{
			d = deg*pi/180;
			glVertex3f(2.0*cos(d),2.0*sin(d),0.0f);
			glVertex3f(2.25*cos(d),2.25*sin(d),0.0f);
		}
	glEnd();