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
Generated at Mon Sep 6 00:41:12 2010 by Doxygen version 1.4.7 for Racer version svn335.