Ich biete Ihnen, liebe Leser von GeekTimes, einen weiteren Artikel aus dem Zyklus über die Verwendung des ESP8266-Chips als drahtlose Brücke für AVR-Mikrocontroller am Beispiel der Hardwareplattform Arduino Uno (Nano) an. Dieses Mal verwenden wir
für den Flug zum Mond zur Steuerung der Plattform ein auf ANDROID basierendes Gerät anstelle eines Computers. Zum Beispiel ein Smartphone.

Details unter dem Schnitt:
Für unsere Arbeit werden wir die im vorherigen Artikel beschriebenen Tools verwenden - den drahtlosen Programmierer BABUINO und das MPDE-Modul (Modul für Programm- und Datenaustausch) zum Flashen in ESP8266.
Wie sich aus den Rückmeldungen der Benutzer herausstellte, kam der Programmierer selbst im Allgemeinen vor Gericht und einige Personen nutzten ihn sogar erfolgreich. Nun, im Grunde ist die Sache wirklich praktisch; Ich habe die Anwendung unter Windows gestartet, die Hex-Datei aus dem gewünschten Ordner ausgewählt und das war alles - in wenigen Sekunden das Programm auf dem richtigen Gerät ohne Kabel. Eine andere Sache ist, dass ich vergeblich mit übermäßigem Eifer ARDUINO-Software-Benutzer angegriffen habe, die in Wiring C schreiben und die ARDUINO-IDE mit ihren Skizzen und Bibliotheken verwenden. Natürlich tut jeder das, was für ihn bequem ist - ob in Arduin Wiring C oder C von AVR Studio. Am Ende entschieden einige Benutzer aus irgendeinem Grund sofort, dass der Programmierer in keiner Weise mit der ARDUINO-Software kompatibel ist.
Tatsächlich gibt es natürlich keine Kompatibilitätsprobleme. Stellen Sie auf jeden Fall auch Ihre Skizze zusammen, wo es für Sie bequem ist, den Status einer Hex-Datei zu erhalten, und senden Sie sie genauso einfach über einen drahtlosen Programmierer an Ihr Arduino UNO oder NANO.
Der Datenaustausch unter der ARDUINO-Software verursacht ebenfalls keine Probleme. Schreiben Sie die magischen Linien:
Serial.begin (9600);und dann so etwas wie:
receiveByte = Serial.read (); // lese das Byte aus dem Puffer
oder:
Serial.write (receiveByte); // Byte-Datensatz
Und Sie können ganz ruhig Byte-Streams über WI-FI austauschen. Denn der AVR-Mikrocontroller sendet an ESP8266 und empfängt von dort Bytes über den seriellen UART-Port, mit dem, wie wir sehen können, jeder humanitäre Helfer die Arbeit in Arduino konfigurieren kann.
Nun zurück zum Thema dieses Artikels. Um den Roboter über ein Smartphone steuern zu können, müssen Sie natürlich die entsprechende Anwendung für dieses Smartphone schreiben.
Als eine Person, die diesen Prozess vor einem Monat äußerst vage vorgestellt hat, kann ich jetzt mit aller Verantwortung erklären, dass die Angelegenheit im Wesentlichen nicht kompliziert ist. Es sei denn natürlich, Sie haben zumindest einige Grundkenntnisse auf dem Gebiet von Java.
Beim Schreiben von Android-Anwendungen wird der Quellcode in Java geschrieben und dann mit herkömmlichen Java-Tools in Standard-Java-Bytecode kompiliert. Dann passieren andere interessante Dinge mit dem Code, aber wir brauchen diese Details hier nicht.
Es scheint, dass es immer noch Möglichkeiten gibt, Anwendungen in C für berüchtigte Hardcore-Mitarbeiter zu schreiben, die im Nanosekundenbereich punkten, und es gibt auch irgendwo eine Art Paket zum Übersetzen Ihres Codes aus Python, aber ich kann hier nichts sagen, da ich schon lange die richtige Wahl getroffen habe .
Java und das Android Studio-Softwarepaket - eine integrierte Entwicklungsumgebung (IDE) für die Arbeit mit der Android-Plattform basierend auf der IntelliJ IDEA-Software von JetBrains, dem offiziellen Entwicklungstool für Android-Anwendungen.

Wenn Sie bereits mit der IntelliJ IDEA-Software arbeiten, werden Sie von der vertrauten Benutzeroberfläche angenehm überrascht sein.
Ich habe die Grundlagen des Erstellens von Anwendungen aus dem Buch von B. Phillips und C. Stewart - „ANDROID“ -Programmierung für Profis - kennengelernt. Nach meinem Verständnis betrachten Profis Leser, die mit Java SE zumindest ein wenig vertraut sind. Etwas Archi-Komplexes in diesem Buch Ich habe es nicht gefunden, und für unsere Zwecke werden die ersten zehn Kapitel des Buches völlig ausreichen. Glücklicherweise werden alle Codebeispiele darin angegeben, wenn Sie mit dem oben genannten Android Studio arbeiten.
Debugging-Anwendungen können entweder auf einem Software-Emulator oder direkt auf einem Smartphone ausgeführt werden, indem Sie in den „Entwicklermodus“ wechseln.
In einem früheren Artikel wurde die Wagensteuerung über eine Windows-Anwendung unter Windows beschrieben. Das heißt, der gesamte Code zum Erstellen von HTTP- und UDP-Verbindungen sowie die Steuerlogik sind theoretisch bereits vorhanden. Nachdem wir den Oracle-Slogan „Es ist an einem Ort geschrieben, funktioniert es überall“ übernommen haben, übertragen wir diese Klassen einfach in ein neues Programm für Android-Anwendungen. Die GUI ist jedoch eine grafische Benutzeroberfläche. Aus offensichtlichen Gründen müssen Sie dort bleiben, wo sie war. Auf der anderen Seite wird auf Android alles sehr ähnlich und ziemlich schnell erledigt, sodass wir nicht im Verlierer bleiben.
Stecke einen Finger in den Bildschirm
Also erstellen wir ein neues Projekt "FourWheelRobotControl" in Android Studio.
Dies ist eine einfache Anwendung, die aus Aktivitäten besteht
Klasse MainActivity.javaimport android.content.Context; import android.hardware.Sensor; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private ImageButton mButtonUP; private ImageButton mButtonDOWN; private ImageButton mButtonLEFT; private ImageButton mButtonRIGHT; public static byte direction = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new HTTP_client(40000); new Udp_client(); mButtonUP = (ImageButton) findViewById(R.id.imageButtonUP); mButtonUP.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { direction = 3; } } if (event.getAction() == MotionEvent.ACTION_UP) { direction = 100; } return false; } }); mButtonDOWN = (ImageButton) findViewById(R.id.imageButtonDown); mButtonDOWN.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { direction = 4; Toast.makeText(MainActivity.this, " " + direction, Toast.LENGTH_SHORT).show(); } if (event.getAction() == MotionEvent.ACTION_UP) { direction = 100; } return false; } }); mButtonLEFT = (ImageButton) findViewById(R.id.imageButtonLeft); mButtonLEFT.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { direction = 1; Toast.makeText(MainActivity.this, " " + direction, Toast.LENGTH_SHORT).show(); } if (event.getAction() == MotionEvent.ACTION_UP) { direction = 100; } return false; } }); mButtonRIGHT = (ImageButton) findViewById(R.id.imageButtonRight); mButtonRIGHT.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { direction = 2; Toast.makeText(MainActivity.this, " " + direction, Toast.LENGTH_SHORT).show(); } if (event.getAction() == MotionEvent.ACTION_UP) { direction = 100; } return false; } }); }
und Layout:
Layout /spoiler/ activity_main.xml <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="mikhail_akhmetov.fourweelsrobotcontrol.MainActivity"> <ImageButton android:id="@+id/imageButtonRight" style="@android:style/Widget.Holo.ImageButton" android:layout_width="52dp" android:layout_height="52dp" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" android:background="@android:color/holo_orange_dark" app:layout_constraintBottom_toTopOf="@+id/linearLayout" app:layout_constraintHorizontal_bias="0.417" app:layout_constraintLeft_toRightOf="@+id/imageButtonLeft" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.513" app:srcCompat="@android:drawable/ic_media_ff"/> <ImageButton android:id="@+id/imageButtonUP" style="@android:style/Widget.ImageButton" android:layout_width="52dp" android:layout_height="52dp" android:layout_marginBottom="8dp" android:layout_marginTop="8dp" android:background="@android:color/holo_orange_dark" app:layout_constraintBottom_toTopOf="@+id/imageButtonDown" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.486" app:srcCompat="@android:drawable/arrow_up_float"/> <ImageButton android:id="@+id/imageButtonDown" style="@android:style/Widget.ImageButton" android:layout_width="52dp" android:layout_height="52dp" android:layout_marginBottom="57dp" android:layout_marginLeft="8dp" android:background="@android:color/holo_orange_dark" android:fadingEdge="horizontal" app:layout_constraintBottom_toTopOf="@+id/linearLayout" app:layout_constraintHorizontal_bias="0.487" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:srcCompat="@android:drawable/arrow_down_float" android:layout_marginStart="8dp"/> <ImageButton android:id="@+id/imageButtonLeft" style="@android:style/Widget.ImageButton" android:layout_width="52dp" android:layout_height="52dp" android:layout_marginLeft="94dp" android:layout_marginStart="94dp" android:background="@android:color/holo_orange_dark" app:layout_constraintBottom_toTopOf="@+id/linearLayout" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.513" app:srcCompat="@android:drawable/ic_media_rew" /> <LinearLayout android:id="@+id/linearLayout" android:layout_width="368dp" android:layout_height="227dp" android:layout_marginBottom="11dp" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" android:orientation="vertical" android:weightSum="1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> <TextView android:id="@+id/textViewX" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.28" /> <TextView android:id="@+id/textViewY" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.28" /> <TextView android:id="@+id/textViewZ" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.23" /> </LinearLayout> </android.support.constraint.ConstraintLayout>
Es ist nicht erforderlich, mit Stiften zu schreiben, es wird automatisch nach Ihren Kreationen im Editor generiert.
Jetzt übertragen wir nur zwei Klassen aus dem im vorherigen Artikel angegebenen Programm:
HTTP_client.java import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; public class HTTP_client extends Thread{ int port; String s; public static String host_address="192.168.1.138";
Udp_clent.java import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class Udp_client extends Thread { int i =0; byte [] data = {0}; int udp_port=50000; InetAddress addr; DatagramSocket ds; public Udp_client() { try { ds = new DatagramSocket(); addr = InetAddress.getByName(HTTP_client.host_address); } catch (Exception e) { } start(); } public void run() { while (true) { byte temp = MainActivity.direction; String s = "" + MainActivity.direction; data = s.getBytes(); if(temp!=100 ) { DatagramPacket pack = new DatagramPacket(data, data.length, addr, udp_port); try { ds.send(pack); i=0; Thread.sleep(200); } catch (Exception e) { } } else { if(i==0) { s = "" + 0; data = s.getBytes(); DatagramPacket pack = new DatagramPacket(data, data.length, addr, udp_port); try { ds.send(pack); Thread.sleep(200); } catch (Exception e) { } } i=1;
Das Wesen des Programms bleibt gleich. MainActivity startet zuerst HTTP- und UDP-Clients und fängt dann Tastendrücke und Drücken ab, wobei ein Richtungs-Push-Code gesendet wird, um ein UDP-Paket zu bilden. Und von dort ist schon alles - "vorwärts", "zurück", "links", "rechts" und wenn Sie "Stopp" drücken, verlassen sie über WI-FI in einem Wagen.
Darüber hinaus müssen wir die Datei des sogenannten Manifests, das wiederum hauptsächlich von sich selbst generiert wird, geringfügig ändern.
Ein Manifest ist eine XML-Datei mit Metadaten, die Ihre Android-Anwendung beschreiben. Die Manifestdatei heißt immer AndroidManifest.xml und befindet sich im Verzeichnis app / manifest Ihres Projekts.
Es stimmt, es gibt sehr wenig Arbeit für uns.
Bildschirmdrehung verbieten:
android:screenOrientation="portrait"
Wir erlauben die Arbeit im Internet:
<uses-permission android:name="android.permission.INTERNET"/>
Und hier ist alles komplett.
AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="mikhail_akhmetov.fourweelsrobotcontrol"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:screenOrientation="portrait" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET"/> </manifest>
Beim Start sollten wir etwas sehen wie:

Das ist im Wesentlichen alles. Jetzt kann der Wagen von einem Mobiltelefon aus gesteuert werden. Die Anwendung ist äußerst einfach, da es sich um eine Demo-Anwendung ohne „Pfeifen und Fälschungen“ handelt, z. B. die Suche nach einem Einkaufswagen in einem Heimnetzwerk, das Verbinden, Trennen und andere nützliche Funktionen, die das Leben erleichtern, aber den Code schwer verständlich machen.
Auf der anderen Seite ist die Bedienung mit den Bildschirmtasten dieselbe
"Wie man nur Wodka trinkt, sogar aus dem Nacken - es ist nichts drin, als vor Geist und Aufregung zu schmachten."
Und Venya Erofeev hatte natürlich Recht damit.
Viel interessanter ist es beispielsweise, einen Wagen mit Hilfe von Standardbeschleunigungsmessern desselben Smartphones zu steuern.
Darüber hinaus wird diese Funktion auch sehr einfach durch die sogenannten Absichten implementiert. Es ist wahr, dass es schwieriger ist, eigene Absichten zu erstellen, als fertige zu verwenden. Glücklicherweise verbietet niemand die Verwendung von vorgefertigten.
Beschleunigungsmesser in Massen
Daher ändert sich unser Code in MainActivity (und nur darin) nur minimal.
Variablen für den Beschleunigungsmesser hinzufügen:
private SensorManager mSensorManager; private Sensor mOrientation; private float xy_angle; private float xz_angle;
Wir holen den Sensor selbst aus dem System und registrieren ihn als Hörer.
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Wir implementieren die Listener-Schnittstelle selbst:
public class MainActivity implements SensorEventListener
Und wir werden vier obligatorische Methoden schreiben, von denen wir nur die letzte verwenden werden. Eine Methode, die beim Ändern der Messwerte des Beschleunigungsmessers funktioniert. Eigentlich wollte ich den Beschleunigungsmesser wie normale Peripheriegeräte mit einer Zeitspanne von ca. 100 ms selbst abfragen, da der Verdacht bestand (aufgrund des Namens onChanged), dass die Methode zu oft funktioniert. Aber dort ist alles privat und Feigen für die Schnittstellen, die Sie durchkommen werden.
@Override public void onAccuracyChanged(Sensor sensor, int accuracy) {
Infolgedessen hat MainActivity.java die folgende Form import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.content.Context; import android.hardware.Sensor; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ImageButton; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements SensorEventListener { private ImageButton mButtonUP; private ImageButton mButtonDOWN; private ImageButton mButtonLEFT; private ImageButton mButtonRIGHT; public static byte direction = 100; private SensorManager mSensorManager; private Sensor mOrientation; private float xy_angle; private float xz_angle; private int x; private int y; private TextView xyView; private TextView xzView; private TextView zyView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new HTTP_client(40000); new Udp_client(); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Das Programm zeigt die Sensoren in zwei Achsen auf dem Bildschirm des Smartphones an. Anstelle der dritten Achse, die nicht verwendet wird, wird die Richtungsvariable "Richtung" angezeigt. Dieselben Daten werden in Form eines Byte-Streams in den Warenkorb übertragen. Aufgrund der Tatsache, dass der Stream ein reines Byte ist, ist es jedoch schwierig zu bestimmen, wo sich der Befehl "Vorwärts" oder "Stopp" befindet. Deshalb habe ich einfach gehandelt: Jede Richtung und jeder Neigungswinkel hat ihren eigenen Zahlenbereich. Grob gesagt ist 1-20 "vorwärts" mit der entsprechenden Geschwindigkeit, 21-40 ist "rückwärts" und so weiter. Natürlich wäre es möglich, reine Daten über UDP zu übertragen, und die Steuerbefehle selbst sollten über das TCP-Protokoll eingestellt werden, und dies wäre sicherlich korrekter. Dafür müssen Sie aber das Programm auf dem ESP8266 selbst bearbeiten, was ich noch nicht will.
Der Wagen rollt also durch die Wohnung und reagiert sensibel auf die Hänge meines GalaxyS7, aber selbst das ist, wie die berüchtigte Venya sagte, immer noch nicht so.
„Jetzt biete ich dir das Letzte und das Beste an. "Die Krone der Arbeit, vor allem Belohnungen", wie der Dichter sagte. Kurz gesagt, ich biete Ihnen den Cocktail „Offal Off“ an, ein Getränk, das alles überschattet. Dies ist kein Getränk mehr - es ist die Musik der Sphären. „„
Gibt es in diesem Zeitalter von Siri und Alexa etwas, das deine Hände dreht? Lassen Sie die Sprachsteuerung gehorchen!
Und jetzt hör mir zu!
Ich zitiere:
Tatsächlich ist das Arbeiten mit Spracherkennung und Sprachsynthese in Android sehr einfach. Alle komplexen Berechnungen sind uns in einer recht eleganten Bibliothek mit einer einfachen API verborgen. Sie können diese Lektion auch dann meistern, wenn Sie nur sehr oberflächliche Programmierkenntnisse für Android haben.
Tatsächlich war alles für mich ziemlich ungeschickt, aber höchstwahrscheinlich, weil ich die einfachste Option verwendet habe und mich nicht richtig mit dieser API befasst habe. Alles geschieht auch durch Absichten, mit deren Hilfe wir uns der Google Voice Engine zuwenden, nämlich ihrer Spracherkennungsfunktion. Daher benötigen Sie ein funktionierendes Internet.
Wieder ändert sich nur MainActivity.java, obwohl ich das Layout etwas mehr geändert habe (vier Schaltflächen sind dort jetzt völlig unbrauchbar, eine ist genug).
Folgendes wurde zu MainActivity.java hinzugefügt:
Die gleiche Absicht:
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); intent.putExtra(RecognizerIntent.EXTRA_PROMPT, ", , -??? "); startActivityForResult(intent, Print_Words);
Und was es zurückgibt:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Und er gibt eine Reihe ähnlicher Wörter zurück, und zwar in einer eher "Müllform" mit allen möglichen Klammern und Kommas. Und Sie müssen nur ein Wort wählen, das dem von Ihnen genannten ähnlich ist. Gut und dementsprechend, wenn das Wort "vorwärts" gefangen wird, dann gehen wir vorwärts, wenn "richtig", dann nach rechts und so weiter. Natürlich müssen wir berücksichtigen, wo durch "E" das zusätzliche Komma angebracht ist (ich habe die Klammern abgeschnitten, aber ich hatte nicht genug Kraft für die Kommas).
Insgesamt wurde der Text von MainActivity.java selbst import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; import android.widget.TextView; import java.util.ArrayList; import android.content.Intent; import android.speech.RecognizerIntent; public class MainActivity extends AppCompatActivity { private ImageButton mButtonUP; public static byte direction = 100; public String stroka_otveta; private static final int Print_Words = 100; private TextView EnteredText1; private TextView EnteredText2; public static TextView EnteredText3; private boolean slovo_raspoznano =false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Udp_client(); new HTTP_client(40000); EnteredText1 = (TextView) findViewById(R.id.textViewX);
Nun, bis zum Heap-Layout mit einer Schaltfläche
activity_main.xml. <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="mikhail_akhmetov.fourwheelsrobotandroidvoice.MainActivity"> <ImageButton android:id="@+id/imageButtonUP" style="@android:style/Widget.ImageButton" android:layout_width="160dp" android:layout_height="146dp" android:layout_marginTop="8dp" android:background="@android:color/holo_orange_dark" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@android:drawable/arrow_up_float" android:layout_marginBottom="8dp" app:layout_constraintBottom_toTopOf="@+id/linearLayout"/> <LinearLayout android:id="@+id/linearLayout" android:layout_width="368dp" android:layout_height="227dp" android:layout_marginBottom="11dp" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" android:orientation="vertical" android:weightSum="1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> <TextView android:id="@+id/textViewTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" " android:textColor="@android:color/holo_red_dark"/> <TextView android:id="@+id/textViewX" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.28" /> <TextView android:id="@+id/textViewY" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.28" /> <TextView android:id="@+id/textViewZ" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.23" /> </LinearLayout> </android.support.constraint.ConstraintLayout>
Das Erstaunlichste ist, dass es wirklich reitet und auf die Stimme hört (in der Regel). Aber natürlich die Bremsschnittstelle; während du sagst, bis es erkannt wird und zurückkehren wird; Kurz gesagt, wählen Sie im Voraus eine kleine Geschwindigkeit oder der Raum ist umgekehrt breiter.
Das ist alles für heute, ich werde mich freuen, wenn es mir gefallen hat.
