domingo, 3 de novembro de 2019

Building Python OpenCV Contrib with Conda on Linux/Ubuntu

Building OpenCV form the source code can be a pain in the ass when working with Conda environment. I haven't found a working conda package, and the few tutorials i found didn't workout of the box, most likely because of different versions of anaconda, ubuntu and environment.

This post is based on these tutorials,which have enough information to get the build working:

https://alexsm.com/building-opencv-with-conda/ https://docs.opencv.org/master/d2/de6/tutorial_py_setup_in_ubuntu.html


Dependencies

First, install the dependencies need for opencv (more information on the opencv tutotrial above):

>sudo apt-get install cmake
>sudo apt-get install gcc g++
>sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev
>sudo apt-get install libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev
>sudo apt-get install libgtk2.0-dev
>sudo apt-get install libgtk-3-dev


Creating conda environment


Create and enable a new conda environment with the wanted python version and numpy:

>conda create -n opencv_build python=3.6 numpy
>conda activate opencv_build


Get source code

Make a folder and clone the opencv and contrib git:

>mkdir opencv_install
>cd opencv_install
>cd opencv_install
>git clone https://github.com/opencv/opencv.git
>git clone https://github.com/opencv/opencv_contrib.git

If you want some specific version do the checkout, otherwise skip the commands bellow:

>cd opencv; git checkout 3.4.1 >cd ../opencv_contrib; git checkout 3.4.1
>cd .. # in opencv_install


Check paths inside conda


It is good to check the correct environment path before building. With the environment activated:

>conda info

You should see something like this:

     active environment : opencv_build
    active env location : /home/jairo/anaconda3/envs/opencv_build
            shell level : 1
       user config file : /home/jairo/.condarc
 populated config files : /home/jairo/.condarc
          conda version : 4.6.11
    conda-build version : 3.17.8
         python version : 3.7.3.final.0
       base environment : /home/jairo/anaconda3  (writable)
           channel URLs : https://repo.anaconda.com/pkgs/main/linux-64
                          https://repo.anaconda.com/pkgs/main/noarch
                          https://repo.anaconda.com/pkgs/free/linux-64
                          https://repo.anaconda.com/pkgs/free/noarch
                          https://repo.anaconda.com/pkgs/r/linux-64
                          https://repo.anaconda.com/pkgs/r/noarch
          package cache : /home/jairo/anaconda3/pkgs
                          /home/jairo/.conda/pkgs
       envs directories : /home/jairo/anaconda3/envs
                          /home/jairo/.conda/envs
               platform : linux-64
             user-agent : conda/4.6.11 requests/2.21.0 CPython/3.7.3 Linux/4.15.0-66-generic ubuntu/16.04.6 glibc/2.23
                UID:GID : 1000:1000
             netrc file : None
           offline mode : False

You need to take note of the active env location. Is this case is /home/jairo/anaconda3/envs/opencv_build.

Check the path for python executable in the active enviroment::

>which python

/home/jairo/anaconda3/envs/opencv_build/bin/python

Take note of these 2 paths.


Create make file

Create the xcmake.sh file in the opencv_install folder. Remember to update the CONDA_ENV_PATH and CONDA_PYTHON_PATH with the information above:

CONDA_ENV_PATH=/home/jairo/anaconda3/envs/opencv_build
CONDA_PYTHON_PATH=/home/jairo/anaconda3/envs/opencv_build/bin/python
WHERE_OPENCV=../opencv
WHERE_OPENCV_CONTRIB=../opencv_contrib
cmake -D CMAKE_BUILD_TYPE=RELEASE \
        -D CMAKE_INSTALL_PREFIX=/usr/local \
        -D PYTHON3_EXECUTABLE=$CONDA_PYTHON_PATH \
        -D INSTALL_C_EXAMPLES=ON \
        -D INSTALL_PYTHON_EXAMPLES=ON \
        -D OPENCV_EXTRA_MODULES_PATH=$WHERE_OPENCV_CONTRIB/modules \
        -D BUILD_EXAMPLES=ON $WHERE_OPENCV


Prepare for building


Create the folder build inside the opencv_install:

>mkdir build
>cd build
>../xcmake.sh

You should get something like this if everything is correct:

--   Python 2:
--     Interpreter:                 /usr/bin/python2.7 (ver 2.7.12)
--     Libraries:                   /usr/lib/x86_64-linux-gnu/libpython2.7.so (ver 2.7.12)
--     numpy:                       /home/jairo/.local/lib/python2.7/site-packages/numpy/core/include (ver 1.16.5)
--     install path:                lib/python2.7/dist-packages/cv2/python-2.7
--
--   Python 3:
--     Interpreter:                 /home/jairo/anaconda3/envs/opencv_build/bin/python (ver 3.6.9)
--     Libraries:                   /home/jairo/anaconda3/envs/opencv_build/lib/libpython3.6m.so (ver 3.6.9)
--     numpy:                       /home/jairo/.local/lib/python3.6/site-packages/numpy/core/include (ver 1.17.3)
--     install path:                lib/python3.6/site-packages/cv2/python-3.6
--
--   Python (for build):            /home/jairo/anaconda3/envs/opencv_build/bin/python
--
--   Java:                         
--     ant:                         NO
--     JNI:                         NO
--     Java wrappers:               NO
--     Java tests:                  NO
--
--   Install to:                    /home/jairo/anaconda3/envs/opencv_build
-- -----------------------------------------------------------------

You want to make sure the Python(for build) and Install to folders are correct and inside your conda environment.


Build it

If everything is fine, make it. In the build folder:

>make -j4

-j4 is a flag for paralel processing. You can remove it if you see any problem.


Install it



>sudo make install
>sudo ldconfig


Test it


Run python and type:


>python
>import cv2
>cv2.__version__

You should see the opencv version installed.
In case of problem you need to check the paths, usually the problem is wrong paths. Check the paths where python is looking for modules (always with the environment activated):

Run python and type:

>python
>import sys
>print ('\n'.join(sys.path))

/home/jairo/anaconda3/envs/opencv_build/lib/python36.zip
/home/jairo/anaconda3/envs/opencv_build/lib/python3.6
/home/jairo/anaconda3/envs/opencv_build/lib/python3.6/lib-dynload
/home/jairo/.local/lib/python3.6/site-packages
/home/jairo/anaconda3/envs/opencv_build/lib/python3.6/site-packages

This will show the folders python is looking for the modules. If they are different from the specified on the build process the installation will fail.


Using the binary in another environment


To use this binary in other environment you should copy the cv2 folder to the respective folder. In this case the folder is located at /home/jairo/anaconda3/envs/opencv_build/lib/python3.6/sites-packages/cv2, and you should copy it to the new environment (change the opencv_build to the name of the new environment already create).

quarta-feira, 25 de setembro de 2019

Rede neural para Mega-sena em Colab + Keras

Como tudo começou

Resolvi aprender um pouco sobre implementação de redes neurais, e um bom projeto para começar é montar uma rede para prever os resultados da mega-sena. Os mais racionais vão dizer que isso é perda de tempo pois, o sorteio sendo aleatório, não é possível a rede aprender nenhum comportamento ou padrão. Bom, isso não importa, só de conseguir montar a rede e não gerar erros na execução já está de bom tamanho para começar.

Começei como acho que todo mundo começa: com linux e python. Baixei os pacotes com pip, e tudo ficou uma merda, com zilhões de versões diferentes, um monte dependencia incompreenssível e sem solução do tipo pacote A precisa do pacote B, que precisa do pacote C que não é compativel com o pacote A. O começo é difícil.

Ai conheci  Anaconda. Isso facilita muito a vida de quem esta começando. Vem tudo bunitinho e a maioria das coisas funciona de primeira. O Jupyter notebook vem instalado e funcionando, assim como os framework de inteligencia artificial como o tensorflow funcionam com facilidade. Começo a rodar diferentes exemplos e percebo que a minha máquina é muito ruim, e serve só para fazer fofoca do facebook e ver youtuber mané. Para rede neural falta memória, falta velocidade e qualquer aplicação boba leva muito tempo para processar.

Encontrando o Colab

Então, por acaso, no meu caminho, aparece o Colab, uma plataforma do Google. As máquinas virtuais alí tem mais memoria RAM que todos meus computadores juntos, e placas GPUs que preciso vender o carro para comprar uma. E tudo de graça. Fora que a conexão de internet dessas máquinas é muito rápida, assim posso baixar qualquer coisa da internet rapidamente na máquina virtual. Beleza, posso continuar com meu computador vagabundo e fazer minhas redes no Colab. Meu computador virou um mero terminal ;-)

O link para o Colab é esse aqui:

https://colab.research.google.com/


E Keras?

Junto com o Colab, descobri o Keras. De inicio achei que Keras era coisa de vagabundo preguiçoso que não queria se importar com os detalhes mais profundos de programação da rede neurais. Coisa de chefe: só fala oque quer, e os outros que se virem para conseguir fazer o negócio funcionar. E era isso mesmo!!! Keras é fácil, funciona e remove boa parte da complicação que vc não quer ter enquanto aprende algo novo. Seria o similar do seguinte: Python é muito facil, e C tem um monte de detalhes que vc precisa saber para utilizar. Keras é o Python, e tensorflow é o C. E Keras já vem instalado dentro da máquino do Colab, dentro do pacote do tensorflow. Nada mais fácil que isso.

E a Mega? Eu quero grana...

Como aprendizado montei um tutorial rápido de como utilizar o Colab, baixar arquivo de resultados da mega-sena no site da Caixa, processar e testar diferentes redes neurais em Keras. O arquivo esta no link abaixo, e pode ser aberto no Colab, procure por um link na página

https://github.com/JairoRotava/Colab_studies/blob/master/megasena_keras.ipynb

Mas não vá acreditar que isso vai em algum momento acertar os resultados da mega. Esse estudo também pode conter erros teóricos, não fazer sentido. Mas é uma boa forma de começar e aprender a sintaxe dos comandos em python e keras.

Boa sorte


sábado, 21 de setembro de 2019

Controle remoto para Linux utilizando um Arduino

Bateu um tédio, pouco serviço pra fazer, e oque precisa ser feito é muito chato. Resolvi fazer um projeto que estava muito tempo na fila: utilizar um controle remoto para controlar um computador que uso no rádio e tv. Da muita preguiça chato ter ir até o computador para mudar de música, pausar o filme no netflix, ou outra coisa qualquer.

O projeto é simples, utiliza um arduino UNO, um controle remoto que estava sobrando - da propria TV, uma panasonic, e um receptor de IR manjado ( TSOP4838 ). O arduino interpreta o sinal vindo do TSOP4838, comunica pelo USB com o computador, e um programa em python converte isso para comandos em Linux.


Receptor IR - Arduino

O hardware não tem nada demais, é o receptor de IR espetado no arduino. Coloquei tudo dentro de um copo do starbuck para não ficar dando curto com o resto dos equipamentos que estão no rack da tv.

O programa utilizado no Arduino é baseado num dos exemplos disponíves com a biblioteca IRremote. Foi adicionado código para lidar coma alimentação do sensor (pino 12 = GND e pino 13 = VCC), e tudo oque era descenessário foi retirado. No meu caso tive sorte do protocolo do controle remoto que eu tinha ser suportado pela biblioteca. No meu caso o protocolo utilizado é o PANASONIC.

#include <IRremote.h>

int RECV_PIN = 11;
int RECV_VCC_PIN = 13;
int RECV_GND_PIN = 12;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  digitalWrite(RECV_GND_PIN, LOW);
  digitalWrite(RECV_VCC_PIN, HIGH);

  pinMode(RECV_GND_PIN, OUTPUT);
  pinMode(RECV_VCC_PIN, OUTPUT);
  
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value
}

Esse programa retorna um número hexadecimal para cada tecla do controle. Mapeando a função com cada código retornado é feito um mapa do controle remoto. Neste controle da Panasonic algumas teclas mandam o mesmo código 3 vezes, geralmente as teclas que vc não que que fique repetindo, como play/pause e outras. As demais teclas com volume ficam mandando o código periodicamente enquanto o botão é apertado.



Interpretador em python

Programa python para recepção dos dados. Utiliza biblioteca pySerial e a ferramenta xdotool. Utilizo o python3. O programa acabou ficando mais complicado que o previsto inicialmente porque o receptor pega um pouco de ruído e envia alguns códigos incorretos. O software também gera uma movimentação não linear para o ponteiro do mouse, ou seja, começa devagar e vai movendo cada vez mais rápido, isso torna o controle pelo controle remoto mais fluido. O código esta bastante comentado.

# Recepção de control remoto
import time
import serial 
import os

VERSION = "0.1"
SERIAL_PORT = "/dev/ttyACM0"
BAUD_RATE = 9600

REPEATABLE = True
NOT_REPEATABLE = False
UNKNOW_COMMAND = '??'
NO_COMMAND = ''
NO_DESCRIPTION = ''
NO_IR_CODE = -1
#Lista de relacao entre codigo IR e comando linux. Formato [Codigo IR, Comando Linux, Descricao, Pode Repetir?]
command_list = [
 ['E17AF807','amixer -q -D pulse sset Master toggle','mute',NOT_REPEATABLE],
 ['BE3BB37','xdotool key XF86AudioRaiseVolume','aumenta volume',REPEATABLE],
 ['D4D9F2A7','xdotool key XF86AudioLowerVolume','baixa volume',REPEATABLE],
 ['21035431','xdotool mousemove_relative -- %MOUSE_MOVE 0','seta para direita',REPEATABLE],
 ['983AB4C1','xdotool mousemove_relative -- -%MOUSE_MOVE 0','seta para esquerda',REPEATABLE],
 ['C20370A1','xdotool mousemove_relative -- 0 -%MOUSE_MOVE','seta para cima',REPEATABLE],
 ['81930A09','xdotool mousemove_relative -- 0 %MOUSE_MOVE','seta para baixo',REPEATABLE],
 ['BB0ED9E1','xdotool click 1; sleep 0.2','ok',NOT_REPEATABLE],
 ['AA7B2167','xdotool key XF86AudioPlay','play',NOT_REPEATABLE],
 ['2E8C2A89','xdotool key XF86AudioNext','fwd',NOT_REPEATABLE],
 ['1F6E01C9','xdotool key XF86AudioPrev','rew',NOT_REPEATABLE],
 ['1D15F4D7','xdotool key XF86AudioStop','stop',NOT_REPEATABLE],
 ['406A954D','systemctl poweroff -i','desliga',NOT_REPEATABLE],
 ['E17A24DB','xset dpms force off; sleep 1','apaga tv',NOT_REPEATABLE],
 ['E17A18E7','xdotool key C; sleep 1','apaga tv',NOT_REPEATABLE],
 ['E17A7887','xdotool getwindowfocus getwindowname;sleep 1','pega nome janela em foco',NOT_REPEATABLE],
 ['A26409C9','pkill --oldest chrome; google-chrome-stable deezer.com/br/ & sleep 1','Abre pagina deezer',NOT_REPEATABLE],
 ['240C9161','pkill --oldest chrome; google-chrome-stable www.netflix.com & sleep 1','Abre pagina netflix',NOT_REPEATABLE],
 ['68E839F1','pkill --oldest chrome; google-chrome-stable www.youtube.com & sleep 1','Abre pagina youtube',NOT_REPEATABLE],
 ['ABBE1086','xdotool key Escape','esc',NOT_REPEATABLE], 
 ['68E69B7F','xdotool click 4','scrool up',REPEATABLE],
 ['223C02A7','xdotool click 5','scrool down',REPEATABLE]
]

#Codigo q corresponde a tecla repetida do IR. Tecla ainda esta apertada
button_down = 'FFFFFFFF'
#inicializa para evitar possivel chamada dessa variavel sem inicilizacao
linux_command = NO_COMMAND
last_command = NO_COMMAND
description = NO_DESCRIPTION
allow_repeat = NOT_REPEATABLE
repetition_count=0
last_ir_code = NO_IR_CODE
ir_code = NO_IR_CODE
#tempo max para interpretar que a tecla foi solta
IR_TIMEOUT = 0.3
#sinaliza q tecla esta pressionada desde ultima vez
pressed = False
#Maximo deslocamento do mouse
max_mouse = 35

# Hello message
print("Controle Remoto Arduino/Linux TabaJairo para controle Panasonic")
print("Versao: " + VERSION);


# Tenta conectar a serial
serial_connected = False
print("Procurando porta serial...")
while (not serial_connected):
 try:
  ser = serial.Serial(port=SERIAL_PORT,baudrate=BAUD_RATE, timeout=1)
  serial_connected = True
  print("yeah...achei")
 except:
  print("buuu...ainda não achei")
  time.sleep(1)
  

#Loop infinito - ctrl+c para terminar
while 1 :
 #Recebe ir code. Aguarda enquanto nao tem nada na serial
 last_ir_code = ir_code
 t = 0
 while ser.inWaiting() == 0:
  time.sleep(0.1)
  t = t + 0.1
  if t > IR_TIMEOUT:
   t=0
   #limpa ultimo codigo pois estourou timeout
   last_ir_code = NO_IR_CODE
 out = ser.readline().rstrip()
 ir_code = out.decode('utf-8')


 #Procura comando na lista
 #Coloca NO_COMMAND em linux_command para indicar q nao foi encontrado
 linux_command = NO_COMMAND
 for command in command_list:
  if ir_code == command[0]:
   linux_command = command[1]
   description = command[2]
   allow_repeat = command[3]

 # Se teve timeout na recepcao do codigo IR entao o ultimo comando eh vazio
 if last_ir_code == NO_IR_CODE:
  last_command = NO_COMMAND
  
 pressed = False
 #Verifica se eh comando repetido (tecla pressionada)
 if (linux_command == last_command) and (last_ir_code != NO_IR_CODE):
  pressed = True
  
 # Aqui tem um truque para melhor responsividade: se o comando atual nao eh reconhecido e 
 #  nao teve timeout na recepcap de IR supoe que houve problema na recepcao do codigo:
 #  o codigo eh diferente mas corresponde a ultima tecla pressionada
 if (linux_command == NO_COMMAND) and (last_ir_code != NO_IR_CODE) and (last_command != NO_COMMAND):
  pressed = True
  linux_command = last_command
  print("Codigo IR invalido! Provavelmente eh o ultimo comando, vamos repetir..."); 
 
 # Incrementa contador de botao pressionado
 if pressed:
  repetition_count+=1
 else:
  repetition_count=0

 # Atualiza last command. A posicao da linha eh importante para o codigo funcionar  
 last_command = linux_command
  
 #subsitui wildcard %MOUSE_MOVE do movimento do mouse para fazer aceleracao
 mouse_move = repetition_count*repetition_count+1;
 if mouse_move > max_mouse:
  mouse_move = max_mouse
 linux_command = linux_command.replace("%MOUSE_MOVE",str(mouse_move)) 

 #executa comando se for conhecido. Verifica se ele pode ser repetido ou nao.
 # Nao queremos o play/pause repetindo, nem o mute por exemplo
 if linux_command != NO_COMMAND:
  if repetition_count == 0 or  (repetition_count > 0 and allow_repeat):
   print(ir_code + ' ' +  str(repetition_count) + ' --> ' + description + ' --> ' + linux_command); 
   os.system(linux_command)
  else:
   print(ir_code + ' ' +  str(repetition_count) + ' --> ' + description + ' --> nao pode repetir');
 else:
  print(ir_code + ' ' +  str(repetition_count) + ' --> buuu, nao conheco esse comando ');


O programa monitor a porta serial /dev/ttyACM0 na qual o arduino esta conectada. Sempre que recebe um comando serial ele dispara o correspondente no linux. A ferramente xdotool permite simular o mouse e teclado, e com isso é possivel enviar comandos como aumentar/baixa volume pelas teclas especiais de volume, play/pause etc. Também é possível utilizar diretamente outros comandos do linux, como por exemplo desligar a tela ou fazer shutdown da máquina.
No exemplo acima estão comandos diretos no linux, comandos que simulam teclado ( xdotool key ... ) e comandos que simulam mouse (xdotool mousemove_relative e click ) .


Na figura acima esta uma amostra do programa recebendo os códugos. O primeiro campo é o código recebido pela IR, depois o numero de repetições, uma descrição do código, e o comando executado no linux.
Para algumas teclas do controle é simulado o uso de teclas de multimedia (volume, play, stop por exemplo), barra de rolagem do mouse, ou é executado algum comando específico, como desligar o sistema.

Ajuste do navegador

Foi encontrado um problema inesperado durante esse projeto: os navegadores de internet de forma geral não aceitam as teclas de acesso rápido multimidia (play, pause, stop...). Para fazer isso funcionar é necessário instalar um plugin no navegador. Não tive sucesso ao utilizar isso no firefox - o plugin não funcionava. No chrome o plugin funcionou corretamente e agora consigo controlar sites de musica, youtube e netflix com o controle remoto.

Falta deixar claro que estamos simulando tecla de atalho multimidia, que é possivel encontra em alguns teclado reais. Existe o padrão XF86 que são as telcas multimidia. Existe diferentes funções que podem ser acessadas com essas teclas.

Recepção Arduino

A comunicação com o Arduino é feita pela USB. Se o sistema não estiver encontrado o arduino verifique o nome da porta que o arduino esta instalado e corrija no programa de recepção em python. Também verifique se o acesso a USB esta liberado. Falta de acesso é um problema comum com o Arduino, existe bastane informação sobre isso na internet.


Como compilar SWAT 2018 rev670 no Gfortran Linux

Instalação do GFortran

Para instalar o GFortran no Ubuntu utilize os comandos:

sudo apt update
sudo apt install gfortran

Modificações do código original

Pode ser necessário alterar os arquivos de código fonte para atendenrem o padrão do fortran. O compilador da intel é mais premissivo quanto ao padrão do arrquivo, enquanto o gfortran é mais chato, requer o código no padrão fixed ou free from, e não lida bem com a mistura dos dois dentro do mesmo arquivo. Os códigos mais recentes do SWAT já tem corrigido essa padronização, mas os antigos podem precisar de bastante modificação.
O SWAT é compilado originalmente com ifortran (intel), e o compilador da intel é mais permissivo que o compilador GFortran para questões de compatibilidade de formato de código antigo (.f) e novo (.f90) . O fortran passou por várias revisões com o tempo, e o código de swat tem arquivos com padrões antigos e novos, as vezes misturados dentro de um mesmo arquivo. O codigo original do SWAT não compila com GFortran, pois ele é mais chato com relação a formatação dos arquivos. Além disso, no SWAT também são utilizadas estruturas que são diferentes das recomendadas pelo padrão fortran, mas que o compilador da intel aceita, pois facilitam o uso da linguangem.
Modificações necessárias para compilar:
  1. Comentar a linha !! include 'modparm.f' no main.f
  2. É necessário alterar o comando "use" em alguns arquivos, para "use parm, except_this_one => tair", onde tair deve ser substituido pelo nome da função do arquivo com erro.
O erro ao compilar caso o comando "use" não seja corrigido é este:
       use parm
         1
Error: ‘regres’ of module ‘parm’, imported at (1), is also the name of the current program unit 
 Os arquivos que precisam ser corrigidos são:

  1. tair.f
  2. layersplit.f
  3. vbl.f
  4. ndenit.f
  5. atri.f
  6. rsedaa.f
  7. regres.h
  8. HQDAV.f90
Para corrigir altere a linha com “use parm” para “use parm, except_this_one => tair”. O nome na exceção deve ser ser o nome da função atual.
Essa modificações devem tornar o código compativel com o GFortran, sem atrapalhar o IFortran. Os os compiladores devem funcionar corretamente.


Arquivo makefile

Foi criado um makefile para facilitar a compilação do sistema. O makefile verifica se o módulo esta disponível e compila, e depois constroi o programa. A versão release e debug estão em diretórios separados. Para compilar executar: make all, make release ou make debug. Make clean limpa os builds antigos e make prep cria os diretórios.
Baixe o arquivo do link disponível no final do post e copie no mesmo diretório do código fonte.


Compilando

Para compilar execute o comando "make all" no diretório do código fonte. Isso vai criar as pastas dos executáveis. O binario está é salvo na pasta /release com o nome swat


Flags do compilador

Aqui é apresentado uma pequena descrição das flags utilizadas no compilador. Voce não precisa entender oque acontece aqui. Elas são apresentadas somente como curiosidade e para ajudar e resolver algum tipo de problema.

Para compilador com sucesso é necessário utilizar algumas flags do compilador. Elas são:
  1. release: -c -O3 -static -ffixed-line-length-none -ffree-line-length-none -std=gnu -ffpe-trap=invalid,zero,overflow -fno-automatic
  2. debug: -c -O0 -static -ffixed-line-length-none -ffree-line-length-none -std=gnu -ffpe-trap=invalid,zero,overflow -fcheck=all -fbacktrace -fno-automatic
Uma breve descrição das flags são:
  1. -O0 ou -O3: nível de otimização do código.
  2. -static: compila bibliotecas estaticamente no código.
  3. -ffixed-line-length-none: informa ao compilador para ler a linha inteira dos arquivos de código que estão no formato fixo. Pode ser necessário retirar essa flag caso o compilador apresente erro ao ler os arquivos.
  4. -ffree-line-length-none: informa ao compilador para ler a linha inteira dos arquivos de código que estão no formato livre. Pode ser necessário retirar essa flag caso o compilador apresente erro ao ler os arquivos.
  5. std=gnu: padrão do fortran utilizado.
  6. -ffpe-trap=invalid,zero,overflow: ativa exceções para capturar erro de overflow, número inválido e divisão por zero. O erro de underflow não é capturado, o número é aproximado para zero.
  7. -fno-automatic: trata variáveis locais como estáticas, ou seja, elas são salvas e mantém o mesmo valor entre as chamadas da função. O fortran inicialmente tratava as variáveis locais como estáticas, mas nas versões mais novas elas não mantém mais o valor entre chamadas. O código swat assume que as variáveis mantém o valor entre as chamadas, por iso precisa dessa flag.
  8. -fcheck=all: verifica por todos erros possíveis durante execução. Pode deixar o programa mais lento. Utilizado somente no debug.
  9. -fbacktrace: faz um rastreamento para a função que gera erro. Utilizado somente no debug.


Sobre os formatos dos arquivos fortran

Os código fontes do fortran seguiam o padrão fixed form (.f), e os mais atuais seguem o free form (.f90). O código do SWAT parece misturar os dois formatos, oque pode gerar erros na compilação com o gfortran.
Os arquivos do SWAT parecem ser todos escritos em fixed form, mas alguns arquivos utilizam a quebra de linha do formato free form. O compilador informa um erro quando isso acontece.
O erro mais comum nos códigos do SWAT é utilizar a extensão .f, e utilizar para quebra de linha o caracter & (que é do padrão .f90). Isso gera um erro. A solução é alterar a extensão do arquivo para .f90, ou corrigir a quebra de linha.
Como regra geral: se o fim da linha tiver um &, a extensão do arquivo deve ser .f90. Se a linha de baixo tiver o & ou outro caracter na coluna 6 então deve ser .f.
Extensão .f → fixed form: primeira cinco colunas em branco. A continuação de linha é incluir algum caracter na coluna 6 da próxima linha. Esse é o primeiro padrão do fortran – F77. F77 le somente até coluna 72 por padrão.
Extensão .f90 → free form: é a versão mais moderna. A continuação de linha é com & no fim a linha atual e no inicio da segunda linha.
É recomendável utilizar .f90.
Alguns arquivos de algumas versões do SWAT tem as duas formas de quebra de linha no mesmo arquivo, oque torna impossível compilar sem corrigir o código para um dos dois padrões definidos.


Link para arquivos

Os arquivos originais do SWAT podem ser obtidos nesse link: https://swat.tamu.edu/software/swat-executables/

Os arquivos já modificados para GFortran e com o arquivo makefile podem ser obtidos no github: https://github.com/JairoRotava/SWAT-2018-GFortran

Vale a pena verificar se os resultados gerados com o binário compilado pelo GFortran é o mesmo que o gerado pelo binário gerado pelo fornecido no site.






quarta-feira, 26 de setembro de 2018

Avaliação e reparo de Fone de ouvido Bose QC25 - Lado esquerdo não funciona!

Eu viajo de avião quase toda semana para trabalho. Avião na minha opinião é a perfeita máquina de tortura: apertado, poltrona ruim e barulhento, seja por causa dos motores ou das pessoas e crianças que ficam gritando (eu sei que isso soa rabugento!). O fone de ouvido que eles dão no avião é horrivel: vc precisa colocar lá no alto para escutar alguma coisa no meio da barulheira, o som é sofrido...me deixa maluco.

Eu já havia utilizado diversos modelos de fone de ouvido, alguns que prometiam até reduzir ruídos, mas nada era legal. Até que encontrei o Bose QC25. Caro pra caralho, mas a redução do ruído era algo mágico, muito melhor que qualquer coisa que eu conhecia na época, e o som infinitamente melhor que qualquer outra coisa que eu já havia utilizado! Isso era em 2015.

Agora, meio de 2018, o lado esquerdo do fone parou de funcionar! Achei na internet um método de colocar um papel no falante para fazer ele funcionar....funciona...mas só por algum tempo. O problema é o falante mesmo que quebra o fio da bobina e ele deixa de funcionar. Para um fone de US$300 eu acho que durou pouco.

É impossivel encontrar os falantes originais na internet aqui no Brazil, tem um monte de gente vendendo coisas parecidas.

Fotos do falante original bose 

Fotos do falante original bose
Achei no mercado livre um cara vendendo falantes de reposição para Bose: ele cobrava quase R$60 cada falante. Encontrei o mesmo falante sendo vendido por outra pessoa por R$30 o par. O modelo que utilizei foi esse aqui: TONLEN P1695. O mesmo modelo que o cara do R$60 reais dizia vender.

Resultado de imagem para tonlen P1695
Imagem do falante TONLEN P1695
Resultado de imagem para tonlen P1695
Imagem do falante TONLEN P1695
Existem vários vídeo no youtube de como fazer esse reparo:



Troquei só o lado esquerdo, mas ficou esquisito: a sensibilidade dos falantes era diferente - o original era mais alto e tinha outra equalização. Parecia que um ouvido ficava tampado e estava dando dor de cabeça. Depois que troquei os dois falantes o desconforto sumiu.

Eu percebí que a equalização esta diferente com os novos falantes. Não é a mesma coisa que o original, a qualidade do som um pouco pior, mas mesmo assim é melhor que turbina de avião e crianças gritando.

Algumas coisas importantes que percebi nessa troca e valem como dica para quem for tentar reparar seu fone de ouvído:

1 - Precisa trocar os dois falantes: se forem diferentes o volume e equalização diferentes vão te deixar maluco se voce tiver uma mínima sensibilidade auditiva. Se vc for um ogro surdo tanto faz.
2 - A polaridade dos falantes é muito importante para o sistema de redução de ruído funcionar. Certifique de soldar o fio positivo no positivo do falante. O fio positivo é vermelho, e está marcado na placa eletrônica com um sinal de +. No falante geralmente tem uma marca vermelha.
3 - Vc vai precisar colar os novos falantes para o som ficar melhor. Eu usei cola quente.
4 - Não vai ficar a mesma coisa. No meu caso a equalização com os novos falantes é melhor com o sistema anti ruído e equalizador desligado.

O fone Bose QC25 é muito bom: confortável, sistema de cancelamento de ruído muito bom e boa qualidade de som. Entretanto durou pouco. Por isso resolvi não dar meu dinheiro para Bose e mandar para um concorrente: comprei, um Sony WH1000XM2. Apesar desse nome que parece numeração de chassi de carro espero que ele seja tão bom quanto o Bose e dure um pouco mais. Vou arriscar.

quinta-feira, 6 de setembro de 2018

Engenharia reversa ECU Bosch 7.5.30 - Parte 1 de várias

Um dia desses resolvi investigar uma ECU, unidade de controle de motor. Os motivos para isso são:

  1. Como é fabricado o hardware para ser robusto e aguentar a pancada em um carro e um monte de mecânico nó cego? Esse módulos são super robustos, e aguentam muito abuso. É difícil projetar e fabricar algo equivalente sem muito teste e dinheiro.
  2. Como é feito o programa desse módulo? O programa deve ser algum muito bem feito, pois precisa lidar com diversos fatores e condições de falhas e garantir que o motor funcione nas condições mais extremas.
  3. Será possível reprogramar esse módulo com um programa feito por mim? Existem algumas ECU open source - por exemplo: speeduino, megasquirt e rusefi - mas o hardware delas não é lá grande coisa. Utilizar um módulo antigo com um código open source é interessante pois junta um hardware muito bom, testado e barato com um software que qualquer um pode alterar e ajustar. Isso permite utilizar esse módulos super robustos para diferentes aplicações.

Pesquisei na internet um módulo que tinha um preço bom e que permitia ser reprogramado, e acabei escolhendo o modelo ME7.5.30 da Bosch, utilizada em carros da volks, como o gol G5.Paguei algo como R$250 num ferro velho.

Módulo Bosch ME7.5.30. A parte HW: H03 deve ser variação de hardware.
Primeiro comecei pelos componentes eletrônicos. Encontrei o datasheet do processador e alguns componentes periféricos como transistores, eeprom e controlador de borboleta. Mas existem vários chips proprietários da Bosch, e não consegui encontrar nenhuma informação sobre eles na internet. Isso dificulta bastante o processo de engenharia reversa.

Com muita paciência puxei o esquema elétrico parcial dessa placa. Como isso foi possivel entender a função da maioria dos componentes. As principais funções estão na figura abaixo.

Placa do módulo. Aqui o conector já foi removido para facilitar o equema elétrico. A figura mostra os princípais blocos funcionais no circuito.
O principais blocos são:

  1. Chave de entrada com proteção de polaridade e proteção contra load dump: isso é feito com dois transistores N-MOSFET  FDD5810 em série. Eles protegem contra um eventual inversão na polaridade de alimenteção e também contra picos de tensão que podem ocorrer no sistema elétrico do veículo em algumas condições. Estes transistores também são utilizados para ligar/desligar a alimentação de parte do circuito.
  2. Circuito de fonte, k-line, rpm (BOSCH 30639): esse circuito faz um monte de coisa. Ele liga/desliga alimentação de parte da placa, tem uma fonte permanente e outra controlada e 5 V, tem um circuito duplicador de tensão utilizado para controlar os gates dos N-MOSFET FDD5810 da chave de entrada. Além de ser fonte, ele fornece tensão para diferentes sensores (deve ter algum tipo de proteção contra excesso de corrente), tem um drivers conversor de RS232 TTL para K-LINE, e um circuito de tratamento de sinal para o sensor de RPM. 
  3. Aquecedor sonda lambda: existem 2 entradas para aquecimento de sonda lambda. Isso é feito com o componente BUK138-50DL, uma chave em estado sólido com proteção contra sobre corrente e sobre temperatura.
  4. CI BOSCH 3061239 : isso aqui provavelmente é da Bosch também, e parece ser um transceiver de CAN, utilizado para comunicação com o painel.
  5. Processador ST10F275: aqui é feito todo o processamento e comunicação do módulo. É o cérebro do negocio.
  6. Whatchdog: é um circuito de whatchdog externo formado pelo oque parece ser um CI que monitora os niveis de tensões na placa e um microcontrolador que coloca uma inteligência no whatchdog. Essa parte do circuito é a mais obscura e dificil de entender.
  7. Sensor detonação: é um circuito de tratamento de sinal para o sensor de detonação. Tem um amplificador operacional e um circuito maluco. O sinal tratado vai para um AD do processador.
  8. Driver Ignição: Bosch 30490: manda sinais para as bobinas. Esse driver deve mandar pulsos positivos para o controle de bobinas. Não pode ser utilizado com bobinas comuns, somente com aquelas que já tem o driver de corrente embutido (acho).
  9. Injetores e atuadores: Bosch 30621: driver de corrente low side, ou seja, conecta a carga no terra. Utilizado para controle dos injetores e reles de diferentes sistemas do carro.
  10. EEPROM: ST 95040. Memoria EEPROM SPI. Tem o codigo imobilizador do carro e mais alguns parametros. Também deve salvar os log de erro do sistema.
  11. Driver Borboleta: ST 9929. Um driver de corrente para controle da posição da borboleta de admissão.
É interessante notar que quase todos os pinos de entrada desse módulo são filtrados com capacitores para o terra. Somente pinos como do sensor e detonação, e talvez a CAN ou sensor de rotação que não tem capacitores de filtragem.

Outra característica importante é que a comunicação CAN é utilizada com o painel do carro. A linha K-LINE é utilizada para comunicação com o scanner. K-LINE nada mais é que uma RS232 utilizando somente um fio, ou seja, tanto o TX como o RX utilizam o mesmo meio físico. Um circuito simples converte RS232 para K-LINE. 

Num próximo post apresento como pode ser feita a leitura e gravação desse módulo.



terça-feira, 10 de julho de 2018

Keppe Motor - Avaliação Técnica

Algum tempo atrás me perguntaram oque eu achava do Keppe Motor: um novo princípio de motor elétrico que chegava a ser 90% mais econômico que os motores convencionais. A pergunta era para auxiliar na decisão sobre investir ou não na empresa. Na época procurei na internet por mais informações, e tudo oque encontrei era suspeito e não técnico suficiente para explicar porque o motor seria mais eficiência. O site oficial ( http://www.keppemotor.com/institucional/ ) mostrava vários certificados e prêmios de origem duvidosas e o criador da teoria era um psicanalista aparentemente sem experiencia em motores ou qualquer outra matéria técnica. Conclui que as informações não eram confiáveis e que investir nisso era um negócio arriscado.

Por ironia do destino fui perguntado sobre o mesmo assunto um ano depois. Por desencargo pesquisei novamente sobre o assunto, encontrei as mesmas coisas suspeitas, mas um informação nova apareceu: teste do INMETRO para ventiladores de teto. Pensei: "pronto, agora tenho informação confiável para mostrar que o Keppe motor não funciona". Para minha surpresa o consumo medido pelo INMETRO mostrou que os ventiladores com motor Keppe eram os modelos que apresentavam menor consumo elétrico entre todos ventiladores avaliados!! E uma redução da ordem de 50% (ou até mais se comparado com os piores ventiladores). 

Como era possível pessoas que pareciam não ter a menor ideia do que estavam falando, parecendo grandes charlatões, conseguirem fazer um motor com menor consumo que grandes fabricante? Como pode um psicanalista criar uma teoria que engenheiros e físicos não conseguiram? Eu precisava investigar melhor isso.

Encontrei alguns sites com as mesma dúvidas que eu, mas a maioria deles só tratava de descascar os caras baseado nas bobagens que eles falam, física desinvertida ressonante da anti matéria, blá blá, veja melhor aqui: http://www.keppemotor.com/institucional/a-nova-fisica-2/  (observação: a física que eu conheço usa muito mais matemática que palavras). Mas ainda não estava claro como de um monte de bobagem eles fizeram um motor com consumo realmente menor do que o resto disponível no mercado, confirmado pelo INMETRO? Ninguém explicava isso!

As hipóteses levantadas foram:

1 - Hipótese: O INMETRO não sabe oque faz!!
O INMETRO fez a medida errada: a potência medida pelo INMETRO seria a potência aparente -VA - (e não real W). Se o fator de potência do motor convencional for muito baixo, e no Keppe motor for próximo a 1, então explicaria a diferença na medida. Se voce não entendeu nada leia isso: https://pt.wikipedia.org/wiki/Fator_de_pot%C3%AAncia. Se a medida fosse realmente potência  aparente (VA) e não real (W),  seria uma barbeiragem gigantesca do INMETRO, e todos os técnicos alí teriam de ser totalmente incompetentes. Por menor que sejam minhas expectativas com esse tipo de órgão, acreditar nisso era um pouco radical. Encontrei dois vídeos no youtube: https://www.youtube.com/watch?v=HOVD08NK5hUhttps://www.youtube.com/watch?v=nysc0MiwUiE mostrando a medida de potência de um ventilador comum e Keppe motor. O instrumento é um yokogawa wt 110, que mede potência real. É um equipamento bom, dá para confiar nas medidas. Para condições parecidas o motor convencional tinha um consumo de 183W e o Keppe 71W. Calculei o fator de potencia que foram 0,9 para o convencional e 0,62 para o Keppe. Eu esperava o contrário, um fator de potência baixo para o motor convencional e alto para o Keppe. Essa hipótese não é válida. As medidas parecem ser corretas.

2 - Hipótese: os motores tem tecnologias diferentes!!
Aqui vc vai dizer, lógico que são diferentes: é o revolucionário Keppe motor. A hipótese aqui é se o Keppe motor não é um outro tipo de motor conhecido fantasiado como revolução. Numa pesquisa rápida encontrei que a eficiência de motores monofásicos - semelhantes aos utilizados em ventiladores - não é das melhores: 50 a 70% segundo dados da WEG. Enquanto isso motores brushless tem eficiência perto de 96%. Essa hipótese parece promissora!! Na lista do INMETRO - http://www.inmetro.gov.br/consumidor/pbe/ventiladores_de_teto_127v.pdf  haviam outros ventiladores com consumo baixo (não tão baixo quanto o Keppe, mas próximos) e pesquisei por eles. Um deles era um da Arno VX10, e o motor utilizado nesse modelo é..........um brushless. O consumo nesse motor é de 33W, no Keppe era 22 a 28W dependendo do modelo.
Aqui vale uma explicação: os ventiladores mais simples devem ter uma eficiência pior fora da velocidade máxima. Isso deve ao tipo de construção e à redução de custos do produto. Por isso os motores vão ser comparados somente na rotação máxima.

3 - Hipótese: os motores Keppe são um tipo de motor brushless!!
Neste vídeo - https://www.youtube.com/watch?v=wiIT-M7S7Io&list=RDQMaiQMWUSGNaw&start_radio=1 - mostra o princípio de um motor Keppe. Isso é similar um motor brushless. Coloque o imã do lado de fora, chaveie a corrente na bobina com um circuito adequado e você tem um motor brushless como esse: https://www.youtube.com/watch?v=bCEiOnuODac . Altamente eficiente.

Aí vc pergunta: Mas e a luzinha que acende com a energia gerada pelo motor Keppe no primeiro vídeo? Ela é de 60V, e a bateria tem 9V somente!!
Isso é um fenômeno conhecido, e não tem nada a ver com geração e energia ou física desinvertida: essa é a energia armazenada na bobina que quando é chaveada descarrega na lâmpada. O mesmo princípio era utilizado nas bobinas e platinado antigamente no sistema de ignição dos carros: a partir de 12V é criada uma faísca da ordem de vários mil volts para a vela de ignição, veja aqui https://www.youtube.com/watch?v=UEmSFDn8Rlw como funciona. Não existe criação de energia aqui.

E voce pergunta novamente: E a ressonância de sei la oque??
Bem, isso eu não tenho ideia do que se trata. Pode ser pura bobagem, ou eles utilizam algum tipo de ressonância no conversor ou no controle da corrente nas bobinas do motor. Existem algumas topologias de conversores DC e controladores de motor que utilizam ressonância para aumento a eficiência. Mas não é possível concluir muita coisa a partir das informações disponíveis.

Conclusão

1 - Uma teoria feita por um psicanalista brasileiro esta revolucionando os motores elétricos? Provavelmente não. Tudo indica que o Keppe motor seja uma variação de um motor DC brushless.

2 - Keppe motor é uma enganação? 
Tudo indica que a física desinvertida e coisas do gênero não devem ser levados a sério. Entretanto o consumo desse motor é muito mais baixo se comparado a motores monofásicos encontrados na maioria dos ventiladores.

3- Por que somente encontro ventiladores com esse motor? 
Porque é nesse mercado que eles conseguem uma economia de energia. A eficiência de motores monofásicos utilizados em ventiladores é muito baixa, por isso com um motor um pouco melhor é possível ter um diferencial de marketing. Competir com motores maiores, trifásicos ou DC é mais difícil pois a eficiência deles geralmente é melhor. Acho improvável que esse tipo de motor acabe ocupando outro nicho de mercado, como motores industriais.

4 - Mas ele consome menos? 
Sim, segundo o INMETRO e comparado com os demais ventiladores. Isso deve acontecer pois utiliza um motor e uma eletrônica de melhor qualidade, e não devido à física desinvertida ou alguma outra maluquice. O preço desse ventilador também deve ser substancialmente maior que ventiladores convencionais.

Alias, no momento em que escrevo isso, não consigo encontrar nenhuma forma de comprar um desses ventiladores Keppe motor.

Caso voce queira mais informações sobre o Keppe motor, este é o site da empresa.

Um comentário importante é que quem fabrica o Keppe Motor sabe oque oque esta fazendo, e entende da física e engenharia clássica. Não entendo porque eles fazem o desserviço de causar confusão com uma nova física e princípios revolucionários.

Esta avaliação é baseada em conhecimentos da física e engenharia clássica. Na improvável hipótese da nova física vir a ser correta e sobrepor aos conhecimentos clássicos então os comentários feitos aqui podem ser inválidos e não se aplicar ao motor Keppe.