mercoledì 19 marzo 2014

Aggiornamento Alcatel One Touch Fire a Firefox OS 1.2

Visto che oramai Alcatel non ha mostrato l'intenzione di effettuare l'upgrade a Firefox OS 1.2 mi sono deciso a farlo da solo e devo ammettere che e' una procedura di gran lunga piu' semplice rispetto a qualsiasi aggiornamento di firmware per telefoni Android



La procedura e' stata eseguita su Linux perche' non avevo voglia di litigare con i driver di Windows
Le istruzioni sono state riprese da questo sito

Si scarica prima il pacchetto di Firefox OS per Alcatel One Touche Fire da questo sito (nel mio caso  ho preso il pacchetto v1.2-20140127 per avere l'ultima versione stabile

Poi si aggiunge al file /etc/udev/rules.d/99-android.rules la seguente riga


SUBSYSTEM==”usb”, ATTR{idVendor}==”18d1″, ATTR{idProduct}==”d00d”, MODE=”0666″, OWNER=”{luca}”(sostituire luca con il proprio nome utente)

Si modifica le impostazioni del telefono con
Impostazioni -> Info sul Dispositivo -> Altre Informazioni -> Sviluppatore abilita Debug remoto e Abilita console.

A questo punto si riavvia il telefono in boot mode (tasto volume - ed accensione) ed il telefono si arresta sulla schermata bianca con la scritta Alcatel



e si lancia il file ./flash.sh


L'operazione e' estremamente veloce ed indolore. Ed ecco il telefono senza la personalizzazione TIM


(per effettuare uno screenshot pulsate di accensione e tasto Home)


WebGL con ThreeJS


Sempre per un uso didattico, per visualizzare gli assi e i piani di simmetria dei minerali, stavo cercando un sistema semplice ed interattivo. Ero rimasto a VRML ma i tempi sono cambiati e la soluzione piu' semplice e' caduta su WebGL e la libreria ThreeJS


questo link c'e' una fonte inesauriibile di esempi ed idee. Io ho preso e modificato l'esempio HelloWorld per creare un cubo con indicato un asse di rotazione di ordine 4, un asse di rotazione di ordine 3 e 3 piani di simmetria.
Il modello e' navigabile (rotazione, spostamento) con il solo mouse ed e' compatibile sia con Chrome che con Firefox alle versioni piu' recenti

Il progetto completo e' scaricabile da qui

---------------------------------------------------------
<!doctype html>
<html lang="en">
<head>
<title>Solido</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link rel=stylesheet href="css/base.css"/>
</head>
<body>

<script src="js/Three.js"></script>
<script src="js/Detector.js"></script>
<script src="js/Stats.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/THREEx.KeyboardState.js"></script>
<script src="js/THREEx.FullScreen.js"></script>
<script src="js/THREEx.WindowResize.js"></script>


<!-- ------------------------------------------------------------ -->

<div id="ThreeJS" style="z-index: 1; position: absolute; left:0px; top:0px"></div>
<script>

// standard global variables
var container, scene, camera, renderer, controls, stats;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();

var cube;

init();
animate();


function init() 
{
scene = new THREE.Scene();
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0,50,40);
camera.lookAt(scene.position);


if ( Detector.webgl )
renderer = new THREE.WebGLRenderer( {antialias:true} );
else
renderer = new THREE.CanvasRenderer(); 

renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);

// attach div element to variable to contain the renderer
container = document.getElementById( 'ThreeJS' );
// alternatively: to create the div at runtime, use:
//   container = document.createElement( 'div' );
//    document.body.appendChild( container );

// attach renderer to the container div
container.appendChild( renderer.domElement );

////////////
// EVENTS //
////////////

// automatically resize renderer
THREEx.WindowResize(renderer, camera);
THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });

//////////////
// CONTROLS //
//////////////

// move mouse and: left   click to rotate, 
//                 middle click to zoom, 
//                 right  click to pan
controls = new THREE.OrbitControls( camera, renderer.domElement );



//////////////
// GEOMETRY //
//////////////


var cubeMaterialArray = [];
// order to add materials: x+,x-,y+,y-,z+,z-
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xff3333 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xff8800 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xffff33 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x33ff33 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x3333ff } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x8833ff } ) );
var cubeMaterials = new THREE.MeshFaceMaterial( cubeMaterialArray );
// Cube parameters: width (x), height (y), depth (z), 
//        (optional) segments along x, segments along y, segments along z
var cubeGeometry = new THREE.CubeGeometry( 10, 10, 10, 0, 0, 0 );
// using THREE.MeshFaceMaterial() in the constructor below
//   causes the mesh to use the materials stored in the geometry
cube = new THREE.Mesh( cubeGeometry, cubeMaterials );
cube.position.set(0, 0, 0);
scene.add( cube );

material = new THREE.LineBasicMaterial({
        color: 0x0000ff
    });

var geometry = new THREE.Geometry();
    geometry.vertices.push(new THREE.Vector3(0, 0, 10));
    geometry.vertices.push(new THREE.Vector3(0, 0, -10));
var line = new THREE.Line(geometry, material);
scene.add(line);

var plane = new THREE.Mesh(new THREE.PlaneGeometry(30, 30), new THREE.MeshNormalMaterial({ color: 0x888888, transparent: true, opacity: 0.5  }));
plane.material.side = THREE.DoubleSide;
    plane.overdraw = true;
    scene.add(plane);

    
    var plane2 = new THREE.Mesh(new THREE.PlaneGeometry(1,1,5, 5), new THREE.MeshNormalMaterial({ color: 0xff0000, transparent: true, opacity: 0.5  }));
plane2.material.side = THREE.DoubleSide;
    plane2.overdraw = true;
    scene.add(plane2);


}

function animate() 
{
    requestAnimationFrame( animate );
render();
update();
}

function update()
{
// delta = change in time since last call (in seconds)
var delta = clock.getDelta(); 

controls.update();
stats.update();
}

function render() 
{
renderer.render( scene, camera );
}

</script>

</body>
</html>

martedì 18 marzo 2014

Comandare Impress con Raspberry + HC-SR04 + Python

Sulla base del precedente post  mi sono chiesto se era possibile ridurre al minimo la spesa (ed il consumo di corrente). In questa ottica ho provato a montare una Raspberry che si interfaccia direttamente con l'HC-SR04 per fare una presentazione. In questo caso si ha la comodita' di poter far girare la presentazione anche su televisori di generose dimensioni vista l'uscita HDMI (nel test e' stato usato un mini monitor ma solo perche' il televisore di casa era occupato)



Il collegamento tra le porte GPIO e la Raspberry e' il seguente
VCC 5 V
GND
GPIO 17 connesso a Trigger
GPIO 27 connesso a Echo con con una resistenza da 1 KOhm


Dato che la prova e' stata fatta con PiBang e non Raspbian c'e' da montare la libreria Gpio per Python che non e' inclusa di default
Per fare cio'
apt-get install build-essential python-dev python-pip
pip install rpi.gpio

il comando xdotool invece e' gia' compreso in PiBanf
lo script che ho utilizzato deriva da questo sito leggermente modificato
Quando la distanza risulta inferiore a 30 cm viene cambiata la diapositiva 
------------------------------------------------------------

#!/usr/bin/python
import os

contatore = 1

def reading(sensor):
    import time
    import RPi.GPIO as GPIO
    
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    
    if sensor == 0:
        GPIO.setup(17,GPIO.OUT)
        GPIO.setup(27,GPIO.IN)
        GPIO.output(17, GPIO.LOW)
        time.sleep(0.3)

        GPIO.output(17, True)
        time.sleep(0.00001)
        GPIO.output(17, False)

        while GPIO.input(27) == 0:
          signaloff = time.time()

        while GPIO.input(27) == 1:
          signalon = time.time()
        
        timepassed = signalon - signaloff
        distance = timepassed * 17000
        return distance
        
        GPIO.cleanup()

    else:
        print "Incorrect usonic() function varible."

while True:        
if (reading(0) < 30):
contatore = contatore + 1
print contatore
if (contatore >= 4):
contatore = 1
os.system("xdotool key 1")
os.system("xdotool key Return")
else:
os.system("xdotool key Right")
------------------------------------------------------------
Rispetto al precedente script si vede che i comandi di xdotool sono stati modificati. Non ho chiaro il motivo per cui e' stata necessaria la modifica ma penso che sia attribuibile al WM che e' differente tra Ubuntu (Gnome) e PiBang(OpenBox)

Con questa configurazione il costo dell'hardware (monitor o televisore escluso) e' dell'ordine dei 50 euro


lunedì 17 marzo 2014

Could not write bytes: Broken pipe su Ubuntu 12.04

L'errore "Could not write bytes: Broken pipe" e' comparso in modo improvviso e francamente non ho capito il motivo. Fatto e' che in fase di boot e' comparso questo messaggio e non era piu' possibile fare niente

Leggendo un po' sui forum di Ubuntu si dice di reinstallare tutto Xserver-Xorg.

La cosa piu' semplice e' partire in modalita' di recupero e selezione "Enable Network" (se si seleziona root si ha il filesystem montato in sola lettura e nessun supporto di rete)



a questo punto ho lanciato
apt-get install xserver-xorg xserver-xorg-video-all

ma niente da fare. allora da shell ho lanciato startx ed il comando non e' stato riconosciuto
Ho quindi installato anche il pacchetto xinit

apt-get install xinit

ed il sistema e' ripartito in modo corretto

venerdì 14 marzo 2014

Comandare Impress con Arduino + HC-SR04 + Python

Sempre alla ricerca di un sistema semplice e poco costoso per fare una postazione interattiva al Museo di Mineralogia, ho provato la strada Arduino

I difetti dei tentativi precedenti erano che Kinect costa un troppo mentre l'accoppiata Raspberry+Webcam e' troppo soggetta ad errori
In questo caso ho provato ad usare una Arduino accoppiata al sensore di distanza HC-SR04 (il costo finale e' inferiore ai 20 euro)


Nella prova ho usato una Arduino Due (nel caso reale va bene una Arduino Mini) che ho scoperto non avere la compatibilita' con la libreria NewPing. Per questo motivo e' stato usato lo sketch di esempio sul sito Arduino (rimuovendo la sezione relativa ai due led)
le connessioni sono semplici

Vcc
GND
Pin 13 : Echo
Pin 12 : Trigger

lo sketch manda la distanza via seriale ad un script in Python in ascolto. Se la distanza e' inferiore ai 50 cm viene cambiata la diapositiva

Video della prova


Con questa configurazione sono minimizzati i falsi click. In versione definitiva puo' essere utile mettere due sensori ultrasonici per permettere di andare avanti ed indietro nella presentazione

Programma Python
---------------------------------------
import serial,os, time

diapositiva = 1
ser = serial.Serial('/dev/ttyACM0', 9600)
while True:
distanza = int(ser.readline())

if (distanza < 50):
diapositiva = diapositiva + 1
if (diapositiva == 5):
os.system("xdotool key --window $(xdotool search --name 'presentazione.odp - LibreOffice Impress') 1")
os.system("xdotool key --window $(xdotool search --name 'presentazione.odp - LibreOffice Impress') KP_Enter")
diapositiva = 1
else:
os.system("xdotool key --window $(xdotool search --name 'presentazione.odp - LibreOffice Impress') Right")
----------------------------------------

Sketch Arduino
----------------------------------------
/*
 HC-SR04 Ping distance sensor]
 VCC to arduino 5v GND to arduino GND
 Echo to Arduino pin 13 Trig to Arduino pin 12
 Red POS to Arduino pin 11
 Green POS to Arduino pin 10
 560 ohm resistor to both LED NEG and GRD power rail
 More info at: http://goo.gl/kJ8Gl
 Original code improvements to the Ping sketch sourced from Trollmaker.com
 Some code and wiring inspired by http://en.wikiversity.org/wiki/User:Dstaub/robotcar
 */

#define trigPin 13
#define echoPin 12

void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  long duration, distance;
  digitalWrite(trigPin, LOW);  // Added this line
  delayMicroseconds(2); // Added this line
  digitalWrite(trigPin, HIGH);
//  delayMicroseconds(1000); - Removed this line
  delayMicroseconds(10); // Added this line
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;
  if (distance < 4) {  // This is where the LED On/Off happens
}
  else {
  }
  if (distance >= 200 || distance <= 0){
    Serial.println(200);
  }
  else {
    Serial.println(distance);
  }
  delay(500);
}


giovedì 13 marzo 2014

Kinect su Ubuntu

Dopo il tentativo non perfettamente andato a buon fine descritto in questo post, sono tornato indietro sui mie passi per installare Kinect su un Ubuntu 12.04 32 Bit ed usando una versione piu' vecchiotta di Processing

I passi sono stati ripresi quasi totalmente da questo link

Si deve scaricare il pacchetto di OpenNi da questo link, si decomprime il pacchetto zip e poi, entrando in ognuna delle sottodirectory si lancia il file ./install.sh (ripeto per ogni sottodirectory)

A questo punto si installa Processing (attenzione versione 1.5) e si scarica la libreria SimpleOpenNi. Questa libreria deve essere decompressa ed inserita nella sottodirectory libraries di Processing (se non e' presente la sottodirectory si deve creare a mano)

Per terminare ho dovuto digitare i seguenti comandi
wget https://simple-openni.googlecode.com/svn/trunk/SimpleOpenNI-2.0/platform/linux/installLinuxRules.sh
wget https://simple-openni.googlecode.com/svn/trunk/SimpleOpenNI-2.0/platform/linux/primesense-usb.rules
sudo ./installLinuxRules.sh

Ovviamente se ci sono problemi di dipendenze delle librerie, questi devono essere risolti via via

A questo punto si puo' procedere lanciando gli esempi contenuti tra gli sketch di Processing

Hands3D Demo

Hands Demo


User3D Demo


User Demo

TorrentBox con Raspberry

A seguito del precedente post, nell'utilizzo sono emersi un po' di problemi che hanno fatto ripensare all'utilizzo di Raspberry come Torrent Box




Il problema principale e' rappresentato dalle dimensioni del disco su cui salvare i dati. La soluzione piu' idonea e' quella di tenere i dati scaricati su una chiave (od un disco esterno) Usb mentre sulla SD Card rimane caricato il solo sistema operativo
L'altro problema e' come al solito l'utente (od utonto). L'amico per cui avevo preparato la Raspberry non vuole complicazione e vuole vedere i file dal suo portatile Windows (non si parla nemmeno di SFtp o simili) per cui e' necessario implementare un server Samba

Per il passo 1 si deve fare in modo che la chiave si monti sempre allo stesso modo.
Per fare cio' prima si trova l'UID della chiavetta con

ls -l /dev/disk/by-uuid/
e ci si segna il codice. Poi si crea la directory di mount

sudo mkdir /media/usb
sudo chmod 775 /media/usb

al termine si modifica il file /etc/fstab aggiungendo la riga (mettendo il giusto UID prima salvato)
UUID=1111-2222 /media/usb vfat rw,defaults 0 0
per permettere al demone di scrivere sulla chiave Usb (che e' formattata Fat e quindi con una gestione un po' casinosa dei permessi) la via piu' semplice e' modificare il file /etc/init.d/transmission-daemon cambiando

USER=root(altrimenti si genera un errore Error: Permission denied (/media/ dopo un po' che si e' avviato il torrent)

a questo punto si modifica il file /etc/transmission-daemon/settings.json e si modificano le due voci per puntare alla posizione della chiave Usb

"download-dir": "/media/usb/complete",
"incomplete-dir": "/media/usb/incomplete",


Per il passo 2 l'installazione del server Samba e' semplice
sudo apt-get install samba samba-common-bin
a questo punto c'e' da configurare il file /etc/samba/smb.conf

si cambia quindi
security=share

per semplicita' il disco Usb verra' visto con un accesso Guest su directory pubblica aggiungendo al termine del file
[Guest] 
 comment = Guest access 
  share path = /path/to/dir/to/share 
  browseable = yes 
  read only = yes 
  guest ok = yes
il fatto che i file siano a sola lettura da Windows non e' un problema perche' eventuali cancellazioni di torrent si effetturano direttamente dall'interfaccia di daemon-transmission

Al termine e' sufficiente collegarsi via browser all'indirizzo della Raspberry sulla porta 9091 per poter iniziare il download. Da Windows la condivisione sara' all'indirizzo //raspberry/Guest



Opencv camera calibration in cpp

Oltre che con uno script Python come visto qui la calibrazione della camera si puo' fare anche con il programma in CPP Questo il proce...