Vehicle Position on Track

I have a few questions relating to the vehicle position along the track, these are listed as follows:

  • Is it possible to obtain data to how far a vehicle (not controlled by IPG Driver) has traversed along the track?
  • Is it possible to get the centre line of a track from CarMaker, for example, as a set of x, y, and z coordinates?
  • Is there functionality to obtain the vehicle position relative to the track centre line?
  • What is the best approach to determining if the vehicle is off the track?

For the last question, I am currently trying to implement it with the help of the following code snippet from MyTire.c:

  tTParamHeader * th;
  tTireIF * IF;
  int rv = 0;
  tRoadGeoIn  rIn;
  tRoadGeoOut rOut;

  if ((IF->TireCalcMode == TireCalcPrepWithRoad
      || IF->TireCalcMode == TireCalcPrepWhlWithRoad
      || IF->TireCalcMode == TireCalcSim) && !Vehicle.ModelCheck.SPMM) {

      rv = RoadGeoEval(th->RoadEval, NULL, &rIn, &rOut);
      if (rv != ROAD_Ok) {
[2] = IF->P_0[2]; /* last z-Value */
          rOut.onRoad = RPK_OffRoad;
          Set_RoadOut_ForNoRoad (&rIn, &rOut);
          rv = 1;

  } else {
  /* Flat plane road for preparation phase */[2] = 0.0;
  rOut.onRoad = RPK_OnRoad;
  Set_RoadOut_ForNoRoad (&rIn, &rOut);

  if (IF->onRoad == RPK_OffRoad && rv >= 0) {
      LogErrF (EC_Sim, "Vehicle leaves road at x=%g, y=%g TireNo=%d",[0],[1], th->TireNo);

However, I am currently stuck on the error of being unable to find RoadGeoEval, and from what I can see, there is only a declaration of this function in road.h. Is this the best approach to take when determining whether the vehicle is off the track? Is all this code necessary to determine if the car is off the track?

I did check if if (IF->onRoad == RPK_OffRoad) would be sufficient to determine if the car was off the road, but from but I could see, RPK_OffRoad is 0, and IF->onRoad would not be equal to 0. Perhaps I am initialising IF incorrectly?

Hello Onish,

  1. Vhcl.sRoad and Vhcl.tRoad could be used for that. As long as a route is selected, even if IPG Driver is turned off, it will still give the distance to the route. The two quantities do need a little bit of modification:
    a. This is technically the position of a “hidden” road sensor inside the vehicle, so it differs from Fr1A. Fr1 starts at the projection of the hitch on the road (so rear of the car is 0,0). The road sensor is actually in the middle of the front axle.
    b. It seems that tRoad is given with respect to the road origin line, which is offset from the driving path. In the basic circuit we provide, the offset is 1.5m, easy to account for, but it’s there so it needs to be added/subtracted.
  2. I’m not sure it’s possible to get the centre of the road. Back in the day CarMaker used to accept simple ascii .road files with XYZC coordinates in a table, but I understand that is no longer the case, plus the capability to include a lot more complicated junctions has been greatly expanded since then. I’ll try to find out if there is a shortcut to do that. If I cannot find one, I can think of two workarounds:
    a. Export the road in the OpenDRIVE standard and find a tool that can export the circuit from that as XYZ.
    b. Run a lap with IPG Driver turned on and corner cutting coefficient down to 0. The driver will follow the reference line of the path in an almost ideal manner. Then record the vehicle XYZ positions during this lap and export this.
  3. That would be the tRoad quantity from point 1.
  4. In a fixed width track such as this, I suppose you can once again use a very simple check whether the current tRoad is larger than the road width (the example track is not symmetrical around the origin, so this needs to be taken into account). That is extremely simplified as in the real world, just because the centre of the front axle is not offroad, doesn’t mean the car has not slipped or spun in a way that has rendered a part of it offroad.

I’ll see if I can find any additional information on point 4, but it seems like you’ve incorporated a little bit of our existing Road API with the RoadGeoEval function. It’s quite possible that the RoadAPI can solve a lot of the queries in this post, but I’ve personally never had the chance to use it. I suggest that you have in mind the additional documentation dedicated to this API, available from CarMaker → Help → Additional Documents → IPG Road API Reference

Hi Onish,

I cannot find a simple solution to the XYZ issue. Probably the best thing to do is to actually do one lap around the circuit with IPG Driver with no corner cutting and at a constant speed and record the XYZ data.

Regarding the offroad detection, I think you were on the right track. For your purposes, you don’t need all this code, a simple check would suffice. However, I suggest you search the RoadAPI documentation for the “onRoad” method as well as the resulting " tRoadPosKind" enumeration output.

There are actually 4 states, and 3 of them might be considered “offroad” depending on your application. In CarMaker, there is an extra lane on each side of the road called “road side”. Technically it’s not off-road, but it’s not really on-road either. For your purposes, perhaps it would be good to check if onRoad != RPK_OnRoad only as all other states might be “off-road” for your needs.

Hi Bogomil,

Apologies for the delay in replying, as you know, I have been busy working on the object detection sensor and cameras, and have therefore not had plenty of time to look into this. Having now looked into it, I believe I may be having an issue with how my code is reading the header files.

When I try:

#include <iostream>
#include "Vehicle.h"

int main() {
    std::cout << Vehicle.tRoad << std::endl;
    return 0;

I will get an error saying undefined reference to Vehicle, however if I write:

#include <iostream>
#include "Vehicle.h"

tVehicle vehicle

int main() {
    std::cout << vehicle.tRoad << std::endl;
    return 0;

The code will compile but the values will be nonsensical and the same is true when I try to get values from tTireIF IF. I assume the values are nonsensical because I am creating a new variable that is not updated by the simulation. In CMNode_ROS1_HelloCM.cpp, I am able to get values from using method 1. So for some reason, in my code it does not see that the Vehicle variable exists after:

extern tVehicle Vehicle;

I have sent you a copy of my CMakeLists.txt to your email. Could the issue be caused by me needing to compile using C++14 instead of C++11? Furthermore, what is the correct way to declare tTireIF.

Hello Onish,

Is this a separate ROS node or a CPP file that is being added to the main CarMaker executable?

The Vehicle data is technically only available when you are inside the main CarMaker executable. The CarMaker ROS node CMNode_ROS1_HelloCM.cpp is actually compiled and linked to that executable, so it has direct access to the internal CM libraries and code that allow interaction with the API and reading of these values.

If you are creating a completely separate ROS node or a CPP file that is not packaged inside CarMaker.linux64, getting to this value purely over C/CPP might be quite tricky.

The function that you wrote can probably work if you manage to somehow include it in the standard project SRC folder (not the ROS sources, but rather <project_root>/src), but I have the feeling that you are trying to create a separate ROS node. In that case, your best bet is to access Vehicle.tRoad from CMNode_ROS1_HelloCM and then publish it over ROS.

In addition, there is a way to query everything that is happening inside CarMaker and even control it from files other than the CM executable. CarMaker actually runs headless and allows multiple clients to connect to it and do whatever they need to with the the current live data. The CarMaker GUI, Instrument Panel, IPG Control, IPG Movie, MovieNX, these are all a lot more disjoint than in a standard piece of software because in a way they are somewhat independent. They all connect to the “headless” CarMaker in the background through an “APO” (Application Online).

I don’t know much about the APO myself, but there is yet another document dedicated to this concept in Help - Additional Documents - APO Communication Service. It shouldn’t be that hard to set that connection, but it’s quite likely that the ROS route might be simpler at this stage.

Hi Bogomil,

Thank you for getting back to me. I was thinking that that was probably the issue and have since created a separate publisher which publishes sRoad and tRoad, however I am unsure if I am using tTireIF correctly. I have tried initialising it using boost::make_shared<tTireIF>(), however when I try to access the onRoad value, I just get 0 even if the vehicle is on the road. I’m guessing I should not be creating a pointer to a new tTireIF struct and should be accessing the pointer from one of the header files, but I do not see where it is.

It might be a bit complicated to integrate my project directly into the CarMaker executable as it is quite large at this point so I think I shall avoid doing that and stick with the ROS method. However that is good to know for future reference as I assume this will allow for the simulation to run at the rate at which my code can process data.

Hi Onish,

Yeah I think you will have to reference the tyres already attached to the vehicle unless you are defining your custom tyre model.

Inside Vehicle.h, you can find a function Tire_GetHandle, this should return a pointer to a structure of tTire type. Then the field tTire->IF is actually the handle to the tyre interface that I think you might be looking for.