středa 21. října 2015

Power Consumption aneb měření spotřeby BLE modulu

Po nějaké době se vracím k BLE modulu od Cypressu a to proto, že chci změřit průměrnou spotřebu proudu při tzv. advertisingu neboli hledání připojitelných zařízení.

Pro zopakování, existují tři typy zařízení s Bluetooth technologií: Bluetooth, Bluetooth Smart a Bluetooth Smart Ready
Bluetooth - klasické zařízení ve verzi nižší než 4.Bluetooth Smart - sensory na baterii (krokoměry, měření srdečního tepu, BlueGEO)Bluetooth Smart Ready - nejvyšší třída zařízení, které komunikuje se všemi druhy Bluetooth (mobilní telefon, tablet, chytré televize)
Pokud by byla spotřeba konstantní, stačilo by připojit ampermetr a změřit ji. Module ale používám v ztv. Deep Sleep režimu, kdy spí a každých 100 ms se probudí a umožní připojení k BLE zařízení.
Možnosti jsou dvě, použít vhodný (tzv. SHUNT) rezistor a pomocí měření úbytku napětí na něm sledovat graf osciloskopu a ten vyhodnotit.

Takže pro měření pulsní spotřeby je nutné použít něco lepšího než jen ampermetr.
Výsledek (hlavně měření spotřeby BLE modulu) může vypadat např. takto:




BLE modul se SHUNT rezistorem 

Nebo, použít něco lepšího, máte-li po ruce.
Já mám k dispozici:

DC Power Supply Portable Device Battery/ Charger Simulator 2308 od Keithley

Což je skvělý přístroj, pokud potřebujete měřit pulsní spotřebu nebo simulovat chování baterie (umožňuje např. nastavit vnitřní odpor v rozmezí 0 až 1 ohm po setině) a výsledek stejného měření jako předchozí vypadá následovně:



BLE modul měření na battery simulátoru

Jak je vidět, měření proudu je mnohem přesnější a detailnější.
Takže po připojení osciloskopu, konkrétně jsem použil MSO2024B od Textronixu.

Po nastavení a zachycení potřebných pulsů následovalo uložení na Flash disk a přestávka na kafe. Osciloskop ukládal cca 1.2 milionu hodnot asi 10 minut.

Po uložení do CSV (Comma Separated Values) následoval pokus o zpracování v Excelu :) Ten byl ale slepou kolejí, neboť Excel zvládá zpracovat 32 000 hodnot a pokud je jich více, musí se rozdělovat do bloků a i přesto s tím měl problémy, aby vykreslil graf.

Ukázka zpracovaných dat vypadal následovně:
Vzpomenul jsem na program Gnuplot a data zpracoval v něm.


Z grafu lze vidět jednotlivé úkony při vysílání (více info od výrobce). Vysílání trvá cca 4.5 ms a opakuje se každých 100 ms. Maximální proud (po přepočtu z poměru mezi napětí je 17 mA).

Následovalo určení plochy (v grafu fialovou barvou), aby se dala spočítat spotřeba. Příkazy pro Gnuplot jsou uvedeny na konci.

Možnosti byly dvě, určit funkci a spočítat plošný integrál nebo si spočítat střední hodnotu a odchylku zanedbat. Jakožto technik se vydávám druhou cestou... a dělám si poznámky na papír:





Takže mám něco jako na obrázku vlevo nahoře a po použití Gnuplotu dostávám hodnoty, díky kterým spočtu plochu pod křivkou, která je 36 % z plochy dané časem 4.5 ms a výškou pulsu 21.1 V.

Jelikož je vysílá jen 4.5 ms, tak dalších 95.5 ms modul spí je úplně vypnutý (téměř úplně). Takže po přepočtu dostávám průměrnou spotřebu 288.4 uA

Srovnávám se sejmutou charakteristikou z oscila od výrobce:


Jeho tabulkovou hodnotou z datasheetu:




A hodnotou spočtenou z Excel formuláře, který výrobce nabízí ke stažení:



Hodnoty mnou změřené a vypočtené jsou celkem podobné.

Moje: 288 uA
Výrobce tabulková hodnota: 262 uA
Výrobce Excel makro: 265 uA


Pozn: Nakonec bylo ve vyvíjené aplikaci potřeba vysílání jen každou vteřinu a spotřeba se dostala na 28 uA (logicky, když je čas deset krát delší) a to je krásné :).
________________________________________________________________________________




Gnuplot - ovládání

Program lze ovládat pomocí jednotlivých polože z menu nebo příkazy psát přímo na řádek (bodobně jako Matlab.



Otevřeme si soubor s daty a pomocí příkazů:

set title 'Power consumption'                                   // název grafu
set xlabel 'time(s)'                                                    // název X osy
set ylabel 'voltage(V)'                                              // název Y osy
set yrange [-1:25]                                                    // nastavení Y osy

set xrange [0:0.01]                                                  // nastavení X osy
set grid ytics mytic                                                 // zapnutí gridu v Y ose
set mytics 5                                                            // počet děličů gridu v Y ose - rozdělí části na 5 dílů
set grid xtics mxtic                                                // zapnutí gridu v X ose
set mxtics 10                                                         // počet děličů gridu v X ose - rozdělí části na 10 dílů
set grid lt 1 lw 1 lc rgb "#880000"                       //nastavení barvy a typu gridu
plot 'test2.csv' using 1:2 with lines, 'test2.csv' using 1:3 with lines            //vykreslí grafy pro Y1 a Y2

Statistika - dělá statistiku pro každý sloupec dat

plot "graf1.txt" using 1:2 with boxes                     //graf s boxičkami
stats "graf1.txt"                                                      //statistika



čtvrtek 12. března 2015

Bluetooth Low Energy (BLE) od Cypress

Bluetooth Low Energy (BLE) od Cypress

Minulý týden mě navštívil vyslanec firmy Cypress a dnes se mi do rukou (za přispění Future Electronics z Prahy) dostal jejich kit CY8CKIT-042-BLE Bluetooth® Low Energy (BLE) Pioneer Kit



Kit tedy slouží k osahání si HW a SW potřebného k vývoji BLE zařízení.
Obsahuje:

- BLE Pioneer Baseboard preloaded with CY8CKIT-142 PSoC 4 BLE module
- CY5671 PRoC BLE Module
- CY5670 - CySmart USB Dongle (BLE Dongle)
- Quick start guide
- USB Standard A to Mini-B cable
- Four jumper wires (4 inch) and two proximity sensor wires (5 inch)
- Coin cell (3V CR2032)

Poznámka pro neznalé, Cypress nabízí modul PSoC a PRoC. Rozdíl je v tom, že PSoC (červený modul na obrázku) je Programmable System on Chip a obsahuje CY8C4247LQI-BL483. Máte tak k dispozici celý Cortex M0 včetně všech rozhraní.


PRoC (černý modul) je Programmable Radio-on-Chip. PSoC a obsahuje CYBL10563-56LQXI. Zde je omezený počet funkcí a rozhraní. I když je zajímavé, že je cena vyšší...

Zajímavé je srovnání počtu součástek nutných k vytvoření antény:

Praktické seznámení s kitem

Nejprve musím uznat, že se mi líbí balení kitu v plastové krabici, vše uspořádáno jak má být včetně Quick start guide. Instalační ISO jsem si stáhl a nainstaloval dle pokynů. Po instalaci se nabídla aktualizace všech částí a vše proběhlo hladce a samo... paráda! Mnoho výrobců by se mohlo učit...








středa 11. března 2015

Baterie 3.6V/14Ah za 79 kč

Narazil jsem na pěknou nabídku u GME.cz, kde nabízí: Baterie lithiová Lisun CR1 D 3,6V 14000mAh za cenu 79 kč



Odkaz na GME



Zajímavá je kapacita udávaná u GME a to 14 Ah, přičemž originál má 19 Ah (že by v GME vyprodávali trochu vybité baterie?). Za tu cenu je to ale paráda. 

Tutéž lze koupit i na Ebay, jen v jiném obalu za cca 240 kč. 


úterý 10. března 2015

Bluetooth Low Energy (BLE) s HM-10 (Texas Instruments CC2541)

Dlouhou dobu používám levné Bluetooth moduly HM-05 s verzí BT 2.1. Nedávno jsem si chtěl vyzkoušet BT Low Energy, kterou nabízí od verze 4.0. Proto jsem si opatřil modul HM-10 od firmy Jnhuamao z Ebay za cenu cca 170 kč.

Modul obsahuje chip od Texaských Nástrojáren CC2540/1, napájecí napětí je 2 až 3.7 V, rozměry 27x13 mm.


Po připojení k UARTu modulu dle schématu:



lze tento ovládat AT příkazy. Z nejzajímavějších uvádím:


Postup ke zprovoznění jako Peripheral:
"AT" - kontrola, zda je modul OK
"AT+RENEW" - reset do defaultního nastavení (ROLE0, MODE0)
"AT+NAMEjmeno" - změní jméno BLE
"AT+ROLE0" - nastavení jako slave (piripheral)
"AT+MODE1" - přeposílá data po připojení, jinak reaguje na UART
"AT+TYPE2" - nutnost vždy zadat PIN při připojení
"AT+PWRM0" - auto SLEEP režim
"AT+RESET" - reset pro uložení parametrů




Další příkazy:

"AT+PASS?" - zjištení PINu
"AT+PASS123456 - natavení PINu na 123456
"AT+MODE0" - 
bez připojení: HM-10 reaguje na AT příkazy z UARTu
           - po připojení: přeposílá data
"AT+MODE1" - jako MODE0, navíc nastavuje výstupy, čte vstupy
"AT+MODE2" - jako MODE1, ale nečte vstupy

"AT+TYPE0" - připojení bez zadání PINu
"AT+TYPE1" - připojení zadáním PINu

Sleep režim: - slibuje spotřebu 60 uA ~ 1.5 mA
                     - ze SLEEP režimu se lze dostat dvěma způsoby (odesláním řetězce delšího než 80 znaků přes UART; stiskem tlačítka na déle než 1 sekundu)

"AT+SLEEP" - přejde do SLEEP režimu

Spotřeba:

Standardní režim - 9 mA
SLEEP režim      - 0.2 mA, LED dioda je OFF

Ve SLEEP režimu je HM-10 viditelné a po připojení se samo probudí. Po odpojení se do SLEEP režimu NEUVEDE, je třeba ho uspat! Proto existuje auto-sleep funkce.

"AT+PWRM0" - auto SLEEP režim
"AT+PWRM1" - bez SLEEP režimu

Po odpojení se sám uspí, což výrazně šetří baterii. 

Power režimy:

Test: Zařízení 1 m od BLE má sílu signálu při různých Power režimech v závorce.

"AT+POWE0" - nastavení výkonu antény na -23 Db (RSSI = -93 dBm)
"AT+POWE1" - nastavení výkonu antény na -6 Db  (RSSI = -76 dBm)
"AT+POWE2" - nastavení výkonu antény na 0 Db   (RSSI = -74 dBm)
"AT+POWE3" - nastavení výkonu antény na 6 Db   (RSSI = -68 dBm)

Je tedy vidět, jak se síla signálu zvyšuje se zvyšujícím se parametrem POWEx (čím vyšší, číslo x, tím větší výkon a nižší záporný parametr RSSI).
Parametr v datasheetu tedy odpovídá měření (srovnání POWE3 je o 6 dB větší než POWE2, což měřením bylo prokázáno (74 - 68 = 6)).
Zajímavé bylo, že spotřeba energie byla při všech režimech stejná... a to jak s auto-sleep režimem, tak i bez něho.

Upgrade FirmWare:

Upgrade FW je snadná záležitost, postačí nahrát nový bootloader přes UART.
1) Stáhnout si nový FW včetně instalačního nástroje ze stránek Huamao Technology
2) Připojit přes UART a zadat AT příkaz "AT+SBLUP", čímž se modul přepne do režimu nahrávání nového FW



3) Odpojíte UART! Jako Admin spustíte staženou aplikaci, vyberete port a stažený BIN soubor.
4) Tlačítkem "Load Image" zahájíte nahrání nového bootloaderu. Po ukončení se objeví hláška o úspěchu.
5) Ověření úspěšnosti provedete příkazem "AT+VERS?" přes UART.



neděle 8. února 2015

Printscreen na Raspberry Pi



Občas je potřeba uložit obsah obrazovky z Maliny, například pro obrázek na blog...

Pěkně pracuje program SCReenshOT neboli Scrot .

Instalace je snadná:

sudo apt-get install scrot

a použití ještě snažší:

scrot

udělá fotku obrzaovky a uloží ji s aktuálním časem a datem do home adresáře. 

Pokud příkaz modifikujete:

scrot -d 5 obrazek.png

pak udělá screen shot za 5 vteřin a uloží ho pod definovaným názvem. Paráda...

OLED display s SSD1306 a Raspberry Pi



Máme-li na Raspberry Pi zprovozněnu I2C sběrnici, můžeme se pustit do připojení OLED displeje a něco pěkného si zobrazit.

Displej si připojíme k Malině následovně:

VCC na pin 1 (3V3)
SDA na pin 3 (GPIO02)
SCL na pin 5 (GPIO03)
GND na pin 9 (GND)



Sluchátka, flash disk a bluetooth dongle nejsou potřeba


Pěkné příklady použití nabízí Lada Ovocná a tak je využijeme.

sudo apt-get update
sudo apt-get install build-essential python-dev python-pip


sudo pip install RPi.GPIO

přidáme pěknou knihovnu pro práci s obrázky Python Imaging Library

sudo apt-get install python-imaging python-smbus

a od Lady z GitHubu přidáme příklady a ovladače:

sudo apt-get install git
git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git
cd Adafruit_Python_SSD1306
sudo python setup.py install


Příklady se nám nainstalují do Home složky a když do ní vejdeme, najdeme složku Examples, kde si otevřeme ukázkový shapes.py (nejlépe opět editorem nano)

sudo nano shapes.py

a vybereme správný display, který používáme. Takže odkomentujeme řádek a uložíme

disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

a pak si jako root pustíme upravený příklad.

sudo python shapes.py


Videoukázka zde:






I2C na Raspberry Pi



Sběrnici I2C známe a připojit skrze ni snímače a zobrazovače je super.

Pro zprovoznění této sběrnice na Malině je třeba udělat pár věcí.


1) Nejprve si nainstalujeme potřebné nástroje:

sudo apt-get install python-smbus
sudo apt-get install i2c-tools



2) Poté si I2C povolíme v configu:


sudo raspi-config

a v Advanced option si najdeme I2C, kterou povolíme.


3) Aby nám I2C dobře fungovala, je vhodné přidat dva řádky do modules ve složce etc, nejlépe v editoru nano:

sudo nano /etc/modules

přidáme řádky:

i2c-bcm2708
i2c-dev


4) V souboru raspi-blacklist.conf příkazem:

sudo nano /etc/modprobe.d/raspi-blacklist.conf

zakomentujeme řádky přidáním # před každý příkaz

5) V souboru config.txt příkazem

sudo nano /boot/config.txt

přidáme dva řádky:

dtparam=i2c1=on
dtparam=i2c_arm=on



a restartujeme např. příkazem sudo shutdown -r now

Po restartu je vhodné vyzkoušet, zda je I2C funkční a zařízení je připojeno. To uděláme příkazem:


sudo i2cdetect -y 1

který nám vypíš připojená zařízení.






OLED display s SSD1306 a Arduino



Že OLED znamená Organická lehce emitující dioda, jistě víte. Podrobnosti o této technologii lze najít na Wikipedii

Zakoupil jsem na Ebay tento malý 0.96" OLED display pro odzkoušení za cenu cca 100 kč. 
Součástí je populární řadič SSD1306, a tak lze display snadno ovládat pomocí I2C. Display díky OLED technologii nepotřebuje podsvícení, což snižuje spotřebu na 0.08 W. 
A k čemu je tento display dobrý? Právě díky své velikosti je vhodný do malých zařízení, kde je potřeba zobrazit více informací a použití několika LED diod by bylo nesrozumitelné.
Je vhodný pro zobrazení krátkých textů a jednoduché grafiky.



Parametry jsou následující:

- rozlišení 128 x 64 pixelů
- pozorovací úhel 160 °
- spotřeba 0.08 W
- napájení 3 až 5 V
- pracovní teplota -30 až 70 °C
- rozměry 27 x 27 x 4 mm

Pro vyzkoušení displeje jsem si vzal jedno Walduino a použil knihovnu pro SSD1306 od Lady Ovocné a GFX knihovnu také od Lady.

HW propojení je na následujícím obrázku. K Walduinu jsem připojil display k pinům (SDA-A4, SCL-A5, GND-GND, VCC-5V).  



Vše funguje bez problémů a dle očekávání. Jen bych upozornil, že má display na zadní straně propojku, kterou lze měnit adresu a případně je potřeba upravit adresu v programu na 0x3C.


V minulosti jsem měl v rukou OLED display od firmy
Vitek VL128644, který obsahuje řadič SSD1303. Ovládání bylo obdobné a stačilo si upravit knihovnu od Lady pro tento řadič.

Dále bych doporučil k vyzkoušení knihovnu U8GLIB, pěkně se mi s ní pracovalo.

Na závěr videoukázka:







středa 28. ledna 2015

PID regulátor

PID regulátor


Co je PID regulátor si můžete přečíst např. na Wikipedii. Pokud i po přečtení nebudete tušit, co PID je, zkusím napsat příklad trochu více lidsky:

P znamená proporcionální, I integrální a D derivační. Regulátor znamená, že něco reguluje, nejčastěji teplotu.
Takže stručně, jasně a zjednodušeně, jde o to, že máme například podlahové topení v domě a chceme PID regulátorem regulovat teplotu podlahy. PID proto, že nabízí nejlepší možnost regulování oproti P, PD nebo PI regulátorům.
Vždy potřebujeme spočítat chybu, resp. chyby. A nejlépe je, když je počítáme ve všech složkách (P, D a I).


P


P značí rozdíl mezi vstupní hodnotou a nastavenou požadovanou hodnotou

Pe = setpoint - input
Pout = Kp * E Kp je vlastně velikost chyby Kp = E


kde Pe - proporcionální chyba, setpoint - nastavená požadovaná hodnota, input - vstupní hodnota, Pout - velikost chyby, Kp - zesílení chyby, E - aktuální chyba

I


I značí integrál, neboli plochu pod křivkou. Je to vlastně chyba s časem. 

Ie = (ΣE + E) * t
Iout = Ki * ΣE Ki je vlastně plocha pod křivkou Ki = E * t



kde Ie - integrační chyba, ΣE je součet (suma) chyb předchozích, E - aktuální chyba, t - čas, Iout - velikost integrační chyby, Ki - zesílení integrační chyby

D


D značí derivaci, což je sklon křivky neboli změna chyby
De = (E - Elast) / t = (In - Inlast) / t
Dout = Kd * De Kd je vlastně sklon křivky Kd = E / t

kde De - derivační chyba, E - aktuální chyba, Elast - poslední známá chyba, t - čas, In - vstupní hodnota, Inlast - poslední známá vstupní hodnota, Dout - velikost derivační chyby, Kd - zesílení derivační chyby


Celkovou chybu spočítáme jako sumaci všech chyb:

OUT = Pout + Iout + Dout



Příklad 1 pro Walduino: (chybu určíme například 0.5)

// setup

t = 1000 ;                             // čas nastavíme na sekunduKp = 0.5;                              
Ki =  0.5 * t;                
Kd = 0.5 / t;                


// loop                                // smyčka vykonávající regulaci

nyni = millis(); // funkce millis vrací hodnotu v ms od spuštění programuzmena = (nyni – posledni);
if (zmena >= time change)
{   error = Setpoint – Input;                                      // výpočet E, neboli chyby
   errorsum = errorsum + error;   Derror = (Input – lastinput);
   Pout = Kp * error;                                              // jednotlivé chyby
   Iout = Ki * errorsum ;   Dout = Kd * Derror ;
   Output = Pout + Iout + Dout ;                                   // výsledná chyba
}
posledni = nyni;



Příklad 2 pro Walduino: (Trimr 200k (1GND, 2-A0, 3-PWM3), C 680uF (1-GND, 2-R), R 100R (1-C, 2-PWM3))


float Kp = .5 , Ki = .5, Kd = .5 ; // PID gain values
float Pout , Iout , Dout , OutputP, OutputI, OutputD, Output; // PID final ouput variables
float now , lasttime = 0 , timechange; // important time
float Input , lastinput , Setpoint = 127.0; // input-based variables
float error , errorsum = 0, Derror; // output of the PID components
int settime = 1000; // this = 1 second, so Ki and Kd do not need modification
void setup () {
  Serial.begin(9600); // serial setup for verification
  pinMode(3, OUTPUT);
} // end void setup (){
void loop () {
  now = millis() ; // get current milliseconds
  timechange = (now - lasttime); // calculate difference
  if (timechange >= settime) { // run PID when the time is at the set time
    Input = (analogRead(0) / 4.0); // read Input and normalize to output range
    error = Setpoint - Input; // calculate error
    errorsum = errorsum + error; // add curent error to running total of error
    Derror = (Input - lastinput); // calculate slope of the input
    Pout = Kp * error; // calculate PID gains
    Iout = Ki * errorsum ;
    Dout = Kd * Derror ;
    if (Iout > 255) // check for integral windup and correct
      Iout = 255;
    if (Iout < 0)
      Iout = 0;
    OutputP = Pout;
    OutputI = Iout;
    OutputD = Dout;
    Output = Pout + Iout + Dout ; // prep the output variable
    //Output = Pout; // prep the output variable
    if (Output > 255) // sanity check of the output, keeping it within the
      Output = 255; // available output range
    if (Output < 0)
      Output = 0;

    if (OutputP > 255) // sanity check of the output, keeping it within the
      OutputP = 255; // available output range
    if (OutputP < 0)
      OutputP = 0;

    if (OutputI > 255) // sanity check of the output, keeping it within the
      OutputI = 255; // available output range
    if (OutputI < 0)
      OutputI = 0;

    if (OutputD > 255) // sanity check of the output, keeping it within the
      OutputD = 255; // available output range
    if (OutputD < 0)
      OutputD = 0;

    lastinput = Input; // save the input and time for the next loop
    lasttime = now;
    analogWrite (3, Output); // write the output to PWM pin 3


    Serial.print ("Setpoint=");
    if (Setpoint < 100) Serial.print ("0");
    Serial.print (Setpoint); // print some information to the serial monitor
    Serial.print (" : ");
    Serial.print ("Input=");
    if (Input < 10) Serial.print ("0");
    if (Input < 100) Serial.print ("0");
    Serial.print (Input);
    Serial.print (" : ");
    Serial.print ("Output=");
    if (Output < 10) Serial.print ("0");
    if (Output < 100) Serial.print ("0");
    Serial.print (Output);
    Serial.print (" : ");
    Serial.print ("OutputP=");
    if (OutputP < 10) Serial.print ("0");
    if (OutputP < 100) Serial.print ("0");
    Serial.print (OutputP);
    Serial.print (" : ");
    Serial.print ("OutputI=");
    if (OutputI < 10) Serial.print ("0");
    if (OutputI < 100) Serial.print ("0");
    Serial.print (OutputI);
    Serial.print (" : ");
    Serial.print ("OutputD=");
    if (OutputD < 10) Serial.print ("0");
    if (OutputD < 100) Serial.print ("0");
    Serial.println (OutputD);

  } // end if (timechange >= settime)
} // end void loop ()

Popisovat program patrně nemá význam vzhledem k množství komentářů, které jsou v programu. Výsledkem je regulace PID regulátorem dle zadaného Setpointu a Vstupní veličiny.

Příklad 3 pro Walduino (využívá knihovnu PID_v1 a byl převzat z Arduino.cc)

/********************************************************
 * PID Basic Example
 * Reading analog input 0 to control analog PWM output 3
 ********************************************************/

#include <PID_v1.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

void setup()
{
  Serial.begin(9600); // serial setup for verification
  //initialize the variables we're linked to
  Input = analogRead(0);

  Setpoint = 100;

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(0);

  Serial.print ("Input=");
       if (Input < 10) Serial.print ("0");
     if (Input < 100) Serial.print ("0");  
  Serial.print (Input);
  Serial.print (" : ");
  
  myPID.Compute();
  analogWrite(3,Output);
  
  Serial.print ("Output=");
       if (Output < 10) Serial.print ("0");
     if (Output < 100) Serial.print ("0");  
  Serial.print (Output);
  Serial.println (" : ");
  delay(100);
  
}

Program funguje stejně jako výše popsaný.

čtvrtek 22. ledna 2015

Raspberry Pi jako Internetové rádio

Myšlenku použít Malinu jako internetové rádio mám od doby, kdy jsem si ji koupil.

Moje požadavky: přehrát dvě rádia, která poslouchám.
A to:

Samson:
mms://netshow5.play.cz/samsonfm128
http://icecast2.play.cz:8000/samsonfm128aac

Humor:
http://mp3stream4.abradio.cz/humor128.mp3

Žel, nepodařilo se mi jedním programem přehrát obě rádia.





Pro přehrání prvního streamu jsem použil MPLAYER


apt-get install mplayer                      - instalace programu MPLAYER

mplayer -playlist "mms://netshow5.play.cz/samsonfm128"         - přidání streamu do playlistu

amixer cset numid=3 1                     - nastavení výstupu pro přehrávání na sluchátka
amixer cset numid=3 2                     - nastavení výstupu pro přehrávání skrze HDMI











Pro přehrání druhého streamu jsem použil MPC a MPD

apt-get install mpc mpd                                                         - instalace MPC a MPD
mpc add http://mp3stream4.abradio.cz/humor128.mp3      - přidání adresy streamu
mpc play 1                                                                              - přehrání prvního streamu
mpc stop                                                                                 - ukončení přehrávání 


Poslech je paráda :) Teď už jen sehnat někde staré rádio, přidat ovládání skrze tlačítka či enkodér a dát Malinu dovnitř.






pondělí 19. ledna 2015

Raspberry Pi - užitečné příkazy

Seznam pro mě užitečných příkazů k Malině:


sudo <příkaz>   - provedení příkazu jako root
raspi-config       - konfigurace Maliny
apt-get update    - update Maliny  
apt-get upgrade  - upgrade Maliny
ls                        - výpis adresáře
cd ..                    - posun o adresář výš

Připojení flash disku:

- připojit flash disk k Malině
- odebrat mountlý disk
apt-get install fuse ntfs-3g                                - instalace ntfs-3g
mkdir /media/usbstick                                      - vytvoření adresáře pro flash disk
tail -f /var/log/messages                                   - zjištění názvu připojeného flash disku (sda1)
mount -t ntfs-3g /dev/sda1 /media/usbstick     - připojení flash disku do adresáře usbstick

GPIO

apt-get install rpi.gpio
apt-get install python-rpi.gpio

pátek 16. ledna 2015

Arduino + Krokový motor

Ze staré jehličkové tiskárny se ke mě dostaly dva krokové motory:

EM-93
Carriage Motor Specifications
Type                              4-phase 200-pole stepper motor
Voltage                          Driving: +36DC
                                     Holding: +5V DC
Coil Resistance              110 +/- 7% at 25°C per phase
Current                         Driving: 0.68A (max.)
                                     Hoding: O. 15A (typical)
Excitation                      1-2 phase, 2-2 phase




EM-50
Paper Feed Motor Specifications
Type                              4-phase 48-pole PM type stepper motor
Voltage                          Driving: + 36 VDC
                                     Holding: +5 VDC
Coil Resistance              780 +/- 3% at 25” per phase
Current                         Driving: 1.2 A (max.)
                                     Holding: 0.08 A(typical)
Excitation                     2-2 phase



Popis krokových motorů je pěkně popsán na stránkách: robotika , odkud jsem převzal obrázek zapojení. 
Propojit tyto motory s Arduinem pomocí tranzistorového pole ULN2803 bylo snadné a použití ukázkového programu přímo ze stránek Arduina také...

Schéma zapojení:

Ukázkový kód z Arduino Stepper motor

/* Stepper Unipolar Advanced
 * -------------------------
 *
 * Program to drive a stepper motor coming from a 5'25 disk drive
 * according to the documentation I found, this stepper: "[...] motor 
 * made by Copal Electronics, with 1.8 degrees per step and 96 ohms 
 * per winding, with center taps brought out to separate leads [...]"
 * [http://www.cs.uiowa.edu/~jones/step/example.html]
 *
 * It is a unipolar stepper motor with 5 wires:
 * 
 * - red: power connector, I have it at 5V and works fine
 * - orange and black: coil 1
 * - brown and yellow: coil 2
 *
 * (cleft) 2005 DojoDave for K3
 * http://www.0j0.org | http://arduino.berlios.de
 *
 * @author: David Cuartielles
 * @date: 20 Oct. 2005
 */

int motorPins[] = {8, 9, 10, 11};
int count = 0;
int count2 = 0;
int delayTime = 500;
int val = 0;

void setup() {
  for (count = 0; count < 4; count++) {
    pinMode(motorPins[count], OUTPUT);
  }
}

void moveForward() {
  if ((count2 == 0) || (count2 == 1)) {
    count2 = 16;
  }
  count2>>=1;
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins[count], count2>>count&0x01);
  }
  delay(delayTime);
}

void moveBackward() {
  if ((count2 == 0) || (count2 == 1)) {
    count2 = 16;
  }
  count2>>=1;
  for (count = 3; count >= 0; count--) {
    digitalWrite(motorPins[3 - count], count2>>count&0x01);
  }
  delay(delayTime);
}

void loop() {
  val = analogRead(0);
  if (val > 540) {
    // move faster the higher the value from the potentiometer
    delayTime = 2048 - 1024 * val / 512 + 1; 
    moveForward();
  } else if (val < 480) {
    // move faster the lower the value from the potentiometer
    delayTime = 1024 * val / 512 + 1; 
    moveBackward();
  } else {
    delayTime = 1024;
  }
}

Program je jednoduchý. V podstatě jen čte hodnotu z potenciometru připojeného na Analogový vstup 0 a dle ní nastavuje směr a rychlost motoru. 
Popis bitových operací (posuvů) je pěkně popsán na: uart




A videoukázka s motorem EM-93 v šasi jehličkové tiskárny:












úterý 13. ledna 2015

Neoriginální FTDI převodník a aktualizace Win 7

Kdo firmu FTDI zná, jistě zná chip FT232 (převodník USB-Serial port). Jistě víte, že existují kopie tohoto chipu a možná se Vám stalo, jako mě, že od poslední aktualizace Win Vám přestal fungovat převodník s FT232... a pokud ne, může se stát později až aktualizujete Win.
Důvodem je použití klonu tohoto chipu v levných převodnících. Klon se od originálu fyzicky nijak neliší, pouzdro je shodné.
Více info zde:  http://zeptobars.ru/en/read/FTDI-FT232RL-real-vs-fake-supereal

Více info v diskuzích zde:
http://www.eevblog.com/forum/reviews/ftdi-driver-kills-fake-ftdi-ft232/
http://forum.arduino.cc/index.php?topic=270175.0

V poslední aktualizaci Win je nová verze ovladačů od FTDI a ty zjistí, že používáte klon a změní mu jeho PID na 0. Tím je pro Win nerozpoznatelný a přestává fungovat.

Zda se to stalo u Vašeho převodníku lze zjistit následovně:

Ve Win: Control Panel:System: Device Manager: Ports: right click on USB device:Properties: Details:Hardware IDs,
Good one shows this: ftdibus\comport&vid_0403&pid_6001
Counterfeits will have 0s instead I think. - a přesně tohle jsem našel ve svém PC.


Řešením je používat originál genuine převodníky od FTDI (drahé) nebo to obejít dle následujícího videa:
https://www.youtube.com/watch?v=LEpSCF-uqvs

Vyzkoušel jsem a funguje to.

LV

pondělí 12. ledna 2015

Automatické testování elektro zařízení pomocí RPi, kamery a OpenCV

Když vyrábím systémy ASTA, občas se při pájení stane, že není některý ze spojů zapájen správně. Často se to stává u pinů budiče segmentového displeje, někdy u LED diody, která indikuje alarm.
Napadlo mě udělat si inspekční systém, který bude kamerou snímat výrobek, na němž poběží test, a výsledkem bude, zda je některý ze segmentů displeje vadný.

Systém ASTAmini s teplotním čidlem
Sestavení: Malina s kamerou mířící na testovaný objekt

Po sestavení jsem si napsal krátký program v Pythonu (priklad_1.py) pro zjištění barev pixelů na pozicích se segmenty. Na ukázku simuluji vadné segmenty a, d, e na první číslici:

Simulace vadných segmentů na první segmentovce
Ukázka programu a výsupu

Výstup z progamu je tedy:


Bystřejší z vás napadne, co se stane když bude testovací zařízení v jiné poloze? Systém totiž v této jednoduché podobě pouze testuje pixely z obrázku. Samozřejmě by se dala vyrobit fixtura, která by testovací zařízení držela v jedné pozici, ale taky se dá detekovat např. hrana displeje a od ní pozici pixelů dopočítat. Nebo lze přímo detekovat segmenty, jak je vidět v následujícím obrázku:

Detekce segmentů (červené barvy) na zařízení. Připojovací kabely stejné barvy nejsou vhodné :)

Zajímavé je ovládání zařízení přímo z Maliny a tím spolupráce při vykonávání testů, ale to až příště...


Camera+PIR+Python - Detekce ptáků v budce včetně záznamu videa

Rozmýšlel jsem, jak zjistit, kdo nám chodí do budky na zrní, když jsem v práci... a tak jsem použil Malinu, kameru, PIR senzor a zaznamenávám fotky a videa z návštěv v budce.

Zapojení je následující (připojení k síti je zatím kabelem, do budoucna bude WiFi dongle):


Fotografie sestavy. Lze vidět Malinu s připojenou kamerou. Barevné kabely vedou k PIR senzoru a pípáku. 



Fotka budky, kde lze vidět (kromě krmiva) i PIR senzor "číhající" na návštěvy.


Fotky z kamery:





A videozáznam pro ukázku:




neděle 4. ledna 2015

SimpleCV + Python

Po instalaci SimpleCV přichází na řadu pár příkladů v Pythonu...

Příklad 1) Zobrazení obrazu z kamery a zjištění barvy určitého pixelu:







import subprocess
from SimpleCV import Image
import time


subprocess.call(“raspistill -n -w %s -h %s -o Obr_1.bmp” % (640, 480), shell=True)
img = Image(“Obr_1.bmp”)
img.show()
pixel = img[2, 2]
print pixel

Nejprve importujeme potřebné komponenty. Spustíme externí proces (raspistill) a uložíme snímek pod názvem Obr_1.bmp z kamery v rozlišení 640x480 pixelů. Do proměnné img načteme uložený obrázek a funkcí show ho zobrazíme. Funkcí img přistupujeme k samotnému obrázku. 

Výstupem je hodnota barvy na souřadnicích ve formátu: (153.0, 202.0, 199.0) 

V programu můžeme například onen pixel změnit na červený a upravený obrázek uložit pod názvem Obr_2.bmp takto:

img[2, 2] = (255,0,0)
img.save(“Obr_2.bmp”)
print pixel

Výsledkem je změna barvy pixelu na pozici x = 2, y = 2 (malá tečka na druhém obrázku). 



Příklad 2) Úprava obrázku funkcí binarize(), která převede obrázek do černobílé varianty.






#!/usr/bin/python
import subprocess
from SimpleCV import Image
import time

subprocess.call(“raspistill -n -w %s -h %s -o
 Obr3_1.png” % (640, 480), shell=True)
img = Image(“
Obr3_1.png”)
img.show()
time.sleep(5)
img = img.binarize()
img.show()
time.sleep(5)
macchie = img.findBlobs()
img.save(“
Obr3_2.png”)
img.show()
time.sleep(20)

Funkce binarize() má jeden parametr a tím je úroveň prahu, při kterém rozlišuje kdy bude pixel bílý a kdy černý. Hodnotu úrovně lze nastavit od 0 do 255. Ukázka hodnot 40, 100 a 200:

 
Funkce findBlobs() slouží k nalezení objektů, jejich orientace, tvar atp. Tyto parametry jsou důležité např. v robotice při vyhodnocení obrazu. Více v následující ukázce. 

Příklad 3) Hledání ploch, úhlů a středů v obrázku



U funkce binarize(40) jsem nastavil parametr na 40, aby nebyl výstup příliš dlouhý. Popravdě, není výstup příliš vhodný. Lépe by se vyhodnocoval obrázek s objekty na stole atp., kde by bylo vidět jednotlivé objekty, jejich plochy, orientaci a středy...

#!/usr/bin/python
import subprocess
from SimpleCV import Image
import time

subprocess.call(“raspistill -n -w %s -h %s -o Obr4_1.png” % (640, 480), shell=True)
img = Image(“Obr4_1.png”)
img.show()
time.sleep(5)
img = img.binarize(40)
img.show()
time.sleep(5)
macchie = img.findBlobs()
img.show()
time.sleep(5)
print “Areas: “, macchie.area()
print “Angles: “, macchie.angle()
print “Centers: “, macchie.coordinates()


Takže jsme prohledali obrázek a výstupem je:

Areas:  [  10.    10.5   13.5   27.5  136. ]
Angles:  [ 75.96375561  90.         -78.69007111  90.          90.        ]
Centers:  [[201 324]
 [200 308]
 [176 440]
 [596 361]
 [177 462]]

Výstup je zajímavý, ale trochu nepraktický. Lepší by bylo detekovat předmět dle barvy... resp. zda se daná barva na obrázku nachází včetně "příbuzných" barev, což jsou barvy trošku odlišné od referenční... a to bude v následující ukázce.

Příklad 4) Vyhledávání barvy z obrázku



#!/usr/bin/pythonimport subprocess
from SimpleCV import Color, Image
import time


subprocess.call(“raspistill -n -w %s -h %s -o Obr5_1.png” % (640, 480), shell=True)
img = Image(“Obr5_1.png”)
img.show()
time.sleep(5)
colore = (22,36,75)
blue_distance = img.colorDistance(colore).invert()
blobs = blue_distance.findBlobs()
blobs.draw(color=Color.BLACK, width=4)
blue_distance.save(“Obr5_2.png”)
blue_distance.show()
time.sleep(5)
img.addDrawingLayer(blue_distance.dl())
img.save(“Obr5_3.png”)
img.show()
time.sleep(5)





 Výsledkem je detekce modrých ploch. 

Příklad 5) Detekce hran  objektů

#!/usr/bin/python
import subprocess
from SimpleCV import Color, Image
import time

subprocess.call("raspistill -n -w %s -h %s -o Obr6_1.png" % (800, 600), shell=True)
img = Image("Obr6_1.png")
img.show()
time.sleep(2)

lines = img.findLines(threshold=150)
lines.draw(color=Color.RED, width=2)
img.save("Obr6_2.png")
img.show()
time.sleep(5)



U funkce threshold lze měnit úroveň rozpoznání. 





Příklad 6) Nalezení kruhů na obrázku

#!/usr/bin/python
import subprocess
from SimpleCV import Color, Image
import time

subprocess.call(“raspistill -n -w %s -h %s -o Obr6_1.png” % (640, 480), shell=True)
img = Image(“
Obr6_1.png”)
img.show()
time.sleep(5)
cerchi = img.findCircle(canny=250,thresh=200,distance=11)
cerchi.draw(color=Color.GREEN, width=4)
cerchi.show()
time.sleep(5)
cerchi = cerchi.sortArea()
cerchi[0].draw(color=Color.RED, width=4)
img_with_circles = img.applyLayers()
img_with_circles.save(“
Obr6
_2.png”)
img_with_circles.show()
time.sleep(5)