InputDeviceAI.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright © 2010 James Legg.
00006     This program is free software: you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation, either version 3 of the License, or
00009     (at your option) any later version.
00010 */
00011 
00012 #include "InputDeviceAI.h"
00013 #include <Debug.h>
00014 #include "GameObjects/Car.h"
00015 
00016 namespace Engine
00017 {
00018 
00022 InputDeviceAI::InputDeviceAI()
00023     :   acceleration(0)
00024     ,   slide(0)
00025     ,   steering(0)
00026     ,   ann(fann_create_from_file("data/ai.net"))
00027 {
00028     fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC_STEPWISE);
00029     fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC_STEPWISE);
00030 }
00031 
00032 InputDeviceAI::~InputDeviceAI()
00033 {
00034     fann_destroy(ann);
00035 }
00036 
00037 int InputDeviceAI::get_acceleration()
00038 {
00039     return acceleration;
00040 }
00041 
00042 int InputDeviceAI::get_slide()
00043 {
00044     return slide;
00045 }
00046 
00047 int InputDeviceAI::get_steering()
00048 {
00049     return steering;
00050 }
00051 
00052 void InputDeviceAI::poll()
00053 {
00054     fann_type sensors[Engine::GameObjects::Car::NUM_SENSORS] ;
00055     assert(car);
00056     car->get_sensors(sensors);
00072     const btScalar min_edge_distance = 0.05; // 5cm or less is full avoision
00073     const btScalar max_edge_distance = 0.8; // 80cm or more is full ANN.
00074     const btScalar edge_distance_range = max_edge_distance - min_edge_distance;
00075     // sensors have the inverse of the distance.
00076     const btScalar min_edge_sensor = 1.0 / min_edge_distance;
00077     const btScalar max_edge_sensor = 1.0 / max_edge_distance;
00078     // slide to avoid edges
00079     btScalar left_sensor = sensors[Track::SENSOR_COUNT * 1 + Track::SENSOR_NAVIGABLE_DISTANCE];
00080     btScalar right_sensor = sensors[Track::SENSOR_COUNT * 2 + Track::SENSOR_NAVIGABLE_DISTANCE];
00081     btScalar edge_avoid_slide = 0;
00082     btScalar slide_avoid_weight = 0;
00083     if (left_sensor > right_sensor)
00084     {
00085         edge_avoid_slide = -32767;
00086         slide_avoid_weight = left_sensor;
00087     }
00088     else if (right_sensor > left_sensor)
00089     {
00090         edge_avoid_slide = 32767;
00091         slide_avoid_weight = right_sensor;
00092     }
00093     // change the weights to give sensible values between 0 and 1.
00094     if (slide_avoid_weight > min_edge_sensor || !std::isfinite(slide_avoid_weight))
00095     {
00096         slide_avoid_weight = 1.0;
00097     }
00098     else if (slide_avoid_weight < max_edge_sensor)
00099     {
00100         slide_avoid_weight = 0.0;
00101     }
00102     else
00103     {
00104         slide_avoid_weight = 1.0 - ((1.0 / slide_avoid_weight) - min_edge_distance) / edge_distance_range;
00105     }
00106     
00107     // steer to avoid edges
00108     btScalar front_left_sensor = sensors[Track::SENSOR_COUNT * 3 + Track::SENSOR_NAVIGABLE_DISTANCE];
00109     btScalar front_right_sensor = sensors[Track::SENSOR_COUNT * 4 + Track::SENSOR_NAVIGABLE_DISTANCE];
00110     btScalar edge_avoid_steer = 0;
00111     btScalar steer_avoid_weight = 0;
00112     if (front_left_sensor > front_right_sensor)
00113     {
00114         edge_avoid_steer = -32767;
00115         steer_avoid_weight = front_left_sensor;
00116     }
00117     else if (front_left_sensor < front_right_sensor)
00118     {
00119         edge_avoid_steer = 32767;
00120         steer_avoid_weight = front_right_sensor;
00121     }
00122     // adjust weight to sensible value between 0 and 1.
00123     if (steer_avoid_weight > min_edge_sensor)
00124     {
00125         steer_avoid_weight = 1.0;
00126     }
00127     else if (steer_avoid_weight < max_edge_sensor)
00128     {
00129         steer_avoid_weight = 0.0;
00130     }
00131     else
00132     {
00133         steer_avoid_weight = 1.0 - ((1.0 / steer_avoid_weight) - min_edge_distance) / edge_distance_range;
00134     }
00135     
00136     // accelerate/reverse to avoid going straight forwards or backwards over the edge.
00137     btScalar front_sensor = sensors[Track::SENSOR_NAVIGABLE_DISTANCE];
00138     btScalar back_sensor = sensors[Track::SENSOR_NAVIGABLE_DISTANCE + (GameObjects::Car::NUM_SENSORS_FEELERS -1)* Track::SENSOR_COUNT];
00139     btScalar edge_avoid_accel = 0;
00140     btScalar accel_avoid_weight = 0;
00141     if (front_sensor > back_sensor)
00142     {
00143         edge_avoid_accel = -32767;
00144         accel_avoid_weight = front_sensor;
00145     }
00146     else if (front_sensor < back_sensor)
00147     {
00148         edge_avoid_accel = 32867;
00149         accel_avoid_weight = back_sensor;
00150     }
00151     // adjust weight to sensible value between 0 and 1.
00152     if (accel_avoid_weight > min_edge_sensor)
00153     {
00154         accel_avoid_weight = 1.0;
00155     }
00156     else if (accel_avoid_weight < max_edge_sensor)
00157     {
00158         accel_avoid_weight = 0.0;
00159     }
00160     else
00161     {
00162         accel_avoid_weight = 1.0 - ((1.0 / accel_avoid_weight) - min_edge_distance) / edge_distance_range;
00163     }
00164     
00165     #if 0
00166     if (sensors[Track::SENSOR_LAP_DIFFERENTIAL] > 0.0)
00167     {
00168     #endif
00169         fann_type *output;
00170         output = fann_run(ann, sensors);
00171         
00172         for (int i = 0; i < 4; i++)
00173         {
00174             output[i] *= 32767.0;
00175             if (output[i] > 32767) output[i] = 32767;
00176             if (output[i] < -32767) output[i] = -32767;
00177         }
00178         //weighted blend outputs for edge avoision
00179         output[0] = output[0] * (1.0 - accel_avoid_weight) + edge_avoid_accel * accel_avoid_weight;
00180         output[1] = output[1] * (1.0 - slide_avoid_weight) + edge_avoid_slide * slide_avoid_weight;
00181         output[2] = output[2] * (1.0 - steer_avoid_weight) + edge_avoid_steer * steer_avoid_weight;
00182         if (int(output[0]) != acceleration)
00183         {
00184             acceleration = int(output[0]);
00185             report(InputReport::RT_CHANGE_ACCEL, output[0]);
00186         }
00187         
00188         if (int(output[1]) != slide)
00189         {
00190             slide = int(output[1]);
00191             report(InputReport::RT_CHANGE_SLIDE, output[1]);
00192         }
00193         
00194         if (int(output[2]) != steering)
00195         {
00196             steering = int(output[2]);
00197             report(InputReport::RT_CHANGE_STEERING, output[2]);
00198         }
00199     #if 0
00200     } else if (std::isfinite(sensors[Track::SENSOR_LAP_DIFFERENTIAL]))
00201     {
00202         // facing backwards.
00203         // try to slow down if going forwards
00204         if (sensors[Engine::GameObjects::Car::NUM_SENSORS_FEELERS * Engine::GameObjects::Car::NUM_FEELER_PROPERTIES + 1] > 0.0)
00205         {
00206             acceleration = -32767;
00207         } else {
00208             acceleration = 0;
00209         }
00210         report(InputReport::RT_CHANGE_ACCEL, acceleration);
00211         report(InputReport::RT_CHANGE_SLIDE, 0);
00212         // turn around.
00213         int ts = sensors[Engine::GameObjects::Car::NUM_SENSORS - 1]*32767;
00214         if (ts != steering)
00215         {
00216             steering = ts;
00217             report(InputReport::RT_CHANGE_STEERING, ts);
00218         }
00219         //DEBUG_MESSAGE("Oh no! Wrong way!");
00220     } else {
00221         // driven over the boundary
00222         if (std::isfinite(sensors[Engine::GameObjects::Car::NUM_FEELER_PROPERTIES * (Engine::GameObjects::Car::NUM_SENSORS_FEELERS - 1) + Track::SENSOR_LAP_DIFFERENTIAL]))
00223         {
00224             // backwards is safe
00225             // reverse hard to reduce change of falling off.
00226             report(InputReport::RT_CHANGE_ACCEL, -32767);
00227         }
00228         if (std::isfinite(sensors[Engine::GameObjects::Car::NUM_FEELER_PROPERTIES * 1 + Track::SENSOR_LAP_DIFFERENTIAL]))
00229         {
00230             // +x is available
00231             report(InputReport::RT_CHANGE_SLIDE, 32767);
00232             report(InputReport::RT_CHANGE_STEERING, 32767);
00233         }
00234         else if (std::isfinite(sensors[Engine::GameObjects::Car::NUM_FEELER_PROPERTIES * 2  + Track::SENSOR_LAP_DIFFERENTIAL]))
00235         {
00236             // -x is available
00237             report(InputReport::RT_CHANGE_SLIDE, -32767);
00238             report(InputReport::RT_CHANGE_STEERING, -32767);
00239         }
00240         //DEBUG_MESSAGE("Argh, I've driven over the edge!");
00241     }
00242     #endif
00243 }
00244 
00245 void InputDeviceAI::save()
00246 {
00247     fann_save(ann, "data/ai.net");
00248 }
00249 
00250 void InputDeviceAI::mutate()
00251 {
00252     // set a few connection weights to random values.
00253     int num_connections = fann_get_total_connections(ann);
00254     fann_connection cs[num_connections];
00255     fann_get_connection_array(ann, cs);
00256     
00257     // decide how many variables to mutate
00258     float v = float(rand())/float(RAND_MAX);
00259     // raise it to the power of three so we get more lower numbers.
00260     v *= v*v;
00261     unsigned int variables_mutated = 1 + int(v * (num_connections - 1));
00262     
00263     // mutate the variables
00264     for (unsigned int i = 0; i < variables_mutated; i++)
00265     {
00266         int w = rand()/(RAND_MAX/num_connections);
00267         btScalar scale = std::pow(2, rand() / (RAND_MAX / 15) - 5);
00268         fann_set_weight(ann, cs[w].from_neuron, cs[w].to_neuron,
00269                 float(rand())/float(RAND_MAX)*scale - scale/2.0);
00270     }
00271 }
00272 
00273 void InputDeviceAI::cross(const InputDeviceAI & p1, const InputDeviceAI & p2)
00274 {
00275     unsigned int num_connections = fann_get_total_connections(ann);
00276     fann_connection c2[num_connections];
00277     fann_get_connection_array(p2.ann, c2);
00278     for (unsigned int i = 0; i < num_connections; i++)
00279     {
00280         if (rand()/(RAND_MAX/2))
00281         {
00282             fann_set_weight(ann, c2[i].from_neuron, c2[i].to_neuron, c2[i].weight);
00283         }
00284     }
00285 }
00286 
00287 } // namespace Engine

Get Racer at SourceForge.net. Fast, secure and Free Open Source software downloads

Generated at Mon Sep 6 00:41:12 2010 by Doxygen version 1.4.7 for Racer version svn335.