My first steps into Ruby and OpenCV(on OSX)

I was writing some robotic code that will run on a mac mini, so I tryied on my macbook for the first time, ruby binding to opencv. It was a weird experience lol.

First, to install OpenCV, brew do the job:

$ brew tap homebrew/science
$ brew install opencv

after a while we see that instalation goes flawlessly:
/usr/local/Cellar/opencv/2.4.13.2: 278 files, 35.6MB
and we have current version: 2.4.13.2. That said, now install ruby gem:

$ gem install ruby-opencv -- --with-opencv-lib=/usr/local/Cellar/opencv/2.4.13.2/lib \
                             --with-opencv-include=/usr/local/Cellar/opencv/2.4.13.2/include/opencv \
                             --with-opencv-include=/usr/local/Cellar/opencv/2.4.13.2/include/opencv2

Fetching: ruby-opencv-0.0.18.gem (100%)
Building native extensions with: '--with-opencv-lib=/usr/local/Cellar/opencv/2.4.13.2/lib --with-opencv-include=/usr/local/Cellar/opencv/2.4.13.2/include/opencv --with-opencv-include=/usr/local/Cellar/opencv/2.4.13.2/include/opencv2'
This could take a while...
Successfully installed ruby-opencv-0.0.18
Parsing documentation for ruby-opencv-0.0.18
Installing ri documentation for ruby-opencv-0.0.18
Done installing documentation for ruby-opencv after 7 seconds
1 gem installed

after that, time to code.

My first try, obviously, is to use HAAR cascade classifier to look for faces.

require "rubygems"
require "opencv"
include OpenCV

window = GUI::Window.new("grab da face!")
camera = CvCapture.open
detector = CvHaarClassifierCascade::load('./haarcascade_frontalface_alt.xml')
loop {
  image = camera.query
  detector.detect_objects(image).each { |rect|
    image.rectangle! rect.top_left, rect.bottom_right, :color => CvColor::Blue
  }
  window.show image
  break if GUI::wait_key(100)
}

It didn’t worked as ruby-opencv currently supports only older type format of trained data xml. To solve that, I grabed older version of haarcascade_frontalface_alt.xml from https://raw.githubusercontent.com/Itseez/opencv/2.4.10.4/data/haarcascades/haarcascade_frontalface_alt.xml and it worked as expected.
Sometimes, OSX Facetime camera stop working, but is easy to fix, just run

sudo killall VDCAssistant

wait a little and voilá.

In the end, was a different experience, it worked but was way too slow. I’ll try to tweak a little but python version are way faster and I believe I’ll keep using it.

Accessing Go compiled applications through FFI

I finally started to create some useful Go code and, just like some previous posts(in pt-BR, ) where I integrated python, lua and C, I would love to use them with old python code instead of C/C++. For that, I had to generate a shared library. The process is easy as expected, requiring only the import of library “C” and a comment before function definition, exporting the function name, as following examples.

package main

import "C"

//export ModXY
func ModXY(x int) int {
        return x * 2
}

func main() {}

Now, let’s compile it to generate a shared lib:

$ go build -o libmod.so -buildmode=c-shared

This results on two files, libmod.so and libmod.h where the first one is a shared library itself and the second one is the headers to include Go types into a C application. More on this soon. First let’s check libmod.so

$ file libmod.so
libmod.so: Mach-O 64-bit dynamically linked shared library x86_64

Nice, as expected on OSX. Now let’s try to import it with python ctypes!

Python 2.7.12 (default, Sep 28 2016, 18:41:32)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> lib = ctypes.CDLL('libmod.so')
>>> lib.ModXY(13,2)
1

It worked like a charm! It is, actually, pretty easy to deal with. Now let’s find out the raison d’etre of this .h file. If, for some crazy reason, you need to embbed Go code inside a C file, simply include the .h and use the functions normally, as the following example:

#include <stdio.h>
#include "libmod.h"

int main(void){
  printf("the rest of division of 13 per 2 is %d", (int)ModXY(13,2));
  return 0;
}

then, compile it with:

$ gcc -o purexecutable testlib.c libmod.so 

and

$ file purexecutable
purexecutable: Mach-O 64-bit executable x86_64
$ ./purexecutable
the rest of division of 13 per 2 is 1

Yey! Again, simple and efficient. The design documentation of this feature may be found here( http://golang.org/s/execmodes ). That’s all

Let it go? Let it go!

Lately, I added Go as one of my favourite programming languages and I’ve tried to rewrite e create new projects in Go. Basically, the reasons Go became one of my favourite languages is that, although the language/compiler/tools is opensource, different from a majority of opensource projects (JS mainly), it is backed up by a huge corporation (Google) and is easy to avoid major mess (hello JS, my old friend). Also, Go is fast (really, really fast), simple (like C, not like python), concurrent and cross-platform by design, what makes Go a great general pourpose language. If all these previous reasons don’t catch your heart, Go is designed by Rob Pike and Ken Thompson, the same guys who designed UNIX and C, so there is no way this would be bad (fanboy attack?). Another very specific issue I had with c++ and libboost: take 3-8 hours compiling libraries whose Go version took 5 seconds, made me embrace Go as a friend.

I saw Go, from very begining, as a “pythonic C” and, for a python guy’s perspective, I loved it. And, being able to handle binary data just like C but structured data just like python, made me fall in love.

In the end, I started to use Go as a main language, I hope to gain more wisdom on it and become a better Gopher.

Python + SSL para aplicações simples

Precisei relembrar uma forma de gerar uma conexão SSL(não apenas a camada de aplicação) para um projeto. O python faz isso de forma muito fluida e simples. Não requer prática, tampouco habilidade haha.

Para gerar o certificado, primeiro geramos uma chave com o openssl. Depois a usamos para gerar um certificado. Uma forma direta e automatica(e insegura, ja que não ha dados no certificado gerado) de fazer isso é:

openssl genrsa -out key.pem
yes '' | openssl req -new -x509 -key key.pem -out crt.pem -days 36500 || exit 1
cat key.pem crt.pem > cert.pem
rm key.pem crt.pem

Lembrando que estou ignorando as entradas para gerar o cert. Este tipo de coisa é mais usado para automatizar e gerar um cert novo a cada sessão. Depois disto é necessario pegar o fingerprint da chave, assim:

openssl x509 -in cert.pem -md5 -fingerprint -noout | sed 's/^[^=]\+=//;s/://g' | tr 'A-Z' 'a-z'

Agora o servidor, extremamente simples, para apenas uma conexão e printar o dado enviado:

import socket, ssl
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', 8081))
sock.listen(1)
newsock, fromaddr = sock.accept()
conn = ssl.wrap_socket(newsock, server_side=True, certfile='cert.pem', keyfile='cert.pem')
conn.setblocking(0)
while True:
    try:
        buf = conn.read(512)
        if buf == '':
            break
        else:
            print buf
    except:
        pass

O cliente é tão simples quanto o servidor. Só lembrar de pegar o fingerprint gerado e usar no client. Ele verifica e só loga no servidor se bater o fingerprint.

import socket, ssl, hashlib, time
CERT="fingerprint que voce pegou"
sock = socket.socket()
sock.settimeout(2)
sock.connect(('localhost', 8081))
conn = ssl.wrap_socket(sock)
if hashlib.md5(conn.getpeercert(True)).hexdigest() != CERT:
    conn.close()
    print 'CERT diferente do esperado, tentando me hackearrrrrrr'
else:
    print '200 OK'
    time.sleep(2)
    conn.write('CHUPA ESSA MANGA, WIRESHARK!1!!')
    print 'enviado'
    conn.close()

E é só isso, bem simples. É uma forma de encriptação e autenticação bem razoavel e resolve para a maioria das aplicações práticas contemporaneas.

link dos sources em : https://github.com/paoloo/simple-ssl

Bottle.py – a solução de um problema que nao deveria existir

Bottle( http://bottlepy.org/docs/dev/index.html ) é um micro web framwork em python leve e muito simples. O mais louco é que ele é distribuido em apenas um arquivo e não tem nenhuma dependencia, alem do interpretador python, o que facilita absurdamente o deploy em qualquer ambiente!!!
Ok, e dai?
Bem, vi muita gente fazendo deploy no raspberryPi de aplicações com front end web, usando apache, php, mysql, postgres, redis, ou até mesmo obscenidades como o tomcat. Por enquanto, isto não é punido com a morte, mas deve ser evitado a todo custo e se buscar leveza e simplicidade. Quando conheci o bottle, tive a certeza que isto que procurava!

Com suporte a templates, roteamento simplificado, gerenciamento de dados e um servidor built-in, não fica faltando nada para sua aplicação subir.

para instalar (deixar o .py no diretorio ou instalar via pip, com # pip install bottle) e ter várias ideias de uso, é muito bom perder um tempinho na página oficial, mas uma aplicação que me deixou emocionado foi fazer uma pseudo-API do GPIO para web, simples assim:

cat > webgpio.py << _EOF_
from bottle import route
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)

@route('/le/<pino:int>')
def readgpio(pino):
    GPIO.setup(pino, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
    saida = GPIO.input(pino)
    return '<pinos><%d>%s</%d></pinos>' % (pino,str(saida),pino)

@route('/escreve/<pino:int>/<val:int>')
def writegpio(pino,val):
    GPIO.setup(pino, GPIO.OUT)
    if val==0 or val ==1:
        GPIO.output(pino, (GPIO.LOW , GPIO.HIGH)[val])
        return 'escrito %d no pino %d' % (val, pino)
    else:
        return 'valores validos para escrita: 0 e 1'
_EOF_

Rodando…

$ python webgpio.py 
Bottle v0.13-dev server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

127.0.0.1 - - [19/Nov/2015 02:20:48] "GET /le/13 HTTP/1.1" 200 26
127.0.0.1 - - [19/Nov/2015 02:21:04] "GET /escreve/15/0 HTTP/1.1" 200 20
127.0.0.1 - - [19/Nov/2015 02:21:14] "GET /escreve/15/1 HTTP/1.1" 200 20

E fazendo os requests…

$ curl http://localhost:8080/le/13
<pinos><13>12.5</13></pinos>
$ curl http://localhost:8080/escreve/15/1
escrito 1 no pino 15
$ curl http://localhost:8080/escreve/15/2
valores validos para escrita: 0 e 1

Obviamente este código não é seguro nem otimizado, é apena um PoC. Mas ainda assim, este treco é lindo, leve e tem suporte a muita coisa. Se a interface de template dele não agradar, ele é facilmente integravel com o jinja2( http://jinja.pocoo.org/docs/dev/ ) e, principalmente para linux embarcado é o framework web definitivo(ok, isso é minha opinião pessoal, mas é o que realmente parece haha).

Lua + C + Python – Mais que uma combinação macabra, uma gambiarra sinistra

Antes de mais nada: Por que?
Eu precisava fazer deploy de uma shared library em um ARM com linux(um raspberry Pi) extremamente capado, e não podia instalar todas as tools de dev, pois estava no limite de espaço do cartão, devido a aplicação dele. Mas precisava desta shared lib para carregar no python, via ctypes, pois o mesmo usaria as informações extraidas do hardware pelo .c, interpretaria e daria ordens ao resto da eletrônica. Acontece que os parametros do C variavam muito, precisavam ser tunados constantemente. Foi daí que rolou a ideia do LUA.
A ideia foi boa? Bom, funcionou. E até que faz um pouco de sentido, de alguma forma haha

vamos la, o loader, em python, é simplezão:

$ cat > loader.py << _EOF_
import ctypes
biblioteca=ctypes.CDLL('./zoalib.so')
biblioteca.zoeira.restype = ctypes.c_int
biblioteca.zoeira.argtypes = [ctypes.c_int]
biblioteca.zoeira(5)
_EOF_

O loader em C:

$ cat >zoalib.c << _EOF_
#include "lua.h"
#include "lauxlib.h"

int zoeira(int a)
{
    double z;
    lua_State *L = lua_open();
    luaL_openlibs(L);
    luaL_loadfile(L, "zoeira.lua");	/* arquivo lua */
    lua_pcall(L, 0, 0, 0);		/* limpa a pilha */
    lua_getglobal(L, "modelamotor");	/* nome da função do lua */
    lua_pushnumber(L, 3);		/* envia primeiro argumento */
    lua_pushnumber(L, 4);		/* envia segundo argumento */
    lua_pcall(L, 2, 1, 0);
    z = lua_tonumber(L, -1);		/* pega resultados */
    printf("Resultado: %f\n",z);
    lua_pop(L, 1);
    lua_close(L);
    return (a+1);
}
_EOF_

E o script em lua:

$ cat > zoeira.lua << _EOF_
function modelamotor (param1, param2)
    return math.sqrt(param1^2 + param^2)
end
_EOF_

Agora, vamos compilar com estes poucos parametros e rodar haha:

$ gcc -I/usr/include/lua5.1 zoalib.c -llua5.1 -lm -fPIC -shared -Wl,-soname,zoalib -o zoalib.so
$ python l.py
Resultado: 5.000000
6

Hell yeah!
Embora isso seja absurdamente mais util nos raspberryPi/beaglebone, talvez haja algum uso no desktop, vai saber haha.

nodeMCU: Mais que uma dev Board, um vício

NodeMCU( http://nodemcu.com/index_en.html ) é uma plataforma de desenvolvimento baseada no SoC ESP8266, com stack TCP/IP, eLua e vários extensões do lua embarcadas, voltadas especialmente para aplicações de IoT.
O SoC ESP8266 usa uma CPU RISC de 32bits Tensilica Xtensa LX106, rodando a 80MH. Tem uma RAM de instruções de 64 Kb, uma RAM de dados de 96Kb e uma flash interna de 4 fucking MBs! A estrela do bolo é o IEEE 802.11 b/g/n com suporte a WEP,WPA/WPA2 disponível, além dos 16 pinos de GPIO, SPI, I2C, UART e ADC de até 10bits.

nodeMCU

No xubuntu, eu tive problemas de conectar nela com o minicom. Mas estou usando lindamento o screen:

$ screen /dev/ttyUSB0 9600

Lua/eLua é linda. coisas extremamente complexas são executadas com uma simplicidade absurda, como listar as redes 802.11 disponiveis:

> function lswifi()
>>  function listap(t)
>>    for k,v in pairs(t) do
>>      print(k.." : "..v)
>>    end
>>  end
>>  wifi.sta.getap(listap)
>>end
>lswifi()

listar os arquivos, o conhecido ‘ls’, é simples:

> for k,v in pairs(file.list()) do print(k,v) end

logar na rede wifi, então, piece of cake:

> wifi.setmode(wifi.STATION);
> wifi.sta.config("SSID","senha")

e pronto! so checar seu ip com:

print(wifi.sta.getip())

Aproveitei e fiz um wget rudimentar hahaha

conn=net.createConnection(net.TCP, false) 
conn:on("receive", function(conn, pl) file.open("oi.lua","a"); file.write(pl); file.close() end)
conn:connect(80,"121.41.33.127")
conn:send("GET / HTTP/1.1\r\nHost: www.nodemcu.com\r\n"
    .."Connection: keep-alive\r\nAccept: */*\r\n\r\n")

Escrevi alguns métodos do GNU coreutils, como ls, cp, mv, df… para facilitar a vida. Em breve posto no github e ponho o link aqui.

O legal é que existem uma infinidade de exemplos e aplicações para esta plaquinha. E ela ganhou um fã haha.

Enjoy!