C/C++ Desenvolvimento de Software Python
Desenvolvimento com KINECT

No primeiro artigo, apresentei a instalação do kinect no ubuntu.

Artigo tratando o kinect no ubuntu

Agora iremos falar e mostrar um pouco sobre seu desenvolvimento.

GITHUB do Projeto

O projeto do libfreenect fica neste repositório.

https://github.com/OpenKinect/libfreenect.git

Site do Projeto

https://openkinect.org/wiki/Low_Level

Meu GITHUB

Ja os meus conjuntos de testes, inclusive os apresentados nos artigos relacionados, podem ser vistos, neste repositório.

https://github.com/marcelomaurin/kinect

Instalação de desenvolvimento

O processo de instalação completo foi visto no artigo anterior, porem para efeito de desenvolvimento os pacotes necessários são:

sudo apt install libudev-dev
sudo apt install libglfw3-dev
sudo apt install freeglut3-dev
sudo apt install libfreenect-dev

Sendo os 3 pacotes iniciais, apenas apoio, e o libfreenect-dev realmente a lib necessária.

Hello World da Biblioteca

Neste primeiro projeto, pouca coisa faremos, apenas iremos compilar identificando o device.

#include <stdio.h>
#include <stdlib.h>
#include <libfreenect.h>

freenect_context *f_ctx;
freenect_device *f_dev;
int user_device_number = 0; // Normalmente 0 se você tiver apenas um Kinect

void depth_cb(freenect_device *dev, void *v_depth, uint32_t timestamp) {
    // Callback para dados de profundidade - não usado neste exemplo
}

void rgb_cb(freenect_device *dev, void *rgb, uint32_t timestamp) {
    // Salva uma imagem RGB capturada pelo Kinect
    FILE *image = fopen("output_image.ppm", "wb");
    if (image == NULL) {
        printf("Erro ao abrir o arquivo para escrita\n");
        return;
    }
    fprintf(image, "P6\n# Kinect RGB test\n640 480\n255\n");
    fwrite(rgb, 640*480*3, 1, image);
    fclose(image);
    printf("Imagem salva como output_image.ppm\n");

    // Depois de salvar a imagem, podemos sair do loop principal
    freenect_stop_video(dev);
    freenect_close_device(dev);
    freenect_shutdown(f_ctx);
    exit(0);
}

int main() {
    if (freenect_init(&f_ctx, NULL) < 0) {
        printf("freenect_init() falhou\n");
        return 1;
    }

    if (freenect_open_device(f_ctx, &f_dev, user_device_number) < 0) {
        printf("Não foi possível abrir o dispositivo\n");
        freenect_shutdown(f_ctx);
        return 1;
    }

    freenect_set_depth_callback(f_dev, depth_cb);
    freenect_set_video_callback(f_dev, rgb_cb);
    freenect_set_video_mode(f_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_RGB));

    freenect_start_video(f_dev);

    while (freenect_process_events(f_ctx) >= 0) {
        // Processa eventos do Kinect até que a captura de imagem seja concluída
    }

    return 0;
}

Neste exemplo o programa pega o kinect e tira uma foto, salvando na maquina local.

Vamos entender o código.

A freenect_init inicia a api.

A próxima função freenect_open_device, abre o device conforme o número que estiver descrito. Isso permite abrir mais de um kinect na mesma maquina.

As funções freenect_set_depth_callback e freenect_set_video_callback criam funções de callback, para controle, se voce não sabe o que é leia este artigo:

A função freenect_set_video_mode indica os parâmetros de resolução.

Por ultimo a função freenect_start_video, dá inicio ao kinect que aciona o callback quando pronto.

Makefile

Criamos aqui o arquivo de compilação do projeto.

CC=gcc
CFLAGS=-c -Wall -I/usr/include/libfreenect
LDFLAGS=-L/usr/lib/x86_64-linux-gnu -lfreenect
SOURCES=kinect.c
OBJECTS=$(SOURCES:.c=.o)
EXECUTABLE=kinect

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS) 
	$(CC) $(OBJECTS) -o $@ $(LDFLAGS)

.c.o:
	$(CC) $(CFLAGS) $< -o $@

clean:
	rm -f $(OBJECTS) $(EXECUTABLE)

Perceba aqui que o pulo do gato neste makefile, é a inclusão da pasta /usr/lib/x86_64-linux-gnu que é onde a lib se encontra. Bem como a /usr/include/libfreenect que é onde o header se encontra.

Compilando o projeto

Para compilar esse projeto, é necessário apenas rodar o script na pasta src do ubuntu:

make all

Compilando o projeto

Rodando o programa

Agora iremos rodar o programa, isso é a parte mais simples.

Ao rodar, ele captura uma foto, e salva, conforme apresentado.

Foto capturada pelo kinect.

pacotes Programação Yocto Project
Criando um daemon no linux

Daemon são programas que rodam em back ground e que são inicializados e controlados pelo sistema operacional.

Os daemon são geralmente serviços que devem ser gerenciados de forma automatica.

Iremos apresentar aqui um bom exemplo de como criar um daemon.

Para criar um daemon, primeiramente seu binário precisa ser incluído em um local que permita o acesso para qualquer usuário, por este motivo a inclusão na pasta /home/[usuário] não é uma boa pratica. Em geral incluímos em uma pasta como /usr/bin.

Os arquivos de configuração , quando houver, poderão ser incluídos na pasta /etc/[nome daemon].

A criação

A criação do daemon é bem simples.

Crie em /etc/systemd/system/ o arquivo [servido].service, tal como o exemplo do meu git:

https://github.com/marcelomaurin/srvFalar/blob/main/srvfalar/etc/systemd/system/srvfalar.service

Edite o arquivo [servico].service conforme apresentado abaixo:

[Unit]
Description=[Descreva o que faz o servico]
After=network.target

[Service]
ExecStart=/usr/bin/[servico_binario]
Restart=always
User=root
Group=root

[Install]
WantedBy=multi-user.target

Salve o serviço e como sudo dê o seguinte comando:

systemctl daemon-reload

Executando o serviço

Para executar um serviço digite:

systemctrl start [serviço]
C/C++ robotinics srvFalar
srvFalar

Estamos preparando os pacotes de instalação do srvFalar, com este pacote será possível rodar a aplicação como serviço.

Houve várias mudanças e outras virão.

Estamos atualizando o projeto para atender as necessidades do projeto robotinics.

Blog
VIM Dividir tela

Uma das coisas mais interessantes no vim é a capacidade de incluir em uma mesma tela, dois fontes e comparar ambos.

Iremos verificar neste artigo como fazer isso.

Chame o vim

vim

Na console crie um artigo, para isso pressione ESC, em seguida, digite:

w teste1234.txt

Criando arquivo teste1234.txt

Pressione o i para inserir texto.

Digite o seguinte texto:

este é um teste

este é outro teste

este é um novo teste

Digitação de um texto no vim

Dividindo em duas janelas Horizontais

Entre no modo de comando , pressionando ESC.

Em seguida CTRL+W e depois o s.

Duas splits horizontalmente

Voltar a uma única janela

Entre no modo de comando, pressionando ESC, em seguida digite:

CTRL+W o

Modo padrão

Dividindo Lateralmente

Entre no modo de Comando, digitando ESC, em seguida digite:

CTRL +W v

Modo vertical

Ajustando tamanho

Para ajustar a largura da janela, pressione

CTRL + w seguido de < ou CTRL + w seguido de >

O < diminui a janela da direita, e o > aumenta.

O = deixa elas da mesma largura.

Os comandos CTRL+W (j e k) navegam verticalmente.

CTRL+w j – indo para cima

CTRL+w k indo para baixo

Referências

https://www.tecmint.com/split-vim-screen/#:~:text=To%20split%20the%20vim%20screen,been%20split%20into%20two%20workspaces.&text=To%20navigate%20to%20the%20bottom,by%20the%20letter%20’j’%20.

IA PHP Python wordpress
Chatbot no wordpress – Parte 2

Agora que criei a página do Chatbot, vou comecar a preparar o recheio.

Definindo objetivo do Chatbot

A primeira coisa que precisamos saber é sobre o que devemos realizar nosso chatbot.

Bom irei falar sobre os projetos da maurinsoft.

Então o primeiro trabalho que irei precisar é criar simulados de perguntas, para facilitar isso, irei criar um conjunto de aplicações.

Neste post irei falar sobre o primeiro.

A melhor forma de criar um conjunto de perguntas é perguntando.

Então vou adicionar ao meu projeto uma tabela historico.

historico.sql

use maurinsoftdb;

create table historico (
  idhistorico int AUTO_INCREMENT PRIMARY KEY,
  pergunta varchar(200) not null,
  ip varchar(40),
  dtquest TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Agora que criei o espaço de armazenamento no banco, irei incluir no web service que processa a pergunta.

Fonte: runpy.php

<?php
    /*phpinfo();*/
	/*Registra webservice para processamento de jobs*/
	ini_set('display_errors', 'ON');
	error_reporting(E_ALL);

	header('Content-Type: application/json');  // <-- header declaration

	include "/var/www/html/python/connectdb.php";

	//header('Cache-Control: no-cache, must-revalidate');

$data = json_decode(file_get_contents("php://input"));

if($data){
		$pergunta = $dbhandle->real_escape_string($data->pergunta);
} else {
		$pergunta = $dbhandle->real_escape_string($_GET['pergunta']);
}

$ip = $_SERVER['REMOTE_ADDR']; /*Pega o ip do cliente*/

//echo "Inseriu";
$query= "INSERT into historico (pergunta, ip) values ( '". $pergunta. "', '".$ip."')";
$dbhandle->query($query); /*Executa*/

$json =  '{"rs":[';
if($pergunta){
  $command = escapeshellcmd('/var/www/html/python/nlp.py "'.$pergunta.'" > /var/log/proclog.log');
  $resposta = shell_exec($command);
  $resposta = str_replace (array("\r\n", "\n", "\r"), ' ', $resposta);

  if($resposta){
     $json = $json  . '{';
     $json = $json  .  '"pergunta":"'.$pergunta.'",';
     $json = $json  .  '"resposta":'.$resposta;
     $json = $json  .  '}';
  } else {
	 $json = $json  . '{';
	 $json = $json  .  '"pergunta":"'.$pergunta.'",';
     $json = $json  .  '"resposta":"'.'sem resposta'.'"';
	 $json = $json  .  '}';
  }
} else {
	$json = $json  . '{';
	$json = $json  .  '"pergunta":"'.$pergunta.'",';
    $json = $json  .  '"resposta":"'.'sem resposta'.'"';
	$json = $json  .  '}';
}
$json = $json  .  ']}';

echo $json
?>

Neste projeto que não irei falar muito, pois ja comentei sobre a maior parte em posts anteriores, fiz a inserção do código abaixo:

//echo "Inseriu";
$query= "INSERT into historico (pergunta, ip) values ( '". $pergunta. "', '".$ip."')";
$dbhandle->query($query); /*Executa*/	

Nela ao receber a pergunta armazenamos ela p pesquisa histórica.

Próximos passos

A seguir os próximos passos que iremos postar.

  • Iremos montar as questões que serão respondidas
  • Iremos cadastrar as respostas possíveis
  • Iremos associar as perguntas as respostas
  • Iremos gerar treinamento da nossa rede
  • Iremos codificar nosso código em python.
C/C++
Threads para Raiz – Parte 2 – Programação C

Neste segundo artigo, utilizaremos o exemplo apresentado e iremos desenvolver nossa aplicação em C para linux.

Github

Para ilustrar nosso exemplo criei uma pasta C no nosso projeto git.

Threads para Raiz – Parte 1

Todos os itens deste artigos estão na pasta C.

Makefile

Para quem acompanha meu canal, o nosso bem amado Makefile é o contrutor da aplicação.

PROGRAMA=threads
PROGRAMA32=threads32

LIBS= -lpthread

CC=gcc

SOURCE= threads.c

all32: clean compile32


all: clean compile

clean:
	rm -f *.o
	rm -f $(PROGRAMA)

compile32:
	$(CC) -m32  $(SOURCE) $(LIBS) -o $(PROGRAMA32)

compile:
	$(CC) $(SOURCE) $(LIBS) -o $(PROGRAMA)

Aqui criamos um construtor para ambas as arquituras 32 e 64bits.

Por padrão iremos manter o uso em 64bits que é a plataforma nativa do meu linux.

Criando a base

O primeiro passo é criar a base do nosso chamador.

Para tanto iremos no main, inicializar as variáveis e chamar os chamadores das threads.

void main(void){
	int rstatus = 0;
	srand(time(NULL));
	pthread_t  pidRecepcao = 0;
	pthread_t  pidControlador = 0;
	pthread_t  pidExecutor = 0;
	//mutex = PTHREAD_MUTEX_INITIALIZER;

	printf("\nBem vindo ao programa das threads\n");
	printf("Este programa faz parte do artigo:\n");
	printf("http://maurinsoft.com.br/index.php/2022/07/02/threads-para-raiz-parte-1/\n\n");
	printf("Inicializando vetor\n\n");
	StartVetor();
	printf("Iniciando Recepcao\n");
	pidRecepcao = Start_Recepcao();
	printf("Iniciando Controlador\n");
	pidControlador = Start_Controlador();
	printf("Iniciando Executor\n");
	pidExecutor = Start_Executor();
	//bool flag = ((pidRecepcao!=0)||(pidControlador!=0)||(pidExecutor!=0));
	flgTerminou = false;
	while(!flgTerminou){
		printf("Status:");

		if(rstatus != 0)
		{
			printf ("Erro ao aguardar finalização do thread A.\n");

		}

		flgTerminou = flgTerminouRecepcao && flgTerminouExecucao;
		sleep(1);
	}
	printf("\n\nFila ordenada:");
	for(int cont = 0;cont<=MAXITEMS-1;cont++)
	{
	  printf("%i ",fila[cont]);
	}
	printf("\n\n");

	printf("\n\nFila executada:");
	for(int cont = 0;cont<=MAXITEMS-1;cont++)
	{
	  printf("%i ",executada[cont]);
	}
	printf("\n\n");

}

As funcoes Start_Recepcao, Start_Controlador, Start_Executor chamam as threads, que serão apresentadas em um próximo momento.

A variavel pidRecepcao , do tipo pthread_t que indica cada uma das threads criadas.

Inicialização de variáveis

A inicialização da fila é feita pela função StartVetor, conforme fonte abaixo:

void StartVetor(){
		for (int cont = 0;cont<=MAXITEMS;cont++)
		{
			fila[cont] = 0;
			executada[cont]=0;

		}
}

Temos também a variável executada, que será utilizada na marcação dos itens executados.

Sessão Crítica

O controle da sessão crítica é feita nas funções IniciaSessaoCritica e TerminaSessaoCritica, conforme fonte abaixo:


int IniciaSessaoCritica()
{
	int  rc;
	int cont = 0;
	while ( (rc = pthread_mutex_lock(&mutex))!=0)
	{
		usleep(100); /*Aguarda um pouco*/
		cont++;
		printf("Sessao critica não conseguida\n");
		if (cont>3) break;
	}
	return rc;


}

int TerminaSessaoCritica()
{
	int  rc;
	int cont = 0;
	while ( (rc = pthread_mutex_unlock(&mutex))!=0)
	{
		usleep(100); /*Aguarda um pouco*/
		cont++;
		printf("Sessao critica não liberada\n");
		if (cont>3) break;
	}
	return rc;


}

Ambas as funções controlam a sessão criada mutex, declarada, conforme fonte abaixo:

pthread_mutex_t    mutex = PTHREAD_MUTEX_INITIALIZER;

Para cada sessão critica, deve-se criar uma variável de controle. Como usaremos apenas a fila, como variável de troca de dados, utilizaremos uma única sessão critica.

Criando a thread da recepção

Agora iremos dar inicio a criação da thread da recepção, na qual incluiremos o inicio da thread.

pthread_t  Start_Recepcao()
{
	pthread_t  pid	= 0;
	int ret;
	ret=pthread_create(&pid,NULL,&threadRecepcao,NULL);

	return pid;
}

Neste segmento do código, podemos acompanhar que criamos a thread com pthread_create, passando o ponteiro da função que será criada a thread threadRecepcao. Desta forma a função threadRecepcao, não mais seguirá na thread pai. O ultimo parâmetro é utilizado para passagens de argumentos, no nosso caso, não será usado.

Por fim a função da thread

/*thread function definition*/
void* threadRecepcao(void* args)
{
	for(int cont = 0;cont<=MAXITEMS;cont++)
	{

		printf("Criando pacote nro %d\n",cont);
		if(IniciaSessaoCritica()==0)
		{
			int Valor = (rand()% 100);
			fila[cont] = Valor; /*Grava Valor na fila*/
			printf("Registrou na fila[%d] = %d\n",cont,Valor);
			TerminaSessaoCritica();
			usleep(1000);
		} else {
				printf("Falha na Recepcao nro:\n",cont);
		}

	}
	printf("Recepcao terminou atendimento\n");

}

Podemos observar que a threadRecepção requisita a sessão crítica para movimentar a fila, apenas depois alocando valor para ela. Também podemos perceber que após seu uso, o mesmo é descartado.

Criando o Controlador

O controlador, é executado, em seguida, ordenando as informações.

void ordenacao()
{
int i, x;
bool flgordenado = false;
while((!flgordenado)&&(!flgTerminou))
{
	//flgordenado = true;
	for (i=0; i<=MAXITEMS-1; i++)
	{
		if ((fila[i]!=0)&&(fila[i+1]!=0))
		{
		  if(fila[i]>fila[i+1])
		  {
		    x = fila[i];
            fila[i] = fila[i+1];
		    fila[i+1] = x;
		    flgordenado = false;
		    //printf("Ordenando os pacote nro %d\n",i);
		  }
		}	else {
			//printf("Posicao vazia %d\n",i);
			flgordenado = false;
		}
    }


  }
}

/*thread function definition*/
void* threadControlador(void* args)
{
  int oldValue, newValue;
  int flgOrdenado = false;
  printf("Iniciou o controlador\n");
  while(!flgTerminou) /*Faz enquanto nao terminar e nao ordenao*/
  {
	if(IniciaSessaoCritica()==0)
	{
		ordenacao();

		TerminaSessaoCritica();
		//usleep(200);

	}
  }

  printf("Terminou ordenação de todos os itens\n");
}

Neste bloco temos duas funções:

A thread em si é a threadControlador, que chama a função de ordenação ordenacao.

A ordenação só para quando for atendida duas condições:

Tiver terminado as demais threads, indicado pelo flag flgTerminou e quando tiver sido totalmente ordenado flgordenado.

Executor

A thread do Executor, pode ser vista conforme apresentado a seguir:

/*thread function definition*/
void* threadExecutor(void* args)
{
  int oldValue, newValue;
  bool flgExecutado = false;
  printf("Iniciou o controlador\n");
  int posicao = 0;
  //while(!flgExecutado)
  while((!flgExecutado)&&(!flgTerminou))
  {
    //printf("Pesquisando Posicao %d\n",posicao);

	//printf("Entrou na sessao critica\n");
	if  (fila[posicao]==0) /*Fila nao foi preenchida*/
	{
		printf("posicao vazia %d\n",posicao);
		posicao = posicao;

	} else
	{
	   executada[posicao] = fila[posicao];
	   printf("Executou[%d] = %d\n",posicao,fila[posicao]);
	   if(posicao==MAXITEMS-1)
	   {
		   printf("Chegou ao fim\n ");
		   flgExecutado= true; /*Finaliza executor*/
	   } else
	   {
		   posicao ++;
	   }

	}
	//printf("terminou while\n");
  }

  flgTerminouExecucao = true;

  printf("Terminou ordenação de todos os itens\n");

}

Ela irá rodar até que duas condições sejam satisfeitas:

  • flgExecutado – Controla a execução de todas as tarefas da lista
  • flgTerminou – Controla o fim de todas as demais threads do sistema

Testando programa

Compilando programa

A compilação em um Raspberry PI ocorreu com sucesso.

Executando o programa

root@raspberrypi:/home/mmm/projetos/Threads-para-Raiz/c# ./threads

Bem vindo ao programa das threads
Este programa faz parte do artigo:
http://maurinsoft.com.br/index.php/2022/07/02/threads-para-raiz-parte-1/

Inicializando vetor

Iniciando Recepcao
Iniciando Controlador
Registrou na fila[0] = 80
Registrou na fila[1] = 11
Registrou na fila[2] = 76
Registrou na fila[3] = 71
Registrou na fila[4] = 27
Registrou na fila[5] = 23
Registrou na fila[6] = 33
Registrou na fila[7] = 68
Registrou na fila[8] = 32
Registrou na fila[9] = 92
Recepcao terminou atendimento
Iniciou o controlador
Iniciando Executor
Status:Iniciou o controlador
Executou[0] = 11
Executou[1] = 23
Executou[2] = 27
Executou[3] = 32
Executou[4] = 33
Executou[5] = 68
Executou[6] = 71
Executou[7] = 76
Executou[8] = 80
Executou[9] = 92
Chegou ao fim
 Terminou ordenação de todos os itens
Status:Terminou ordenação de todos os itens


Fila ordenada:11 23 27 32 33 68 71 76 80 92



Fila executada:11 23 27 32 33 68 71 76 80 92

Como a execução ficou um pouco longa, resolvi jogar como código.

Foto da execução

Conclusão

Podemos perceber que a execução de threads pode ser facilitada com uso de flags externos, que facilitam a comunicação entre os processos. Pudemos ver tambem, que a programação em threads é de fato, um estado de arte da programação C, pois envolve alem de um algoritmo bem desenvolvido, a elaboração de estratégias pensando em que uma thread não sabe exatamente quando a outra irá cumprir suas atividades.

Desta forma cada thread tem que ser pensada em aguardar e esperar as informações das threads que colaboraram com esta.

Desta forma o controle interno das informações é bem mais complicado.

Pudemos ver por ultimo o uso dos sinalizadores, que visão identificar o uso de uma sessão crítica do sistema. Que nada mais é que um recurso compartilhado.

Espero que tenham gostado do artigo.

Em caso de dúvidas ou sugestões, fico a disposição como sempre.

marcelomaurinmartins@gmail.com

Bibliografia

maurinsoft.com.br