NN3DWalkers.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. /*
  2. Bullet Continuous Collision Detection and Physics Library
  3. Copyright (c) 2015 Google Inc. http://bulletphysics.org
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. */
  13. #include "NN3DWalkers.h"
  14. #include <cmath>
  15. #include "btBulletDynamicsCommon.h"
  16. #include "LinearMath/btIDebugDraw.h"
  17. #include "LinearMath/btAlignedObjectArray.h"
  18. #include "LinearMath/btHashMap.h"
  19. class btBroadphaseInterface;
  20. class btCollisionShape;
  21. class btOverlappingPairCache;
  22. class btCollisionDispatcher;
  23. class btConstraintSolver;
  24. struct btCollisionAlgorithmCreateFunc;
  25. class btDefaultCollisionConfiguration;
  26. class NNWalker;
  27. #include "NN3DWalkersTimeWarpBase.h"
  28. #include "../CommonInterfaces/CommonParameterInterface.h"
  29. #include "../Utils/b3ReferenceFrameHelper.hpp"
  30. #include "../RenderingExamples/TimeSeriesCanvas.h"
  31. static btScalar gRootBodyRadius = 0.25f;
  32. static btScalar gRootBodyHeight = 0.1f;
  33. static btScalar gLegRadius = 0.1f;
  34. static btScalar gLegLength = 0.45f;
  35. static btScalar gForeLegLength = 0.75f;
  36. static btScalar gForeLegRadius = 0.08f;
  37. static btScalar gParallelEvaluations = 10.0f;
  38. #ifndef SIMD_PI_4
  39. #define SIMD_PI_4 0.5 * SIMD_HALF_PI
  40. #endif
  41. #ifndef SIMD_PI_8
  42. #define SIMD_PI_8 0.25 * SIMD_HALF_PI
  43. #endif
  44. #ifndef RANDOM_MOVEMENT
  45. #define RANDOM_MOVEMENT false
  46. #endif
  47. #ifndef RANDOMIZE_DIMENSIONS
  48. #define RANDOMIZE_DIMENSIONS false
  49. #endif
  50. #ifndef NUM_WALKERS
  51. #define NUM_WALKERS 50
  52. #endif
  53. #ifndef EVALUATION_TIME
  54. #define EVALUATION_TIME 10 // s
  55. #endif
  56. #ifndef REAP_QTY
  57. #define REAP_QTY 0.3f // number of walkers reaped based on their bad performance
  58. #endif
  59. #ifndef SOW_CROSSOVER_QTY
  60. #define SOW_CROSSOVER_QTY 0.2f // this means REAP_QTY-SOW_CROSSOVER_QTY = NEW_RANDOM_BREED_QTY
  61. #endif
  62. #ifndef SOW_ELITE_QTY
  63. #define SOW_ELITE_QTY 0.2f // number of walkers kept using an elitist strategy
  64. #endif
  65. #ifndef SOW_MUTATION_QTY
  66. #define SOW_MUTATION_QTY 0.5f // SOW_ELITE_QTY + SOW_MUTATION_QTY + REAP_QTY = 1
  67. #endif
  68. #ifndef MUTATION_RATE
  69. #define MUTATION_RATE 0.5f // the mutation rate of for the walker with the worst performance
  70. #endif
  71. #ifndef SOW_ELITE_PARTNER
  72. #define SOW_ELITE_PARTNER 0.8f
  73. #endif
  74. #define NUM_LEGS 6
  75. #define BODYPART_COUNT (2 * NUM_LEGS + 1)
  76. #define JOINT_COUNT (BODYPART_COUNT - 1)
  77. #define DRAW_INTERPENETRATIONS false
  78. void* GROUND_ID = (void*)1;
  79. class NN3DWalkersExample : public NN3DWalkersTimeWarpBase
  80. {
  81. btScalar m_Time;
  82. btScalar m_SpeedupTimestamp;
  83. btScalar m_targetAccumulator;
  84. btScalar m_targetFrequency;
  85. btScalar m_motorStrength;
  86. int m_evaluationsQty;
  87. int m_nextReaped;
  88. btAlignedObjectArray<class NNWalker*> m_walkersInPopulation;
  89. TimeSeriesCanvas* m_timeSeriesCanvas;
  90. public:
  91. NN3DWalkersExample(struct GUIHelperInterface* helper)
  92. : NN3DWalkersTimeWarpBase(helper),
  93. m_Time(0),
  94. m_SpeedupTimestamp(0),
  95. m_targetAccumulator(0),
  96. m_targetFrequency(3),
  97. m_motorStrength(0.5f),
  98. m_evaluationsQty(0),
  99. m_nextReaped(0),
  100. m_timeSeriesCanvas(0)
  101. {
  102. }
  103. virtual ~NN3DWalkersExample()
  104. {
  105. delete m_timeSeriesCanvas;
  106. }
  107. void initPhysics();
  108. virtual void exitPhysics();
  109. void spawnWalker(int index, const btVector3& startOffset, bool bFixed);
  110. virtual bool keyboardCallback(int key, int state);
  111. bool detectCollisions();
  112. void resetCamera()
  113. {
  114. float dist = 11;
  115. float pitch = -35;
  116. float yaw = 52;
  117. float targetPos[3] = {0, 0.46, 0};
  118. m_guiHelper->resetCamera(dist, yaw, pitch, targetPos[0], targetPos[1], targetPos[2]);
  119. }
  120. // Evaluation
  121. void update(const btScalar timeSinceLastTick);
  122. void updateEvaluations(const btScalar timeSinceLastTick);
  123. void scheduleEvaluations();
  124. void drawMarkings();
  125. // Reaper
  126. void rateEvaluations();
  127. void reap();
  128. void sow();
  129. void crossover(NNWalker* mother, NNWalker* father, NNWalker* offspring);
  130. void mutate(NNWalker* mutant, btScalar mutationRate);
  131. NNWalker* getRandomElite();
  132. NNWalker* getRandomNonElite();
  133. NNWalker* getNextReaped();
  134. void printWalkerConfigs();
  135. };
  136. static NN3DWalkersExample* nn3DWalkers = NULL;
  137. class NNWalker
  138. {
  139. btDynamicsWorld* m_ownerWorld;
  140. btCollisionShape* m_shapes[BODYPART_COUNT];
  141. btRigidBody* m_bodies[BODYPART_COUNT];
  142. btTransform m_bodyRelativeTransforms[BODYPART_COUNT];
  143. btTypedConstraint* m_joints[JOINT_COUNT];
  144. btHashMap<btHashPtr, int> m_bodyTouchSensorIndexMap;
  145. bool m_touchSensors[BODYPART_COUNT];
  146. btScalar m_sensoryMotorWeights[BODYPART_COUNT * JOINT_COUNT];
  147. bool m_inEvaluation;
  148. btScalar m_evaluationTime;
  149. bool m_reaped;
  150. btVector3 m_startPosition;
  151. int m_index;
  152. btRigidBody* localCreateRigidBody(btScalar mass, const btTransform& startTransform, btCollisionShape* shape)
  153. {
  154. bool isDynamic = (mass != 0.f);
  155. btVector3 localInertia(0, 0, 0);
  156. if (isDynamic)
  157. shape->calculateLocalInertia(mass, localInertia);
  158. btDefaultMotionState* motionState = new btDefaultMotionState(startTransform);
  159. btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, motionState, shape, localInertia);
  160. btRigidBody* body = new btRigidBody(rbInfo);
  161. return body;
  162. }
  163. public:
  164. void randomizeSensoryMotorWeights()
  165. {
  166. //initialize random weights
  167. for (int i = 0; i < BODYPART_COUNT; i++)
  168. {
  169. for (int j = 0; j < JOINT_COUNT; j++)
  170. {
  171. m_sensoryMotorWeights[i + j * BODYPART_COUNT] = ((double)rand() / (RAND_MAX)) * 2.0f - 1.0f;
  172. }
  173. }
  174. }
  175. NNWalker(int index, btDynamicsWorld* ownerWorld, const btVector3& positionOffset, bool bFixed)
  176. : m_ownerWorld(ownerWorld),
  177. m_inEvaluation(false),
  178. m_evaluationTime(0),
  179. m_reaped(false)
  180. {
  181. m_index = index;
  182. btVector3 vUp(0, 1, 0); // up in local reference frame
  183. NN3DWalkersExample* nnWalkersDemo = (NN3DWalkersExample*)m_ownerWorld->getWorldUserInfo();
  184. randomizeSensoryMotorWeights();
  185. //
  186. // Setup geometry
  187. m_shapes[0] = new btCapsuleShape(gRootBodyRadius, gRootBodyHeight); // root body capsule
  188. int i;
  189. for (i = 0; i < NUM_LEGS; i++)
  190. {
  191. m_shapes[1 + 2 * i] = new btCapsuleShape(gLegRadius, gLegLength); // leg capsule
  192. m_shapes[2 + 2 * i] = new btCapsuleShape(gForeLegRadius, gForeLegLength); // fore leg capsule
  193. }
  194. //
  195. // Setup rigid bodies
  196. btScalar rootAboveGroundHeight = gForeLegLength;
  197. btTransform bodyOffset;
  198. bodyOffset.setIdentity();
  199. bodyOffset.setOrigin(positionOffset);
  200. // root body
  201. btVector3 localRootBodyPosition = btVector3(btScalar(0.), rootAboveGroundHeight, btScalar(0.)); // root body position in local reference frame
  202. btTransform transform;
  203. transform.setIdentity();
  204. transform.setOrigin(localRootBodyPosition);
  205. btTransform originTransform = transform;
  206. m_bodies[0] = localCreateRigidBody(btScalar(bFixed ? 0. : 1.), bodyOffset * transform, m_shapes[0]);
  207. m_ownerWorld->addRigidBody(m_bodies[0]);
  208. m_bodyRelativeTransforms[0] = btTransform::getIdentity();
  209. m_bodies[0]->setUserPointer(this);
  210. m_bodyTouchSensorIndexMap.insert(btHashPtr(m_bodies[0]), 0);
  211. btHingeConstraint* hingeC;
  212. //btConeTwistConstraint* coneC;
  213. btTransform localA, localB, localC;
  214. // legs
  215. for (i = 0; i < NUM_LEGS; i++)
  216. {
  217. float footAngle = 2 * SIMD_PI * i / NUM_LEGS; // legs are uniformly distributed around the root body
  218. float footYUnitPosition = std::sin(footAngle); // y position of the leg on the unit circle
  219. float footXUnitPosition = std::cos(footAngle); // x position of the leg on the unit circle
  220. transform.setIdentity();
  221. btVector3 legCOM = btVector3(btScalar(footXUnitPosition * (gRootBodyRadius + 0.5 * gLegLength)), btScalar(rootAboveGroundHeight), btScalar(footYUnitPosition * (gRootBodyRadius + 0.5 * gLegLength)));
  222. transform.setOrigin(legCOM);
  223. // thigh
  224. btVector3 legDirection = (legCOM - localRootBodyPosition).normalize();
  225. btVector3 kneeAxis = legDirection.cross(vUp);
  226. transform.setRotation(btQuaternion(kneeAxis, SIMD_HALF_PI));
  227. m_bodies[1 + 2 * i] = localCreateRigidBody(btScalar(1.), bodyOffset * transform, m_shapes[1 + 2 * i]);
  228. m_bodyRelativeTransforms[1 + 2 * i] = transform;
  229. m_bodies[1 + 2 * i]->setUserPointer(this);
  230. m_bodyTouchSensorIndexMap.insert(btHashPtr(m_bodies[1 + 2 * i]), 1 + 2 * i);
  231. // shin
  232. transform.setIdentity();
  233. transform.setOrigin(btVector3(btScalar(footXUnitPosition * (gRootBodyRadius + gLegLength)), btScalar(rootAboveGroundHeight - 0.5 * gForeLegLength), btScalar(footYUnitPosition * (gRootBodyRadius + gLegLength))));
  234. m_bodies[2 + 2 * i] = localCreateRigidBody(btScalar(1.), bodyOffset * transform, m_shapes[2 + 2 * i]);
  235. m_bodyRelativeTransforms[2 + 2 * i] = transform;
  236. m_bodies[2 + 2 * i]->setUserPointer(this);
  237. m_bodyTouchSensorIndexMap.insert(btHashPtr(m_bodies[2 + 2 * i]), 2 + 2 * i);
  238. // hip joints
  239. localA.setIdentity();
  240. localB.setIdentity();
  241. localA.getBasis().setEulerZYX(0, -footAngle, 0);
  242. localA.setOrigin(btVector3(btScalar(footXUnitPosition * gRootBodyRadius), btScalar(0.), btScalar(footYUnitPosition * gRootBodyRadius)));
  243. localB = b3ReferenceFrameHelper::getTransformWorldToLocal(m_bodies[1 + 2 * i]->getWorldTransform(), b3ReferenceFrameHelper::getTransformLocalToWorld(m_bodies[0]->getWorldTransform(), localA));
  244. hingeC = new btHingeConstraint(*m_bodies[0], *m_bodies[1 + 2 * i], localA, localB);
  245. hingeC->setLimit(btScalar(-0.75 * SIMD_PI_4), btScalar(SIMD_PI_8));
  246. //hingeC->setLimit(btScalar(-0.1), btScalar(0.1));
  247. m_joints[2 * i] = hingeC;
  248. // knee joints
  249. localA.setIdentity();
  250. localB.setIdentity();
  251. localC.setIdentity();
  252. localA.getBasis().setEulerZYX(0, -footAngle, 0);
  253. localA.setOrigin(btVector3(btScalar(footXUnitPosition * (gRootBodyRadius + gLegLength)), btScalar(0.), btScalar(footYUnitPosition * (gRootBodyRadius + gLegLength))));
  254. localB = b3ReferenceFrameHelper::getTransformWorldToLocal(m_bodies[1 + 2 * i]->getWorldTransform(), b3ReferenceFrameHelper::getTransformLocalToWorld(m_bodies[0]->getWorldTransform(), localA));
  255. localC = b3ReferenceFrameHelper::getTransformWorldToLocal(m_bodies[2 + 2 * i]->getWorldTransform(), b3ReferenceFrameHelper::getTransformLocalToWorld(m_bodies[0]->getWorldTransform(), localA));
  256. hingeC = new btHingeConstraint(*m_bodies[1 + 2 * i], *m_bodies[2 + 2 * i], localB, localC);
  257. //hingeC->setLimit(btScalar(-0.01), btScalar(0.01));
  258. hingeC->setLimit(btScalar(-SIMD_PI_8), btScalar(0.2));
  259. m_joints[1 + 2 * i] = hingeC;
  260. m_ownerWorld->addRigidBody(m_bodies[1 + 2 * i]); // add thigh bone
  261. m_ownerWorld->addConstraint(m_joints[2 * i], true); // connect thigh bone with root
  262. if (nnWalkersDemo->detectCollisions())
  263. { // if thigh bone causes collision, remove it again
  264. m_ownerWorld->removeRigidBody(m_bodies[1 + 2 * i]);
  265. m_ownerWorld->removeConstraint(m_joints[2 * i]); // disconnect thigh bone from root
  266. }
  267. else
  268. {
  269. m_ownerWorld->addRigidBody(m_bodies[2 + 2 * i]); // add shin bone
  270. m_ownerWorld->addConstraint(m_joints[1 + 2 * i], true); // connect shin bone with thigh
  271. if (nnWalkersDemo->detectCollisions())
  272. { // if shin bone causes collision, remove it again
  273. m_ownerWorld->removeRigidBody(m_bodies[2 + 2 * i]);
  274. m_ownerWorld->removeConstraint(m_joints[1 + 2 * i]); // disconnect shin bone from thigh
  275. }
  276. }
  277. }
  278. // Setup some damping on the m_bodies
  279. for (i = 0; i < BODYPART_COUNT; ++i)
  280. {
  281. m_bodies[i]->setDamping(0.05, 0.85);
  282. m_bodies[i]->setDeactivationTime(0.8);
  283. //m_bodies[i]->setSleepingThresholds(1.6, 2.5);
  284. m_bodies[i]->setSleepingThresholds(0.5f, 0.5f);
  285. }
  286. removeFromWorld(); // it should not yet be in the world
  287. }
  288. virtual ~NNWalker()
  289. {
  290. int i;
  291. // Remove all constraints
  292. for (i = 0; i < JOINT_COUNT; ++i)
  293. {
  294. m_ownerWorld->removeConstraint(m_joints[i]);
  295. delete m_joints[i];
  296. m_joints[i] = 0;
  297. }
  298. // Remove all bodies and shapes
  299. for (i = 0; i < BODYPART_COUNT; ++i)
  300. {
  301. m_ownerWorld->removeRigidBody(m_bodies[i]);
  302. delete m_bodies[i]->getMotionState();
  303. delete m_bodies[i];
  304. m_bodies[i] = 0;
  305. delete m_shapes[i];
  306. m_shapes[i] = 0;
  307. }
  308. }
  309. btTypedConstraint** getJoints()
  310. {
  311. return &m_joints[0];
  312. }
  313. void setTouchSensor(void* bodyPointer)
  314. {
  315. m_touchSensors[*m_bodyTouchSensorIndexMap.find(btHashPtr(bodyPointer))] = true;
  316. }
  317. void clearTouchSensors()
  318. {
  319. for (int i = 0; i < BODYPART_COUNT; i++)
  320. {
  321. m_touchSensors[i] = false;
  322. }
  323. }
  324. bool getTouchSensor(int i)
  325. {
  326. return m_touchSensors[i];
  327. }
  328. btScalar* getSensoryMotorWeights()
  329. {
  330. return m_sensoryMotorWeights;
  331. }
  332. void addToWorld()
  333. {
  334. int i;
  335. // add all bodies and shapes
  336. for (i = 0; i < BODYPART_COUNT; ++i)
  337. {
  338. m_ownerWorld->addRigidBody(m_bodies[i]);
  339. }
  340. // add all constraints
  341. for (i = 0; i < JOINT_COUNT; ++i)
  342. {
  343. m_ownerWorld->addConstraint(m_joints[i], true); // important! If you add constraints back, you must set bullet physics to disable collision between constrained bodies
  344. }
  345. m_startPosition = getPosition();
  346. }
  347. void removeFromWorld()
  348. {
  349. int i;
  350. // Remove all constraints
  351. for (i = 0; i < JOINT_COUNT; ++i)
  352. {
  353. m_ownerWorld->removeConstraint(m_joints[i]);
  354. }
  355. // Remove all bodies
  356. for (i = 0; i < BODYPART_COUNT; ++i)
  357. {
  358. m_ownerWorld->removeRigidBody(m_bodies[i]);
  359. }
  360. }
  361. btVector3 getPosition() const
  362. {
  363. btVector3 finalPosition(0, 0, 0);
  364. for (int i = 0; i < BODYPART_COUNT; i++)
  365. {
  366. finalPosition += m_bodies[i]->getCenterOfMassPosition();
  367. }
  368. finalPosition /= BODYPART_COUNT;
  369. return finalPosition;
  370. }
  371. btScalar getDistanceFitness() const
  372. {
  373. btScalar distance = 0;
  374. distance = (getPosition() - m_startPosition).length2();
  375. return distance;
  376. }
  377. btScalar getFitness() const
  378. {
  379. return getDistanceFitness(); // for now it is only distance
  380. }
  381. void resetAt(const btVector3& position)
  382. {
  383. btTransform resetPosition(btQuaternion::getIdentity(), position);
  384. for (int i = 0; i < BODYPART_COUNT; ++i)
  385. {
  386. m_bodies[i]->setWorldTransform(resetPosition * m_bodyRelativeTransforms[i]);
  387. if (m_bodies[i]->getMotionState())
  388. {
  389. m_bodies[i]->getMotionState()->setWorldTransform(resetPosition * m_bodyRelativeTransforms[i]);
  390. }
  391. m_bodies[i]->clearForces();
  392. m_bodies[i]->setAngularVelocity(btVector3(0, 0, 0));
  393. m_bodies[i]->setLinearVelocity(btVector3(0, 0, 0));
  394. }
  395. clearTouchSensors();
  396. }
  397. btScalar getEvaluationTime() const
  398. {
  399. return m_evaluationTime;
  400. }
  401. void setEvaluationTime(btScalar evaluationTime)
  402. {
  403. m_evaluationTime = evaluationTime;
  404. }
  405. bool isInEvaluation() const
  406. {
  407. return m_inEvaluation;
  408. }
  409. void setInEvaluation(bool inEvaluation)
  410. {
  411. m_inEvaluation = inEvaluation;
  412. }
  413. bool isReaped() const
  414. {
  415. return m_reaped;
  416. }
  417. void setReaped(bool reaped)
  418. {
  419. m_reaped = reaped;
  420. }
  421. int getIndex() const
  422. {
  423. return m_index;
  424. }
  425. };
  426. void evaluationUpdatePreTickCallback(btDynamicsWorld* world, btScalar timeStep);
  427. bool legContactProcessedCallback(btManifoldPoint& cp, void* body0, void* body1)
  428. {
  429. btCollisionObject* o1 = static_cast<btCollisionObject*>(body0);
  430. btCollisionObject* o2 = static_cast<btCollisionObject*>(body1);
  431. void* ID1 = o1->getUserPointer();
  432. void* ID2 = o2->getUserPointer();
  433. if (ID1 != GROUND_ID || ID2 != GROUND_ID)
  434. {
  435. // Make a circle with a 0.9 radius at (0,0,0)
  436. // with RGB color (1,0,0).
  437. if (nn3DWalkers->m_dynamicsWorld->getDebugDrawer() != NULL)
  438. {
  439. if (!nn3DWalkers->mIsHeadless)
  440. {
  441. nn3DWalkers->m_dynamicsWorld->getDebugDrawer()->drawSphere(cp.getPositionWorldOnA(), 0.1, btVector3(1., 0., 0.));
  442. }
  443. }
  444. if (ID1 != GROUND_ID && ID1)
  445. {
  446. ((NNWalker*)ID1)->setTouchSensor(o1);
  447. }
  448. if (ID2 != GROUND_ID && ID2)
  449. {
  450. ((NNWalker*)ID2)->setTouchSensor(o2);
  451. }
  452. }
  453. return false;
  454. }
  455. struct WalkerFilterCallback : public btOverlapFilterCallback
  456. {
  457. // return true when pairs need collision
  458. virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const
  459. {
  460. btCollisionObject* obj0 = static_cast<btCollisionObject*>(proxy0->m_clientObject);
  461. btCollisionObject* obj1 = static_cast<btCollisionObject*>(proxy1->m_clientObject);
  462. if (obj0->getUserPointer() == GROUND_ID || obj1->getUserPointer() == GROUND_ID)
  463. { // everything collides with ground
  464. return true;
  465. }
  466. else
  467. {
  468. return ((NNWalker*)obj0->getUserPointer())->getIndex() == ((NNWalker*)obj1->getUserPointer())->getIndex();
  469. }
  470. }
  471. };
  472. void NN3DWalkersExample::initPhysics()
  473. {
  474. setupBasicParamInterface(); // parameter interface to use timewarp
  475. gContactProcessedCallback = legContactProcessedCallback;
  476. m_guiHelper->setUpAxis(1);
  477. // Setup the basic world
  478. m_Time = 0;
  479. createEmptyDynamicsWorld();
  480. m_dynamicsWorld->setInternalTickCallback(evaluationUpdatePreTickCallback, this, true);
  481. m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
  482. m_targetFrequency = 3;
  483. // new SIMD solver for joints clips accumulated impulse, so the new limits for the motor
  484. // should be (numberOfsolverIterations * oldLimits)
  485. m_motorStrength = 0.05f * m_dynamicsWorld->getSolverInfo().m_numIterations;
  486. { // create a slider to change the motor update frequency
  487. SliderParams slider("Motor update frequency", &m_targetFrequency);
  488. slider.m_minVal = 0;
  489. slider.m_maxVal = 10;
  490. slider.m_clampToNotches = false;
  491. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  492. slider);
  493. }
  494. { // create a slider to change the motor torque
  495. SliderParams slider("Motor force", &m_motorStrength);
  496. slider.m_minVal = 1;
  497. slider.m_maxVal = 50;
  498. slider.m_clampToNotches = false;
  499. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  500. slider);
  501. }
  502. { // create a slider to change the root body radius
  503. SliderParams slider("Root body radius", &gRootBodyRadius);
  504. slider.m_minVal = 0.01f;
  505. slider.m_maxVal = 10;
  506. slider.m_clampToNotches = false;
  507. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  508. slider);
  509. }
  510. { // create a slider to change the root body height
  511. SliderParams slider("Root body height", &gRootBodyHeight);
  512. slider.m_minVal = 0.01f;
  513. slider.m_maxVal = 10;
  514. slider.m_clampToNotches = false;
  515. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  516. slider);
  517. }
  518. { // create a slider to change the leg radius
  519. SliderParams slider("Leg radius", &gLegRadius);
  520. slider.m_minVal = 0.01f;
  521. slider.m_maxVal = 10;
  522. slider.m_clampToNotches = false;
  523. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  524. slider);
  525. }
  526. { // create a slider to change the leg length
  527. SliderParams slider("Leg length", &gLegLength);
  528. slider.m_minVal = 0.01f;
  529. slider.m_maxVal = 10;
  530. slider.m_clampToNotches = false;
  531. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  532. slider);
  533. }
  534. { // create a slider to change the fore leg radius
  535. SliderParams slider("Fore Leg radius", &gForeLegRadius);
  536. slider.m_minVal = 0.01f;
  537. slider.m_maxVal = 10;
  538. slider.m_clampToNotches = false;
  539. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  540. slider);
  541. }
  542. { // create a slider to change the fore leg length
  543. SliderParams slider("Fore Leg length", &gForeLegLength);
  544. slider.m_minVal = 0.01f;
  545. slider.m_maxVal = 10;
  546. slider.m_clampToNotches = false;
  547. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  548. slider);
  549. }
  550. { // create a slider to change the number of parallel evaluations
  551. SliderParams slider("Parallel evaluations", &gParallelEvaluations);
  552. slider.m_minVal = 1;
  553. slider.m_maxVal = NUM_WALKERS;
  554. slider.m_clampToIntegers = true;
  555. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
  556. slider);
  557. }
  558. // Setup a big ground box
  559. {
  560. btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(200.), btScalar(10.), btScalar(200.)));
  561. m_collisionShapes.push_back(groundShape);
  562. btTransform groundTransform;
  563. groundTransform.setIdentity();
  564. groundTransform.setOrigin(btVector3(0, -10, 0));
  565. btRigidBody* ground = createRigidBody(btScalar(0.), groundTransform, groundShape);
  566. ground->setFriction(5);
  567. ground->setUserPointer(GROUND_ID);
  568. }
  569. for (int i = 0; i < NUM_WALKERS; i++)
  570. {
  571. if (RANDOMIZE_DIMENSIONS)
  572. {
  573. float maxDimension = 0.2f;
  574. // randomize the dimensions
  575. gRootBodyRadius = ((double)rand() / (RAND_MAX)) * (maxDimension - 0.01f) + 0.01f;
  576. gRootBodyHeight = ((double)rand() / (RAND_MAX)) * (maxDimension - 0.01f) + 0.01f;
  577. gLegRadius = ((double)rand() / (RAND_MAX)) * (maxDimension - 0.01f) + 0.01f;
  578. gLegLength = ((double)rand() / (RAND_MAX)) * (maxDimension - 0.01f) + 0.01f;
  579. gForeLegLength = ((double)rand() / (RAND_MAX)) * (maxDimension - 0.01f) + 0.01f;
  580. gForeLegRadius = ((double)rand() / (RAND_MAX)) * (maxDimension - 0.01f) + 0.01f;
  581. }
  582. // Spawn one walker
  583. btVector3 offset(0, 0, 0);
  584. spawnWalker(i, offset, false);
  585. }
  586. btOverlapFilterCallback* filterCallback = new WalkerFilterCallback();
  587. m_dynamicsWorld->getPairCache()->setOverlapFilterCallback(filterCallback);
  588. m_timeSeriesCanvas = new TimeSeriesCanvas(m_guiHelper->getAppInterface()->m_2dCanvasInterface, 300, 200, "Fitness Performance");
  589. m_timeSeriesCanvas->setupTimeSeries(40, NUM_WALKERS * EVALUATION_TIME, 0);
  590. for (int i = 0; i < NUM_WALKERS; i++)
  591. {
  592. m_timeSeriesCanvas->addDataSource(" ", 100 * i / NUM_WALKERS, 100 * (NUM_WALKERS - i) / NUM_WALKERS, 100 * (i) / NUM_WALKERS);
  593. }
  594. }
  595. void NN3DWalkersExample::spawnWalker(int index, const btVector3& startOffset, bool bFixed)
  596. {
  597. NNWalker* walker = new NNWalker(index, m_dynamicsWorld, startOffset, bFixed);
  598. m_walkersInPopulation.push_back(walker);
  599. }
  600. bool NN3DWalkersExample::detectCollisions()
  601. {
  602. bool collisionDetected = false;
  603. if (m_dynamicsWorld)
  604. {
  605. m_dynamicsWorld->performDiscreteCollisionDetection(); // let the collisions be calculated
  606. }
  607. int numManifolds = m_dynamicsWorld->getDispatcher()->getNumManifolds();
  608. for (int i = 0; i < numManifolds; i++)
  609. {
  610. btPersistentManifold* contactManifold = m_dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
  611. const btCollisionObject* obA = contactManifold->getBody0();
  612. const btCollisionObject* obB = contactManifold->getBody1();
  613. if (obA->getUserPointer() != GROUND_ID && obB->getUserPointer() != GROUND_ID)
  614. {
  615. int numContacts = contactManifold->getNumContacts();
  616. for (int j = 0; j < numContacts; j++)
  617. {
  618. collisionDetected = true;
  619. btManifoldPoint& pt = contactManifold->getContactPoint(j);
  620. if (pt.getDistance() < 0.f)
  621. {
  622. //const btVector3& ptA = pt.getPositionWorldOnA();
  623. //const btVector3& ptB = pt.getPositionWorldOnB();
  624. //const btVector3& normalOnB = pt.m_normalWorldOnB;
  625. if (!DRAW_INTERPENETRATIONS)
  626. {
  627. return collisionDetected;
  628. }
  629. if (m_dynamicsWorld->getDebugDrawer())
  630. {
  631. m_dynamicsWorld->getDebugDrawer()->drawSphere(pt.getPositionWorldOnA(), 0.1, btVector3(0., 0., 1.));
  632. m_dynamicsWorld->getDebugDrawer()->drawSphere(pt.getPositionWorldOnB(), 0.1, btVector3(0., 0., 1.));
  633. }
  634. }
  635. }
  636. }
  637. }
  638. return collisionDetected;
  639. }
  640. bool NN3DWalkersExample::keyboardCallback(int key, int state)
  641. {
  642. switch (key)
  643. {
  644. case '[':
  645. m_motorStrength /= 1.1f;
  646. return true;
  647. case ']':
  648. m_motorStrength *= 1.1f;
  649. return true;
  650. case 'l':
  651. printWalkerConfigs();
  652. return true;
  653. default:
  654. break;
  655. }
  656. return NN3DWalkersTimeWarpBase::keyboardCallback(key, state);
  657. }
  658. void NN3DWalkersExample::exitPhysics()
  659. {
  660. gContactProcessedCallback = NULL; // clear contact processed callback on exiting
  661. int i;
  662. for (i = 0; i < NUM_WALKERS; i++)
  663. {
  664. NNWalker* walker = m_walkersInPopulation[i];
  665. delete walker;
  666. }
  667. CommonRigidBodyBase::exitPhysics();
  668. }
  669. class CommonExampleInterface* ET_NN3DWalkersCreateFunc(struct CommonExampleOptions& options)
  670. {
  671. nn3DWalkers = new NN3DWalkersExample(options.m_guiHelper);
  672. return nn3DWalkers;
  673. }
  674. bool fitnessComparator(const NNWalker* a, const NNWalker* b)
  675. {
  676. return a->getFitness() > b->getFitness(); // sort walkers descending
  677. }
  678. void NN3DWalkersExample::rateEvaluations()
  679. {
  680. m_walkersInPopulation.quickSort(fitnessComparator); // Sort walkers by fitness
  681. b3Printf("Best performing walker: %f meters", btSqrt(m_walkersInPopulation[0]->getDistanceFitness()));
  682. for (int i = 0; i < NUM_WALKERS; i++)
  683. {
  684. m_timeSeriesCanvas->insertDataAtCurrentTime(btSqrt(m_walkersInPopulation[i]->getDistanceFitness()), 0, true);
  685. }
  686. m_timeSeriesCanvas->nextTick();
  687. for (int i = 0; i < NUM_WALKERS; i++)
  688. {
  689. m_walkersInPopulation[i]->setEvaluationTime(0);
  690. }
  691. m_nextReaped = 0;
  692. }
  693. void NN3DWalkersExample::reap()
  694. {
  695. int reaped = 0;
  696. for (int i = NUM_WALKERS - 1; i >= (NUM_WALKERS - 1) * (1 - REAP_QTY); i--)
  697. { // reap a certain percentage
  698. m_walkersInPopulation[i]->setReaped(true);
  699. reaped++;
  700. b3Printf("%i Walker(s) reaped.", reaped);
  701. }
  702. }
  703. NNWalker* NN3DWalkersExample::getRandomElite()
  704. {
  705. return m_walkersInPopulation[((NUM_WALKERS - 1) * SOW_ELITE_QTY) * (rand() / RAND_MAX)];
  706. }
  707. NNWalker* NN3DWalkersExample::getRandomNonElite()
  708. {
  709. return m_walkersInPopulation[(NUM_WALKERS - 1) * SOW_ELITE_QTY + (NUM_WALKERS - 1) * (1.0f - SOW_ELITE_QTY) * (rand() / RAND_MAX)];
  710. }
  711. NNWalker* NN3DWalkersExample::getNextReaped()
  712. {
  713. if ((NUM_WALKERS - 1) - m_nextReaped >= (NUM_WALKERS - 1) * (1 - REAP_QTY))
  714. {
  715. m_nextReaped++;
  716. }
  717. if (m_walkersInPopulation[(NUM_WALKERS - 1) - m_nextReaped + 1]->isReaped())
  718. {
  719. return m_walkersInPopulation[(NUM_WALKERS - 1) - m_nextReaped + 1];
  720. }
  721. else
  722. {
  723. return NULL; // we asked for too many
  724. }
  725. }
  726. void NN3DWalkersExample::sow()
  727. {
  728. int sow = 0;
  729. for (int i = 0; i < NUM_WALKERS * (SOW_CROSSOVER_QTY); i++)
  730. { // create number of new crossover creatures
  731. sow++;
  732. b3Printf("%i Walker(s) sown.", sow);
  733. NNWalker* mother = getRandomElite(); // Get elite partner (mother)
  734. NNWalker* father = (SOW_ELITE_PARTNER < rand() / RAND_MAX) ? getRandomElite() : getRandomNonElite(); //Get elite or random partner (father)
  735. NNWalker* offspring = getNextReaped();
  736. crossover(mother, father, offspring);
  737. }
  738. for (int i = NUM_WALKERS * SOW_ELITE_QTY; i < NUM_WALKERS * (SOW_ELITE_QTY + SOW_MUTATION_QTY); i++)
  739. { // create mutants
  740. mutate(m_walkersInPopulation[i], btScalar(MUTATION_RATE / (NUM_WALKERS * SOW_MUTATION_QTY) * (i - NUM_WALKERS * SOW_ELITE_QTY)));
  741. }
  742. for (int i = 0; i < (NUM_WALKERS - 1) * (REAP_QTY - SOW_CROSSOVER_QTY); i++)
  743. {
  744. sow++;
  745. b3Printf("%i Walker(s) sown.", sow);
  746. NNWalker* reaped = getNextReaped();
  747. reaped->setReaped(false);
  748. reaped->randomizeSensoryMotorWeights();
  749. }
  750. }
  751. void NN3DWalkersExample::crossover(NNWalker* mother, NNWalker* father, NNWalker* child)
  752. {
  753. for (int i = 0; i < BODYPART_COUNT * JOINT_COUNT; i++)
  754. {
  755. btScalar random = ((double)rand() / (RAND_MAX));
  756. if (random >= 0.5f)
  757. {
  758. child->getSensoryMotorWeights()[i] = mother->getSensoryMotorWeights()[i];
  759. }
  760. else
  761. {
  762. child->getSensoryMotorWeights()[i] = father->getSensoryMotorWeights()[i];
  763. }
  764. }
  765. }
  766. void NN3DWalkersExample::mutate(NNWalker* mutant, btScalar mutationRate)
  767. {
  768. for (int i = 0; i < BODYPART_COUNT * JOINT_COUNT; i++)
  769. {
  770. btScalar random = ((double)rand() / (RAND_MAX));
  771. if (random >= mutationRate)
  772. {
  773. mutant->getSensoryMotorWeights()[i] = ((double)rand() / (RAND_MAX)) * 2.0f - 1.0f;
  774. }
  775. }
  776. }
  777. void evaluationUpdatePreTickCallback(btDynamicsWorld* world, btScalar timeStep)
  778. {
  779. NN3DWalkersExample* nnWalkersDemo = (NN3DWalkersExample*)world->getWorldUserInfo();
  780. nnWalkersDemo->update(timeStep);
  781. }
  782. void NN3DWalkersExample::update(const btScalar timeSinceLastTick)
  783. {
  784. updateEvaluations(timeSinceLastTick); /**!< We update all evaluations that are in the loop */
  785. scheduleEvaluations(); /**!< Start new evaluations and finish the old ones. */
  786. drawMarkings(); /**!< Draw markings on the ground */
  787. if (m_Time > m_SpeedupTimestamp + 2.0f)
  788. { // print effective speedup
  789. b3Printf("Avg Effective speedup: %f real time", calculatePerformedSpeedup());
  790. m_SpeedupTimestamp = m_Time;
  791. }
  792. }
  793. void NN3DWalkersExample::updateEvaluations(const btScalar timeSinceLastTick)
  794. {
  795. btScalar delta = timeSinceLastTick;
  796. btScalar minFPS = 1.f / 60.f;
  797. if (delta > minFPS)
  798. {
  799. delta = minFPS;
  800. }
  801. m_Time += delta;
  802. m_targetAccumulator += delta;
  803. for (int i = 0; i < NUM_WALKERS; i++) // evaluation time passes
  804. {
  805. if (m_walkersInPopulation[i]->isInEvaluation())
  806. {
  807. m_walkersInPopulation[i]->setEvaluationTime(m_walkersInPopulation[i]->getEvaluationTime() + delta); // increase evaluation time
  808. }
  809. }
  810. if (m_targetAccumulator >= 1.0f / ((double)m_targetFrequency))
  811. {
  812. m_targetAccumulator = 0;
  813. for (int r = 0; r < NUM_WALKERS; r++)
  814. {
  815. if (m_walkersInPopulation[r]->isInEvaluation())
  816. {
  817. for (int i = 0; i < 2 * NUM_LEGS; i++)
  818. {
  819. btScalar targetAngle = 0;
  820. btHingeConstraint* hingeC = static_cast<btHingeConstraint*>(m_walkersInPopulation[r]->getJoints()[i]);
  821. if (RANDOM_MOVEMENT)
  822. {
  823. targetAngle = ((double)rand() / (RAND_MAX));
  824. }
  825. else
  826. { // neural network movement
  827. // accumulate sensor inputs with weights
  828. for (int j = 0; j < JOINT_COUNT; j++)
  829. {
  830. targetAngle += m_walkersInPopulation[r]->getSensoryMotorWeights()[i + j * BODYPART_COUNT] * m_walkersInPopulation[r]->getTouchSensor(i);
  831. }
  832. // apply the activation function
  833. targetAngle = (std::tanh(targetAngle) + 1.0f) * 0.5f;
  834. }
  835. btScalar targetLimitAngle = hingeC->getLowerLimit() + targetAngle * (hingeC->getUpperLimit() - hingeC->getLowerLimit());
  836. btScalar currentAngle = hingeC->getHingeAngle();
  837. btScalar angleError = targetLimitAngle - currentAngle;
  838. btScalar desiredAngularVel = 0;
  839. if (delta)
  840. {
  841. desiredAngularVel = angleError / delta;
  842. }
  843. else
  844. {
  845. desiredAngularVel = angleError / 0.0001f;
  846. }
  847. hingeC->enableAngularMotor(true, desiredAngularVel, m_motorStrength);
  848. }
  849. // clear sensor signals after usage
  850. m_walkersInPopulation[r]->clearTouchSensors();
  851. }
  852. }
  853. }
  854. }
  855. void NN3DWalkersExample::scheduleEvaluations()
  856. {
  857. for (int i = 0; i < NUM_WALKERS; i++)
  858. {
  859. if (m_walkersInPopulation[i]->isInEvaluation() && m_walkersInPopulation[i]->getEvaluationTime() >= EVALUATION_TIME)
  860. { /**!< tear down evaluations */
  861. b3Printf("An evaluation finished at %f s. Distance: %f m", m_Time, btSqrt(m_walkersInPopulation[i]->getDistanceFitness()));
  862. m_walkersInPopulation[i]->setInEvaluation(false);
  863. m_walkersInPopulation[i]->removeFromWorld();
  864. m_evaluationsQty--;
  865. }
  866. if (m_evaluationsQty < gParallelEvaluations && !m_walkersInPopulation[i]->isInEvaluation() && m_walkersInPopulation[i]->getEvaluationTime() == 0)
  867. { /**!< Setup the new evaluations */
  868. b3Printf("An evaluation started at %f s.", m_Time);
  869. m_evaluationsQty++;
  870. m_walkersInPopulation[i]->setInEvaluation(true);
  871. if (m_walkersInPopulation[i]->getEvaluationTime() == 0)
  872. { // reset to origin if the evaluation did not yet run
  873. m_walkersInPopulation[i]->resetAt(btVector3(0, 0, 0));
  874. }
  875. m_walkersInPopulation[i]->addToWorld();
  876. m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
  877. }
  878. }
  879. if (m_evaluationsQty == 0)
  880. { // if there are no more evaluations possible
  881. rateEvaluations(); // rate evaluations by sorting them based on their fitness
  882. reap(); // reap worst performing walkers
  883. sow(); // crossover & mutate and sow new walkers
  884. b3Printf("### A new generation started. ###");
  885. }
  886. }
  887. void NN3DWalkersExample::drawMarkings()
  888. {
  889. if (!mIsHeadless)
  890. {
  891. for (int i = 0; i < NUM_WALKERS; i++) // draw current distance plates of moving walkers
  892. {
  893. if (m_walkersInPopulation[i]->isInEvaluation())
  894. {
  895. btVector3 walkerPosition = m_walkersInPopulation[i]->getPosition();
  896. char performance[20];
  897. sprintf(performance, "%.2f m", btSqrt(m_walkersInPopulation[i]->getDistanceFitness()));
  898. m_guiHelper->drawText3D(performance, walkerPosition.x(), walkerPosition.y() + 1, walkerPosition.z(), 1);
  899. }
  900. }
  901. for (int i = 2; i < 50; i += 2)
  902. { // draw distance circles
  903. if (m_dynamicsWorld->getDebugDrawer())
  904. {
  905. m_dynamicsWorld->getDebugDrawer()->drawArc(btVector3(0, 0, 0), btVector3(0, 1, 0), btVector3(1, 0, 0), btScalar(i), btScalar(i), btScalar(0), btScalar(SIMD_2_PI), btVector3(10 * i, 0, 0), false);
  906. }
  907. }
  908. }
  909. }
  910. void NN3DWalkersExample::printWalkerConfigs()
  911. {
  912. #if 0
  913. char configString[25 + NUM_WALKERS*BODYPART_COUNT*JOINT_COUNT*(3+15+1) + NUM_WALKERS*4 + 1]; // 15 precision + [],\n
  914. char* runner = configString;
  915. sprintf(runner,"Population configuration:");
  916. runner +=25;
  917. for(int i = 0;i < NUM_WALKERS;i++) {
  918. runner[0] = '\n';
  919. runner++;
  920. runner[0] = '[';
  921. runner++;
  922. for(int j = 0; j < BODYPART_COUNT*JOINT_COUNT;j++) {
  923. sprintf(runner,"%.15f", m_walkersInPopulation[i]->getSensoryMotorWeights()[j]);
  924. runner +=15;
  925. if(j + 1 < BODYPART_COUNT*JOINT_COUNT){
  926. runner[0] = ',';
  927. }
  928. else{
  929. runner[0] = ']';
  930. }
  931. runner++;
  932. }
  933. }
  934. runner[0] = '\0';
  935. b3Printf(configString);
  936. #endif
  937. }