FEMTO-ST Institute / DISC /OMNI VisibleSim documentation September 2015

VisibleSim documentation

This page gives some help for users of VisibleSim modular robots simulator.

Compilable version

A full documentation of the C++ core code of visiblesim is available at this address.

A online step by step tutorial for creating codeblock source files is now available here.

Online visiblesim

The interface

First load the page  http://ceram.pu-pm.univ-fcomte.fr:5015/visiblesim/ in Mozilla firefox or Google Chrome browser.
Enter your login and password to access to the server.

Home page

You may use the 'w' key to enter in fullscreen mode, the 'h' key gives some help about the interface.

The main part of the window shows the scene with an initial set of blinky blocks. We can observe that blocks may have different initial color.

The identifier of the block appears when the mouse pointer roll over a Blinky Block.

Mouse actions:

You can open the scrolling tab using the green arrow in the right bottom of the window. 

Home page

  This window shows some information about the selected block (its position and its color). This window will recieve the message of the selected block if one is selected, or the whole list of messages after the running of a simulation.

Running a code in a block.

During a simulation, each block executes the same code, writed in Meld or in C++.

In this first tutorial, we present a simple code in c++ named "flooding.cpp" (download this code in your local disk).

#include "bbSimulator.h"
#include <cstdio>
#include <memory>
#include <sstream>

class ColorMessage : public Message {
public :
	int color;
	ColorMessage(int c):color(c) {};
	~ColorMessage() {};
};

typedef std::shared_ptr ColorMessage_ptr;

class test1BlockCode : public BlinkyBlocks::BlinkyBlocksBlockCode {
    BlinkyBlocks::BlinkyBlocksBlock *block;
    BlinkyBlocks::BlinkyBlocksScheduler *scheduler;
    bool colored;

public :
    test1BlockCode(BlinkyBlocks::BlinkyBlocksBlock *host): BlinkyBlocks::BlinkyBlocksBlockCode(host) {
        block=host;
        scheduler = BlinkyBlocks::getScheduler();
    }

    void startup() {
        colored = false;
        scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,255,255,255,0));
        if (block->blockId==1) {
          colored = true;
          scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,0,0,255,0));
          sendMessageToAllNeighbors(1);
        }
    }

    void processLocalEvent(EventPtr pev) {
        MessagePtr message;
        stringstream info;

        if (pev->eventType == EVENT_RECEIVE_MESSAGE) {
            message = (std::static_pointer_cast(pev))->message;
            ColorMessage_ptr recvMessage = std::static_pointer_cast(message);
            if (!colored) {
                colored = true;
                getScheduler()->trace(info.str(),block->blockId);

                scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,0,0,255,0));
                sendMessageToAllNeighbors(1);
            }
        }
    }

    void sendMessageToAllNeighbors(int c) {
        P2PNetworkInterface * p2p;
        for(int i = 0; i<6; i++) {
            p2p = block->getInterface((BlinkyBlocks::NeighborDirection::Direction)i);
            if(p2p->connectedInterface) {
                stringstream info;
                scheduler->trace(info.str(),block->blockId);
                ColorMessage *message = new ColorMessage(c);
                scheduler->schedule(new NetworkInterfaceEnqueueOutgoingEvent(scheduler->now()+1000, message, p2p));
            }
        }
    }
};

extern "C" {
    BlinkyBlocks::BlinkyBlocksBlockCode* buildNewBlockCode(BlinkyBlocks::BlinkyBlocksBlock *host) {
        return(new test1BlockCode(host));
    }
}

This code has for goal to change the color of all blocks from an initial 'Master block'. To do that, the Master Block sends a message to its direct neighbors, message that is step by step transmitted to the other blocks.

More precisely, this codeblock realises two actions:

In order to test the code, click in the 'file selection button' under Source code in the scrolling tab, select your code and then click in the 'load code' button.

 Sending a code

The code is compiled on the server and executed (you can re-execute the same code using 'r' key). 

Then you see the color changing during the execution of the code, and the list of events appears in the scrolling tab. You may analyse the steps of the running using the interface at the bottom of the screen:

Visualisation of a time of simulation

Visualisation of a time of simulation

Changing the configuration of blocks

You may add, delete blocks using the context menu. This menu appears when you click on a block with the right button combined with [ctrl] key.

You may test the code in the new configuration using 'r' key.

Modifying the scene

If you need to define a very different configuration you may write a complete xml configuration file and send if to the server using the 'file selection dialog' under XML configuration title in the scrolling tab and then click to the 'load XML' button.

The file 'config1.xml' shows an example of such a configuration file, it contains some information about the scene, the camera, the light and a list of all blocks precising their position on the grid and their initial colour.

<world gridsize="10,10,10" windowSize="1800,900">
<camera target="200,200,200" directionSpherical="0,70,400" angle="45"/>
<spotlight target="200,20,200" directionSpherical="45,60,500" angle="40"/>
<blockList color="0,255,0" blocksize="40,40,41">
<block position="5,5,5" color="0,0,255"/>
<block position="5,5,6" color="255,255,255"/>
<block position="5,5,7" color="255,255,255"/>
<block position="4,5,6" color="255,255,255"/>
<block position="6,5,6" color="255,255,255"/>
<block position="5,5,8" color="255,255,255"/>
<block position="5,5,9" color="255,255,255"/>
<block position="3,5,7" color="255,255,255"/>
<block position="4,5,7" color="255,255,255"/>
<block position="6,5,7" color="255,255,255"/>
<block position="7,5,7" color="255,255,255"/>
<block position="5,6,5" color="255,255,255"/>
<block position="5,7,5" color="255,255,255"/>
<block position="5,8,5" color="255,255,255"/>
<block position="7,6,7"/>
<block position="7,7,7"/>
<block position="7,8,7"/>
<block position="7,9,7"/>
<block position="5,8,6"/>
<block position="5,8,7"/>
<block position="4,8,7"/>
<block position="3,8,7"/>
<block position="4,5,9"/>
<block position="4,5,9"/>
<block position="3,5,9"/>
<block position="2,5,9"/>
<block position="1,5,9"/>
</blockList>
</world>

To go further

The two following files present another configuration file and a code-block that realise more complexe actions: config2.xml, visiblesim2.cpp.

The goal of this distributed program is to find the block that admits the maximum id and then to set its color to all the other blocks.

 

more complex example

<world gridsize="10,10,10" windowSize="1800,900">
<camera target="200,200,200" directionSpherical="0,70,400" angle="45"/>
<spotlight target="200,20,200" directionSpherical="45,60,500" angle="40"/>
<blockList color="0,255,0" blocksize="40,40,41">
<block position="5,5,5" color="0,0,255"/>
<block position="5,5,6" color="255,0,0"/>
<block position="5,5,7" color="0,255,0"/>
<block position="5,5,8" color="255,255,0"/>
<block position="6,5,7" color="0,255,255"/>
<block position="7,5,7" color="255,0,255"/>
<block position="5,6,5" color="0,0,255"/>
<block position="5,7,5" color="255,0,0"/>
<block position="5,8,5" color="0,255,0"/>
<block position="5,8,6" color="255,255,0"/>
<block position="5,8,7" color="255,0,255"/>
<block position="5,8,8" color="0,0,255"/>
<block position="5,8,8" color="255,0,0"/>
<block position="5,7,8" color="0,255,0"/>
<block position="5,6,8" color="255,255,0"/>
<block position="6,8,5" color="255,0,255"/>
<block position="7,8,5" color="255,0,0"/>
<block position="7,8,4" color="0,0,255"/>
<block position="7,8,4" color="0,255,0"/>
<block position="7,7,4" color="255,255,0"/>
<block position="7,6,4" color="255,0,128"/>
<block position="7,5,4" color="128,0,255"/>
<block position="7,5,5" color="64,64,128"/>
<block position="7,5,6" color="255,0,0"/>
</blockList>
</world>
#include "bbSimulator.h"
#include <cstdio>
#include <memory>
#include <sstream>

#define COLOR_MESSAGE	1001
#define SEARCH_MASTER_MESSAGE	1002
#define RETURN_MASTER_MESSAGE	1003

const int COM_DELAY=1000;

class SearchMasterMessage : public Message {
public :
	int blockId;
	Color blockColor;
	SearchMasterMessage(int i,Color c):blockId(i),blockColor(c) { type=SEARCH_MASTER_MESSAGE; };
	~SearchMasterMessage() {};
};

class ReturnMasterMessage : public Message {
public :
	int blockId;
	Color blockColor;
	ReturnMasterMessage(int i,Color c):blockId(i),blockColor(c) { type=RETURN_MASTER_MESSAGE; };
	~ReturnMasterMessage() {};
};

class ColorMessage : public Message {
public :
	Color color;
	ColorMessage(Color c):color(c) { type=COLOR_MESSAGE; };
	~ColorMessage() {};
};


typedef std::shared_ptr ColorMessage_ptr;
typedef std::shared_ptr SearchMasterMessage_ptr;
typedef std::shared_ptr ReturnMasterMessage_ptr;

class test2BlockCode : public BlinkyBlocks::BlinkyBlocksBlockCode {
    BlinkyBlocks::BlinkyBlocksBlock *block;
    BlinkyBlocks::BlinkyBlocksScheduler *scheduler;
	int masterId;
	Color masterColor;
	bool searchDone;
	int nbreOfWaitedAnswers;
	P2PNetworkInterface *block2answer;
	bool colored;
public :
    test2BlockCode(BlinkyBlocks::BlinkyBlocksBlock *host): BlinkyBlocks::BlinkyBlocksBlockCode(host) {
        block=host;
        scheduler = BlinkyBlocks::getScheduler();
    }

    void startup() {
		masterId = block->blockId;
		searchDone=false;
		masterColor = block->color;
		block2answer=NULL;
		nbreOfWaitedAnswers=0;
		colored=false;
		scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,masterColor[0]*255,masterColor[1]*255,masterColor[2]*255,0));
		if (block->blockId==1) {
			scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,0,0,255,0));
			sendMasterMessageToAllNeighbors(NULL);
		}
	}

    void processLocalEvent(EventPtr pev) {
        MessagePtr message;
        stringstream info;

        if (pev->eventType == EVENT_RECEIVE_MESSAGE) {
			message = (std::static_pointer_cast(pev))->message;
            switch (message->type) {
				case SEARCH_MASTER_MESSAGE : {
					SearchMasterMessage_ptr recvMessage = std::static_pointer_cast(message);
					if (masterIdblockId) {
						masterColor = recvMessage->blockColor;
						masterId = recvMessage->blockId;
					}

					if (searchDone) {
						sendReturnMessageTo(recvMessage->destinationInterface);
					} else {
						searchDone=true;
						block2answer=recvMessage->destinationInterface;
						sendMasterMessageToAllNeighbors(block2answer);
						scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,255,0,255,0));

						if (nbreOfWaitedAnswers==0) {
							if (block2answer!=NULL) {
								sendReturnMessageTo(block2answer);
								block2answer=NULL;
								scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,0,255,255,0));
							} else {
								scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,255,0,0,0));
								sendColorMessageToAllNeighbors(NULL);
							}
						}
					}				
				} 
				break;
				
				case RETURN_MASTER_MESSAGE : {
					ReturnMasterMessage_ptr recvMessage = std::static_pointer_cast(message);
					if (masterIdblockId) {
						masterColor = recvMessage->blockColor;
						masterId = recvMessage->blockId;
					}

					nbreOfWaitedAnswers--;
					if (nbreOfWaitedAnswers==0) {
						if (block2answer!=NULL) {
							sendReturnMessageTo(block2answer);
							block2answer=NULL;
							scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,0,255,255,0));
						} else {
							scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,255,0,0,0));
							sendColorMessageToAllNeighbors(NULL);
						}
					}
				} 
				break;
					
				case COLOR_MESSAGE : {
					ColorMessage_ptr recvMessage = std::static_pointer_cast(message);
					masterColor = recvMessage->color;
					if (!colored) {
						colored = true;
						scheduler->schedule(new BlinkyBlocks::SetColorEvent(scheduler->now(),block,masterColor[0]*255,masterColor[1]*255,masterColor[2]*255,0));
						sendColorMessageToAllNeighbors(message->destinationInterface);
					}
				}
				break;
            }
        }
    }

    void sendMasterMessageToAllNeighbors(P2PNetworkInterface *except) {
		P2PNetworkInterface * p2p;
		nbreOfWaitedAnswers = 0;
		searchDone=true;

		for(int i = 0; i<6; i++) {
			p2p = block->getInterface((BlinkyBlocks::NeighborDirection::Direction)i);
			if (p2p->connectedInterface && p2p->connectedInterface!=except) {
				nbreOfWaitedAnswers++;
				SearchMasterMessage *message = new SearchMasterMessage(masterId,masterColor);
				scheduler->schedule(new NetworkInterfaceEnqueueOutgoingEvent(scheduler->now()+COM_DELAY, message, p2p));
			}
		}
    }
	
	void sendReturnMessageTo(P2PNetworkInterface *p2p) {
		ReturnMasterMessage *message = new ReturnMasterMessage(masterId,masterColor);
		scheduler->schedule(new NetworkInterfaceEnqueueOutgoingEvent(scheduler->now()+COM_DELAY, message, p2p));
    }

	void sendColorMessageToAllNeighbors(P2PNetworkInterface *except) {
		P2PNetworkInterface * p2p;

		for(int i = 0; i<6; i++) {
			p2p = block->getInterface((BlinkyBlocks::NeighborDirection::Direction)i);
			if (p2p->connectedInterface && p2p->connectedInterface!=except) {
				ColorMessage *message = new ColorMessage(masterColor);
				scheduler->schedule(new NetworkInterfaceEnqueueOutgoingEvent(scheduler->now()+COM_DELAY, message, p2p));
			}
		}
	}
};

extern "C" {
    BlinkyBlocks::BlinkyBlocksBlockCode* buildNewBlockCode(BlinkyBlocks::BlinkyBlocksBlock *host) {
        return(new test2BlockCode(host));
    }
}

Benoît Piranda