6 Legged Walker
Hi
I'm new to breve (and AL simulation programming) but really getting into it.
Anyway, I set about the project of adding a couple of extra legs to the walker demo, like an ant. I wanted to see how the development would cope with the 2 extra legs, would it use them for stability etc.
After a few generations it appears the little critter decided it didn't need these legs and just holds them up in the air, using the original 4 legs to move. I was absolutely stunned by this. Can someone check my code and make sure I added the extra legs correctly?
#
# Walker.tz
# jon klein
#
# Walker is an attempt to evolve locomotion behavior for a simple
# creature using a genetic algorithm. THIS DEMO MAY REQUIRE AT
# LEAST 30 MINUTES BEFORE WALKING BEHAVIORS ARE OBSERVED.
# It may be best to run this demo overnight. Additionally, it
# is possible that no evolution will occur during the course of
# a simulation, so if you don't see results after an hour or two,
# start the simulation over again so that a new random population
# is used. Remember that the behaviors are evolved starting with
# completely random individuals.
#
# The algorithm can be described as thirty monkeys attempting to learn
# to drive a bus--they take turns one at a time, breeding the best
# individuals together to replace the worst individuals.
#
# We place the physical creature in the world and then attempt to evolve
# individuals (non-physical objects in this simulation) which will control
# the physical creature.
#
# The algorithm is described in the steps below:
# 1) create a number of random individuals
# 2) pick four individuals at random
# 3) let each individual control the body and record how far it moves
# 4) sort the four best individuals based on which could go the furthest
# 5) breed the best two individuals, create two offspring which will
# replace the two worst individuals.
# 6) return to step 2 and repeat.
#
# The creatures quickly learn to move by dragging the body along the
# ground and after longer simulations, realistic "walking" has been
# observed.
#
@use PhysicalControl.
@use Link.
@use Genome.
@use Shape.
@use Stationary.
@use MultiBody.
@define SPEED_K 10.
Controller Walker.
PhysicalControl : Walker {
+ variables:
seats, monkeys (list).
currentSeat (int).
wigglyThing (object).
# the following are flags that can be controlled by the user
# via the simulation menu
locked (int).
lockMenu, symMenu (object).
cloudTexture (object).
+ to init:
floor (object).
number (int).
item (object).
locked = 0.
self set-random-seed-from-dev-random.
self enable-fast-physics.
self set-fast-physics-iterations to 5.
# these are the default values anyway...
self enable-lighting.
self enable-smooth-drawing.
self move-light to (0, 20, 0).
# Create the floor for the critter to walk on.
floor = new Floor.
floor catch-shadows.
floor set-color to (1.0, 1.0, 1.0).
floor set-eT to .9.
cloudTexture = (new Image load from "images/clouds.png").
self enable-shadow-volumes.
self enable-reflections.
self set-background-color to (.4, .6, .9).
self set-background-texture-image to cloudTexture.
# Create the Creature.
wigglyThing = new Creature.
wigglyThing move to (0, 6, 0).
self offset-camera by (3, 13, -13).
self watch item wigglyThing.
# The "Monkeys" are the individuals that will control the Creature.
# Create the Monkeys and assign them numbers.
monkeys = 15 new Monkeys.
foreach item in monkeys: {
(item set-number to number).
number += 1.
}
self pick-drivers.
# set up the menus...
lockMenu = (self add-menu named "Lock Driver" for-method "toggle-driver-lock").
self add-menu-separator.
self add-menu named "Save Current Genome" for-method "save-current-genome".
self add-menu named "Load Into Current Genome" for-method "load-into-current-genome".
# schedule the first driver change and we're ready to go.
self schedule method-call "change-drivers" at-time (self get-time) + 20.0.
self display-current-driver.
+ to display-current-driver:
currentNumber (int).
currentNumber = (seats{currentSeat} get-number).
self set-display-text to "Driver #$currentNumber" at-x -.95 at-y -.9.
+ to iterate:
seats{currentSeat} control robot wigglyThing at-time (self get-time).
super iterate.
+ to pick-drivers:
# pick 4 new drivers at random. we do this by sorting the
# list randomly and picking the first 4 items.
sort monkeys with random-sort.
seats{0} = monkeys{0}.
seats{1} = monkeys{1}.
seats{2} = monkeys{2}.
seats{3} = monkeys{3}.
currentSeat = 0.
+ to random-sort objectA a (object) objectB b (object):
return random[3] - 1.
+ to change-drivers:
newDriver (int).
newOffset (vector).
# if they have locked the current driver, do nothing.
if locked: return.
# pick a new camera angle and pan...
newOffset = random[(30, 6, 30)] + (-15, 1, -15).
if |newOffset| < 14: newOffset = 14 * newOffset/|newOffset|.
self pan-camera-offset by newOffset steps 30.
# we change the drivers every time a monkey is finished it's
# turn. if we have seen the last monkey, breed them together.
seats{currentSeat} set-distance to |(wigglyThing get-location)|.
wigglyThing center.
currentSeat += 1.
if currentSeat > 3: {
self breed-new-monkeys.
self pick-drivers.
}
newDriver = (seats{currentSeat} get-number).
# schedule a new driver change in 20 seconds.
self schedule method-call "change-drivers" at-time (self get-time) + 20.0.
self display-current-driver.
+ to breed-new-monkeys:
print "breeding monkeys...".
sort seats with compare-distance.
# print out the distance for each individual tested
print "driver ", (seats{0} get-number), (seats{0} get-distance).
print "driver ", (seats{1} get-number), (seats{1} get-distance).
print "driver ", (seats{2} get-number), (seats{2} get-distance).
print "driver ", (seats{3} get-number), (seats{3} get-distance).
# breed the two best twice, replacing the two worst.
seats{0} breed with seats{1} to-child seats{2}.
seats{1} breed with seats{0} to-child seats{3}.
# give each individual a mutation
(seats{2} get-genome) mutate.
(seats{3} get-genome) mutate.
+ to compare-distance of a (object) with b (object):
result (float).
result = (b get-distance) - (a get-distance).
return result.
# the following methods are accessed from the simulation menu.
+ to toggle-driver-lock:
if locked == 1: {
locked = 0.
wigglyThing center.
self schedule method-call "change-drivers" at-time (self get-time) + 20.0.
lockMenu uncheck.
} else {
locked = 1.
lockMenu check.
}
+ to save-current-genome:
(seats{currentSeat} get-genome) save-with-dialog.
+ to load-into-current-genome:
(seats{currentSeat} get-genome) load-with-dialog.
}
Object : Monkeys {
+ variables:
distanceTraveled (float).
genome (object).
number (int).
+ to set-number to n (int):
number = n.
+ to get-number:
return number.
+ to init:
genome = new MonkeyGenome.
self randomize.
+ to randomize:
genome randomize.
+ to get-genome:
return genome.
+ to breed with otherMonkey (object) to-child child (object):
(child get-genome) crossover from-parent-1 (otherMonkey get-genome) from-parent-2 (self get-genome).
+ to control robot theRobot (object) at-time t (float):
theRobot set-joint-velocity-0 to SPEED_K * (genome calculate-torque-0 at t).
theRobot set-joint-velocity-1 to SPEED_K * (genome calculate-torque-1 at t).
theRobot set-joint-velocity-2 to SPEED_K * -(genome calculate-torque-2 at t).
theRobot set-joint-velocity-3 to SPEED_K * -(genome calculate-torque-3 at t).
theRobot set-joint-velocity-4 to SPEED_K * -(genome calculate-torque-4 at t).
theRobot set-joint-velocity-5 to SPEED_K * -(genome calculate-torque-5 at t).
+ to set-distance to value (float):
distanceTraveled = value.
+ to get-distance:
return distanceTraveled.
}
Genome : MonkeyGenome {
+ variables:
genomeData (11 floats).
+ to randomize:
genomeData[10] = random[5.0] - 2.5.
genomeData[0] = random[2.0] - 1.0.
genomeData[1] = random[2.0] - 1.0.
genomeData[2] = random[2.0] - 1.0.
genomeData[3] = random[2.0] - 1.0.
genomeData[4] = random[6.3] - 3.15.
genomeData[5] = random[6.3] - 3.15.
genomeData[6] = random[6.3] - 3.15.
genomeData[7] = random[6.3] - 3.15.
genomeData[8] = random[6.3] - 3.15.
genomeData[9] = random[6.3] - 3.15.
+ to calculate-torque-0 at time (float):
return .5 * (sin(genomeData[10] * (time + genomeData[4])) - (genomeData[0])).
+ to calculate-torque-1 at time (float):
return .5 * (sin(genomeData[10] * (time + genomeData[5])) - (genomeData[1])).
+ to calculate-torque-2 at time (float):
return .5 * (sin(genomeData[10] * (time + genomeData[6])) - (genomeData[2])).
+ to calculate-torque-3 at time (float):
return .5 * (sin(genomeData[10] * (time + genomeData[7])) - (genomeData[3])).
+ to calculate-torque-4 at time (float):
return .5 * (sin(genomeData[10] * (time + genomeData[8])) - (genomeData[4])).
+ to calculate-torque-5 at time (float):
return .5 * (sin(genomeData[10] * (time + genomeData[9])) - (genomeData[5])).
+ to mutate:
n (int).
n = random[10].
if n < 4: genomeData[n] = random[2.0] - 1.0.
else if n < 10: genomeData[n] = random[6.3] - 3.15.
else genomeData[n] = random[5.0] - 2.5.
print "mutated item $n of $self".
}
MultiBody : Creature {
+ variables:
bodyLink (object).
links (list).
joints (list).
+ to get-root:
return bodyLink.
+ to init:
counter (int).
linkShape, lowerLinkShape, bodyShape (object).
self add-menu named "Send to Center" for-method "center".
lowerLinkShape = (new Cube init-with size (.36, 1, .36)).
linkShape = (new Cube init-with size (.38, 1, .38)).
bodyShape = (new Cube init-with size (4, 3, .4)).
links = 12 new Links.
joints = 12 new RevoluteJoints.
links{0} set-shape to linkShape.
links{2} set-shape to linkShape.
links{4} set-shape to linkShape.
links{6} set-shape to linkShape.
links{8} set-shape to linkShape.
links{10} set-shape to linkShape.
links{1} set-shape to lowerLinkShape.
links{3} set-shape to lowerLinkShape.
links{5} set-shape to lowerLinkShape.
links{7} set-shape to lowerLinkShape.
links{9} set-shape to lowerLinkShape.
links{11} set-shape to lowerLinkShape.
self add-dependency on joints{0}.
self add-dependency on joints{1}.
self add-dependency on joints{2}.
self add-dependency on joints{3}.
self add-dependency on joints{4}.
self add-dependency on joints{5}.
self add-dependency on joints{6}.
self add-dependency on joints{7}.
self add-dependency on joints{8}.
self add-dependency on joints{9}.
self add-dependency on joints{10}.
self add-dependency on joints{11}.
links set-color to random[(1.0, 1.0, 1.0)].
bodyLink = new Link.
bodyLink set-shape to bodyShape.
joints{0} link parent bodyLink to-child links{0}
with-normal (0, 0, 1)
with-parent-point (2.0, -1.5, 0)
with-child-point (0, .5, 0).
joints{1} link parent links{0} to-child links{1}
with-normal (1, 0, 0)
with-parent-point (0, -.5, 0)
with-child-point (0, .5, 0).
joints{8} link parent bodyLink to-child links{8}
with-normal (0, 0, 1)
with-parent-point (0.0, -1.5, 0)
with-child-point (0, .5, 0).
joints{9} link parent links{8} to-child links{9}
with-normal (1, 0, 0)
with-parent-point (0, -.5, 0)
with-child-point (0, .5, 0).
joints{10} link parent bodyLink to-child links{10}
with-normal (0, 0, 1)
with-parent-point (0.0, 1.5, 0)
with-child-point (0, -.5, 0).
joints{11} link parent links{10} to-child links{11}
with-normal (1, 0, 0)
with-parent-point (0, .5, 0)
with-child-point (0, -.5, 0).
joints{4} link parent bodyLink to-child links{4}
with-normal (0, 0, 1)
with-parent-point (-2.0, -1.5, 0)
with-child-point (0, .5, 0).
joints{5} link parent links{4} to-child links{5}
with-normal (1, 0, 0)
with-parent-point (0, -.5, 0)
with-child-point (0, .5, 0).
joints{2} link parent bodyLink to-child links{2}
with-normal (0, 0, 1)
with-parent-point (2.0, 1.5, 0)
with-child-point (0, -.5, 0).
joints{3} link parent links{2} to-child links{3}
with-normal (1, 0, 0)
with-parent-point (0, .5, 0)
with-child-point (0, -.5, 0).
joints{6} link parent bodyLink to-child links{6}
with-normal (0, 0, 1)
with-parent-point (-2.0, 1.5, 0)
with-child-point (0, -.5, 0).
joints{7} link parent links{6} to-child links{7}
with-normal (1, 0, 0)
with-parent-point (0, .5, 0)
with-child-point (0, -.5, 0).
self set-root to bodyLink.
# rotate the creature and move it to above the origin.
self rotate around-axis (1, 0, 0) by 1.57.
joints set-double-spring with-strength 400 with-max .8 with-min -.8.
joints set-strength-limit to 300.
+ to center:
# to center the object, we set the X and Z components to 0, but not
# the Y, otherwise we would push the walker into the ground
currentLocation (vector).
currentLocation = (self get-location).
self move to (0, currentLocation::y, 0).
# The following four method allow external objects to manipulate
# the torque values of the links.
+ to set-joint-velocity-0 to value (float):
joints{0} set-joint-velocity to value.
joints{6} set-joint-velocity to -value.
+ to set-joint-velocity-1 to value (float):
joints{1} set-joint-velocity to value.
joints{7} set-joint-velocity to -value.
+ to set-joint-velocity-2 to value (float):
joints{2} set-joint-velocity to value.
joints{4} set-joint-velocity to -value.
+ to set-joint-velocity-3 to value (float):
joints{3} set-joint-velocity to value.
joints{5} set-joint-velocity to -value.
+ to set-joint-velocity-4 to value (float):
joints{8} set-joint-velocity to value.
joints{10} set-joint-velocity to -value.
+ to set-joint-velocity-5 to value (float):
joints{9} set-joint-velocity to value.
joints{11} set-joint-velocity to -value.
+ to destroy:
free links.
free bodyLink.
}
| Attachment | Size |
|---|---|
| simulation.png | 47.08 KB |

randomly, a couple of
randomly, a couple of restarts later I had a critter using all 6 legs. This was very similar to an ants movement (end 2 legs on 1 side and middle leg on oppisite side move forward while the rest move backwards), the back legs need to catch up a little but it was amazing. after this I may try a segmented body, or maybe a more doglike posture with more vertical legs with restricted rotation limits.
Making Progress
Looks cool. Just cut+paste from the demos, after some time you will discover how easy it is to make simulations. Have you thought about jumping rather than walking?
I have not failed! I have only tried 100,000 ways that will not work. —Thomas Edison
I linked up the legs in 2
I linked up the legs in 2 sets of 3 on my latest version
12
21
12
This way all legs in 1 set move in the same way, very good results (but it is cheating slightly).
I've had 1 evolution where the subject did start jumping (push up with rear 4 legs and grab the ground with front 2). I would really like to work on swimming objects, like the karl sims projects, is there support in breve for this (not zero gravity, but actually applying a force to a volume surrounding the subject)?
also, is it possible to
also, is it possible to measure the vertical distance travelled (for height jumped) or the height of a ¨creature¨ from head to toe as it were?
Here is a ¨spider¨ version
Here is a ¨spider¨ version of the SuperWalker demo, 8 legs and a whole lot of leg tangling going on.
#
# SuperWalker.tz
# jon klein
#
# This demo is an enhanced version of the Walker demo in which
# 1) the limbs are not bounded to move symmetrically and 2) limb
# lengths are evolved along with walking behaviors.
#
# Both of these changes make the search space much larger meaning
# that evolution goes much more slowly than for the Walker. It is
# best to let this simulation over night in order to observe real
# walking behaviors.
#
@use PhysicalControl.
@use Shape.
@use Genome.
@use Link.
@use Stationary.
@use MultiBody.
@define SPEED_K 10.
Controller Walker.
PhysicalControl : Walker {
+ variables:
seats, monkeys (list).
currentSeat (int).
wigglyThing (object).
# the following are flags that can be controlled by the user
# via the simulation menu
locked (int).
lockMenu (object).
+ to init:
floor (object).
number (int).
item (object).
locked = 0.
self enable-lighting.
self enable-smooth-drawing.
self enable-fast-physics.
self set-fast-physics-iterations to 5.
# Create the floor for the critter to walk on.
floor = new Floor.
floor catch-shadows.
floor set-eT to .9.
floor set-mu to 1.0.
self set-background-texture-image to (new Image load from "images/clouds.png").
self enable-reflections.
self set-background-color to (.4, .6, .9).
# The "Monkeys" are the individuals that will control the Creature.
# Create the Monkeys and assign them numbers.
monkeys = 15 new Monkeys.
foreach item in monkeys: {
(item set-number to number).
number += 1.
}
self pick-drivers.
# set up the menus...
lockMenu = (self add-menu named "Lock Driver" for-method "toggle-driver-lock").
self add-menu-separator.
self add-menu named "Save Current Genome" for-method "save-current-genome".
self add-menu named "Load Into Current Genome" for-method "load-into-current-genome".
# schedule the first driver change and we're ready to go.
self schedule method-call "change-drivers" at-time (self get-time) + 20.0.
self display-current-driver.
# Create the Creature.
wigglyThing = new Creature.
wigglyThing init-with genome (seats{0} get-genome).
wigglyThing move to (0, 3, 0).
self offset-camera by (-3, 3, 13).
self watch item wigglyThing.
+ to display-current-driver:
current (object).
current = seats{currentSeat}.
self set-display-text to "Driver #$currentSeat" at-x -.95 at-y -.9.
+ to iterate:
seats{currentSeat} control robot wigglyThing at-time (self get-time).
super iterate.
+ to pick-drivers:
# pick 4 new drivers at random. we do this by sorting the
# list randomly and picking the first 4 items.
sort monkeys with random-sort.
seats{0} = monkeys{0}.
seats{1} = monkeys{1}.
seats{2} = monkeys{2}.
seats{3} = monkeys{3}.
currentSeat = 0.
+ to random-sort objectA a (object) objectB b (object):
return random[2] - 1.
+ to save-drivers:
driver (object).
n (int).
foreach driver in monkeys: {
monkeys{n} = ((driver get-genome) save-as-xml file "driver$n.xml").
n++.
}
+ to load-drivers:
n (int).
for n=0,n<15,n++: {
((monkeys{n} get-genome) load-from-xml file "driver$n.xml").
}
self pick-drivers.
print monkeys{currentSeat}.
+ to change-drivers:
newDriver (int).
newOffset (vector).
# if they have locked the current driver, do nothing.
if locked: return.
# pick a new camera angle and pan...
newOffset = random[(30, 6, 30)] + (-15, 1, -15).
if |newOffset| < 30: newOffset = 30 * newOffset/|newOffset|.
self pan-camera-offset by newOffset steps 30.
# we change the drivers every time a monkey is finished it's
# turn. if we have seen the last monkey, breed them together.
seats{currentSeat} set-distance to |(wigglyThing get-location)|.
currentSeat += 1.
if currentSeat > 3: {
self breed-new-monkeys.
self pick-drivers.
}
newDriver = (seats{currentSeat} get-number).
if wigglyThing: {
free wigglyThing.
}
wigglyThing = new Creature.
wigglyThing init-with genome (seats{currentSeat} get-genome).
wigglyThing move to (0, 3, 0).
self watch item wigglyThing.
# schedule a new driver change in 20 seconds.
self schedule method-call "change-drivers" at-time (self get-time) + 20.0.
self display-current-driver.
+ to breed-new-monkeys:
print "breeding monkeys...".
sort seats with compare-distance.
# print out the distance for each individual tested
print "driver ", (seats{0} get-number), (seats{0} get-distance).
print "driver ", (seats{1} get-number), (seats{1} get-distance).
print "driver ", (seats{2} get-number), (seats{2} get-distance).
print "driver ", (seats{3} get-number), (seats{3} get-distance).
# breed the two best twice, replacing the two worst.
seats{0} breed with seats{1} to-child seats{2}.
seats{1} breed with seats{0} to-child seats{3}.
# give each individual a mutation
(seats{2} get-genome) mutate.
(seats{3} get-genome) mutate.
+ to compare-distance of a (object) with b (object):
result (float).
result = (b get-distance) - (a get-distance).
return result.
# the following methods are accessed from the simulation menu.
+ to toggle-driver-lock:
if locked == 1: {
locked = 0.
wigglyThing center.
self schedule method-call "change-drivers" at-time (self get-time) + 20.0.
lockMenu uncheck.
} else {
locked = 1.
lockMenu check.
}
+ to save-current-genome:
(seats{currentSeat} get-genome) save-with-dialog.
+ to load-into-current-genome:
(seats{currentSeat} get-genome) load-with-dialog.
}
Object : Monkeys {
+ variables:
distanceTraveled (float).
genome (object).
number (int).
+ to set-number to n (int):
number = n.
+ to get-number:
return number.
+ to init:
genome = new MonkeyGenome.
genome randomize.
self add-dependency on genome.
+ to get-genome:
return genome.
+ to breed with otherMonkey (object) to-child child (object):
(child get-genome) crossover from-parent-1 (otherMonkey get-genome) from-parent-2 (self get-genome).
+ to control robot theRobot (object) at-time t (float):
n (int).
while n < 16: {
theRobot set-joint-velocity number n to SPEED_K * (genome calculate-torque number n at t).
n+=1.
}
+ to set-distance to value (float):
distanceTraveled = value.
+ to get-distance:
return distanceTraveled.
}
Genome : MonkeyGenome {
+ variables:
waveCompression (float).
phaseShifts (16 floats).
ampShifts (16 floats).
limbLengths (16 floats).
+ to randomize:
n (int).
for n=0, n<16, n++: {
phaseShifts[n] = random[6.3] - 3.15.
ampShifts[n] = random[1.0] - .5.
limbLengths[n] = random[2.0] + .5.
}
waveCompression = random[5.0] - 2.5.
+ to calculate-torque number jointNum (int) at time (float):
# calculates the torque for a certain joint number.
return .5 * sin(waveCompression * (time + phaseShifts[jointNum]) ) - (ampShifts[jointNum]).
+ to get-limb-length number n (int):
return limbLengths[n].
+ to mutate:
n (int).
# we need to decide which of the elements in this genome to mutate
n = random[25].
if n < 8: ampShifts[n] = random[2.0] - 1.0.
else if n < 16: phaseShifts[n - 8] = random[6.3] - 3.15.
else if n < 24: limbLengths[n - 16] = random[2.0] + .5.
else waveCompression = random[5.0] - 2.5.
print "mutated item $n of $self".
}
MultiBody : Creature {
+ variables:
bodyLink (object).
links (list).
joints (list).
linkShape, lowerLinkShape, bodyShape (object).
+ to get-root:
return bodyLink.
+ to init-with genome g (object):
x, y (float).
lowerLimbSize, upperLimbSize (vector).
lowerLimbLinkPoint, upperLimbLinkPoint (vector).
counter (int).
self add-menu named "Send to Center" for-method "center".
# we want the limb volume to be constant at 16, but the dimensions can change.
y = (g get-limb-length number 0).
x = sqrt(.16/y).
x = sqrt(.16/y).
lowerLimbSize = (x, y, x).
lowerLimbLinkPoint = (0, y/2, 0).
y = (g get-limb-length number 1).
x = sqrt(.16/y).
x = sqrt(.16/y).
upperLimbSize = (x, y, x).
upperLimbLinkPoint = (0, y/2, 0).
lowerLinkShape = (new Cube init-with size lowerLimbSize).
linkShape = (new Cube init-with size upperLimbSize).
bodyShape = (new Cube init-with size (4, 3, .4)).
counter = 0.
links = 16 new Links.
joints = 16 new RevoluteJoints.
links{0} set-shape to linkShape.
links{2} set-shape to linkShape.
links{4} set-shape to linkShape.
links{6} set-shape to linkShape.
links{8} set-shape to linkShape.
links{10} set-shape to linkShape.
links{12} set-shape to linkShape.
links{14} set-shape to linkShape.
links{1} set-shape to lowerLinkShape.
links{3} set-shape to lowerLinkShape.
links{5} set-shape to lowerLinkShape.
links{7} set-shape to lowerLinkShape.
links{9} set-shape to lowerLinkShape.
links{11} set-shape to lowerLinkShape.
links{13} set-shape to lowerLinkShape.
links{15} set-shape to lowerLinkShape.
links set-color to random[(1.0, 1.0, 1.0)].
bodyLink = new Link.
bodyLink set-shape to bodyShape.
self set-root to bodyLink.
joints{0} link parent bodyLink to-child links{0}
with-normal (1, 0, 1)
with-parent-point (2.0, -1.5, 0)
with-child-point upperLimbLinkPoint.
joints{1} link parent links{0} to-child links{1}
with-normal (1, 0, 0)
with-parent-point -upperLimbLinkPoint
with-child-point lowerLimbLinkPoint.
joints{4} link parent bodyLink to-child links{4}
with-normal (1, 0, 1)
with-parent-point (-2.0, -1.5, 0)
with-child-point upperLimbLinkPoint.
joints{5} link parent links{4} to-child links{5}
with-normal (1, 0, 0)
with-parent-point -upperLimbLinkPoint
with-child-point lowerLimbLinkPoint.
joints{2} link parent bodyLink to-child links{2}
with-normal (1, 0, 1)
with-parent-point (2.0, 1.5, 0)
with-child-point -upperLimbLinkPoint.
joints{3} link parent links{2} to-child links{3}
with-normal (1, 0, 0)
with-parent-point upperLimbLinkPoint
with-child-point -lowerLimbLinkPoint.
joints{6} link parent bodyLink to-child links{6}
with-normal (1, 0, 1)
with-parent-point (-2.0, 1.5, 0)
with-child-point -upperLimbLinkPoint.
joints{7} link parent links{6} to-child links{7}
with-normal (1, 0, 0)
with-parent-point upperLimbLinkPoint
with-child-point -lowerLimbLinkPoint.
joints{8} link parent bodyLink to-child links{8}
with-normal (1, 0, 1)
with-parent-point (1.0, -1.5, 0)
with-child-point upperLimbLinkPoint.
joints{9} link parent links{8} to-child links{9}
with-normal (1, 0, 0)
with-parent-point -upperLimbLinkPoint
with-child-point lowerLimbLinkPoint.
joints{12} link parent bodyLink to-child links{12}
with-normal (1, 0, 1)
with-parent-point (-1.0, -1.5, 0)
with-child-point upperLimbLinkPoint.
joints{13} link parent links{12} to-child links{13}
with-normal (1, 0, 0)
with-parent-point -upperLimbLinkPoint
with-child-point lowerLimbLinkPoint.
joints{10} link parent bodyLink to-child links{10}
with-normal (1, 0, 1)
with-parent-point (1.0, 1.5, 0)
with-child-point -upperLimbLinkPoint.
joints{11} link parent links{10} to-child links{11}
with-normal (1, 0, 0)
with-parent-point upperLimbLinkPoint
with-child-point -lowerLimbLinkPoint.
joints{14} link parent bodyLink to-child links{14}
with-normal (1, 0, 1)
with-parent-point (-1.0, 1.5, 0)
with-child-point -upperLimbLinkPoint.
joints{15} link parent links{14} to-child links{15}
with-normal (1, 0, 0)
with-parent-point upperLimbLinkPoint
with-child-point -lowerLimbLinkPoint.
# rotate the creature and move it to above the origin.
self rotate around-axis (1, 0, 0) by 1.57.
joints set-double-spring with-strength 200 with-max .6 with-min -.6.
joints set-strength-limit to 250.
self enable-self-collisions.
# to center the object, we set the X and Z components to 0, but not
# the Y, otherwise we would push the walker into the ground
+ to center:
currentLocation (vector).
currentLocation = (self get-location).
self move to (0, currentLocation::y, 0).
# The following four method allow external objects to manipulate
# the torque values of the links.
+ to set-joint-velocity number jointNum (int) to value (float):
joints{jointNum} set-joint-velocity to value.
+ to destroy:
free links.
free joints.
free bodyLink.
free linkShape.
free lowerLinkShape.
free bodyShape.
super destroy.
}
PrismaticJoints
Have not surveyed to much of the Walker code, until I could use more time to study the PushGP features. It appears the following code is where fitness scores are stored:
seats{currentSeat} set-distance to |(wigglyThing get-location)|.
Place a stationary object above your walker or maybe two ramps have the walker move in the direction of the ramp as it approaches the end activate the prismaticjoints to exert an upward force to jump to the next ramp. You would have to add an additional link for the prismatic. You could also load the physics demo with the ball on the stairs, load the stairs objects for starters.
Consider rewarding vertical ascent
replace
seats{currentSeat} set-distance to |(wigglyThing get-location)|.
with
v (vector).
v= (wigglyThing get-location).
verticalposition = v get-value at 2. #y
vertialposition*=1.3.
v set-value to vertialposition at 2.
seats{currentSeat} set-distance to |v|.
I have not failed! I have only tried 100,000 ways that will not work. —Thomas Edison
Re: Graphics
I can keep the code straight forward. For instance load-scene at vector, independent of your code with some options similar to the controller enable-water-fx etc..
I have not failed! I have only tried 100,000 ways that will not work. —Thomas Edison
Obstacle Course
Don't have plans for working on the PushGP for some time. I can give you a hand with some obstacles, ever play put-put we can make it look cool with windmills, moats, and tunnels. I can work on the graphics if you want to spend more time on the spiders. A millipede would look really cool. We are looking three weeks for some good demos. I can send you more robotic code if you need help. or some sketches with side notes. If your game.
Don't try to force it to be all advanced with real life like movements, let the unexpected work as well, if its to constrained in its final design, it could limit our ingenuity.
I have not failed! I have only tried 100,000 ways that will not work. —Thomas Edison
Refactor your Code
Make the leg a separate object:
Object : Effector {
+ variables:
links (list).
joints (list).
shapes (list).
+ to init:
shapes{0} = (new Cube init-with size (1.3, 1.0, 1.3)).
shapes{1} = (new Cube init-with size (1.2, 3.0, 1.2)).
shapes{2} = (new Cube init-with size (1.1, 3.0, 1.1)).
shapes{3} = (new Cube init-with size (1.0, 3.0, 1.0)).
links = 4 new Links.
links{0} set-shape to shapes{0}.
links{1} set-shape to shapes{1}.
links{2} set-shape to shapes{2}.
links{3} set-shape to shapes{3}.
links{0} set-color to (.9, 0, 0).
links{1} set-color to (.8, 0, 0).
links{2} set-color to (.6, 0, 0).
links{3} set-color to (.4, 0, 0).
links{ 0 } move to ( 0, 4, 0 ).
links{ 1 } move to ( 0, 8, 0 ).
links{ 2 } move to ( 0, 10, 0 ).
links{ 3 } move to ( 0, 10, 0 ).
+ to get-rootnode:
return links{0}.
+ to set-rotation-velocity at-x x (float) at-y y (float) at-z z (float):
joints{0} set-joint-velocity to x.
joints{1} set-joint-velocity to y.
joints{2} set-joint-velocity to z.
+ to adjust-velocity of-joint j (object):
j set-joint-velocity to sin((controller get-time)/8)/2.
+ to make-multi-joint:
joints{0} = new RevoluteJoint.
joints{0} link parent links{0} to-child links{1} with-normal (0, 1, 0)
with-parent-point (0, -1.0, 0) with-child-point (0, 1.0, 0).
joints{1} = new RevoluteJoint.
joints{1} link parent links{1} to-child links{2} with-normal (1, 0, 0)
with-parent-point (0, -1.0, 0) with-child-point (0, 1.0, 0).
joints{2} = new PrismaticJoint.
joints{2} link parent links{2} to-child links{3} with-normal (0, 1, 0)
with-parent-point (0, 0, 0) with-child-point (0, 0, 0).
joints{0} set-strength-limit to 1000.
joints{0} set-joint-torque to 1000.
joints{1} set-strength-limit to 1000.
joints{1} set-joint-torque to 1000.
joints{2} set-strength-limit to 1000.
+to iterate:
self adjust-velocity of-joint joints{1}.
super iterate.
}
Then I run something like this:
+ to init:
connectors = 6 new Links.
effectors = 6 new Effector.
base = 1 new Link.
.
.
.
connectors{i} = (effectors{i} get-rootnode).
joints{i} link parent base to-child connectors{i} with-normal (0, 1, 0)
with-parent-point (-x, 0, -z) with-child-point (0, 0, 0).
effectors{i} make-multi-joint.
This makes your code is more compact and easier to debug.
I have not failed! I have only tried 100,000 ways that will not work. —Thomas Edison