Team:Grenoble Alpes/Contribution

PyoBuster - Contribution

Contribution

One part of our project is to create an incubator. To do that we designed a hardware and software system.

In the hardware system we built a module to move a plate in 2D. This module is used to agitate, and line up the wells with the detection module. To build it, we used 3D printed pieces, motors, ball bearing, etc… On this page we explain how to build this module.

For the software system we designed a communication protocol to permit great communication between the different microcontrollers. This protocol is the HermAs protocol, and we explain on this page how it works and how to use it. To fully understand this part, it is useful to have bases in object-oriented programming.

We also worked on a way to control the whole incubator using a graphical interface. For that we used a web server that directly communicate with Arduino microcontrollers using the communication protocol described above. As the web server is coded using the js language (nodejs), and the interface using html,css and js; knowing the basics of web/js programming is useful.

How to build an agitation module for a 96 well plate

List of necessary equipment:

  • 4 linear rail bearing (ref. SCS8UU, dimensions, Ø: 8mm)
  • 4 linear axis chromed steel (dimensions, l: 200mm, Ø: 8mm)
  • 1m belt (dimensions, 6mm large)
  • 2 pulley (dimensions, Ø: 5mm)
  • 2 ball bearing (ref. 608Zz, dimensions, 8mmx22mmx7mm)
  • bolts
  • PLA plastic for the 3D printer
  • 2 step motors Nema 17HS4401
  • 2 motor drivers TMC2130
  • 1 arduino + the power cable
  • some arduino wires
  • 2 Micro Switch V-156-1C25
  • 2 steel axis with different diameters (dimensions, Ø: 5mm on 16mm and Ø: 8mm on 8mm)

List of necessary tools:

  • 3D printer
  • screwdrivers adapted to the screws

Building steps:

You can find here the .stl files needed to build the agitation module. With those files and with the help of the software Cura, you can managed the parameters of the printed pieces to have the best result depending on the 3D printer you have.
After printing the seven plastic pieces, it’s now time to build the system !

Step 1: Insert the steel axis into the linear bearing before putting the two pieces from at the end from either side.

image1

Step 2: Repeat the operation on the other side with the two same pieces.

image2

Step 3: Insert the steel axis with the linear bearings into the two blue pieces.

image3

Step 4: Fix with four screws from either side the part previously assembled.

image4 image5 image6 image7

Step 5: You can now fix the last plastic piece of this agitation module. It’s the 96 well plate holder, which is screwed to the two linear bearing.


image8 image9

Step 6: Insert the two ball bearing into the two pieces and the two steel axis needed to fix joint the bearings and the pulleys.


image_pulley1 image_pulley2 image_pulley2
image_pulley4 image_pulley5 image_pulley6

Step 7: Insert the pulley on the rotor axis of the two Nema motors and fix them wit screws to the two plastic pieces adapted.


image_pulley7 image_pulley8

Now the agitation module is complete, let’s deal with the electronic part !


Agitation module build



The motors, the drivers, the switches and the Arduino Mega need power and a correct wire network to function properly. In order to make the circuit connections, you juste have to follow the wire network displayed below.

Electric Scheme of the agitation module

You can find here the .stl files needed to build the agitation module.


HermAs protocol

The HermAs protocol is a master/slave communication protocol between a web interface named Pythie (master), and several Arduino microcontrollers (slaves). This protocol has the advantage to be adapted for any Arduino applications, for several Arduino at the same time, and to parallelize actions and requests in the same Arduino. The protocol is coded in javascript, css, html for the Pythie web interface, and in c++ for the Arduino microcontrollers. This page describes in detail the protocol and how to use it for your own engineer project.

To understand this page and use the protocol you need to have prerequisites in c++ programmation, and in web server development.


Explanation of HermAs

The HermAs protocol Arduino side is coded in c++. The c++ language is an object-oriented language, thus the HermAs c++ is a c++ class. The HermAs C++ class allows to read a message from the Raspberry, to interpret it, and to execute actions according to the message. These actions can be to only send an information, a confirmation, or to perform classic tasks for an Arduino (i.e. move a motor, open a relay, light a led, etc…). To do these tasks and to have a unique HermAs class for all the Arduinos (no matter the Arduino goal), the HermAs class has a OperatingClass argument, which is a class containing all the functions and all the arguments to release the Arduino goal.

the .ino arduino programs
sample code in a .ino (Arduino scipt) file using HermAs communication

The figure shows the main points of the HermAs communication for the Arduinos. In the first 2 lines we include 2 librairies: HermAs.h is the header file of the HermAs class. OpClassTest.h is the header file of the operating class.

On line 3, we create the operating object with its constructor. On the next line we create the HermAs object, with as parameters the arduino id, and the operating object. The operating object becomes an argument of the HermAs object.

In order for the HermAs object to have access to the arguments and execute the operating class’s methods (function of the class), the operating class must have an array of pointers for each type of arguments, but also for the methods. To simplify the code with the pointers, the operating class can only access to unint8_t, uint16_t, uint32_t, or float arguments. And it can only have methods with this prototype: uint8_t NameFunction( unint8_t notuse );, no matter if the method uses or doesn't use the parameter (because of the message from the Raspberry, this parameter uses only 5 bits, and not 8). The arguments and methods are numbered.

To force the operating class to have this array, this class inherits to a virtual superclass (named: OperatingClass). This superclass allows to implement polymorphism in the HermAs class, and to imperatively have arguments and methods. The mandatory arguments are: a methods pointers array, the number of methods, pointer arrays to each argument types, the number of each types. There are 3 mandatory methods: 1 virtual method, and 2 pure virtual methods. The first virtual method permits to have a setup function for the operating class (to initiate the pin for example). These 2 other pure virtual functions are used to initialise the pointers arrays. The arrays are initiated in a HermAs method: void setup_OpClass(); (used on the line 6, in the example). To initialise the arrays, the first pure virtual method ( void nbArgMeth(); ) permits to define the number of each type and the number of methods. Then a HermAs method does a dynamic memory allocation of the arrays. Finally the second pure virtual method (void SetArgMeth_inTab();) permits to address the pointers at the arguments, and at the methods. Thus each argument has an argument number, and each method has a method number.


The Waiting list

With these arrays, the HermAs class has easy access to the operating class arguments and methods. One HermAs protocol goal is to allow one or several operating class methods to be executed. To do that we use a waiting list. When the Raspberry demands to execute a function, it indicates if it is a loop execution and its periode. If it is not a loop execution, it indicates the time before the execution. The structure named WlFct contains all this information: the method’s number, the method parameter, the time before the execution, if it is a loop function, the loop periode. Thus the waiting list is a WlFct array. Every time the Raspberry asks to execute a function, the arduino fills the waiting list with a WlFct structure corresponding to the request. At each arduino loop, the HermAs object browses the array and updates the time before the execution (on line 12, in the Arduino script). If this time becomes negative, the HermAs object executes the function. And if it is a looping function the time before the execution is evaluated at the loop periode. Else the function is removed from the waiting list. The function can also be removed from the waiting list, if it returns an error (with the number 0), or if it is a loop function and it returns the number 2 (means that it works correctly but it is time to be removed from the waiting list). If the function works correctly, it returns 1.


The messages

Now that the HermAs c++ class can execute operating class methods, it must read and interpret a message from the Raspberry. The message is coded on 32 bits, with 8 header bits, and 24 body bits. In the header we find the id Arduino (to know for or from which Arduino is the message) on 3 bits. There is also the type of the message (on 2 bits): an acknowledgement / error message (noted ack), a debug message (noted debug), a request message (noted rqt), and an information message (noted inf). The last 3 bits are for the type of acknowledgement, the type of request, or the type of information. According to these types, the message's body has a different structure.

The debug messages are used to help the developer to design the HermAs class. The developer puts in the body message the data to send, so that the developer analyzes this data.

The ack messages are sent by an Arduino, for the Raspberry. They indicate an operation success, an error from the HermAs class, or an error from the operating class. The next figure explains the link between the coding message and its meaning:

header Body Note
id arduino Type of message T type
id Arduino [3 bits]

0b111 to broadcast to all the Arduinos
Tack
0b00
succes
0b000
0b000: "Hello" To says that everthing is okay
0b001: "Ok"
0b010: "processing" time before the end of the execution [21 bits]
0b011: "continue"
0b100: "request well executed" Type of request [21 bits]
0b101: "function well executed" function number [21 bits]
error interpret
0b001
0b000: "wrong recipient" id recipient [21 bits] To says that there are an error with the operating class
0b001: "not understand"
0b010: "no content argument" request argument number [21 bits]
0b011: "no content function" request function number [21 bits]
0b100: "error remove function from the waiting list"
0b101: "waiting list full" number of functions in the waiting list [21 bits]
error functioning
0b010
0b000: "error pointer allocation" type of allocation [21 bits] To says that there are an error in the Hermes process
0b001: "error functioning operation class" function number [21 bits]
0b010: "error delay"
0b011: "error clacul"


The inf messages are sent by an Arduino, for the Raspberry. They are an answer to a request message to give information about an argument, the waiting list, etc… The next table explains the link between the coding message and this meaning.

header Body Note
id arduino Type of message T type
id Arduino [3 bits]

0b111 to broadcast to all the Arduinos
Tinf
0b11
1 argument
0b000
argument number [6 bits] argument type [2 bits] argument value [16 bits] Give the value and the type of an argument
2 arguments
0b001
argument number 1 [6 bits] arguments type [2 bits] argument value 1 [8 bits] argument value 2 [8 bits] Give the value and the type of 2 arguments. They are consecutive and with the same type
number of arguments and functions
0b010
number of function [6 bits] number of float type [5 bits] number of uint8_t type [5 bits] number of uint16_t type [5 bits] number of uint32_t type [3 bits] Give the number of function and the number of each type
Waiting list
0b011
number of function [6 bits] the function parameter [5 bits] loop function [1 bit] time unit [2 bits] time value [10 bits] Give a waiting list content


The rqt messages are sent by the Raspberry, for an Arduino. These messages can request to give information, set an argument, add a function in the waiting list, etc… The next table explains the link between the coding message and this meaning.

header Body Note
id arduino Type of message T type
id Arduino [3 bits]

0b111 to broadcast to all the Arduinos
Trqt
0b10
get 1 information
0b000
Type of information (Tinf) [3 bits] argument number [6 bits] ask an information
get 2 informations
0b001
Tinf 1 [3 bits] Tinf 2 [3 bits] argument number 1 [6 bits] argument number 2 [6 bits] ask 2 informations
set 1 argument
0b010
argument number [6 bits] argument value [16 bits] ask to set an argument
set 2 arguments
0b011
argumenr number 1 [6 bits] argument value 1 [8 bits] argument value 2 [8 bits] ask to set 2 consecutive argument
add in the waiting list
0b100
number of function [6 bits] the function parameter [5 bits] loop function [1 bit] time unit [2 bits] time value [10 bits] ask to add a function to the waiting list
resend a message
0b101
the half part of a message [16 bits] ask to resend a message. request send in 2 messages. Use for the debug development.
remove a function from the waiting list
0b110
function number [6 bits] ask to remove a function from the waiting list
reset the Arduino
0b111
reset the Arduino

The next parts explains some specific point of the HermAs functioning.

Each Arduino has an id coding on 3 bits. For our incubator our Arduinos have these id:

id arduino Arduino
0b001 TH control
0b010 plate move
0b011 measurement control

The id: 0b111 is kept to send a message to all the Arduinos.

There are 4 argument types, and 1 method type. Each argument type has an id (coding on 2 bits), and a limited number of allocation (define by the length message):

argument type id maximum number per type
float 0b00 32 (coding on 5 bits)
uint8_t 0b01 32 (coding on 5 bits)
uint16_t 0b10 32 (coding on 5 bits)
uint32_t 0b11 8 (coding on 3 bits)

Each argument has a number coding on 6 bits. So the operating class can not have more than 64 arguments. Thus the operating class is limited either by the total number of arguments, or by the allocation limit of an argument type.

The number of an is equal to its position in the array pointers of this own argument type, plus the maximum number of the previous types. For example, if the operating class has 3 float arguments, 2 uint8_t arguments, 1 uint16_t argument, and 4 uint32_t arguments.

Thus the first uint8_t argument is numbered 4 = 3 (number of float argument) + 1 (its position in the uint8_t argument) - 1 (because count starts to 0).

The uint16_t argument is numbered 5 = 3 (number of float argument) + 2 (number of uint8_t argument) + 1 (its position in the uint8_t argument) - 1 (because count starts to 0).

The second uint32_t argument is numbered 7 = 3 + 2 +1 + 2 - 1.


The id method type is 0b100. Each method has a number coding on 6 bits. So the operating class can not have more than 64 methods. Because there is only one method type, the numbering is simpler. The number of a method is the method position in the array pointers method.

A float argument is set (with a request message) with 2 decimals. Thus because a float setting message is coded on 16 bits

Because of the length message from the Raspberry, the loop periode is coding on 12 bits: 10 bits for the value, 2 bits for the units:

bit code unit time
0b00 milliseconds
0b01 seconds
0b10 minutes
0b11 hours

The next figure is a class diagram of the 3 classes used in the HermAs protocol. The diagram resumes the principal methods and arguments used for each class.

class diagram

Use the HermAs protocol

To use the HermAs protocol for your project, you must follow different steps:

  • First you have to download the HermAs folder (with the HermAs.cpp and the HermAs.h files), and put it in the Arduino library.
  • Secondly you have to create an Arduino library (a .cpp and .h files in the library Arduino folder). In this library, you have to create an operating class.
    • As explained before, this class must inherit the superclass named: OperatingClass (this superclass is defined in the HermAs.h file). Your class must use only these arguments: float, uint8_t, uint16_t, uint32_t. And use only methods with this prototype: uint8_t MethodName( uint8_t parameter);, no matter if you use or not the parameter. If you need several parameters you can use the class's arguments as parameters.
    • Your class must override the 3 pure virtual functions of the OperatingClass: void setup(): Write in this method the setup lines you need for your Arduino. For example the pinMode(); functions, or complex constructors from other libraries.
      void SetNbArgMeth(): In this method you must write the number of each argument type, and the number of methods from your class, in the arguments (define in the superclass): nbArgFloat, nbArgInt8, nbArgInt16, nbArgInt32, nbMethod.
      void SetArgMeth_inTab(): In this method you set the arguments and the methods in the pointers arrays. To do that you must associate the arguments address to the array element: Tabi8[0] = & Int8Arg1; Tabi8[1] = & Int8Arg2; Tabi16[0] = & Int16Arg; Tabi32[0] = & Int32Arg; TabF[0] = & FloatArg;. For the method you must cast the address method with the pointer type ptrf (define in the HermAs.h file): TabMeth[0] = (OperatingClass::ptrf) & OpClassName::MethodName;
  • Finally create the .ino file as in the figure XX example. You have to change the opClassTest initialisation with your operating class, and put it in the second parameters of the HermAs constructor. The first parameter is the id Arduino that you want to give to your Arduino.

The files are ready to be uploaded in your Arduino. You can now launch the Pyhtie web server, and use its interface to send requests to your Arduino.

You can find here our sources, in order to use it and have an example of an operating class.

Web-server and Pythie Interface

To use the testing bench, and program experiments, we conceived a GUI (Graphical User Interface) that is both easy to use, and does everything it needs to. This interface is provided by a web server ran on the Raspberry Pi that communicates with the Arduino microcontrollers used to operate the incubator. This web server is already pretty complex for the beginners, thus, we made a simpler, light-weight version of it that is available here to download. Yet event this version needs some explanation, and this is what we'll be doing below.

To fully understand the oncoming explanations, please be advised that you may need to know basics of web development and specifically the usage of "js" language.

Schema of the web server
Schema of the web server

Explanation of Pythie, the GUI (Graphical User Interface)

One of the main advantages of using an interface that is a web application is that it is available on a very large amount of devices. From smartphones to computers, as well as tablets and even game consoles, any device that includes a web browser could access the interface. The only requirement to do that is to be connected to the same private network as the testing bench (it is possible to connect the web server to a public domain, but it would expose it to possible hacks if it is not secure enough). On its light-weight version, the GUI is only composed of terminal allowing the used to send messages to the microcontrollers and see their answer(s). Various methods exist to send messages, it is possible to send hexadecimal and binary code, using respectively "HEX:FFFFFFFF" (8 characters) or "BIN:01010101010101010101010101010101" (32 characters). It is also possible to make specific headers to send instructions, for example: "LED:0:0:255:255:255" will light the led at the position (0,0) of the matrix in white (using rgb code).

Pythie terminal
Pythie terminal

The advantages of having such way of communicating are numerous, first, it is very versatile, it is very easy to make new headers, and based on its size, they can be very descriptive. Second, the answers received by the arduino can easily be read, if the necessary is done during the step of translation of the messages (see above for the correspondence between a message and its meaning). Finally, scaling such a simple interface to one more complex is very easy, adding buttons that does the equivalent of sending a message is simple, and everything will still be displayed on the terminal.

For the interface to be able to freely send AND receive data from the server, we use the Websocket communication protocol, allowing for many users to connect to the server at the same time without problems. More informations on this protocol will be given below as the whole data exchange is based on it.


Brief explanation of the Web Server

The web server has, in the system, the role of the orchestra conductor. Everything goes through it, and it is the one that decides what to do with what it is given. It has the role of interpreting the requests given through the web interface, the answers given by the microcontrollers, and consequently executing specific functions.

command to execute the web server
The command to execute the web server

In its light-weight version, the web server only has to initialize the communication with the microcontrollers, the Websocket protocol and to actually start the server to deliver the interface. In its more complex version, the server also communicates with a database that holds all of the experiments data, initialize a security protocol allowing the existence of users, admins, and the logging.


Detection and interfacing of Arduino microcontrollers

To detect the microcontrollers connected to the Raspberry Pi, the web server makes use of various modules (npm packages). The ones used are visible at the start of the file hermAs.js situated in the folder of the same name. The init() function, called in the main file, is used to browse through all the usb devices connected to the Raspberry. Using the productId and the vendorId of the connected devices, the server is able to determine which ones are Arduino or not. This is done by providing the init() function the combinations of corresponding ids of microcontrollers. Those can be found using various softwares available for free and very easily with a browser research. As you can see in the screen below, we used different microcontrollers, some being counterfeits as they are everywhere on the market.

code that discover the microcontrollers
The code that discover the microcontrollers

Once identified, the microcontrollers are initialized, the serial ports used for the communication are configured, and a Parser is put on this port. The role of this last one is to send a signal once data is available on the port, this data generally is an answer coming from an Arduino. This parser is configured to look for 4 bytes of data as the HermAs protocol use messages of the same size, thus the communication is easily scalable to use longer messages by replacing this value to a bigger one.

All of these configurations are stored in an array of variables, holding information for the connected microcontrollers. This array will then be used by the web server to send messages. The hermAs file also holds all of the functions used to communicate, the ones to send requests and the ones to interpret answers following the protocol. Receiving an answer will trigger an event that can be processed by informing the user using the Pythie interface and also by executing specific functions depending on for example, the argument received, the function executed, etc...

code used to match an answers to the execution of a function
The code used to match an answers to the execution of a function

You can see above, the code in the file requests.js used to match an argument received by a specific arduino to a function. The array keyValuePair is easily scalable, and clearly specifies what function will be executed upon receiving an argument. This is done by calling the function computeArg() while interpreting the answers in the file hermAs.js


WebSockets: Exchange of information between client and server

Websockets are used to exchange information between the server and the possibly many clients connected to it. They work by attributing to every client an id that is used to know from whom the information comes from and to whom they have to be sent. One of the advantages of using websockets is that this protocol is symmetric on the way of coding the exchanges. Using the package socket-io, the code below shows how, in the light-weight version, the data is processed.

The code that represent the utilisation of websockets
The code that represent the utilisation of websockets

On the server-side, we need to differentiate two ways of sending messages, the standard one, used by calling socket.emit(), and the broadcast one, using io.emit(). Using socket refers to a single client, while the other refers to all of them. the key-word emit is used to send data, this data can be labelled, making it simple for the recipient to interpret it. In the example above, "consoleInput" and "serverResponse" are used. the key-word on is used to detect when data is received, labelled with the subsequent string. A function can then be executed using the data received, resulting on an action with the microcontrollers and most of the time, an answer using another label. The symmetry of this protocol makes it so that the coding on the client-side is very similar, also using the same key-words and corresponding labels.


Extra information

The explanation above concerns the simpler, light-weight version of the web server, while in reality we used a more complex one. The one that we actually run in our different proof of concept videos has many more possibilities including the presence of a logging page, the usage of a database to store data, extra security to ensure that only authorized users can access the interface, etc...

You can find all the files we used on the following github repository. The software is spread across different folders which names are made to be as explicit as possible for the advanced programmers out there.