Achieving UTI

From SpaceElevatorWiki.com
Jump to navigationJump to search

Intro

C# code design was depending a lot on C++ code due to compatibility constraint with Torcs plugins.

However, with time, we finally ended up rewriting almost everything but the car simulation engine (which is the big part of the simuv2 plugin)

We then removed lot of C++ code, mainly track and robots related code, then their dependencies.

The C# code can now be redesigned properly (without constraints), starting with the track interface (see Universal Track Interface).

Step 1: kill some C++

  • 1- We got rid of all C++ code not needed by simuv2.
    • 1. we disabled legacy c++ robots, which in turn allowed to remove learning, robottools, plib (almost completely).
    • 2. C# code that needed to access/modify t* struct now do it through an interface (called UTI).
    • 3. We removed as much C++ code as possible.
  • 2- Simplifying simuv2
    • simuv2 no longer manages collisions, we got rid of solid.

Progress indicator

The indicator is the number of lines of C++ compiled in libsimulator.so. Goal is 0 (one day maybe).

  • 22/06, 05:00pm. 39223 lines
  • 23/06, 03:00pm. 32984 lines (removed c++ drivers)
  • 23/06, 03:30pm. 31697 lines (removed learning)
  • 23/06, 05:00pm. 31565 lines (tried to remove robottools... but track have a dependency over it. simplifying what can be)
  • 24/06, 05:00pm. 30817 lines (removed gnulinux)
  • 24/06, 06:00pm. 30116 lines (removed simuv2 collision handling code, removed simuv2's dependency over the track format)
  • 26/06, 11:00am. 24528 lines (removed track, finished to remove robottools)
  • 26/06, 12:30pm. 21975 lines (removed most of plib. cleaning some commented lines)
  • 26/06, 07:30pm. 18289 lines (removed solid and portability)
  • 26/06, 10:00pm. 17949 lines (removed lot of raceman, cleaning)

Going further

Almost half the remaining C++ code is related to parsing XML and storing/managing GfParm (which is a list of Metadata -- or Dictionnary -- done in C++).

A quick grep approximates that SimuV2 retrieves about 103 static informations about the car from its GfParm files. If we create a structure in which we store those informations, we can then load them from C# (using far-far less code).

When all those 103 informations are loaded from C#, we can drop the txml and tgf c++ modules. Only simuv2 and math will remain (and I guess we then can't go any further except by porting simuv2 to C#).

Torcs' data structures and C#

OpenRacing is still relying on a few data structures which are defined in C++, they are used to keep synchronized simulation state between C++ and C#.

However, the C++ code is now absolutely free of informations about the track. So, concerning UTI's work, we have nothing to change on that part.

Alpha UTI

On the process to remove track from C++, I needed to add a minimal UTI interface in order to be able to run the simulation.

AlphaUTI is an extremely minimalist implementation of it. It gives a single starting position (0,0,2) and point its path to the street-1 folder so Ode and Ogre load their data from there.

We now need to transfer some intelligence from Ode/Ogre to UTI (so an UTI is not just a folder!).

Step 2: Conception

Plan

  1. Solve the problems
    1. What informations needs each modules?
      1. Ode?
      2. Ogre?
      3. Robots?
      4. RaceManager?
    2. How blender can define those?
    3. How UTI should present this to OpenRacing's modules, in an abstract way?
  2. Provide class specifications.
    1. For physics
    2. For graphics
    3. For robots
  3. Implement AlphaUTI and/or tools (depends where the methods goes)
    1. .OTF (pseudo collada) loader
    2. convert .OTF to OGRE
  4. Adapt
    1. Ode to use UTI
    2. Ogre to use UTI
    3. Robots to use UTI
  5. Enjoy the new track made with blender!

Basic design

Initial conception gives this.

UTI-Integration.png

After question Q3, I decided to split UTI into two layers, so the robot is given only a very high level detail of informations whereas physics and graphics can see more details.

UTI-UTD.png

Ode needs

Ode needs:

  • a list of meshes
    • with physical properties
    • with normals

API

 struct PhysicalSurface {
   Vector3[] Vertices;
   Vector3[] Normals;
   int[]     Indices;
   
   float RollingResistance; // Resistance to rolling of the surface
   float Friction; // Friction of the surface
 }

Integration to UTD

 interface UTD {
   ...
   // Returns the surfaces in the physical scene
   List<PhysicalSurface> PhysicalSurfaces { get; }
   ...
 }

Ogre needs

  • 3d model in OgreMesh format.

However, we like the OgreMesh to be generated by code using the UTD interface (see Question Q4).

UTD should provide all necessary data.

API

Let's go straight to the API

 struct VisualMesh {
   Vector3[] Vertices;
   Vector3[] Normals;
   Vector3[] Tangents;
   Vector3[] Texcoords;
   int[]     Indices;
   
   // Material associated with this mesh
   VisualMaterial Material;
 }
 
 // A material with its attributes
 struct VisualMaterial {
   string Name; // Name of the material
   string Type; // Type of material (shader to apply)
   // Shader's parameters
   Dictionary<string, string> StringProperties;
   Dictionary<string, double> FloatProperties;
   Dictionary<string, int>    IntProperties;
 }

Integration to UTD

interface UTD {
  ...
  List<VisualMesh> VisualMeshes { get; }
  List<VisualMaterial> VisualMaterials { get; }
  ...
}

Robots needs

  • Way-Points
  • Drivable area (lanes or other areas / parking / etc)

The goal of a robot is to make a car drive to a given waypoint without leaving drivable areas.

He needs to know:

  • which drivable area he stands on
  • boundaries of this area
  • connection to other drivable areas
  • his destination
  • distance between those areas and the destination (so he can choose the shortest path)

WayPoint

A location in space. What we need to know from a way-point is whether we reached it or not.

The robot also need a mean to reference it: so it has an Id in the UTI.

API

Thus the proposed, very simple API for UTI.

 interface WayPoint {
   float Distance(Vector3 pos); // distance between waypoint and given position
   Vec3 Direction(Vector3 pos); // direction leading to the waypoint from given position
   bool Reached(BoundingBox box); // returns true if box reached the waypoint.
 }

Integration to UTI

 interface UTI {
   ...
   WayPoint GetWayPoint(string id); // Return WayPoint with given ID
   ...
 }

Drivable Area

The surface on which the car is allowed to drive.

API

 // Connection to a drivable area (find better name?)
 interface Portal {
   float DrivingDistance(Waypoint wp); // Returns the driving distance to a given waypoint
   List<Vector2> Entry { get; } // The shared vertice between the two drivable areas
   DrivableArea To { get; } // The portal is connected to this DrivableArea
 }
 
 // Define an area the car can drive onto
 interface DrivableArea {
   bool IsInside(BoundingBox box); // returns
   Collection<Vector2> Boundaries { get; } // Polygon the car is not allowed to go through (except those in portals).
   Collection<Portal> Portals { get; } // Connected DrivableAreas
 }

Example

DrivableArea.png

DrivableArea B is connected to DrivableArea A and C. Boundaries are in black. Portals in red.


Integration to UTI

 interface UTI {
   ...
   List<DrivableArea> GetDrivableAreasUnder(BoundingBox box); // Return the drivable areas a vehicle stands on.
   ...
 }

RaceManager needs

The RaceManager takes care of initializing car at specified positions (which is very specific to a simulator but needs to be done).

RaceManager need to be provided an array of possible starting positions.

Starting Position

In addition to avoid putting cars randomly on the road, starting positions will allow to make races.

API

 interface StartingPosition {
   Vector3 Position { get; }
   Quaternion Orientation { get; }
 }

Integration to UTI

 interface UTI {
   ...
   List<StartingPosition> StartingPositions { get; }
   ...
 }

Blender exports

UTI's API

http://bazaar.launchpad.net/~openracing/openracing/trunk/annotate/head%3A/src/core/UTI.cs

AlphaUTI

Questions

Q1: Should the robot decide the features of his car?

It seems more natural to me to build a car then put a driver into the car (instead of the opposite). Maybe some AI are very specific to drive a particular car.

[solved] Let's forget about complications first: we simplify!

Q2: For blender, we may also need an OTF importer, can we share this code with UTI (C#)?

If we store .blend file next to .otf file, that is not necessary. But what if the .OTF file comes from other mean (like an eventual Torcs to OTF convertion tool)?

Q3: In order to make UTI as extensible as possible, we like to present very few (or no) datas to high-level code. If Ogre and Ode relies on UTI directly we need to expose them very low-level informations (like the meshes and materials). If a scene exporter relies on UTI, same problem. Is it an issue?

[solved] I think we can split the abstraction into two levels. A very high level called Universal Track Interface, presents only algorithms (no data). A lower level presents an abstracted view of datas (which still allows to change lightly the file format, but gives modules access to low-level data (without exposing that to robots or the race manager for instance.

UTI-UTD.png

Q4: Will the OgreMesh be generated at runtime?

[solved] In all case (runtime or preprocessing), it's good that the generator use the provided interface so we can change the underlying file format without changing anything dealing with Ogre. So UTD should provide necessary data to generate a visual scene.