16 Relay Module With Raspberry Pi 3 Using Socket
by Fernando Koyanagi in Circuits > Electronics
5955 Views, 10 Favorites, 0 Comments
16 Relay Module With Raspberry Pi 3 Using Socket
Today, we are going to talk about Raspberry Pi 3, which is actually an enormous microcomputer due to its Quad core processor that comes with plenty of memory and a Linux operating system. In this project, which consists of a 16 relay module with Socket, my goal here is to start automation with Raspberry PI, introduce socket and Layer concepts, program in C Unix / Linux, show a client-server, and use Lib WiringPI functions.
Resources Used
In this tutorial, we will cover important things about network and communication protocol, which summarizes IoT (Internet Of Things). For those who want to do the project today but don’t have the 16 relay boards, this won’t be a problem. You can use LEDs attached to the ports of the Raspberry Pi using a 330-Ohm resistor.
Goals
- Start automation with Raspberry Pi
- Introduce socket and layer concepts
- Show a client-server
- Introduce programming in C Unix / Linux
- Use Lib WiringPI functions
Geany Configuration
After installing Raspberry Pi 3, you need to configure the Geany IDE before compiling the codes. Inside Raspberry Pi, we will program in C language using GCC compiler.
1. Click the menu
Build -> Set Build Commands
(Build -> Define Construction Commands);
2. Add the following commands:
In "Compile" add: "-lwiringPi" and "-lthread"
In "Build" add: "-lwiringPi" and "-lthread"
In "Execute" add: "sudo" as in the image
Client.c and Server.c Programs
In our example today, we will make a program Client.c and Server.c. Both will run within the Linux operating system of Raspberry Pi 3 using IP 127.0.0.1, which is the internal IP LoopBack. So there are two memory processes, where one Client / Server will be talking to the other. But, of course, you can change the IP and run it on your notebook, for example, as long as you have a GCC there for the compiling that is required.
Connecting the Jumpers
In the assembly, we made it so the jumpers connect to the relay board to the GPIOs of the Raspberry.
Socket or HTTP?
The type of programming we are talking about today is a type of communication we call a socket. But which is better? Socket or HTTP? There are some scenarios that are critical; some of these require speed, while others demand security. These scenarios often occur during more complicated projects. Usually these situations involve military applications or financial applications. In these cases, Socket is the preferred method. The same goes for robotics.
The Socket, for Americans reading this, is like a wire with plugs at both ends, which enables the connection between two devices, as well as the exchange of information between such components.
So imagine a situation: you have an executable program, and it has to go through several layers of the operating system until you get to the physical layer and go through it. It goes through the operating system again until it reaches the other executable program. This second executable program responds and proceeds with the same path. In this process, we have a smaller amount of layers, and we have binary data traffic, with everything quick and reliable.
In another situation, this time in HTTP, we have, for example, an application that is in PHP or Java Script, and it will have to go through the browser, through apache, through the Java script. Thus, it will be interpreted several times until it reaches the operational system. Only there are already the eight layers until you reach the physical layer of the network that will take you to the second application, where it goes through the layers of the operating system. Here, I have more layers and text-mode data.
What I mean is that the excess number of layers increases insecurity, as you consequently increase the number of entry points that allow your system to be invaded or monitored, among other situations. You can understand this better by watching the movie "Snowden".
However, I want to make it clear that I have no preference for Socket or HTTP, since each has its own application.
Some time ago, IBM did a study that compared HTTP communication to the binary TCP with Socket. The Socket result was at almost 100% when compared to HTTP. However, I've seen cases that the performance of the binary TCP is up to ten times greater.
Status Diagram of the Client / Server Model
We are going to have two programs that we will compile and run on Raspberry Pi. I then assembled this diagram to make it easier to see.
Below is an example of a smartphone, a computer, an ESP8266, and an ESP32 as the client of Raspberry Pi, which can also serve as a Server, with the differentiation made through the program that is running within this device or devices.
Código Servidor Main()
int main(int argc , char *argv[]) { int socket_servidor; setaPinos(); //seta os pinos dos reles if(!preparaSocket(&socket_servidor)) //cria e prepara o socket return 0; iniciaServidor(socket_servidor); //inicia o servidor e executa um loop de recepção de mensagens }
Still creating the Socket:
<p>bool preparaSocket(int *conexao)<br>{ struct sockaddr_in servidor; //cria conexão socket *conexao = socket(AF_INET, SOCK_STREAM , 0); if (*conexao == -1) { puts("Nao foi possivel criar o socket"); return false; } puts("Socket criado"); //Prepara a estrutura sockaddr_in servidor.sin_family = AF_INET; servidor.sin_addr.s_addr = INADDR_ANY; servidor.sin_port = htons(PORTA);</p>
When INADDR_ANY is specified in the connection call, the socket is bound to all local interfaces.
Still in the Server Code, we go to the Bind function:
//efetua ligação if(bind((*conexao),(struct sockaddr *)&(servidor) , sizeof(servidor)) < 0) { puts("Falha na ligacao"); return false; } puts("Ligacao efetuada"); return true; }
Server_function (int socket_server), which involves Listen and Accept:
void iniciaServidor(int socket_servidor) { int socket_cliente, *novo_socket; //inicia a recepção de mensagens listen(socket_servidor , 3); puts("Aguardando novas conexoes..."); //loop infinito, para cada conexão criada uma thread que recebe as mensagens while((socket_cliente = accept(socket_servidor, (struct sockaddr *)0, (socklen_t*)0))) { puts("Conexao aceita"); //cria thread pthread_t thread; novo_socket = malloc(sizeof(*novo_socket)); *novo_socket = socket_cliente; //caso ocorra algum erro neste momento o loop é abortado if(pthread_create(&thread,NULL , comunicacaoSocket, (void*) novo_socket) < 0) { puts("Nao foi possivel criar a thread."); close(*novo_socket); free(novo_socket); return; } puts("Thread criada"); }
void *comunicacaoSocket(void *conexao) { puts("Thread de conexao iniciada"); int tamanhoMensagemRecebida, i; char mensagem[TF_MENSAGEM]; mensagem[0] = '\0'; //enquanto não for recebida nenhuma mensagem, permanece em loop while(1) { //recebe mensagem tamanhoMensagemRecebida = recv(*(int*)conexao ,&mensagem, sizeof(mensagem), MSG_PEEK); //define o final da mensagem (este comando impede que o 'lixo' de memória fique junto à mensagem) mensagem[tamanhoMensagemRecebida] = '\0'; //imprime mensagem recebida printf("\nRecebido: %s\n",mensagem); //deixa a mensagem em maiusculo, assim tanto faz "a1" ou "A1" for(i=0; i<tamanhoMensagemRecebida; i++) { mensagem[i] = toupper(mensagem[i]); }
//acende ou apaga reles de acordo com a mensagem recebida if(strcmp(mensagem,"A1")==0) ativaRele(PINORELE_1); else if(strcmp(mensagem,"D1")==0) desativaRele(PINORELE_1); else if(strcmp(mensagem,"A2")==0) ativaRele(PINORELE_2); else if(strcmp(mensagem,"D2")==0) desativaRele(PINORELE_2); else if(strcmp(mensagem,"A3")==0) ativaRele(PINORELE_3); else if(strcmp(mensagem,"D3")==0) desativaRele(PINORELE_3); // continua assim até o A16 e D16
puts("Thread finalizada e socket fechado."); //libera memória desta conexão free(conexao); return 0; }
void ativaEmSequencia() { int vet[16]; vet[0] = PINORELE_1; vet[1] = PINORELE_2; vet[2] = PINORELE_3; vet[3] = PINORELE_4; vet[4] = PINORELE_5; vet[5] = PINORELE_6; vet[6] = PINORELE_7; vet[7] = PINORELE_8; vet[8] = PINORELE_9; vet[9] = PINORELE_10; vet[10] = PINORELE_11; vet[11] = PINORELE_12; vet[12] = PINORELE_13; vet[13] = PINORELE_14; vet[14] = PINORELE_15; vet[15] = PINORELE_16; for(int i=0; i<16; i++) { digitalWrite(vet[i],LOW); delay(200); digitalWrite(vet[i],HIGH); delay(200); } }
Client Code
connects () - Socket creation
//cria socket e conecta,
bool conecta(int *conexao) { struct sockaddr_in client; //cria conexão socket *conexao = socket(AF_INET , SOCK_STREAM , 0); //caso ocorra um erro na criação, aborta a conexão if (*conexao == -1) return false; //imprime mensagem puts("Socket criado");
Connect
//prepara estrutura do cliente para conexão
client.sin_addr.s_addr = inet_addr("127.0.0.1"); client.sin_family = AF_INET; client.sin_port = htons(PORTA); //conecta o cliente if (connect(*conexao , (struct sockaddr *)&client, sizeof(client)) < 0) return false; //imprime mensagem puts("Conectado\n"); return true; }
Send and Close Function
int main()
{ int conexao; char msg[TF_MENSAGEM]; //recebe mensagem puts("Digite a mensagem:\n[1] - Para sair\n"); fflush(stdin); gets(msg); //envia mensagens até que "1" seja recebido while(strcmp(msg,"1")!=0) { //conecta cliente if(!conecta(&conexao)) { puts("Erro de conexão"); break; } //envia mensagem if(send(conexao ,&msg, TF_MENSAGEM, 0) < 0) puts("Falha no envio\n"); else puts("Enviada!\n"); puts("Digite a mensagem:\n[1] - Para sair\n"); fflush(stdin); gets(msg); } //fecha o socket close(conexao); return 0; }
Pin Treatment (wiringPi.h Library)
The sequence of the relays used in this example is from pin 8 to pin 10, respecting the following sequence:
#define PINORELE_1 8
#define PINORELE_2 9 #define PINORELE_3 7 #define PINORELE_4 15 #define PINORELE_5 16 #define PINORELE_6 0 #define PINORELE_7 1 #define PINORELE_8 2 #define PINORELE_9 3 #define PINORELE_10 4 #define PINORELE_11 5 #define PINORELE_12 12 #define PINORELE_13 13 #define PINORELE_14 6 #define PINORELE_15 14 #define PINORELE_16 10
For any questions concerning the outputs of Raspberry P, consult the table.
Connecting the Jumpers
Here I'll show you the connection: the output of Raspberry 3 on relay 1, output 5 on relay 2, and so on, as shown in the table.
Starting the Server
After compiling, you need to run the program with the "./server" command. This will start the server and all incoming messages will be reported to the console.
Sending Commands by Putty
I always recommend that you have some program like this putty, which works as a client for SSH, Telnet, and Rlogin network protocols.
Type the IP of Raspberry Pi (to find out this IP, type 'ifconfig' in the console) and the same port used in the algorithm.