W dzisiejszym poście, zamierzam podzielić się tym jak ustanowić komunikację USB pomiędzy Androidem a Arduino. Stworzyłem wcześniej wiele projektów, w których połączyłem Androida i Arduino i komunikowałem się między nimi, ale w tych projektach, jako trybu komunikacji, używałem albo Wi-Fi albo Bluetooth. Ale ostatnio dostałem projekt, w którym muszę użyć komunikacji USB między Androidem i Arduino, mając ograniczenie konieczności korzystania z USB. Musiałem więc nad tym popracować i udało mi się to zrobić. Powinieneś również rzucić okiem na tekst Jak zainstalować Android Studio oraz Rozpoczęcie pracy z Androidem.
Dlatego dziś pomyślałam, żeby się nim z Wami podzielić. Nie jest to bardzo trudne, ale będzie wymagać trochę cierpliwości. Kiedy zacząłem nad nim pracować, nie mogłem znaleźć w sieci żadnych danych na jego temat i musiałem się sporo napracować, żeby go uruchomić. Dlatego więc dzielę się nim, aby inni mogli go łatwo uzyskać. Kiedy zaczynałem ten projekt, nie byłem pewny, czy użyć nakładki (Shield) USB Host z Arduino, czy użyć przewodu USB, przez który łączymy Arduino z komputerem. Po pewnych poszukiwaniach wpadłem na pomysł, że zwykłe USB będzie dobrze działać, więc właśnie jego użyłem. Ten poradnik zawiera szczegółowe wyjaśnienia. Najpierw zrobiłem część Arduino, ponieważ jest ona dość łatwa, a potem zabrałem się za część Androida, która jest trochę bardziej skomplikowana i trzeba mieć wcześniejszą wiedzę na ten temat, jeśli chcemy, aby wszystko dobrze działało. Tak więc, rozpocznijmy ten projekt.
Projektowanie obwodu do monitorowania danych przychodzących
Po pierwsze, użyłem przewodu OTG do połączenia Androida z Arduino, co jest pokazane na poniższym rysunku:
Z powyższego rysunku wyraźnie widać, dlaczego użyłem tego przewodu, jedna jego strona, którą jest mini USB, będzie podłączona do telefonu z Androidem, podczas gdy druga, która jest żeńskim portem USB, będzie podłączona do przewodu USB Arduino, jak pokazano poniżej:
Na powyższym rysunku podłączyłem dwa przewody. Teraz jeden koniec tego przewodu będzie włożony do telefonu z systemem Android, podczas gdy druga strona będzie podłączona do Arduino i w ten sposób ustanowimy komunikację USB między Androidem i Arduino.
Ale jest pewien problem. Potrzebujemy jakiegoś sposobu na wyświetlenie w Arduino danych, które dostajemy z Androida. Z tego też powodu, połączyłem kolejne Arduino z tym Arduino i używam komunikacji szeregowej pomiędzy tymi dwoma urządzeniami.
Tak więc, w prostych słowach, Android jest podłączony do pierwszego Arduino przez USB, a pierwsze Arduino jest połączone z drugim Arduino przez port szeregowy. Zatem, kiedy Android wyśle dane do pierwszego Arduino, wtedy wyśle ono te dane do drugiego Arduino, co możemy łatwo zobaczyć na terminalu szeregowym. Oto schemat połączeń dwóch Arduino.
Teraz można mieć pojęcie, zgodnie z powyższym rysunkiem, że dwa Arduino komunikują się przez Pin 2. i 3., które ustawiłem jako szeregowe w oprogramowaniu. Teraz piny wysyłają dane z pierwszego Arduino do drugiego Arduino. Przyjrzyjmy się teraz kodowaniu obu Arduino.
Kod programistyczny dla Arduino
Jak w powyższej sekcji, połączyliśmy dwa Arduino poprzez komunikację szeregową, w której użyliśmy połączenia szeregowego z poziomu oprogramowania.
Następną rzeczą, którą musimy zrobić jest napisanie kodu dla obu z nich, więc wystarczy skopiować poniższy kod i wgrać go do obu płytek Arduino.
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2,3);
void setup()
{
Serial.begin(9600);
Serial.println("www.TheEngineeringProjects.com");
mySerial.begin(9600);
mySerial.println("www.TheEngineeringProjects.com");
}
void loop()
{
if (mySerial.available())
Serial.println(mySerial.read() - 48);
if (Serial.available())
mySerial.println(Serial.read() - 48);
}
Powyższy kod jest dość prosty i zwyczajnie wysyłam wszelkie dane, które otrzymuję na porcie szeregowym do oprogramowania szeregowego. Zatem kiedy dostaję dane z Androida przez USB, otrzymam te dane, a następnie przekażę je do oprogramowania szeregowego, do którego podłączone jest moje drugie Arduino, które otrzyma te dane, a następnie pokaże je do terminala szeregowego.
Teraz przyjrzyjmy się kodowi po stronie Androida, który jest nieco skomplikowany.
Programowanie kodu dla Androida
Trzeba mieć wcześniejszą styczność z Androidem, jeśli chcemy, aby to działało. Zatem jeśli znasz podstawy Androida, to wiesz, że istnieją dwa główne pliki zaprojektowane w Androidzie, które są plikami Java i XML.
Tak więc, najpierw stwórz projekt w Androidzie i umieść poniższy kod w jego pliku XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidusbhostarduino.MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://www.TheEngineeringProjects.com/"
android:textStyle="bold" />
<ToggleButton
android:id="@+id/arduinoled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textOn="ON"
android:textOff="OFF" />
</LinearLayout>
Następną rzeczą jaką musimy zrobić jest dodanie uprawnienia USB w pliku manifestu, więc wklej poniższy kod do swojego pliku manifestu:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.theengineeringprojects.dani" >
<uses-feature android:name="android.hardware.usb.host" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>
</manifest>
Teraz ostatnia rzecz, którą musisz zrobić to dodać kod do pliku Java, więc skopiuj poniższy kod i wklej go do swojego pliku Java:
package com.theengineeringprojects.dani;
import java.nio.ByteBuffer;
import android.support.v7.app.ActionBarActivity;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbRequest;
import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.SeekBar;
import android.widget.ToggleButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
public class MainActivity extends ActionBarActivity implements Runnable{
private static final char CMD_LED_OFF = '1';
private static final char CMD_LED_ON = '2';
SeekBar bar;
ToggleButton buttonLed;
private UsbManager usbManager;
private UsbDevice deviceFound;
private UsbDeviceConnection usbDeviceConnection;
private UsbInterface usbInterfaceFound = null;
private UsbEndpoint endpointOut = null;
private UsbEndpoint endpointIn = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonLed = (ToggleButton)findViewById(R.id.arduinoled);
buttonLed.setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(isChecked){
sendCommand(CMD_LED_ON);
}else{
sendCommand(CMD_LED_OFF);
}
}});
usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
}
@Override
public void onResume() {
super.onResume();
Intent intent = getIntent();
String action = intent.getAction();
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
setDevice(device);
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
if (deviceFound != null && deviceFound.equals(device)) {
setDevice(null);
}
}
}
private void setDevice(UsbDevice device) {
usbInterfaceFound = null;
endpointOut = null;
endpointIn = null;
for (int i = 0; i < device.getInterfaceCount(); i++) {
UsbInterface usbif = device.getInterface(i);
UsbEndpoint tOut = null;
UsbEndpoint tIn = null;
int tEndpointCnt = usbif.getEndpointCount();
if (tEndpointCnt >= 2) {
for (int j = 0; j < tEndpointCnt; j++) {
if (usbif.getEndpoint(j).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (usbif.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_OUT) {
tOut = usbif.getEndpoint(j);
} else if (usbif.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_IN) {
tIn = usbif.getEndpoint(j);
}
}
}
if (tOut != null && tIn != null) {
// Ten interfejs posiada zarówno USB_DIR_OUT
// i USB_DIR_IN z USB_ENDPOINT_XFER_BULK
usbInterfaceFound = usbif;
endpointOut = tOut;
endpointIn = tIn;
}
}
}
if (usbInterfaceFound == null) {
return;
}
deviceFound = device;
if (device != null) {
UsbDeviceConnection connection =
usbManager.openDevice(device);
if (connection != null &&
connection.claimInterface(usbInterfaceFound, true)) {
usbDeviceConnection = connection;
Thread thread = new Thread(this);
thread.start();
} else {
usbDeviceConnection = null;
}
}
}
private void sendCommand(int control) {
synchronized (this) {
if (usbDeviceConnection != null) {
byte[] message = new byte[1];
message[0] = (byte)control;
usbDeviceConnection.bulkTransfer(endpointOut,
message, message.length, 0);
}
}
}
@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(1);
UsbRequest request = new UsbRequest();
request.initialize(usbDeviceConnection, endpointIn);
while (true) {
request.queue(buffer, 1);
if (usbDeviceConnection.requestWait() == request) {
byte rxCmd = buffer.get(0);
if(rxCmd!=0){
bar.setProgress((int)rxCmd);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
} else {
break;
}
}
}
}
Teraz naciśnij przycisk Enter w Android Studio i jeśli wszystko pójdzie dobrze, otrzymasz na telefonie komórkowym ekran, jaki pokazano poniżej:
Oto prosty przycisk. Kiedy go naciśniesz, pokaże ON i wyśle dane, które chcesz wysłać. W moim przypadku, wysyłam znak "1" i "2" po naciśnięciu przycisku.
Komunikacja USB pomiędzy Androidem i Arduino
Teraz ustanówmy komunikację USB pomiędzy Androidem i Arduino. Mam nadzieję, że do tej pory skonfigurowałeś telefon z systemem Android i oba Arduino tak, że ogólnie będą wyglądać tak jak poniżej:
Na powyższym rysunku widać wyraźnie, że telefon z Androidem jest połączony z Arduino, które jest dalej połączone z drugim Arduino, a USB drugiego Arduino jest połączone z komputerem, gdzie sprawdzam dane przychodzące z Androida w terminalu szeregowym.
Teraz, gdy nacisnę przycisk na aplikacji Android, wyśle 1 lub 2 do Arduino, co jest pokazane na poniższym rysunku:
Nacisnąłem przycisk przełączania na Androidzie wiele razy, dlatego mam wiele 1 i 2 w terminalu szeregowym.
W ten oto sposób odbieram dane z Androida do Arduino. Teraz zamiast wysyłać 1 i 2, możesz wysyłać dowolny rodzaj danych z Androida do Arduino. Będę zamieszczał kolejne poradniki, w których będę wysyłał dane takie jak współrzędne GPS z Androida do Arduino. Będę również zamieszczał komunikację dwukierunkową, czyli odbieranie danych z Androida do Arduino.
Część dotycząca Arduino jest dość łatwa. Za to część dotycząca Androida jest wręcz przeciwnie, więc jeśli potrzebujesz pomocy, pytaj, a ja chętnie pomogę. To wszystko na dziś.