Sto sviluppando una applicazione, non destinata al PlayStore, da usare in un gruppo ristretto di persone. Al momento c'e' il problema e' che l'applicazione funziona perfettamente sul mio Nexus 5 con Android 6.0.1 ma crasha miseramente su un Samsung Galaxy A3 sempre con Android 6.0.1
Non potendo avere il telefono A3 a disposizione per le prove l'unica soluzione e' quella di usare una libreria di crash report. Il supporto di Firebase e' semplicemente fantastico e semplice da implementare
Esiste una procedura automatica interna ad Android Studio per aggiungere il crash reporting ad un progetto gia' esistente. Si parte dal menu' Tools e si seleziona Firebase
Si seleziona quindi crash reporting tra i vari servizi forniti.
Si arriva quindi al menu della pagina sottostante
Cliccando sui due pulsanti (Connect to Firebase ed Add Crash....) il progetto viene configurato in modo automatico....i meglio dovrebbe. Seguendo la procedura automatica e tenendo la build del progetto viene generato l'errore Execution failed app:processDebugGoogleServices missing api_key/current..la soluzione e' quello di inserire a mano il file google-services.json a mano nella root del progetto.
Da qui in poi e' una passeggiata. Ogni volta che viene generato un errore, l'applicazione la notifichera' sulla consolle di Firebase con un ritardo massimo di un paio di minuti
Premessa: puo' essere che non sia stato capace io....
E' da tempo che non trovavo un hardware non compatibile con la mia Debian..la cosa divertente e' che il dongle in foto e' stato ripreso da una Raspberry (Raspbian) su cui funzionava perfettamente. Iniziamo la storia
Il dispositivo con lsusb si presenta come Bus 001 Device 002: ID 0bda:8176 Realtek Semiconductor Corp. RTL8188CUS 802.11n WLAN Adapter
su Debian il modulo che gestisce la Realtek 8188CUS e' gestito dal driver rtl8192cu e si installa facilmente mediante apt-get install firmware-realtek
fino a qui niente di strano...il dispositivo viene montato e si mostra in ifconfig...sembra tutto funzionare.. root@debian:/home/luca# iwconfig wlan0 IEEE 802.11bgn ESSID:"AndroidAP" Nickname:"<WIFI@REALTEK>" Mode:Managed Frequency:2.462 GHz Access Point: 02:1A:11:FD:D2:1B Bit Rate:72.2 Mb/s Sensitivity:0/0 Retry:off RTS thr:off Fragment thr:off Encryption key:****-****-****-****-****-****-****-**** Security mode:open Power Management:off Link Quality=100/100 Signal level=100/100 Noise level=0/100 Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0 Tx excessive retries:0 Invalid misc:0 Missed beacon:0
quando si cerca pero' di accoppiare con l'access point accade qualcosa di strano
wpa_supplicant -B -i wlan0 -c <(wpa_passphrase AndroidAP passwortd)
Successfully initialized wpa_supplicant
nl80211: Driver does not support authentication/association or connect commands
wlan0: Failed to initialize driver interface
a questo punto viene iniziata l'autenticazione con l'access point che non va mai a buon fine
cercando su Internet sembra che il problema sia relativo al kernel Linux e sono state apportate patch al pacchetto standard dei driver in particolare su https://github.com/pvaret/rtl8192cu-fixes. Ho seguito le istruzioni niente successo.
Se con i vecchi Nokia era molto semplice creare un SMS server, con Android cio' non e' possibile perche' i dati sono contenuti in una sezione del disco non accessbile in modo immediato e non esiste la possibilita' di default di creare un backup.
Alcuni hanno sviluppati applicazioni Android che leggono il database degli SMS e li reinviano via mail ma la soluzione non e' molto elegante e flessibile...l'ideale e' accedere via ADB
Per prima cosa pero' e' necessario effettuare il root del dispositivo (nel mio caso un Moto E)
i dati degli SMS sono contenuti nel file /data/data/com.android.providers.telephony/databases/mmssms.db
(e' un database Sqlite) che risulta essere accessibile solo a root....il gioco e' quindi copiarlo in una porzione del disco raggiungibile via adb pull come /data/local/tmp (da creare a mano via adb shell una volta per tutte).
In questo post viene aggiornato il programma Geocompass per Micro:Bit visto qui aggiungendo la possibilita' di salvare i dati sulla memoria non volatile di Micro:Bit
Geocompass in uso di campagna
E la bussola meccanica per confronto
prima di tutto per accedere al file system di Microbit e' necessario installare microfs mediante
pip install microfs
per listare il file si usa ufs list
per copiare i file da Microbit al pc si usa ufs get nomefile.ext
i dati di strike e dip vengono salvati in un file testo nel formato nr.progr strike/dip
2 197/32
3 116/41
4 17/34
5 153/26
e' presente anche un file last_data.txt che contiene il progressivo dell'ultima misura.
MicroPython ha alcune limitazione rispetto a Python normale.
Le piu' evidenti nella gestione dei file sono:
- non esiste l'append in scrittura file ..si deve quindi leggere tutto il file, metterlo in un buffer, aggiungere una stringa in coda al buffer e poi si riscrive sulla memoria non volatile. Il comando write semplicemente cancella il file se gia' presente
- per verificare su un file e' gia' presente non si puo' usare os.path.isfile(fname) ma si usa il costrutto try..except per la gestione delle ecccezioni
- non e' possibile scorrere un file di testo riga per riga con una sintassi classica
Attenzione : ogni volta che viene flashato il programma, i dati vengono cancellati
----------------------- from microbit import display import microbit import math display.scroll("GEOCOMPASS") cc = 180/math.pi teta = 0 dip = 0 buffer = "" ls = 0 # contatore progressivo delle misure # guarda se ci sono misure gia' presenti e prende l'ultimo # dato progressivo dal file nel variabile ls try: with open("last_data.txt") as ll2: ls = int(ll2.read()) except: ls = 0 while True: if microbit.button_a.is_pressed(): # if necessary calibrate the compass if not microbit.compass.is_calibrated(): display.scroll("Calibrate compass") microbit.compass.calibrate() microbit.sleep(2500) gx = microbit.accelerometer.get_x() gy = microbit.accelerometer.get_y() gz = microbit.accelerometer.get_z() hd = microbit.compass.heading() # change the sign to uniform to Android gx = - gx gz = - gz pitch = math.atan2(gy, math.sqrt((gx*gx)+(gz*gz))) roll = math.atan2(-gx, gz) # from pitch/roll to strike/dip p2 = math.sin(pitch)*math.sin(pitch) r2 = math.sin(roll)*math.sin(roll) t1 = math.sqrt(p2+r2) # --- teta = (cc * math.asin(t1)) sigma = math.asin(math.sin(roll)/t1) sigma = (cc * sigma) # ----- # primo quadrante if ((gy <= 0) and (gx < 0)): sigma = sigma # secondo quadrante if ((gy > 0) and (gx < 0)): sigma = 180 - sigma # terzo quadrante if ((gy > 0) and (gx >= 0)): sigma = 180 - sigma # quarto quadrante if ((gy <= 0) and (gx >= 0)): sigma = 360 + sigma ss = (sigma + hd) % 360 display.scroll("Str " + str(int(ss)) + "/Dip " + str(int(teta)), 300) # controlla se c'e' il file su disco try: with open("geodata.txt") as ll: buffer = ll.read() except: buffer = "" # scrive i dati sul disco ultima misura ls = ls + 1 # incrementa contatore with open("geodata.txt", 'w') as out: aa = str(ls) + " " + str(int(ss)) + "/" + str(int(teta)) + "\n" out.write(buffer + aa) with open("last_data.txt", "w") as out2: out2.write(str(ls)) microbit.sleep(500) if microbit.button_b.is_pressed(): # the B button repeat the last measure display.scroll("Str " + str(int(ss)) + "/Dip " + str(int(teta)), 300)
Microbit e' un progetto promosso per introduzione all'informatica dei bambini nel Regno Unito. In estrema sintesi vengono regalati ai ragazzi di 11-12 anni delle piccole schede dotate di un processore Arm, Accelerometro, Bluetooth, un array di led 5x5, due pulsanti ..ed altre cose; con queste in classe fanno dei piccoli esperimenti
Questo esperimento non e' nuovo perche' agli inizi degli anni 80 era stato lanciato il progetto BBC Micro (basato su 6502)
Comfronto tra la scheda ed una moneta da 1 euro
In Italia la scheda si trova su Amazon a circa 25 euro nel kit con il cavo USB ed il pacco batterie
Quando si apre la confezione la cosa che salta piu' all'occhio e' l'assenza della scheda...e' talmente piccola che e' stata messa nel pacchetto di cartone sulla sinistra
Per programmare la scheda ci sono molte opzioni on line, dall'interfaccia tipo Blockly all'editor testuale. In alcuni casi e' presente anche un emulatore per provare il codice. Usare Python e' particolarmente fastidioso perche' non e' presente l'emulatore e non si puo' fare l'upload diretto del programma nella scheda (si deve compilare e scaricare il compilato e quindi trascinare il file dentro alla cartella di Micro:bit che si presenta come un disco USB)
Questa e' la IDE per Javascript con l'emulatore sulla sinistra ed il sistema di composizione dei comandi a blocchi sulla destra
Molto piu' comodo (anche se ha le sue idiosincrasie) e' usare Mu, un editor offline per MicroPython che effettua direttamente l'upload e permette alla riga di comando REPL di Python
La cosa un po' folle e' il sistema di debugging...l'errore scorre, carattere a carattere sul display...giusto per cronaca l'errore del video sottostante e'
Line 27 AttributeError module object has no attribute arcsin
Aggiornamento qui
Un semplice programma in MicroPython per usare l'accelerometro e la bussola di Micro:bit come bussola da rilevamento geologico
Premendo il pulsante A si acquisisce la misura (se la bussola non e' stata calibrata sara' necessario farlo ruotando il dispositivo fino a creare un cerchio sul display). Il pulsante B ripete la visualizzazione dell'ultima misura
Il costo finale, compreso di batterie, e' di circa 25 euro
Il calcolo matematico di pitch e roll partendo dai dati dell'accelerometro e' stato ripreso da qui
in questa immagine l'orientazione degli assi dell'accelerometro e della bussola rispetto alla scheda (da notare che l'accelerazione Gz e' negativa perche' all'accelerometro e' saldato sulla parte opposta della scheda)
(nota : i valori di accelerazione vengono mostrati come numeri interi e non come float (m/s2) o come frazioni dell'accelerazione di gravita' (come in Android)
----------------------
from microbit import display
import microbit
import math
display.scroll("GEOCOMPASS")
cc = 180/math.pi
teta = 0
dip = 0
while True:
if microbit.button_a.is_pressed():
# if necessary calibrate the compass
if not microbit.compass.is_calibrated():
display.scroll("Calibrate compass")
microbit.compass.calibrate()
microbit.sleep(2500)
gx = microbit.accelerometer.get_x()
gy = microbit.accelerometer.get_y()
gz = microbit.accelerometer.get_z()
hd = microbit.compass.heading()
# change the sign to uniform to Android
gx = - gx
gz = - gz
pitch = math.atan2(gy, math.sqrt((gx*gx)+(gz*gz)))
roll = math.atan2(-gx, gz)
# from pitch/roll to strike/dip
p2 = math.sin(pitch)*math.sin(pitch)
r2 = math.sin(roll)*math.sin(roll)
t1 = math.sqrt(p2+r2)
# ---
teta = (cc * math.asin(t1))
sigma = math.asin(math.sin(roll)/t1)
sigma = (cc * sigma)
# -----
# primo quadrante
if ((gy <= 0) and (gx < 0)):
sigma = sigma
# secondo quadrante
if ((gy > 0) and (gx < 0)):
sigma = 180 - sigma
# terzo quadrante
if ((gy > 0) and (gx >= 0)):
sigma = 180 - sigma
# quarto quadrante
if ((gy <= 0) and (gx >= 0)):
sigma = 360 + sigma
dip = (sigma + hd) % 360
display.scroll("Dip " + str(int(teta)) + "/Str " + str(int(dip)))
microbit.sleep(500)
if microbit.button_b.is_pressed():
# the B button repeat the last measure
display.scroll("Dip " + str(int(teta)) + "/Str " + str(int(dip)))
----------------------