buzz_examples

This is an old revision of the document!


Buzz Example Gallery

The aim of this code is to have a group of robots form a distance gradient from a source.

There is one robot that acts as the source; for simplicity here it is the robot with id 0. Every robot, including the source, emits its estimated distance from the source, a listens to other robots. * The robots that can see the source directly emit the distance they sense; * The robots that cannot see the source are in two categories:

  • Those who don't know any distance yet: these robots emit nil
  • Those who received a distance broadcast from one or more neighbors: these robots calculate their distance as the minimum among the received distances

This algorithm keeps running in the step() function, so it can adjust the distance gradient if the robots move around.

gradient.bzz
function init() {
  if(id == 0) {
    # Source robot
    mydist = 0.
  }
  else {
    # Other robots
    mydist = 1000.
    # Listen to other robots' distances
    neighbors.listen("dist_to_source",
      function(value_id, value, robot_id) {
        mydist = math.min(
          mydist,
          neighbors.get(robot_id).distance + value)
      })
  }
}
 
function step() {
  neighbors.broadcast("dist_to_source", mydist)
}
 
function destroy() {
}

Hexagonal patterns can be formed in a simple way by mimicking particle interaction. A simple model of particle interaction is the Lennard-Jones potential, which we use in the following code in a slightly modified way. Instead of the big exponents (12 and 6), we use the exponents 4 and 2, which give us smaller but more manageable numbers.

The idea in the code is that every robot can use the neighbors structure to sense the distance and angle of every direct neighbor. Using the distance, we calculate the magnitude of the “virtual force” (attraction or repulsion) due to a neighbor (function lj()). We then use the force magnitude and the angle to make an interaction vector (function to_lj), and proceed to sum all of these contributions together into an accumulator vector (functions sum and neighbors.reduce()). Finally, we scale the accumulator and feed it to the goto() function, which transforms a 2D vector into motion.

hexagon.bzz
# We need this for 2D vectors
include "../include/vec2.bzz"
 
# Lennard-Jones parameters
TARGET     = 283.0
EPSILON    = 150.0
 
# Lennard-Jones interaction magnitude
function lj_magnitude(dist, target, epsilon) {
  return -(epsilon / dist) * ((target / dist)^4 - (target / dist)^2)
}
 
# Neighbor data to LJ interaction vector
function lj_vector(rid, data) {
  return math.vec2.newp(lj_magnitude(data.distance, TARGET, EPSILON), data.azimuth)
}
 
# Accumulator of neighbor LJ interactions
function lj_sum(rid, data, accum) {
  return math.vec2.add(data, accum)
}
 
# Calculates and actuates the flocking interaction
function hexagon() {
  # Calculate accumulator
  var accum = neighbors.map(lj_vector).reduce(lj_sum, math.vec2.new(0.0, 0.0))
  if(neighbors.count() > 0)
    math.vec2.scale(accum, neighbors.count())
  # Move according to vector
  goto(accum.x, accum.y)
}
 
# Executed at init time
function init() {
}
 
# Executed every time step
function step() {
  hexagon()
}
 
# Execute at exit
function destroy() {
}
hexagon.bzz
# Lennard-Jones parameters
TARGET_KIN     = 283.
EPSILON_KIN    = 150.
TARGET_NONKIN  = 200.
EPSILON_NONKIN = 100.
 
# Lennard-Jones interaction magnitude
function lj(dist, target, epsilon) {
  return -(epsilon / dist) * ((target / dist)^4 - (target / dist)^2)
}
 
# Neighbor data to kin LJ interaction
function to_lj_kin(rid, data) {
  data.x = lj(data.distance, TARGET_KIN, EPSILON_KIN) * math.cos(data.azimuth)
  data.y = lj(data.distance, TARGET_KIN, EPSILON_KIN) * math.sin(data.azimuth)
  return data
}
 
# Neighbor data to non-kin LJ interaction
function to_lj_nonkin(rid, data) {
  data.x = lj(data.distance, TARGET_NONKIN, EPSILON_NONKIN) * math.cos(data.azimuth)
  data.y = lj(data.distance, TARGET_NONKIN, EPSILON_NONKIN) * math.sin(data.azimuth)
  return data
}
 
# Accumulator of neighbor LJ interactions
function sum(rid, data, accum) {
  accum.x = accum.x + data.x
  accum.y = accum.y + data.y
  return accum
}
 
# Calculates and actuates the flocking interaction
function flock() {
  # Create accumulator
  var accum
  accum = {}
  accum.x = 0
  accum.y = 0
  # Calculate accumulator
  accum = neighbors.kin().map(to_lj_kin).reduce(sum, accum)
  accum = neighbors.nonkin().map(to_lj_nonkin).reduce(sum, accum)
  if(neighbors.count() > 0) {
    accum.x = accum.x / neighbors.count()
    accum.y = accum.y / neighbors.count()
  }
  # Move according to vector
  goto(accum.x, accum.y);
}
 
# Executed at init time
function init() {
  s1 = swarm.create(1)
  s1.join()
  s1.select(id % 2 == 0)
  s2 = s1.others(2)
}
 
# Executed every time step
function step() {
  s1.exec(flock)    
  s2.exec(flock)
}
 
# Execute at exit
function destroy() {
}
  • buzz_examples.1472822154.txt.gz
  • Last modified: 2016/09/02 13:15
  • by ilpincy