The online racing simulator
Searching in All forums
(987 results)
blackbird04217
S3 licensed
I'll give that a go a bit later. I may just have to live with it as it is, but it would be really nice to be able to control things through the AIRS application without having the car careen off course when leaving it running. Worst case I think I can keep dealing with it.
blackbird04217
S3 licensed
So I've just modified my firewall and had a few users successfully connect to the server I use for the artificial driver to drive. He doesn't drive safely, so if you join the server please just spectate for now. You can join the server: SRS:TestingGrounds

lfs://join=SRS:TestingGrounds
blackbird04217
S3 licensed
Interesting. I was unable to get it to work (Windows XP) although I was trying to click from LFS to a different application. Do you know what situations provoke the device to be released?
blackbird04217
S3 licensed
Last night I started a major refactoring of some of the base code in hopes to add some features and easier debugging information to the AIRS in LFS project. This went fairly well, there was a minor hitch in the first part of the refactoring but I got that solved by essentially reading through each change from the previous commit. Thank you source control!

However today, I've encountered the strangest issue with the artificial driver. For some odd and unexplainable reason the driver seems to drive slowly about 5 to 10 meters to the left of the racing line for almost a full lap, then it seems to kick in and find the racing line and start driving faster and on the line as expected doing the ~1:02 to 1:03 range of laptimes.

Mind you during this refactoring nothing logical should have changed and I was trying to remain meticulous about this. I decided then to build the previous version, which excludes any possibility of the refactoring, and the behavior is identical. I am extremely confused why the driver is behaving this way. The only other change I had done in the midst of this was attempting the dinput8.dll injection that MadCatX suggested, however the dll is not being injected at the time of these issues.

I'm at a loss as to how this is possible. The artificial driver follows the racing line, even though all positions seem correct INCLUDING the position it wants to drive towards. Then about 80% through the first lap it corrects itself on the back chicane and starts racing around properly.

My hopes was to get things refactored a bit, improve the primary AIRS application and InSim/OutSim/OutGuage connections. Primarily to collect more state information, and add ability to send messages to LFS, add a way to debug the sensors / track information with player controlled car, and some other support to make it easier to develop further so I could continue along the idea of determining corners vs straights on the racing line and detecting the actual limits of the car.

So, other than the artificial driver suddenly becoming immensely stupid on the first lap, everything else has been going good.
blackbird04217
S3 licensed
MadCatX that was a brilliant idea and was quite easy to test with that template. Unfortunately it didn't work. I did ensure that the DLL was being injected properly by building it with a message box that did appear, (although LFS would crash with the MessageBox popping up I do assume that it was working without the message box).

I think LFS is detecting that it is not the active window, and will then skip the input updates. I could be wrong, but it feels like this is what is happening, and I'm not sure there is a way around that without support from the developers.
Driving when LFS loses focus...
blackbird04217
S3 licensed
Is this possible?

With my AI project it would be super useful to be able to have LFS being controlled by the virtual steering wheel even when the LFS window doesn't have primary focus. Does anyone know of a way to do this?
blackbird04217
S3 licensed
@vladvlad, knowledge is not exactly a requirement to start working on anything you want to create, be it a movie, game, house or what have you. Time, energy, dedication and the desire to do so can push you to learn new things, try new things and persist at the task even in the darkest of times when you seem only to fail. The trick is finding what you truly want to work on an pursuing it completely, so don't be afraid to learn the knowledge you don't yet have, actually most of this thread is about my learning experience.

...

Regarding progress with the project, I have cleaned up a few sections and added minor features will help from and thanks to amp88. I need to rework that area a little bit more. I also started, but didn't get far at all, trying to compute the corner points from the racing line computer. I also started, and also didn't get far, predicting the state of the car with isOversteering(), isUndersteering(), isOverBraking(), isOverThrottle(), but before I did much I realized that my isOverBraking() method will not produce good results, and I haven't found a good solution yet.

My 'breakthrough' idea was to use the longitudinal g-forces, in thinking that if the tires are locked it will be less than the ideal force ... but so would braking less than the threshold, so does this indicate braking below limit, or above? Unfortunately I have no great solution here. The only recovering thought I have, given the information from LFS / the sensors, is to set the brake balance in a manner that locks the drive wheels and then check the speedometer vs physical speed like the isOverThrottling(), but this is not optimum and requires the artificial driver to have a specific setup, which I currently use a specified setup to more accurately judge if my changes made the driver slower/faster.
blackbird04217
S3 licensed
Why don't you do something like:

PLC.Cars = 0;
if (Conn.Cars.Contains("XFG")) { PLC.Cars = PLC.Cars | CarFlags.XFG; }
if (Conn.Cars.Contains("FBM")) { PLC.Cars = PLC.Cars | CarFlags.FBM; }


If I understand the question correctly, this should give you what you're looking for.
blackbird04217
S3 licensed
I've had a break through last night. Sometimes on this project all I need is a little bit of time and voila new bits come to me. I've been pondering how to handle the situation with the many different variables at play and how to make the artificial driver faster without hardcoding information specific to FE1, the XRG or the particular setup being used. I went through reading some of my older posts about the reference points and how I wanted to use them previously, (way back when I had wanted to have braking, turn in, apex points instead of just left/right edge, though in my defense I just never got that far... yet)

Last night the light bulb went off, I can modify how I compute the racing line ever so slightly and add a brand new reference point for the driver to keep track of. If you recall from previous bits, the artificial driver is already driving towards a driveToPoint that moves in front of the car along the racing line. This new reference point will be added at the start of every corner on the racing line, or at least after some length of a straight section, to be determined by the angle between the hinges used in the computation.

This new TurnPoint will go into the drivers memory unit, and will hold some information that cannot be changed, where the turn begins, and the distance and position at the end. With this information I should be able to determine if the driveToPoint is within a turn, and/or if the car is within a turn. When it is within a turn the driver will attempt to drive at the limits of the car or try smoothly accelerating to the limit.

The TurnPoint will also hold a few values that will change over time like brakingPoint and entrySpeed. As the driver is approaching a turn, he will begin braking once he reaches the brakingPoint and attempt to reach entrySpeed before reaching the actual turn in. I can then set these values to long braking areas and slow entry speeds which should allow the driver to smoothly enter the corner, but obviously not be at the limit. The driver could then check on the conditions of the car, how much at the limit was the car at various points, and determine if more braking area is needed, extend the brakingPoint. If more or less speed is required to take the corner quickly but safe, it can also be modified in the long term memory.

This should allow the driver to tune his braking points and driving as I originally wanted to using pseudo-reference points. This "TurnPoint" won't be the same as the points on left/right track edges, instead it will exist only in drivers long term memory, and always be "seen" or at least thought of.

...

Now, this gets me back to a slightly minor problem, which last nights brilliance solved most of but still a slight issue exists. This method of driving requires me to semi-accurately judge how "at the limit" the car is at a given point. This is the job of the prediction unit however instead of using the future predicted path, (which as we can see has been unreliable and may eventually need to be fixed or stripped out), it will need to predict several immediate states of the car:
  • isOverSteering() - (can be determined by comparing carHeading with velocityDirection)
  • isUnderSteering() - (possibly determined by comparing steeringAngle vs yaw rotation?)
  • isFrontLocked() / isRearLocked() - (can't be accurately determined that I am aware of, but would be great!)
  • isOverBraking() - (possible determined by comparing longitudinal G forces with a value specific for the car)
  • isOverThrottling() - (can be determined by comparing carSpeed (speedometer) with velocityMagnitude (physical speed))
So the unknown is how accurate I can determine understeer condition and over braking conditions. Both are needed for the driver to tune corner entry and determine if the car is at or over the limit. I also need to find a way, which I haven't figured out yet, how to determine that the car is NEAR the limit. It is easy to determine over the limit (any one or more of the above conditions is true), and reasonable easy to determine under the limit (all of the above conditions are false), but the artificial driver should be able to find when the car has neared the limit so he doesn't push too far. The best thought here so far, and I don't really like it, is to determine if one of the conditions were true within the last tenth or two tenths of a second, then assume the car is near the limit. Of course this requires driving over the limit to be near the limit...

Those functions won't only be black and white, for instance isOverSteering() can and likely will use a different function quantifyOverSteering() to determine if the car is in an oversteer state... Something like:

bool isOverSteering() { return quantifyOverSteering() > limitThreshold; }

So it MAY be possible, to determine if the car is near the limit if one or more of the states are less than the limitThreshold but greater than some grandmaThreshold.

If I haven't lost you yet, great! If I have, and this is likely to be the case, please ask questions. Get involved! It makes me think more about the solutions, and keeps my motivation up.

....

So this means I need to do several things:
  1. I should seriously consider removing the curve path, and possibly even reducing visual sensor wasted time.
  2. Modify the Racing Line Computer to find/separate straights and turns.
  3. Create TurnPoint reference points and put in the long-term memory unit with default slow values.
  4. Modify prediction unit to accurately determine state of car, and if it is near limit.
  5. Create a driving state to get the artificial driver to drive near the limit and handle over limit cases.
  6. Make driver modify long term memory based on what happened at different points during the turn.
This is a pretty heft list, but I think if I pull it off correctly the driver might be reasonable fast without hard-coded values specific to a car/track/setup configuration. It will be amazing to see the airs_artificial_driver with lap times closer to 107% of WRs
blackbird04217
S3 licensed
I see what your saying, actually I got them to get beyond the first turn in that last video I posted, it just took tuning the fitness function, and at that it wouldn't really work for the AIRS with LFS project. I've been thinking a lot about that portion of the project a bit, to make the LFS artificial driver faster, but it is tricky. Ultimately I need to figure out how to fix the prediction unit to be smoother and more accurate. It is often accurate, but as you can see in the driving around video, it bounces around too much, and that would cause the driver to have bad information.

If the prediction unit was working as expected, it would give the driver the ability to read the future of the car and feel a bit better "am I on the limit" and react to being over the limit whether understeering or oversteering - which is essentially the next step needed.

I need to take a few steps backward in-order to go forward. I've learned the curve implementation I added to "add other tracks easier" actually doesn't work in practice. I don't want to keep the AI doing only FE1 because I don't want to accidentally hardcode values/algorithms that work good on FE1 but not on other tracks. So I probably need to remove the curves. I do need to spend some time on optimizing, possibly even remove the terrain occlusion from the visual sensor (it is reasonably slow).

I've got the artificial driver to follow a line, now I need to teach the driver to do so at the limits of the car, on the verge of understeering or oversteering but not over the limit. Of course this means I'll need to teach the driver how to handle the car over the limits as well.
blackbird04217
S3 licensed
It has been a fair bit of time again since I've made forward progress, but I've uploaded two videos recently that you guys may be interested in, the first is of the artificial driver controlling the car around FE1 exactly as I had it back in June, but I'm now just creating and uploading a video of it instead of just a replay.

Artificial Intelligence in Rac ... mulations: Driving Around

The other is of the small genetic algorithm that was previously discussed and that I've put some more effort into tweaking. It actually turned out pretty reasonable - but a pain to tune. I've realized some things I've done wrong but not sure how much more I will push the genetic algorithm technique. The original intention of this was to try out other techniques, and learn them, and see if it would be good to apply to the AIRS project. With the tuning difficulty, and only 1 artificial driver in control at a time in LFS this would be too extreme. Not to mention the simulation these bots are running in is extremely simple with no camber or grip changes, no weight transfer or loss of grip. So I think a genetic algorithm is out of play for AIRS, which means a neural network is also out.

Artificial Intelligence in Rac ... ations: Genetic Algorithm
blackbird04217
S3 licensed
And what in the setup, beyond the restrictor, is going to modify the engine? I would not want to change tire pressures or wing levels and have the car change sounds.

BigPeBe - You are correct with that, although with the available options you could make the XRG loud and still sound pretty similar, not identical of course. But my point stands that I don't want just sounds created by anyone- but I do support the idea of more audio differences which it sounds like LFS could be setup for.
blackbird04217
S3 licensed
I both support this idea and go against it.

I don't want to listen to someones awful sounding, clipping XRG. Nor do I want to hear the XRG sounding like an FZR, (not entirely sure, but I think that could be achieved through the in game sound editing?).

But I do support the idea of at least having multiple sound files for each type of car that get chosen at random _except for_ the players car which always gets the same. I don't want to get into my XRG and have it sound different from run to run. But I would like to hear slight differences so I know who might be near me while racing. Maybe the selection algorithm should take into consideration username if online to keep that consistent between runs.

Just my thoughts.
blackbird04217
S3 licensed
That is the idea and why the totalFitness is important... Using your example,

Bill 10/16 has a 62.5% chance of being selected to reproduce each time a chromosome is grabbed.

Tom 5/16 31.25% chance.
Bill 6.25% chance.

Which makes Bill much more likely to become an influencing chromosome in the next generation. The totalFitness added up is only used to make the selection give the better chromosomes better odds.

Going back to what you said earlier, it'd be better to remove the bottom portion of the barrel before this. But this is the way I understood it, giving the more fit chromosomes more chance of being selected more times. Of course this does not guarantee it will be selected, which could be undesirable but I was described as it also has chances of still helping to do that as well.

Maybe this will help understand what I've done and how it does what you said above.


Chromosome GetRandomChromosome(allChromosomes, totalFitness)
randomValue = Random(0, 1);
elapsed = 0;
foreach chromosome in allChromosomes
elapsed += chromosome.fitness / totalFitness;
if (elapsed >= randomValue)
return chromosome;
return allChromosome.back(); //should never actually reach here.

EDIT: You could also also achieve the same thing removing the division and calling Random(0, totalFitness);
blackbird04217
S3 licensed
I think you misunderstood how the totalFitness was being used. I implemented it the way that I understood from my readings and a few videos I watched prior to. Now we could go ahead and do what you are suggesting, it does actually make the most sense for finding the best path the quickest way possible, and maybe I will modify the GA so that it can handle this case and just kill off the bottom X% of the population each generation so the better portion breeds more.

I was actually using the totalFitness for that current generation, not keeping it around for previous generations also. So basically in my previous example totalFitness = 100. Car A: fitness of 60, had a 60% chance of breeding because 60 / 100 = 0.6. The totalFitness does not need be 100. It can be any number and dividing the fitness for an individual by the totalFitness for that generation gives that individuals chance of breeding. Again, I understand your thought about removing the bottom of the barrel, it was just that this is how I understood and saw from the resources I had at the time.

I also understand where you are coming from with the differences between a gene being a bit and a gene being a byte, although I am still not quite understanding how to take a bunch of bits and apply them to the algorithm though, and just messing with bits and interpreting as a float or value seems less useful?, so I will hold off on that for now. Although to be fair, I do need to, and will, reread what you said earlier and recently so that I can understand it a bit better and get all the information you've given me, thanks very much!

I did manage to toss in a new controller using the two genes to represent k1 and k2 in the function: steering = leftRightDistance * k1 + leftRightVelocity * k2; and it manages to get beyond the hairpin of turn 1 once the throttle input is lowered. I had to stick it down to 20% throttle. Obviously I will tie the throttle and brakes to some genes and functions as well, but considering I am working right now, I can't spend too much time playing around with it.

Thanks very much for the discussion and all the shared information!
blackbird04217
S3 licensed
I believe I do understand the Genetic Algorithm fairly well, but given it is my first experience with it there may be some things that I messed up. I did not choose to go the purely binary way, and instead used floats like you stated. It looks similar to this:


struct Chromosome
{
float genes[kMaximumGenes];

//For each gene, if chance is within kMutationChance, add a random amount max of kMutationAmount
void Mutate(void);

//If chance is within kCrossoverChance, choose a random number 1 to kMaximumGenes and swap the genes
void Crossover(Chromosome& offspring1, Chromosome& offspring2);
}

For my particular situation I had, and this changed constantly as I attempted to configure the GA:


kMaximumGenes = numberOfReferencePoints * 2;
kCrossoverChance = 40%
kMutationChance = 10%
kMutationAmount = +/- 0.2 (at max, the actual mutation is random within this amount)

The population runs for a generation, and before spawning the next generation compute the totalBestFit by adding all the fitnesses up. This allows me to choose chromosomes randomly, while giving the 'better' genes a better chance to spawn again. I do not remove chromosomes once selected, so ultimately it could be selected several times, I was unsure on this detail, but it makes sense to me that it would remain in the pool.

If we had a population of 4 chromosomes, with the following fitness:

A: 60
B: 32
C: 5
D: 3

Then total fitness is 100, for simplicity. A then has a 60% chance of being selected each time the GetRandomChromosome() is called, which it will be called 4 times. B has a 32% chance, and C and D are fairly small. This means A and B are more likely to spawn again, and then possibly crossover, and possibly mutate....

This is how I understood the genetic algorithm / process to work. Let me try real quick the way you mentioned above using only 2 genes, to modify k values.
blackbird04217
S3 licensed
Todd, well written, lots of good points in there. You had the concept of what I was doing with the genetic algorithm perfectly correct, sorry for the poor explanation before. The input was essentially the t, interpolating between the outputs for reference point X and X + 1, and the out puts was -1 to 1 steering and -1 to 1 throttle/brake.

While the 't' value is computed in an iterative process, it isn't using anything as smart as bisecting half the segment each time, the primary reason I do it is to detect validity of laps. Sure this can be improved - a lot, I do realize this. And really the boost in speed could happen by not calling the bezier interpolate while iterating through; I will see about changing it to line segments, and iterate to find the closest line segment, which should be much much faster. Another option for optimizing this, was to make and have each car contain a "tracker" that has information about where it was previously located, then perform the iteration going away from the tracker in both ways until the distance grows. Doing either, or both, of these optimizations should eliminate the problem completely - I just haven't done it.



steeringOutput = leftRightDistance * k1 + leftRightVelocity * k2;

Maybe I'm being pessimistic, or silly, or thinking wrongly about something but I feel that steeringOutput computed this way is somewhat using logic to do so. Although there are no if (leftRightDistance > k1) like I was writing before, the if statement is slightly hidden when leftRightDistance has negative/positive values. I do like it though, it is pretty simple, and I will give it a try when I play with this project again.

Actually might be quick enough to throw in, modify the gene count to 2 (for k1 and k2) and see what happens with throttle stuck at 50%. (100% would surely throw them off track at some point).
blackbird04217
S3 licensed
yeager, updating out of DirectX 9 is not going to magically supply better graphics or anything that LFS will gain from. I don't understand your point and this thread is not for complaining. Of course your posts and mine will likely be cleaned up, but you're complaining about something so silly.

I'm glad to see the development is continuing, and yes it might be slow, but I will certainly continue trying out the new developments, and also continue waiting for more.
blackbird04217
S3 licensed
@w126 - Yes you do have a point that drivers that fall off the road and die off do not have a chance to continue if by chance they would. Initially I was going to allow them to do this, and since it is easy to try I try to do it sometime when I get back around to it. As Keling was mentioning though, it is undesirable for the drivers to drive off track and killing them off helps with this while reducing wasted training cycles.

I do understand that the inputs do depend on the location of the driver, but in this 'simulation' with the fixed setup and all, I still feel, it should have still found a way around the track. The problem almost certainly belongs with the fitness function. Currently the fitness is based on furthest distance reached along the track. This can, and does, cause a slight issue with the hairpin turn, where the "most fit" drivers will cut as closely to the left edge without even turning...

I attempted to correct this by also adding a modifier to the fitness function that accumulated as time went on, the closer the cars direction is to the desired direction (next reference point) the more accumulated. This was added with the distance. This would reward the driver more for remaining close to the centerline while nearly always aiming at the next reference point and driving...

This failed too. The first method I thought about doing was a little more logical, where: IF distance to leftEdge < geneA THEN steering = -geneB * distance ... or something to the effect of making the genes have some modifying behavior over a logical algorithm, I chose not to go this way because it felt a little cheap to me, not quite like the AI really figured out anything except more optimal parameters for the given logic, which I found limiting.

Another thought I've had recently, is possibly to make a combination of these. Perhaps I work on the logic idea, and then instead of using the next reference point directly (as I talked about above), the driver would store in genes the desired location (left or right) of each reference point. The algorithm would then steer and accelerate toward that desired point. Essentially the genes then control the logic for the "racing line" and controls based on angle toward next point and current speed.

This again still feels a little limited, and I can already imagine the first many generations are going to be zig zagging around left and right of each reference point, but it should eventually straighten out, and likely even make a better racing line than my geometric attempt last year- because they would account for speed and braking. Not sure, it still feels slightly limited, although less so than the pure algorithmic approach.
blackbird04217
S3 licensed
No, you can't. And the bottle neck is not the rendering, the rendering take such a small amount of time (it shouldn't be vsync'd). The slow down is caused by the computing the closest point on the track, which is required for validating the lap and the interpolation between current and next reference points.

It is only called once per step per car, instead of two, which obviously helped significantly, but this is the current problem. Making it faster is possible as I stated above, but it then gets sloppy and the validation is not as accurate. Ultimately it comes down to an iterative process that happens a lot. Even if that were removed, the artificial drivers don't get much better, they never make it around turn one.
blackbird04217
S3 licensed
Well that was certainly a demoralizing day. It happens. I've spent all day attempting to adjust the fitness function, the population size, the mutation rate, crossover rate, etc etc to attempt to get the genetic algorithm working. I've even attempted to make the track wider.

In some way you can watch it improve, but then they get to the hairpin known as turn 1 and don't make around the bend. I did see a few times where one or two drivers made a fair attempt and became more fit, but randomly died out. I have found I can run it in release mode with a population of about 200 before it slows down tooo much, so maybe I'll just let it run overnight, and see if anything interesting happens. I suspect I will come back and they will still be falling off turn 1.

I've gone ahead and attached the current version of this project, it is really nothing amazing, I will let it run all night here to see what comes out, but I suspect the drivers will be falling off T1 when I wake up. There are 100 drivers and 40 reference points (80 genes).

@bishtop - Yea that would be nice but LFS does not give me that information so the artificial driver won't get that as an input. That said I am not specifically working on the LFS AIRS project at the current moment, but instead the Genetic Algorithm / 2D simulation project for testing some other thoughts out.

Edit

So after leaving it running all night, for just under 2500 generations with a population of 500, as expected they did not make it beyond turn 1. I was a little hopeful that I was wrong with my prediction and that when coming back they would be getting further along on the track. I'm writing that off as a failed attempt at a genetic algorithm for the moment. I may attempt to do the "logic controlled genetic algorithm" that I described several posts back, however as I said initially that feels like a bit of cheating. I would basically be giving the drivers a guideline that they then modify the limits of to go faster.
Last edited by blackbird04217, .
blackbird04217
S3 licensed
No, actually I don't necessarily feed inputs to get outputs. The artificial drivers in this simulation know about their car position in the world, and several reference points that happen to be on the center line of the track. Using this the driver will choose the current reference point, and the next reference point and get a value t where 0 <= t <= 1. When t is near 0, the car is closer to the current reference point and nearer to the next reference point when t is near 1.

The genes in the genetic algorithm then control what input the drivers have/use at each reference point and the system will interpolate between the current/next using t. It is fairly simple in implementation, and so far is not working so well. I'm not entirely sure why. In theory the drivers that make it the longest distance should survive on and continue to mutate their genes ahead until they can drive a full lap, however I am not seeing that happen in practice.

I'm not yet sure what the problem might be, possibly too many genes that make the mutation too random? Too low of a mutation chance? Too high a mutation chance? Is it the fitness function of distance? There are so many variables in this system it is difficult to place blame. Another possibility has been swarm size too small? I've allowed this swarm to run for a really long time with a population of 50, but it doesn't seem to be doing much better either.

The computation to find the correct referencePoints and value of T is actually taking a fair bit of processing time, so much so that with more than 6 artificial drivers the player can no longer play. I know the location of the problem spot and am looking for a way to change it. Ultimately it comes down to computing the closest location on the curve of the track, which is a fairly intense iterative process and using less iterations causes inaccurate validation checks.

I certainly expected to watch the artificial drivers fall off the track, and even take some time to figure out to turn left, but I did assume they would mutate towards the correct point and make it beyond each turn. I've tried 25 reference points (50 genes) and I've tried 125 reference points (250 genes) and neither seemed more or less successful.
blackbird04217
S3 licensed
bishtop - Yea I did indeed have that information, but thanks for searching around. I've loaded the PTH file correctly, and it works for the purposes of my AI collecting information about the track edges. I wouldn't use the racing line from it just because I wanted (and now have the ability) to have the artificial driver compute it.

I am more curious about where the AI driver paths actually get stored in LFS, as I was attempting to modify it so I could share that with other players, but it wasn't as straightforward as modifying the PTH files, which is a little obvious since they don't come with LFS on an initial install.

-------------------------------

Genetic Algorithm

Back to my focus for today, with the simple two dimensional simulation, last night was a fairly sleepless night as I was pondering how best to make the genes work in the genetic algorithm. Actually I got a very basic, first attempt of a genetic algorithm coded up last night. It remains currently untested and still needs to make use of the genes and create a fitness as well as iterate through several attempts.

My original thought in my long post above was to use bits of logic. Such as get a point ahead of the driver, and using some of the genes make comparisons with track edges and apply steering. This would probably work pretty well and would likely evolve to work better, but it is still based on logic that I put in place. Then I had a breakthrough and I am not sure what caused it.

Lets use reference points!

Calling these reference points for the first pass will be a little more difficult, but the general idea is the driver can see a reflector, a painted line, a change in pavement, or whatever it is, a reference point, at the center of the track every X distance. This should be extremely easy to setup from my track curve, although this is a simplified version of the initial plan where the reference points were randomly placed away from the center-line. Then each of the drivers in the population would use genes to figure out what to do.

In my first implementation of a GA each gene has a value from -1 to 1. I may later change this to be from 0 to 1, but it seems like a reasonable approach. If the application of a particular gene needs a larger range it can always be multiplied later. If there are 100 reference points along the track, then there would be 200 genes in each chromosome which the driver gets. One for steering input, one for brake/throttle input where negative is braking.

Taking this approach I will then compute the current and next reference points and interpolate their genes for the input of the car. I like the approach because it doesn't have me working on any logic, it represents a more genetic approach and should produce some interesting results, including going off track, just spinning in a circle, just stopping. However, the drivers should get better over time, theoretically even becoming faster than a human.

The approach for fitness

The drivers would not get faster, and would seem rather dumb, if they never mutated or crossed genes with other drivers. The genes of two drivers will be mixed at random, with more fit drivers having a much better chance of getting picked. The drivers fitness will be determined by a few things. At the start of each generation they will all start in exactly the same place as the player does, and all fitness levels will start at 0.

As the drivers move around the track (in the correct direction) the fitness level will increase to whatever the maximum distance reached is. Once a lap is complete 100 will be added. Anyone who finishes a lap will have the exact same value 100 + track distance for a fitness. It will then add another 100 points that gets scaled by lap time, so that a lap-time of 10 seconds (theoretically impossible with the current settings as my lap times are ~17 seconds) will give all 100 points, while a lap time of 30 seconds might give 20 points.

Any driver that falls off the track will stop moving, and fitness will remain the distance where they went off the track.

Next generation

After 30 seconds or when every driver has fallen off track, which ever comes first, the generation will spawn a new generation. The new generation will start all the cars back at the same exact starting position, and start the timer for 30 seconds, letting the cars start racing and repeat by spawning a new generation after the condition is reached.

I am looking forward to watching the results. Although I am not convinced this will be usable in the airs project, it is still neat to create, and learn, and watch.
blackbird04217
S3 licensed
Learning happens all the time ...

Sometimes I am an idiot. Someone very recently mentioned just using the PTH files to determine track edges, rather than placing the cones all around the track by hand in a layout file like I did when I first started the project. This came up recently when I was adding a new track and failed by making the corner too sharp for the center line algorithm to work. I proceeded to continue by creating curves from these points that would theoretically remove the problem entirely...

Well, a new problem seems to appear. I have not yet narrowed it down, but it is caused by creating the curve, especially during a straight portion of track, or a portion of track immediately after a long straight. I'm not entirely sure. I was however attempting to create a layout on the drag strip, to improve the artificial drivers shifting and acceleration/launch from a standstill. I attempted this three times however it all failed due to the curves, so I gave up and moved on with other things.

I recently started the tiny simulation for playing with a Genetic Algorithm, as some of you have downloaded and tried and hopefully had some mild entertainment with. I had also read through the entire thread, for the most part, and noticed that before I even started using layout files (although the idea was there) someone had mentioned the I could get the track information from the PTH files. So this has been mentioned recently and was mentioned a long, long, time ago as well.

I was considering giving back to the community a little bit, with an idea the Dygear had last year when I was working on the Racing Line computations. He had mentioned I load the LFS PTH for comparison, and then hinted that it would be neat to see those paths edited. At the time I agreed but was focused on the racing line. Today I decided to look into modifying those files for laughs and have not yet found out how. The AI path seems to be stored somewhere besides the PTH files, which is a little evident since LFS does not contain the PTH files during an initial install.

So unfortunately I failed to modify the path the LFS drivers take. But I decided since I had changed some code to see how difficult it would be to use the PTH files for creating a track... So I added an additional left/right/center of track lines and loaded them from the PTH file and it was extremely easy, takes the time of editing away.

Pros and Cons ...

So, an obvious advantage to using the PTH files is no longer needing to edit the track layout by hand, this should reduce or remove entirely the chance for something to go wrong during computation. Actually the center line algorithm is much more simpler this way, so those problems are automatically removed. This would allow the artificial driver to know ANY track in LFS that has a PTH file immediately without anything except a few moments to compute the racing line.

However nothing comes for free and there are a few disadvantages to using the PTH files. First, the track edges are defined by LFS and while this reduced errors and effort, in some places the edges may not be where desired, say a chicane/curbing that would typically be used for faster laps. It would also eliminate the possibility to create auto cross layouts for the artificial driver, or allow him to drive on the drag strip - without creating special cases.

Now even though I have all this information now, and probably should have just done that to begin with I am unsure whether or not it is a good idea to use the PTH files or not. It wouldn't be hard, but it would take a little bit of time to change the use of Layouts and start using the PTH file, and with the other limitations of the PTH file I'm not entirely convinced it is worth it. Although the prospect of having the driver on more than just FE1 is certainly welcomed.

Can anyone let me know if ...

Does anyone know how to get LFS to use the modified PTH files, which is likely impossible? Or to modify the LFS AI path? Has anyone attempted this before? I won't be looking into it any more than I have already but if someone knows what file to modify and the specified format of that file I would be interested to know it.

Back to the simple two-dimensional simulation... (downloadable here)
Last edited by blackbird04217, .
blackbird04217
S3 licensed
Using the tiny/simple two-dimensional simulation I've created above, which is playable, I will dabble with the idea of using a Genetic Algorithm to create an AI that can drive around the track, hopefully reasonably well. I actually have a feeling that it should end up becoming much better than a human... I've never tried creating a genetic algorithm and a few things are still a bit fuzzy. If you (looks at Todd and maybe Keling) have any help to offer that would be super useful for my attempt this weekend.

The following is a very rough outline of what I have planned out.


kMutationRate //a percentage from 0 to 1 of how much mutation will occur if mutation is triggered, a control over all genes. (not the same as mutationChance)

Gene { value, maxMutation,
Mutate() { value += maxMutation * kMutationRate; }
}

Chromosome { genes[], fitness
SetFitness() //0 to 100 with 100 being the longest distance traveled, or closest to racing line, or best lap time, etc... (Not normalized at this stage)
}

Driver { chromosome, position, direction, velocity,
}

drivers[] = InitializePopulation(); //Randomly

forever {
SimulateGeneration(); //Timed, or end when all generation dead (from going off track).

ScoreFitness(); //sets the fitness of the chromosomes in each driver basted on fitness function, (distance, time, etc)

RegeneratePopulation(); //creates new drivers based on the random pool/roulette wheel probability, including possible crossover and mutation rates.

++generationCount;
}

This is a basic skeleton of what I understand, my implementation would have each gene have a meaning, and skip the 'random bits' because I don't find it useful to manipulate values by flipping the bit, there is more control over the step size by using the maxMutation in each gene.

The genes I have planned as items that will control the algorithm, but I haven't fully planned this out. For example, one gene might represent a maximum angle (from driver direction to desired direction) that the driver will use to control the steering input. That in combination with another gene that might represent the maximum speed at that angle might control the throttle / braking response.

The idea is to have some basic logic which the genes then control the values for this logic. I may be thinking about this the wrong way, my brain is hardwired for thinking about things in terms of IF a THEN b, and it has been a bit challenging to get thinking about how best to use the GA. This is so far an approach I am at least happy with trying, although if anyone has advice before the weekend, I'd like to hear it and think it over!

Either way the results should be neat, and maybe after I get the GA I can think about adding an artificial neural network as has been suggested also. This could remove the logic and the inputs would be things such as currentSpeed, currentDirection, desiredDirection with the outputs being throttle, braking and steering responses. This would take the logic described above and put it in a black box of magic that I would no longer have control over, but in theory should still produce very good results. One step at a time though.
FGED GREDG RDFGDR GSFDG