Sign in to follow this  
xDennis0811

Help with Ground Movement

Recommended Posts

Hello Guys,

I try to code a simple Pushback addon but I stuck for hours now on how to move the Aircraft on the Ground without reloading the whole Scenario.I hope someone can help me :) Thank you :)

 

 

Share this post


Link to post
Share on other sites
Help AVSIM continue to serve you!
Please donate today!

Hi,

there are basically two ways to move objects with SimConnect. You have to decide if you want to move them directly (SetDataOnSimobject using the position variables) or if you want to slew them (put the object in slew mode and apply directional movement commands). First method is better, as slew has too many drawbacks. If you pass the user object id to the simconnect method, whatever it does will affect your own vehicle.

On top of that there are sim events related to pushback that you can use. Check the reference list of Event-IDs in the SDK documentation (toggle pushback, tug heading, tug speed).

Best regards

Share this post


Link to post
Share on other sites

First I wanted to read out the Velocity Body and Velocity World Values from an aircraft to get a better experience with these variables. Then I wanted to move the aircraft directly but that didn't work.So should I enable a sim event for the Pushback and then manipulate the tug heading and tug speed ? Will that work ? :) And how do I enable the Pushback event ? :)

 

Share this post


Link to post
Share on other sites

You can't override the velocity variables unless you disconnect the object from the simulator control.The easiest way to go is to use the plane lat/lon/alt/p/b/h variables (there are several options). You need to write an algorithm that calculates the position and orientation of your aircraft correctly for every tiny simulator frame and sets those variables to the calculated values. Again, there are multiple ways to do this, and every developer comes up with a unique solution I guess. The task that you have set for yourself is not an easy one, especially if you lack the SimConnect basics. I suggest working through the specification and the sample code projects in the SDK first to get a better idea. For more advanced concepts it is usually a good idea to search through the FsDeveloper forums - these are also a more suitable place to post actual coding questions.

Developing SimConnect clients is for the most part trial & error. The spec doesn't give you answers or examples for specific problems, so a large part of the development process consists of hunting the net or simply trying things out and working with the results. 

And there usually isn't a "quick fix". For a "simple pushback app" I would estimate the development effort for the initial prototype to be around 20 hours, and maybe another 40 hours to expand and redesign until you are satisfied with the result. Depending on what you mean by "simple", the chosen development method, and your personal skill level, it could be twice that number too. 

Best regards

Share this post


Link to post
Share on other sites

Okay I will do that thank you :) I managed the Pushback and now Im working on that the program dectect if the Parking Brake is set or not and also Im working on Tug Heading and speed but thanks for your help! :)

Share this post


Link to post
Share on other sites

One short Question: Can I set the following Variables with these functions ?

 

Full Right Nose Steering: SimConnect_TransmitClientEvent(hSimConnect, SIMCONNECT_OBJECT_ID_USER, EVENT_NOSE_STEERING, 16383, SIMCONNECT_GROUP_PRIORITY_DEFAULT, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);

45 Degree Angle Tug: SimConnect_TransmitClientEvent(hSimConnect, SIMCONNECT_OBJECT_ID_USER, EVENT_TUG_HEADING, 4294967295 / 8, SIMCONNECT_GROUP_PRIORITY_DEFAULT, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);

Tug Speed: SimConnect_TransmitClientEvent(hSimConnect, SIMCONNECT_OBJECT_ID_USER, EVENT_TUG_SPEED, 30, SIMCONNECT_GROUP_PRIORITY_DEFAULT, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);

 

And they are defined as following:

hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_NOSE_STEERING, "STEERING_SET");

hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUPA, EVENT_NOSE_STEERING);

hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_TUG_SPEED, "key_tug_speed");

hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUPA, EVENT_TUG_SPEED);

hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_TUG_HEADING, "key_tug_heading");

hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUPA, EVENT_TUG_HEADING);

Share this post


Link to post
Share on other sites

Sorry no idea without the rest of the code and a test of my own. There is just so much that can go wrong. But why not, code looks alright.

Not all event ids work for every aircraft though. If you use them to set variables on aircraft that don't have the corresponding system (or implement their own logic for that specific instance), they may fail. Make sure that you implement a method to collect the SimConnect exceptions. They may not make a lot of sense (and there is practically no description of what they mean exactly), but at least you know that something is going wrong.

Best regards

Share this post


Link to post
Share on other sites

Already implemented that method but there is no Exception thrown.I start the Aircraft and the Pushback with a PMDG777 works but when I press a button which should change the Tug Heading, Tug Speed or the Nose wheel Steering nothing happens :)

Share this post


Link to post
Share on other sites

PMDG may not be a good choice for testing, there is a lot of custom coding involved in those planes. I would try it with default aircraft first, like the Beech 350. But the issue can be anywhere, so a careful step-through debug run is your best bet. 

Best regards

Share this post


Link to post
Share on other sites

I pasted the whole code here.I hope there aren't so many mistakes in it :D And I try a Beech 350 next time instead of a PMDG :)

 

CODE:

//Copyright (c) Lockheed Martin Corporation.  All rights reserved. 
//------------------------------------------------------------------------------
//
//  SimConnect Text Menu sample
//  
//	Description:
//				Ctrl F1 displays a menu on the screen
//				Ctrl F2 removes the menu from the screen
//				Selecting any menu option sends an event and removes the menu
//------------------------------------------------------------------------------

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include "SimConnect.h"
#include <strsafe.h>
#include <stdlib.h>

void Pushback();
void changeSpeedAndHeading();

struct Struct1
{
	char    title[256];
	double  kohlsmann;
	double  altitude;
	double  latitude;
	double  longitude;
	double  airspeed;
	double groundAltitude;
	double groundVelocity;
	double heading;
};

struct StructSpeed
{
	double velocityX;
	double velocityY;
	double velocityZ;
	SIMCONNECT_DATA_XYZ velo;
};

struct StructBrake
{
	double brakeSet;
};

enum GROUP_ID {
	GROUP0,
	GROUPA,
};

enum EVENT_ID {
	EVENT_SIM_START,
	EVENT1,
	EVENT2,
	EVENT_MENU_1,
	EVENT_TEXT_1,
	EVENT_MESSAGE_1,
	EVENT_PUSHBACK,
	EVENT_TUG_SPEED,
	EVENT_TUG_HEADING,
};

enum INPUT_ID {
	INPUT0,
};

enum DATA_DEFINE_ID {
	DEFINITION_1,
	DEFINITION_6,
	DEFINITION_THROTTLE,
	DEFINITION_SPEED,
	DEFINITION_AIRCRAFT,
	DEFINITION_PARKINGBRAKE
};

enum DATA_REQUEST_ID {
	REQUEST_1,
	REQUEST_SPEED,

};

bool enginesRunning;

int quit = 0;
HANDLE hSimConnect = NULL;
static const char Empty1[] = "";
static const char Menu1[] = "BetterPushback Menu\0 Choose which item:\0 Pushback straight Backward\0 Pushback with Nose to the Left\0 Pushback with Nose to the Right\0 Spawn at Eglin Airport Runway 12";

char title[];
double latitude;
double longitude; 
double altitude;
double heading;

double parkingBrakeSet;

Struct1 *pS;

StructSpeed *pp;
StructBrake *pb;

const char* MenuText(SIMCONNECT_TEXT_RESULT result)
{
	switch (result)
	{
	case SIMCONNECT_TEXT_RESULT_MENU_SELECT_1:
		Pushback();
		return "";
		break;
	case SIMCONNECT_TEXT_RESULT_MENU_SELECT_2:
		system("cls");
		return "";
		break;
	case SIMCONNECT_TEXT_RESULT_MENU_SELECT_3:
		changeSpeedAndHeading();
		return "";
		break;
	case SIMCONNECT_TEXT_RESULT_MENU_SELECT_4:
		return "";
		break;
	case SIMCONNECT_TEXT_RESULT_DISPLAYED:
		return "";
		break;
	case SIMCONNECT_TEXT_RESULT_QUEUED:
		return "Queued";
		break;
	case SIMCONNECT_TEXT_RESULT_REMOVED:
		return "Removed from Queue";
		break;
	case SIMCONNECT_TEXT_RESULT_REPLACED:
		return "Replaced in Queue";
		break;
	case SIMCONNECT_TEXT_RESULT_TIMEOUT:
		return "Timeout";
		break;
	default:
		return "<unknown>";
		break;
	}
}

void CALLBACK MySignalProc(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
{
	HRESULT hr;

	switch (pData->dwID)
	{

	case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE:
	{
		SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData;

		switch (pObjData->dwRequestID)
		{
		case REQUEST_1:
		{
			DWORD ObjectID = pObjData->dwObjectID;
			pS = (Struct1*)&pObjData->dwData;


			if (SUCCEEDED(StringCbLengthA(&pS->title[0], sizeof(pS->title), NULL))) // security check
			{
				 latitude = pS->latitude;
				 longitude = pS->longitude;
				 altitude = pS->altitude;
				 heading = pS->heading;

				printf("Title is: %s \n", pS->title);
				printf("Latitude is: %f \n", latitude); 
				printf("Longitude is: %f \n", longitude);
				printf("Altitude is: %.0f \n", altitude);
				printf("Airspeed is: %.0f \n", pS->airspeed);
				printf("Ground Altitude is: %.0f \n", pS->groundAltitude);
				printf("Ground Velocity is: %.0f \n", pS->groundVelocity);
				printf("Heading: %.2f \n\n", pS->heading);

			}

			pp = (StructSpeed*)&pObjData->dwData;

			float fpsToKnotsX = pp->velocityX * 0.592484;
			float fpsToKnotsY = pp->velocityY * 0.592484;
			float fpsToKnotsZ = pp->velocityZ * 0.592484;


//			printf("Velocity BODY X is: %.6f \n", fpsToKnotsX);
//			printf("Velocity BODY Y is: %.6f \n", fpsToKnotsY);
//			printf("Velocity BODY Z is: %.6f \n", fpsToKnotsZ);
//			printf("Data is: %f \n", pp->velo);

			pb = (StructBrake*)&pObjData->dwData;

			parkingBrakeSet = pb->brakeSet;

			printf("Parking Brake: %f \n", parkingBrakeSet);

			break;
		}

		default:
			break;
		}
		break;
	}

	case SIMCONNECT_RECV_ID_OPEN:
	{
		SIMCONNECT_RECV_OPEN *pOpen = (SIMCONNECT_RECV_OPEN*)pData;
		printf("Open: AppName=\"%s\"  AppVersion=%d.%d.%d.%d  SimConnectVersion=%d.%d.%d.%d\n", pOpen->szApplicationName,
			pOpen->dwApplicationVersionMajor, pOpen->dwApplicationVersionMinor, pOpen->dwApplicationBuildMajor, pOpen->dwApplicationBuildMinor,
			pOpen->dwSimConnectVersionMajor, pOpen->dwSimConnectVersionMinor, pOpen->dwSimConnectBuildMajor, pOpen->dwSimConnectBuildMinor
		);

		break;
	}

	case SIMCONNECT_RECV_ID_EVENT:
	{
		SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData;

		switch (evt->uEventID)
		{
			case EVENT_SIM_START:
			{
				printf("\nRequesting Data..\n");

				// Now the sim is running, request information on the user aircraft
				hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_1, DEFINITION_1, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);

				hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_SPEED, DEFINITION_SPEED, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);

				break;
			}
		case EVENT1:
			// Display menu
			SimConnect_Text(hSimConnect, SIMCONNECT_TEXT_TYPE_MENU, 0, EVENT_MENU_1, sizeof(Menu1), (void*)Menu1);
			break;

		case EVENT2:
			// Stop displaying menu
			SimConnect_Text(hSimConnect, SIMCONNECT_TEXT_TYPE_MENU, 0, EVENT_MENU_1, sizeof(Empty1), (void*)Empty1);
			SimConnect_Text(hSimConnect, SIMCONNECT_TEXT_TYPE_SCROLL_BLUE, 0, EVENT_TEXT_1, sizeof(Empty1), (void*)Empty1);
			SimConnect_Text(hSimConnect, SIMCONNECT_TEXT_TYPE_MESSAGE_WINDOW, 0, EVENT_MESSAGE_1, sizeof(Empty1), (void*)Empty1);
			break;

		case EVENT_MENU_1:
			// Respond to the users menu selection
			printf("\n");
			printf(MenuText((SIMCONNECT_TEXT_RESULT)evt->dwData));
			break;

		default:
			printf("");
			break;
		}
		break;
	}

	case SIMCONNECT_RECV_ID_QUIT:
	{
		printf("\n***** SIMCONNECT_RECV_ID_QUIT *****\n");
		quit = 1;
		break;
	}

	case SIMCONNECT_RECV_ID_EXCEPTION:
	{
		SIMCONNECT_RECV_EXCEPTION *except = (SIMCONNECT_RECV_EXCEPTION*)pData;
		printf("\n\n***** EXCEPTION=%d  SendID=%d  uOffset=%d  cbData=%d\n", except->dwException, except->dwSendID, except->dwIndex, cbData);
		break;
	}

	default:
		printf("\nUNKNOWN DATA RECEIVED: pData=%p cbData=%d\n", pData, cbData);
		break;
	}
}

void Pushback()
{
	HRESULT hr;

	printf("Pushback begins\n");

	SimConnect_TransmitClientEvent(hSimConnect, 0, EVENT_PUSHBACK, 0, SIMCONNECT_GROUP_PRIORITY_DEFAULT, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
}

void changeSpeedAndHeading()
{
	printf("Setting Speed \n");

	SimConnect_TransmitClientEvent(hSimConnect, SIMCONNECT_OBJECT_ID_USER, EVENT_TUG_HEADING, 16383, SIMCONNECT_GROUP_PRIORITY_DEFAULT, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);

	SimConnect_TransmitClientEvent(hSimConnect, SIMCONNECT_OBJECT_ID_USER, EVENT_TUG_HEADING, 4294967295 / 8, SIMCONNECT_GROUP_PRIORITY_DEFAULT, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
}


//------------------------------------------------------------------------------
//  main
//------------------------------------------------------------------------------
int __cdecl main(int argc, char* argv[])
{

	HANDLE hEventHandle = ::CreateEvent(NULL, FALSE, FALSE, NULL);

	if (hEventHandle == NULL)
	{
		printf("Error: Event creation failed!  Quiting");
		return GetLastError();
	}

	if (FAILED(SimConnect_Open(&hSimConnect, "SimConnect Text", NULL, 0, hEventHandle, 0)))
	{
		printf("\nConnection to Prepar3D failed! Quiting");
		return 1;
	}

	printf("\nConnection to Prepar3D established!\n");

	HRESULT hr;

	// Request a simulation started event
	hr = SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_SIM_START, "SimStart");

	// Set up a data definition for positioning data
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_6, "Initial Position", NULL, SIMCONNECT_DATATYPE_INITPOSITION);

	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_AIRCRAFT, "ENG COMBUSTION", "BOOL");

	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_SPEED, "VELOCITY WORLD X", "feet per second");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_SPEED, "VELOCITY WORLD Y", "feet per second");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_SPEED, "VELOCITY WORLD Z", "feet per second");
	
	// Set up the data definition, but do not yet do anything with it
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Title", NULL, SIMCONNECT_DATATYPE_STRING256);
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Kohlsman setting hg", "inHg");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Altitude", "feet");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Latitude", "degrees");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Longitude", "degrees");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Airspeed True", "knots");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Ground Altitude", "meters");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "GROUND VELOCITY", "Knots");
	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "PLANE HEADING DEGREES TRUE", "degrees");

	hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_PARKINGBRAKE, "BRAKE PARKING POSITION", "bool");

	hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT1);
	hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT2);

	hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, EVENT1, TRUE);
	hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, EVENT2, TRUE);

	hr = SimConnect_SetNotificationGroupPriority(hSimConnect, GROUP0, SIMCONNECT_GROUP_PRIORITY_HIGHEST);

	hr = SimConnect_MapInputEventToClientEvent(hSimConnect, INPUT0, "Ctrl+Shift+F12", EVENT1);
	hr = SimConnect_MapInputEventToClientEvent(hSimConnect, INPUT0, "Ctrl+F2", EVENT2);

	hr = SimConnect_SetInputGroupState(hSimConnect, INPUT0, SIMCONNECT_STATE_ON);

	hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_PUSHBACK, "toggle_pushback");
	hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUPA, EVENT_PUSHBACK);

	hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_TUG_SPEED, "key_tug_speed");
	hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUPA, EVENT_TUG_SPEED);

	hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_TUG_HEADING, "STEERING_SET");
	hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUPA, EVENT_TUG_HEADING);

	while (0 == quit && ::WaitForSingleObject(hEventHandle, INFINITE) == WAIT_OBJECT_0)
	{
		hr = SimConnect_CallDispatch(hSimConnect, MySignalProc, NULL);
		if (FAILED(hr))
		{
			break;
		}
	}

	hr = SimConnect_Close(hSimConnect);
	CloseHandle(hEventHandle);

	return 0;
}

 

Share this post


Link to post
Share on other sites

Hi,

So I take it that you are implementing a DLL to be added to the sim at startup? You then call up a text menu with a keyboard combo? And then what? What is working and what isn't? Are your TransmitClientEvent methods even called?

the most obvious error is your usage of data structures, definition IDs and Request IDs. These combinations are unique, you cannot "cast" the same &pObjData->dwData to different data structures in the same request. The request always returns only the one data structure that you defined for it. In your case you could gather all the data that you need in one single structure. And I never use the "RequestDataOnSimObjectType" method unless I really need it. Plus, you should give all your enumeration items clear and readable lables, not just EVENT_1-2-3. Call them after what they do. Once the code gets longer, it is very hard to keep track of what generic literals mean.

Btw. a text menu is not really suitable for steering something - you always have to recall the menu after every button press, because it closes automatically once you have selected something. A gauge is better suited for immediate interaction. And I am pretty sure that aircraft steering and tug heading cannot be influenced at the same time. A hunch says that the tug heading might not work like you expect it to either. Could be that this variable just sets the angle of the last turn that the tug makes on the pushback (like pressing 1/2 directly after initiating the PB). Not sure though, would have to try that myself.

Best regards

 

Share this post


Link to post
Share on other sites

Finally get it managed to work :) So now I will cleanup the Code and rename the Events and IDs.After that I try to play a Sound on Pushback which seems to be very hard because I don't find anything about it in the documentation and then I will implement some Maths algorithms for for the Pushback :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this