giovedì 20 maggio 2010

Aspire One, Linux Linpus lite: abilitare il tasto destro

L'interfaccia grafica che Linux Linpus lite presentata all'utente è fortemente personalizzata. Quattro quadranti colorati dividono lo schermo, in ognuno di questi vengono raggruppate le applicazioni. Un click con il tasto sinistro sull'icona dell'applicazione da avviare ed in pochi secondi si può iniziare a lavorare. E il tasto destro del mouse?
Xfce è il desktop manager usato da Linux Linpus lite, un ambiente grafico leggero e veloce che si addice proprio alle caratteristiche dell'Aspire One. Solitamente con Xfce (ma anche con altri desktop manager come ad esempio Fluxbox) il click con il tasto destro richiama il menu per avviare i programmi. Tale funzionalità è stata tuttavia disabilitata dagli esperti di Linpus ma può essere tranquillamente ripristinato in pochi passaggi. Per fare questo occorre per prima cosa avviare una sessione di terminal, la shell di Linux. Premendo i tasti "ALT" + "F2" dovrebbe comparire una finestra che permette di eseguire programmi Linux. Nell'area di testo disponibile digitiamo il comando "terminal" e clicchiamo, quindi, sul bottone "Run" (è anche possibile premere il tasto "INVIO"):


Abbiamo appena avviato una sessione di terminal! Digitiamo ora il seguente comando:

[user@localhost ~]$ xfce-setting-show


Non appena diamo "Invio" si presenterà a noi una nuova finestra con nome "Xfce Setting Manager". Attraverso questa finestra è possibile accedere a numerose impostazioni per personalizzare il desktop di Xfce, vi consiglio di esplorare i tanti menu ma attenti a non fare danni! Per abilitare il tasto destro del mouse occorre cliccare sull'icona "Desktop", quella cioè mostrata in questa figura:


Verrà caricata una nuova finestra con nome "Desktop Preferences" e con due schede: "Appareance" e "Behavior". Attraverso la prima scheda della finestra, la scheda "Appareance", è possibile impostare un colore come sfondo oppure un'immagine e regolarne i toni di luce. Clicchiamo ora sulla scheda "Behavior":


Ci siamo, per abilitare il tasto destro del mouse occorre spuntare la voce "Show desktop menu on right click". E' più semplice farlo che spiegarlo! In questa stessa finestra è possibile regolare la dimensione dei font e delle icone sul desktop. Questa regolazione non verrà tuttavia apprezzata finchè il desktop a quadranti di Linpus sarà presente sulla nostra scrivania. Vedremo in seguito come eliminare l'ambiente a quadranti predisposto da Linux Linpus Lite. L'abilitazione del tasto destro ci consente adesso l'accesso a nuovi menu e fra questi anche quello per aggiungere nuovi programmi!

venerdì 14 maggio 2010

Arduino: dove c'è più luce?


Il primo sketch con Arduino è servito a introdurne solo alcune delle caratteristiche. In questo secondo esempio realizzeremo l'interfacciamento con alcuni dispositivi: un sensore di luce o fotoresistenza e un servocomando. L'obiettivo è quello di farci suggerire da Arduino l'angolazione da cui proviene più luce.
Come avrete già capito il fotoresistore realizzerà per Arduino l'input, il servocomando sposterà invece il sensore facendolo ruotare di 180°. L'output viene realizzato comunicando l'angolo di massima luce rilevato attraverso la porta usb. Dopo la rotazione completa del sensore faremo inoltre puntare il servocomando (con il sensore) nell'angolo misurato.
Il fotoresistore è un componente elettronico la cui resistenza varia al variare della luce che lo colpisce. All'interno del programma faremo riferimento al sensore attraverso la costante SENSORE, che ne indica tra l'altro il pin usato nel collegamento con Arduino. Con la funzione analogRead(SENSORE) avviene la lettura del valore di tensione applicata ai morsetti del fotoresistore. Il valore ritornato è un numero compreso fra 0 e 1023, esso rappresenta intervalli di tensione compresi fra 0 e 5V. Possiamo rimediare la tensione da applicare al sensore direttamente da uno dei pin di Arduino. Se dunque la tensione ai morsetti del sensore è di 2,5V la funzione analogRead(SENSORE) ritornerà il valore 512. Nel circuito ho aggiunto un resistore di pochi ohm per cercare di correggere i valori tornati dal sensore (in maniera tale da farli ricadere in una fascia di valori più distante dall'ultimo valore leggibile).
La comunicazione fra Arduino e il PC avviene attraverso la porta usb. L'inizializzazione della porta seriale è stata già accennata in occasione del primo articolo con Arduino.
Il fotoresistore viene montato sull'albero del servocomando che ruotando sposta dunque il sensore. All'interno del programma faremo riferimento al servocomando attraverso la costante SERVO, passata in fase di setup alla funzione attach dell'oggetto Servo (per indicare su che pin è mappato il motore). Manovrare un servocomando con Arduino è semplice, ecco come fare:
  • dichiarare un oggetto Servo: Servo myservo;
  • mappare il servomotore in fase di setup con la funzione myservo.attach(int pin);
  • spostare il servomotore scrivendo con la funzione myservo.write(int angolo);
Altre funzioni per i servocomandi possono essere trovate a questo indirizzo. Ogni volta che spostiamo il servocomando, prima di impartire allo stesso una nuova posizione occorre dare al motore il tempo di raggiungere quella posizione. Ecco quindi l'importanza dell'istruzione delay(WAIT1)!
Con un ciclo for possiamo orientare il servocomando facendolo muovere di STEP (altra costante del programma) gradi per volta. Questi ultimi due parametri sono in qualche modo legati fra loro, il valore letto dal sensore è cioè influenzato dal precedente valore. In altre parole occorre dare al sensore il tempo di far assestare la lettura. Tuttavia se spostiamo il fotoresistore di pochi gradi per volta possono basatare pochi millisecondi. In tutti gli altri casi occorre introdurre un ritardo dopo ogni spostamento del servomotore.
Quest'ultima osservazione mi ha permesso di correggere un fastidioso difetto che ho riscontrato nel circuito poi provato. Dopo aver completato la scansione il servocomando si sposta nella posizione con più luce (ricordate la descrizione fatta all'inizio?) e vi rimane fino a una nuova scansione (che inizierà non appena termine una funzione di blinking per un led di stato). L'inizio di una nuova scansione provoca la rotazione del servomotore, quindi del sensore, dalla vecchia posizione (quella con più luce) a quella iniziale. Il valore immediatamente letto si porta allora dietro l'influenza dei valori che si alternano ai morsetti del sensore proprio durante questo spostamento. Ecco allora che l'aggiunta di una banale istruzione può correggere il comportamento falsato appena descritto. Se il sensore sta leggendo il valore della prima posizione (il servomotore è quindi a 0°) viene osservata una pausa di WAIT3 secondi (if (position==0) delay(WAIT3)). Questo farà assestare i valori prima di leggerli!
Niente di complicato nell'algoritmo che rileva l'angolo con più luce. Per ogni valore del ciclo for vengono memorizzati i valori letti dal sensore e la posizione del servomotore. Tali valori vengono quindi scartati solo se uno dei successivi valori di tensione, letti dal sensore, supera quello precedentemente memorizzato.

#include

#define SENSORE 0
#define SERVO 11
#define LED 13
#define WAIT1 40
#define WAIT2 1000
#define WAIT3 1000
#define STEP1 1

Servo myservo;
int max_light;
int max_light_position;
int current_light;
int position;

void setup() {
   Serial.begin(9600);
   myservo.attach(SERVO);
   pinMode(LED, OUTPUT);
}

void loop() {
   max_light=0;
   max_light_position=0;
   current_light=0;
   digitalWrite(LED, HIGH);
   for (position=0;position<180;position+=STEP1) {
      myservo.write(position);
      delay(WAIT1);
      if (position==0) delay(WAIT3);
      current_light=analogRead(SENSORE);
      Serial.println(current_light);
      if (current_light>max_light) {
         max_light=current_light;
         max_light_position=position;
      }
   }
   digitalWrite(LED, LOW);
   Serial.print("Massima luce rilevata a: ");
   Serial.print(max_light_position);
   Serial.print(" gradi.\n");
   myservo.write(max_light_position);
   blink(10);
}

void blink(int nBlink) {
   while (nBlink!=0) {
      digitalWrite(LED, HIGH);
      delay(WAIT2/2);
      digitalWrite(LED, LOW);
      delay(WAIT2/2);
      nBlink--;
   }
}


domenica 9 maggio 2010

Java: programmazione grafica (1)

Netbeans, ma anche Eclipse, permettono la costruzione grafica delle interfacce in maniera molto semplice. I componenti vengono disposti all'interno dell'ambiente e la maggior parte del codice java viene generato automaticamente (bisogna poi scrivere il codice per gli eventi). Sebbene questo sia il metodo più semplice e veloce per realizzare una GUI (graphic user interface) è opportuno conoscere cosa c'è effettivamente dietro. Può sempre capitare di dover mettere mano al codice, meglio quindi non dimenticare almeno le basi (e vi assicuro che capita).
Nelle prime versioni di Java la libreria di riferimento per le GUI era la libreria AWT (abstract windows toolkit) che delegava al sistema operativo il compito di disegnare i componenti. La stessa applicazione, allora, risultava diversa (graficamente) in ogni sistema operativo! Inoltre, per stabilire lo stesso comportamento per ogni componente venne individuato un insieme minimo di componenti (comuni quindi ai sistemi operativi). La gestione di tali componenti avveniva tramite dei peer che ne traducevano il comportamento.
La libreria da tenere in considerazione per questo genere di cose è la libreria Swing (che estende la vecchia AWT mantenendo la compatibilità con la stessa, ora usata solo per la gestione degli eventi). L'obiettivo di Swing è quello di offrire all'utente lo stesso risultato anche su piattaforme diverse (uno degli slogan sempre pubblicizzati da Sun per Java: write one, run everywhere)
In Java una finestra viene anche detta frame mentre la classe incaricata di istanziare la stessa è JFrame. Un frame è un contenitore di oggetti, o come vedremo a breve di pannelli e componenti dell'interfaccia grafica. Se vogliamo generare una finestra non ci resta che estendere la classe JFrame e descrivere nel costruttore le proprietà da attribuire alla finestra con uno dei seguenti metodi:
  • setTitle(String title): riceve come parametro una stringa, il titolo cioè da assegnare alla finestra;
  • setSize(int width, int height): riceve come parametro due interi (oppure un oggetto Dimension nell'altra versione del metodo: setSize(Dimension dimension)) per dimensionare la finestra;
  • setLocation(int x, int y): riceve come parametro due interi (oppure un oggetto Dimension nell'altra versione setLocation(Dimension dimension) per le coordinate da assegnare alla finestra. L'angolo in alto a sinistra dello schermo ha coordinate (0,0);
  • setBounds(int x, int y, int width, int height): con questo metodo possiamo assegnare all'istante sia le coordinate della finestra che le sue dimensioni;
  • setResizable(boolean resizable): riceve come paramentro un valore booleano che abilita/disabilita le operazioni di ridimensionamento della finestra;
  • setIconImage(Image icon): riceve come parametro il riferimento a un oggetto Image da associare alla finestra come icona;
  • setBackground(Color background): riceve come parametro un oggetto Color che verrà usato come colore di background per la finestra;
  • setUndecorated(boolean undecorated): permette di mostrare la finestra senza le decorazioni aggiunte dal sistema operativo. E' utile ad esempio per creare splash screen di applicazioni in fase di avvio delle stesse;
La sola istanza di un frame non ne abilita la visione sul desktop, essa avviene invocando sull'oggetto il metodo setVisible(boolean visible). Adesso il metodo show() è stato deprecato da Java che invita i programmatori a usare il nuovo metodo (esistente anche nelle versioni precedenti di Java). Tutti i metodi finora visti applicano al frame una proprietà senza ritornare alcun valore. Java mette a disposizione anche i metodi per interrogare i campi di un'oggetto JFrame, come ad esempio: isVisible() e getLocation().
Ecco un frame vuoto, senza componenti:

class MyFrame extends JFrame {
   public MyFrame(String title, int width, int height, boolean isResizable) {
      this.title=title;
      this.width=width;
      this.height=height;
      setSize(width,height);
      setTitle(title);
      if (isResizable) setResizable(true);
   }
   public void centered() {
      Toolkit system=Toolkit.getDefaultToolkit();
      Dimension screenSize=system.getScreenSize();
      int screenWidth=screenSize.width;
      int screenHeight=screenSize.height;
      this.setLocation((screenWidth/2)-(width/2),(screenHeight/2)-(height/2));
   }
   private String title;
   private int width;
   private int height;
   static final long serialVersionUID=-1L;
}


Ricordo che va ovviamente importato il package javax.swing con l'istruzione: import javax.swing.*. Il metodo centered() implementato nella classe permette di centrare la finestra nel monitor dell'utente! Come ricavare le dimensioni dello schermo?
Occorre chiamare il metodo (statico, quindi non necessita di oggetti per l'invocazione) getDefaultToolkit() della classe Toolkit. Sull'oggetto, ritornato accediamo alle dimensioni del desktop con la chiamata a getScreenSize(), che ritorna un oggetto Dimension. Ricavate le dimensioni dell'area di lavoro e disponendo di quelle del frame si calcola, poi, la coordinata dell'angolo superiore sinistro da assegnare alla finestra (ad esempio con setLocation()).
Ecco il main che costruisce il frame, notate qualcosa di particolare?

public class TestMyFrame {
   public static void main(String[] args) {
      MyFrame frame=new MyFrame("Test",400,400,true);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.centered();
      frame.setVisible(true);
   }
}


La chiamata al metodo setDefaulCloseOperation() serve a specificare il comportamento dell'applicazione quando il frame viene chiuso dall'utente. Cosa fare? Chiudere tutta l'applicazione? Mostrare un nuova finestra? In questo esempio la chiusura della finestra fa terminare l'applicazione, ciò avviene passando al metodo la costante (della classe JFrame) EXIT_ON_CLOSE. Altre possibili opzioni sono:
  • DO_NOTHING_ON_CLOSE: non fare nulla alla chiusura del frame;
  • HIDE_ON_CLOSE: il frame viene in realtà nascosto (è come fare frame.setVisible(false). La finestra può essere resa nuovamente visibile;
  • DISPOSE_ON_CLOSE: nasconde e libera tutte le risorse impegnate dalla finestra (che dovrà essere creata di nuovo, se occorre);

Nell'esempio ho aggiunto al frame altri componenti: un pannello con un immagine e una stringa. Vi piace? Ci occuperemo dei pannelli in uno dei prossimi articoli.