android things in action
TRANSCRIPT
Giovanni di Gialluca - Stefano Sanna
in action!2017-04-06
WE WILL TALK ABOUT…
Physical World Cloud
TIMELINE2008
2011
2014
2015
2016
FEEL AT HOME…Same architectureSame IDE (Android Studio)Same programming languagesSame frameworkSame app (Activity) lifecycleSame UI widgets (UI?)Same application packagingSame reliable security for apps and firmwareSame passionate community!
… MORE OR LESS! Where is the UI?
IN & OUT
CastDriveFirebase AnalyticsFirebase Cloud MessagingFirebase Realtime DatabaseFirebase Remote ConfigFirebase StorageFitInstance IDLocationNearbyPlacesMobile Vision
AdMobAndroid PayFirebase App IndexingFirebase AuthenticationFirebase Dynamic LinksFirebase InvitesFirebase NotificationsMapsPlay GamesSearchSign-In
CalendarContractContactsContractDocumentsContractDownloadManagerMediaStoreSettingsTelephonyUserDictionaryVoicemailContract
Basic rule: “is there any UI for the user to interact why the app?”
BOARDS FOR PROTOTYPING
Intel Edison Intel Joule NXP Pico i.MX6UL Raspberry Pi3
PRICE $55 > $200 $70 $22
SDK PRICE $150 > $300 - $22
CPU Atom DC @500Mhz Atom QC @1.5GHz NXP i.MX6Ultralite ARM Cortex A7 @500MHz
Broadcom BCM2837 QC @1.2GHz Cortex A53
RAM 1GB 3-4GB 512MB 1GB
STORAGE 4GB 8-16GB 4GB microSD
DISPLAY NO HDMI NO HDMI
CAMERA NO CSI-2 NO CSI-2
AUDIO USB 2.0 USB 2.0 3.5mm Analog USB 2.0 & 3.5mm Analog
NET WiFi n, BT 4.0 WiFi ac, BT 4.2 Ethernet, WiFi n, BT 4.1 GB Ethernet, WiFi n, BT 4.1
USB USB 2.0 OTG 2x USB 2.0 HOST + USB 3.0 OTG
USB 2.0 HOST + USB 2.0 OTG 4x USB 2.0 HOST
GPIO 2x UART, 2x I2C,SPI 2ch, 14 GPIO
4x UART, 5x I2C, 2x SPI, up to 48 GPIO
8x UART, 4x I2C, 4x SPI, > 20 GPIO
2x UART, 2x I2C, 2x SPI, up to 26 GPIO
WHICH BOARD?
• Intel Edison • Damn small!• No UI, no Ethernet• ADB via USB
• Raspberry Pi3• Damn cheap!• Ethernet + WiFi• HDMI + Camera + lot of
extension boards: AI+VR+IoT!• Different configurations can be tested just swapping the SD
ANDROID THINGS vs ANDROID
Current supported boards lack some of “universally available” features of any Android Device:
• Bluetooth is no supported in DP2
• Latest news: added in DP3, released April 6th!• There is no RTC: PKI support may be broken unexpectedly• RPi3 has OS on a removable memory: security risk• Any “visual alarm” on battery level: must be monitored manually• There is no GPS onboard: location must be fed with NMEA
stream• No Power-button (adb shell reboot -p)
“Hello Things”
System.out.println(“Hello World!”)System.out.println(“Hello World!”)
“Hello Things”
dependencies { provided 'com.google.android.things:androidthings:0.2-devpreview'}
app/module build.gradle
<application… ><uses-library android:name=“com.google.android.things”/><activity android:name=“.HomeActivity">
<intent-filter> <action android:name=“android.intent.action.MAIN"/> <!-- Launch activity automatically on boot --> <category android:name="android.intent.category.IOT_LAUNCHER"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter>
</activity></application>
AndroidManifest.xml
“Hello Things”public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
PeripheralManagerService service = new PeripheralManagerService();
mLedGpio = service.openGpio(“IO13”);mLedGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
new Thread(new Runnable() { public void run() { for (int i=0;i<10;i++) { try { mLedGpio.setValue(i%2 == 0);
Thread.sleep(250); } catch (Exception e) { // uh! uh! } } } }).start();
}}
longer pin
330 ohm
GPIO: • Two logical values and two electric states:
• true or false, high or low • Change association using gpio.setActiveType()
• Gpio.ACTIVE_HIGH • Gpio.ACTIVE_LOW
GPIO1
2 PWM
3 ANALOG
PeripheralManagerService manager = new PeripheralManagerService();List<String> portList = manager.getGpioList();
mGpio = manager.openGpio(portList.get(0));
mGpio.setValue(true | false); // writeboolean state = mGpio.getValue(); // read
PERIPHERAL I/O
GPIO1
2 PWM
3 ANALOG
GpioCallback mGpioCallback = new GpioCallback() { @Override public boolean onGpioEdge(Gpio gpio) { // Read the active low pin state
mDevice.getValue()
// Continue listening for more interrupts return true; }
@Override public void onGpioError(Gpio gpio, int error) {
//oh nooo }};
mGpio.setEdgeTriggerType(EDGE_BOTH);// |EDGE_NONE | EDGE_RISING | EDGE_FALLINGmGpio.registerGpioCallback(mGpioCallback);
PERIPHERAL I/O
PWM: • Signal Specs
(Frequency & DutyCycle) • Use it to drive Servo Motors
GPIO1
2 PWM
3 ANALOGPERIPHERAL I/O
PERIPHERAL I/O
PeripheralManagerService manager = new PeripheralManagerService(); List<String> portList = manager.getPwmList(); //List of all PWM portsPwm mPwm = manager.openPwm(portList.get(0));
open connection
mPwm.setPwmFrequencyHz(50); mPwm.setPwmDutyCycle(7.5);mPwm.setEnabled(true); //start pulsing
setup connection
Signal 5V
GND
50HZ , 7.5% -> Neutral position(90°)50HZ , 3.75% -> Min position (0°)50HZ , 11.25% -> Max position (180°)
Values for this servo
GPIO1
2 PWM
3 ANALOG
Analog Signal: • Hardware available only on Intel Edison Arduino
Breakout Board • Not supported yet on Android Things • For the moment use external analog-to-digital
converter (ADC)
PERIPHERAL I/O
mcp3008adc0832
GPIO1
2 PWM
3 ANALOG
ADC0832
• 2 channel Analog to digital converter
Start communication
Analog input
Power
Clock
Output
Channel selection
gpioD0.setDirection(Gpio.DIRECTION_IN); gpioD1.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH); gpioCLK.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH); gpioCS.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
open connectionsDRIVER ADC0832
for (int i = 0; i < 8; i++) { // Read 8 bits from ADC gpioCLK.setValue(true); //Clock signal gpioCLK.setValue(false); ad = ad << 1; boolean value = gpioD0.getValue(); if (value) ad |= 0x01; }
read the analog value
for (int i = 0; i < 3; i++) { // Input MUX address if (i == 0 || i == 1 || channel == 1) gpioD1.setValue(true); else gpioD1.setValue(false); gpioCLK.setValue(true); //Clock signal gpioCLK.setValue(false); }
channel selection
allprojects {repositories {
...maven { url 'https://jitpack.io' }
}}
root build.gradle
DRIVER ADC0832
dependencies {compile ‘com.github.User:Repo:Tag' //AVAILABLE SOON
}
add dependency
SPI
1
2
I2C
3
UART
SERIAL COMMUNICATION
PeripheralManagerService manager = new PeripheralManagerService();
List<String> mI2Cs = manager.getI2cBusList();
List<String> mUARTs = manager.getUartDeviceList();
List<String> mSPIs = manager.getSpiBusList();
• Synchronous, fixed clock speed, half-duplex, master-slave (SW), low boundrate
• Peripheral specs: addresses for all connected slave, addresses for all information, MSB only
• Connection: • Shared clock signal (SCL) • Shared data line (SDA) • Common ground reference (GND)
The world of addressesI2C
PeripheralManagerService manager = new PeripheralManagerService();
I2cDevice mI2C = manager.openI2cDevice(I2C_DEVICE_NAME, I2C_ADDRESS);
SPI
1
2
I2C
3
UART
byte value = mI2C.readRegByte(address);mI2C.writeRegByte(address, value);
byte[] data = new byte[3];mI2C.readRegBuffer(startAddress, data, data.length);mI2C.writeRegBuffer (startAddress, data, data.length)
read / write register
read / write buffer
read / write word
short value = mI2C.readRegWord(address); //2 byte Little EndianmI2C.writeRegWord(address, value);
System Management Bus (SMBus)
S slave address register address S slave address data[N] S
I2C SPI
1
2
I2C
3
UART
UART
• The simplest serial, often used for expansion boards or even home appliances, often for logging
• Description: point to point, asynchronous (no clock), full duplex • Peripheral specs: boundrate, parity bit, data size, stop bit • Interface: 3 basic wires TX, RX, GND + 2 optional wires:
request to send (RTS) and clear to send (CTS)
SPI
1
2
I2C
3
UART
PeripheralManagerService manager = new PeripheralManagerService();UartDevice mUart = manager.openUartDevice(UART_DEVICE_NAME);
mUart.setBaudrate(115200);
// 8N1mUart.setDataSize(8);mUart.setParity(UartDevice.PARITY_NONE); mUart.setStopBits(1);
//enable/disable HW flow controlmUart.setHardwareFlowControl(UartDevice.HW_FLOW_CONTROL_AUTO_RTSCTS);mUart.setHardwareFlowControl(UartDevice.HW_FLOW_CONTROL_NONE);
open connection
set configuration
UART SPI
1
2
I2C
3
UART
mUart.write(buffer, buffer.length);mUart.read(buffer, buffer.length))
send/read data
mUart.registerUartDeviceCallback(new UartDeviceCallback() { @Override public boolean onUartDeviceDataAvailable(UartDevice uart) { byte[] buffer = new byte[20]; int count; try { while ((count = uart.read(buffer, buffer.length)) > 0) { Log.d("TAG", "Read " + count + " bytes from peripheral"); } } catch (IOException e) { Log.d("TAG", "Unable to access UART device");} return true; // Continue listening for more interrupts } @Override public void onUartDeviceError(UartDevice uart, int error) { Log.d("TAG", "UART device error: " + error); } });
listening for data
UART SPI
1
2
I2C
3
UART
SERIAL COMMUNICATION - PRACTICE
I2C UART
USB
BMP280 TTL-USB converter Terminal
Logic Level Converter or jumper on Intel Edison Arduino Breakout board
Serial communication trick
• Full duplex, synchronous, master-slave (HW) • Params: Frequency, BPW, MSB/LSB, CLOCK mode • Connection:
• 2 Bus lines • Master Out Slave In (MOSI) • Master In Slave Out (MISO)
• Clock [CLK] • Slave selection pin [CS or SS]
SPI SPI
1
2
I2C
3
UART
// Shift data out to slavemSpi.write(buffer, buffer.length);
// Read the responsebyte[] response = new byte[32];mSpi.read(response, response.length);
byte[] response = new byte[buffer.length];mSpi.transfer(buffer, response, buffer.length);
half duplex
full duplex
mSpi.setMode(SpiDevice.MODE0); // MODE0 | MODE1 | MODE2 | MODE3mSpi.setFrequency(500000); // 500 KHzmSpi.setBitsPerWord(8); // 8 BPWmSpi.setBitJustification(false); // MSB first
set configuration
PeripheralManagerService manager = new PeripheralManagerService();mSpi = manager.openSpiDevice(SPI_DEVICE_NAME);
open connectionSPI SPI
1
2
I2C
3
UART
THE EQUATION OF FUN
+ +
=
+
BRICKPI3
• Raspberry Pi3 extension module that provides:• 4 Mindstorms NXT/EV3 Motor ports• 4 Mindstorms NXT/EV3 Sensor ports• Extra I2C sensor bus• SPI interface to Raspberry Pi3• Uniform request/response binary protocol• Seamless power management (internal, external,
both)
NEVER FORGET TO READ THE RELEASE NOTES!
NEVER FORGET TO READ THE RELEASE NOTES!
List<String> portList = mManager.getGpioList(); for (String gpioName: portList) { Gpio gpio; if (gpioName.equals("BCM4") || gpioName.equals("BCM5") || gpioName.equals("BCM6")) { gpio = mManager.openGpio(gpioName); gpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW); gpio.setActiveType(Gpio.ACTIVE_HIGH); gpio.setValue(false); gpio.close(); } }
BRICKPI3 LOW LEVEL PROTOCOLREQUEST (NO RESPONSE)
TARGET DEVICE MESSAGE PARAM
0 0x01 1 byte optional
TARGET DEVICE MESSAGE PADDING PADDING CHECK RESPONSE PAYLOAD
0 0x00 0x00 0x00 0x00 0xA5N bytes according
to expected response length
TARGET DEVICE MESSAGE PARAM RESPONSE BUFFER
0 0x01 1 byte optional2+N bytes according
to expected response length
REQUEST (WITH RESPONSE)
RESPONSE
BRICKPI3 LOW LEVEL PROTOCOL
0x01 // target device 0x14 + portNumber // message “set sensor type” on porttype // sensor type
Example: 0x01 0x14 0x05 // set sensor type NXT TOUCH on port 0
SET SENSOR TYPE
BRICKPI3 LOW LEVEL PROTOCOL
0x01 // target device 0x18 + portNumber // message “read sensor data” on port0x00 0x00 // padding0x00 … 0x00 // expected response payload length
Example: 0x01 0x18 0x00 0x00 0x00 0x00 0x00 // read sensor on port 0
READ SENSOR DATA REQUEST
0x00 0x00 0x00 // header (?) 0xA5 // fourth byte must be 0x0A5 if message is valid0x** … 0x** // response payload
Example: 0x00 0x00 0x00 0xA5 0x05 0x00 0x01 // touch sensor is pressed
READ SENSOR DATA RESPONSE
Message is valid
It is a touch sensorData sample is valid
Button is pressed
BRICKPI3 LOW LEVEL PROTOCOL
public void setSensorType(int port, int type) { byte[] request = { 0x01; // target device (byte) (0x14 + port), // message “set sensor type” (byte) (type) // sensor type }; mSpi.write(request, request.length); }
SET SENSOR TYPE
BRICKPI3 LIBRARY FOR ANDROID THINGS
BrickPi4 mBrick = BrickPi3.getInstance(); mBrick.open(); mBrick.setSensorType(BrickPi3.SENSOR_PORT.S4, BrickPi3.SENSOR_TYPE.NXT_TOUCH);
if (mBrick.isPressed(BrickPi3.SENSOR_PORT.S4)) { mBrick.setMotorSpeed(BrickPi3.MOTOR_PORT.A, (byte) 80); mBrick.setMotorSpeed(BrickPi3.MOTOR_PORT.D, (byte) 80);}
SET SENSOR TYPE, READ SENSOR DATA AND START MOTORS!
mBrick.setSensorType(BrickPi3.SENSOR_PORT.S1, BrickPi3.SENSOR_TYPE.EV3_ULTRASONIC_CM);
if (mBrick.getDistanceInCm(BrickPi3.SENSOR_PORT.S1) < 20) { mBrick.setMotorSpeed(BrickPi3.MOTOR_PORT.A, (byte) -60); mBrick.setMotorSpeed(BrickPi3.MOTOR_PORT.D, (byte) 60); // sleep while rover rotates…}
DEMO, PLEASE!
CONCLUSIONS
Android Things is for IoT what Android has been for mobile devices: power, richness, simplicity, full access to the cloud!
Android Things brings unexpected potential to developers, makers and enables the entire IoT industry with a powerful platform ready-to-run.
Looking forward to seeing “powered by “ logo in our next appliances!
RESOURCES
• Android Things• https://developer.android.com/things/index.html
• BrickPi3 Protocol• https://www.dexterindustries.com/BrickPi
• LEGO Mindstorms• https://www.lego.com/mindstorms/
• Link to source code will be added in the public version of this presentation
SPEAKERS
• Giovanni Di Gialluca• [email protected]• https://www.linkedin.com/in/giovanni-di-gialluca-9237a776
• Stefano Sanna• [email protected]• @gerdavax• https://www.linkedin.com/in/gerdavax