MPI Artificial Intelligence for robots and swarms

Language


Home

While our robots are not yet foraging, they are already engaged in an exploratory task (or even in a seeking task if you kept the light). This creates already an interesting dynamic as the network is both spatially structured and dynamic. So now, let’s introduce communication to our robots!

Reaching out

Range and bearing is both a recognition system between robots, as well as a communication system. It gives you the range - distance, and the bearing - angle, between you and any other robots, and allow you to share a payload - data with them.

Here, we will use it as a detection system and use it similarly as the proximity sensor (e.g., the closer another robot is, the bigger the force that points away from the other robot). While this is yet another repulsion force between robots, it can as well be adjusted to be an attraction force between robots, or even an inbetween (repulsion if too close, attraction if too far). While avoidance in this context only works with robots (and not walls or boxes), the range of detection is bigger than the one of the proximity sensor. While proximity helps with avoiding immediate collision, range and bearing controls the swarm structure, helping to achieve better and smoother movement between robots.

function rab_to_force()
  local f = vector2(0, 0)

  for i = 1, #robot.range_and_bearing do
    local p = robot.range_and_bearing[i]

    local dir = vector2(1, 0)
    dir:rotate(p.bearing)

    local w = 1 / (p.range + 0.01)  -- avoid divide by zero
    f = f - dir * w
  end

  return f
end

As mentioned, you might want to change the repulsive force into an attraction, if you want to aggregate robots, for example. Try as well to have a force that tries to force a specific distance between robots. This creates interesting crystal shapes as a swarm!

Minimal Naming Game

The Minimal Naming Game (MNG) is a simplified version of the Naming Game, which is one of the many language game that are used for the study of language evolution and emmergence.

A simplified exlpanation would be (for a more indepth explanation, see REF) that all robot have a vocabulary, and will talk to each other. To do so, first a speaker needs to be selected, that will send a word to a hearer. If the hearer know of the word, then the game is a success, and it keeps in its memory only that word. If the hearer doesn’t know the word, then the game is a failure, and the robot add this new word to its current vocabulary. If the speaker doesn’t have any word to send, then it will randomly create one.

So, first of all, we needs words. They are going to be numbers, between 1 and 255. And we need a vocabulary, defines a global table at the begining of our Lua code file:

voc = {}

Second, here are the three message sending protocols we will use that encompass the MNG:

-- 4-byte protocol:
-- Beacon:   [my_id, 0, 0, 0]
-- Start:    [my_id, other_id, 1, word]     word in 1..255
-- Answer:   [my_id, other_id, 2, 0|1]      0 fail, 1 success


function send_beacon()
    -- the 0 in third place means we are broadcasting our presence
  robot.range_and_bearing.set_data( {tonumber(robot.id:sub(3)), 0, 0, 0} )
end


function start_game(hearer_id, word)
    -- the 1 in third place means we want to start a game
  robot.range_and_bearing.set_data( {tonumber(robot.id:sub(3)), hearer_id, 1, word} )
end


function send_answer(speaker_id, success)
    -- the 2 in third place means we are answering in a game
  robot.range_and_bearing.set_data( {tonumber(robot.id:sub(3)), speaker_id, 2, success} )
end

Last, let’s implement the behavior of the game itself. For the speaker, it is about a probability of speaking, and then finding a robot in range:

function speaker_step()
    
  local pSpeak = 0.1

    -- Should we speak?
  if (math.random() < pSpeak) then
    return false
  end

    -- Build list of neighboors and their ids
  local neighboors = {}
  for i = 1, #robot.range_and_bearing do
    neighboors[#neighboors + 1] = robot.range_and_bearing[i].data[1]
  end

    -- No neighboors :(
  if #neighboors == 0 then
    return false
  end

    -- pick a random neighboors
  local hearer_id = neighboors[math.random(#neighboors)]

    -- no known words, then invent one!
  if #voc == 0 then
    voc[1] = math.random(1,255)
  end

  local word = voc[1]

  start_game(hearer_id, word)
  return true
end

as for the hearer:

local function hearer_step()

  for i = 1, #robot.range_and_bearing do
    local from    = robot.range_and_bearing[i].data[1]
    local target  = robot.range_and_bearing[i].data[2]
    local type    = robot.range_and_bearing[i].data[3]
    local payload = robot.range_and_bearing[i].data[4]

    -- If I receive a message from a speaker, addressed to me then I answer
    if type == 1 and target == tonumber(robot.id:sub(3)) then
      local word = payload

      -- check if word is in vocabulary
      local success = 0
      for j = 1, #voc do
        if voc[j] == word then
          success = 1
          break
        end
      end

      if success == 1 then -- simplify vocabulary to only that word
        voc = {word}
      else -- add word to vocabulary
        voc[#voc + 1] = word
      end

      send_answer(from, success)
      return true
    end
  end

  return false
end

And as a whole in the step function :


  local busy = false

    -- First check if you need to act as a hearer
  busy = hearer_step()
  
    -- If not, maybe you might act as a speaker then
  if not busy then
    busy = speaker_step()
  end

    -- If not, then broadcast about yourself
  if not busy then
    send_beacon()
  end

Now, all the above will allow you to run an experimentation with your robots playing a MNG. Ideally, you would have graphical representation on top of the robots for the words being used (coming soon!), but for now, you can probe the brain of any robots either by clickig on them with Shift pressed, and looking into their memory, or more globally, output in ARGoS at each tick the vocabulary of all robots:

log("---")
for i = 1, #voc do
    log(voc[i] .. " ")
end

With all code, the robots can now play a MNG, and it is up to you to change their behavior, would it be giving them a task to do, and to see how it impact the language dymanics, or make changes to the MNG and see what happens then!