Programmation et transmission de données à Arduino par voie aérienne à l'aide de l'ESP8266. Troisième partie. Bonjour, ANDROID

Je vous propose, chers lecteurs de GeekTimes, un autre article du cycle sur l'utilisation de la puce ESP8266 comme pont sans fil pour les microcontrôleurs AVR, en utilisant la plate-forme matérielle Arduino Uno (Nano) comme exemple. Cette fois, pour le vol vers la lune pour contrôler la plateforme, nous utilisons un appareil basé sur ANDROID au lieu d'un ordinateur. Eh bien, par exemple, un smartphone.



Détails sous la coupe:

Pour notre travail, nous utiliserons les outils décrits dans l'article précédent - le programmateur sans fil BABUINO et le module MPDE (module de programmation et d'échange de données) pour flasher en ESP8266.

Comme il s'est avéré des commentaires des utilisateurs, le programmeur lui-même, en général, est venu au tribunal et certaines personnes l'ont même utilisé avec succès. Eh bien, fondamentalement, la chose est vraiment pratique; J'ai lancé l'application sous Windows, sélectionné le fichier hexadécimal dans le dossier souhaité et c'est tout - en quelques secondes, le programme dans le bon appareil sans aucun fil. Une autre chose est qu'en vain, avec une ardeur excessive, j'ai attaqué les utilisateurs du logiciel ARDUINO qui écrivent dans Wiring C et utilisent l'ARDUINO IDE avec ses croquis et bibliothèques. Bien sûr, tout le monde fait ce qui lui convient - que ce soit dans Arduin Wiring C ou C du studio AVR. Mais au final, certains utilisateurs pour une raison quelconque ont immédiatement décidé que le programmeur n'était en aucune façon compatible avec le logiciel ARDUINO.

En fait, il n'y a bien sûr aucun problème de compatibilité. Compilez également votre croquis où il vous convient à l'état d'un fichier hexadécimal et envoyez-le tout aussi facilement via un programmeur sans fil à votre Arduino UNO ou NANO.

L'échange de données sous le logiciel ARDUINO ne pose pas non plus de problème. Écrivez les lignes magiques:

Serial.begin (9600);

puis quelque chose comme:

receiveByte = Serial.read (); // lit l'octet du tampon

ou:

Serial.write (receiveByte); // enregistrement d'octets

Et vous pouvez échanger des flux d'octets sur WI-FI très calmement. Pour le microcontrôleur AVR envoie à ESP8266 et reçoit des octets à partir de là via le port série UART, qui, comme nous pouvons le voir, tout humanitaire peut configurer le travail avec lequel dans Arduino.

Revenons maintenant au sujet de cet article. Afin de contrôler le robot via un smartphone, vous devez bien sûr écrire l'application appropriée pour ce smartphone.

En tant que personne qui a présenté ce processus il y a un mois de façon extrêmement vague, je peux maintenant déclarer en toute responsabilité que la question n'est essentiellement pas compliquée. Sauf si bien sûr, vous avez au moins quelques connaissances de base dans le domaine de Java.

Pour l'écriture d'applications Android, le code source est écrit en Java, puis compilé en bytecode Java standard à l'aide d'outils Java traditionnels. Ensuite, d'autres choses intéressantes arrivent au code, mais nous n'avons pas besoin de ces détails ici.

Il semble qu'il y ait encore des possibilités d'écrire des applications en C pour les travailleurs hardcore notoires qui marquent en nanosecondes, et aussi quelque part il y a une sorte de package pour traduire votre code à partir de Python, mais je ne peux rien dire ici, car j'ai fait le bon choix depuis longtemps .

Ainsi, Java et le progiciel Android Studio - un environnement de développement intégré (IDE) pour travailler avec la plate-forme Android basée sur le logiciel IntelliJ IDEA de JetBrains, l'outil de développement officiel pour les applications Android.



Si vous travaillez déjà avec le logiciel IntelliJ IDEA, vous serez agréablement surpris par l'interface familière.

Je me suis familiarisé avec les bases de la construction d'applications à partir du livre de B. Phillips et C. Stewart - Programmation «ANDROID» pour les professionnels. "Si je comprends bien, les professionnels considèrent les lecteurs qui sont au moins un peu familiers avec Java SE. Quelque chose d'archi-complexe dans ce livre Je n'ai pas trouvé, et pour nos besoins, les dix premiers chapitres du livre suffiront, heureusement, tous les exemples de code y sont donnés lorsque vous travaillez avec Android Studio susmentionné.

Le débogage des applications peut être effectué soit sur un émulateur logiciel soit directement sur un smartphone en le basculant en «mode développeur».

Dans un article précédent, le contrôle du chariot via une application Windows sur Windows a été décrit. Autrement dit, tout le code pour créer des connexions HTTP et UDP, ainsi que la logique de contrôle, est déjà présent en théorie. Par conséquent, après avoir adopté le slogan d'Oracle «Il est écrit en un seul endroit, il fonctionne partout», nous transférons simplement ces classes vers un nouveau programme pour les applications Android. Mais l'interface graphique est une interface utilisateur graphique, pour des raisons évidentes, vous devez laisser où elle était. Mais d'un autre côté, sur Android, tout se fait de manière très similaire et assez rapidement, donc nous ne resterons pas dans le perdant.

Piquez un doigt sur l'écran



Nous créons donc un nouveau projet «FourWheelRobotControl» dans Android Studio.
Ceci est une application simple et consistera en une activité

Classe MainActivity.java
import 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; } }); } 

et mise en page:

mise en page
  /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> 


Il n'est pas nécessaire d'écrire avec des stylos, il est généré automatiquement après vos créations dans l'éditeur.

Maintenant, nous transférons simplement deux classes du programme donné dans l'article précédent:

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";//    public String Greetings_from_S; HTTP_client(int port) { this.port = port; start(); } public void run() { try (Socket socket = new Socket(host_address,port)){ PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); pw.println("stop data\r");//  ,    pw.println("data\r");// Greetings with SERVER Greetings_from_S = br.readLine(); if (Greetings_from_S.equals("ready")) { new Udp_client(); } } catch (Exception e) { e.printStackTrace(); } } } 


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;//     } } } } 

L'essence du programme reste la même. MainActivity lance d'abord les clients HTTP et UDP, puis intercepte les pressions sur les boutons et les dépressions, envoyant un code push de direction pour former un paquet UDP. Et à partir de là, tout est déjà - "avant", "arrière", "gauche", "droite" et lorsque vous appuyez sur "stop", ils partent via WI-FI dans un panier.

En plus de tout cela, nous devons légèrement modifier le fichier du soi-disant manifeste, qui, encore une fois, est principalement généré par lui-même.

Un manifeste est un fichier XML avec des métadonnées décrivant votre application Android. Le fichier manifeste est toujours appelé AndroidManifest.xml et se trouve dans le répertoire app / manifest de votre projet.

Certes, il y a très peu de travail pour nous.

interdire la rotation de l'écran:

 android:screenOrientation="portrait" 

Nous autorisons le travail sur Internet:

 <uses-permission android:name="android.permission.INTERNET"/> 

Et ici, tout est complètement.

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> 


Au démarrage, nous devrions voir quelque chose comme:



C'est essentiellement tout. Maintenant, le chariot peut être contrôlé à partir d'un téléphone mobile. L'application est extrêmement simple, car il s'agit d'une application de démonstration sans «sifflets et contrefaçons», comme la recherche d'un panier sur un réseau domestique, la connexion, la déconnexion et d'autres fonctionnalités utiles qui facilitent la vie, mais rendent le code difficile à comprendre.

D'un autre côté, le fonctionnement avec les boutons à l'écran est le même
"Comment boire juste de la vodka, même du cou - il n'y a rien d'autre que languissant d'esprit et d'agitation."
Et Venya Erofeev avait raison, bien sûr.

Il est beaucoup plus intéressant, par exemple, de diriger un chariot à l'aide d'accéléromètres standard du même smartphone.

De plus, cette fonctionnalité est également mise en œuvre très simplement, à travers les soi-disant intentions. Il est vrai que la création de vos propres intentions est plus difficile que l'utilisation de celles toutes faites. Heureusement, personne n'interdit d'utiliser des prêts à l'emploi.

ACCÉLÉROMÈTRE EN MASSES



Par conséquent, notre code dans MainActivity (et uniquement dans celui-ci) changera de manière minimale.

Ajoutez des variables pour l'accéléromètre:

 private SensorManager mSensorManager; private Sensor mOrientation; private float xy_angle; private float xz_angle; 

Nous obtenons le capteur lui-même du système et l'enregistrons en tant qu'auditeur.

 mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); //    mOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //    mSensorManager.registerListener(this, mOrientation, SensorManager.SENSOR_DELAY_NORMAL); 

Nous implémentons l'interface d'écoute elle-même:

 public class MainActivity implements SensorEventListener 

Et nous écrirons quatre méthodes obligatoires dont nous n'utiliserons que la dernière. Une méthode qui fonctionne lors du changement des lectures de l'accéléromètre. En fait, je voulais interroger l'accéléromètre moi-même, comme des périphériques normaux avec une période d'environ 100 ms, car il y avait un soupçon (en raison du nom onChanged) que la méthode fonctionnait trop souvent. Mais là tout est privé et figé pour les interfaces que vous traverserez.

 @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { //    } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); } @Override public void onSensorChanged(SensorEvent event) {} //   

Par conséquent, MainActivity.java prendra la forme suivante
 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); //    mOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //    mSensorManager.registerListener(this, mOrientation, SensorManager.SENSOR_DELAY_NORMAL); xyView = (TextView) findViewById(R.id.textViewX); // xzView = (TextView) findViewById(R.id.textViewY); //       zyView = (TextView) findViewById(R.id.textViewZ);//   "direction" mButtonUP = (ImageButton) findViewById(R.id.imageButtonUP); mButtonDOWN = (ImageButton) findViewById(R.id.imageButtonDown); mButtonLEFT = (ImageButton) findViewById(R.id.imageButtonLeft); mButtonRIGHT = (ImageButton) findViewById(R.id.imageButtonRight); //    } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { //    } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); } @Override public void onSensorChanged(SensorEvent event) { //   xy_angle = event.values[0]*10; // XY xz_angle = event.values[1]*10; // XZ x=-(int) xy_angle*1; y=-(int) xz_angle*1; xyView.setText(" x = "+ String.valueOf(x)); xzView.setText(" y = "+String.valueOf(y)); zyView.setText(" direction "+String.valueOf(direction)); if(y>-40&&y<-20){ direction=100;//   ,   ,     if (x>10){//   10  30  20  direction=(byte)(x+30); if (direction>60){direction=60;} } if(x<-10){ direction=(byte)(-x+50); if (direction>80){direction=80;} } } else { if (y > -20) {//  ,  -20: 20  40  direction = (byte) (y / 2 + 10); if (direction > 20) { direction = 20; } ; } if (y < -40) {//  ,  -40: -80  40  direction = (byte) (-y - 20); if (direction > 40) { direction = 40; } ; } } } } //   direction 100  // 1-20  ,   -20 // 21-40  ,   -40 // 41-60 ,  10 // 61-80 ,   -10 


Le programme affiche les capteurs sur deux axes sur l'écran du smartphone. Au lieu du troisième axe, qui n'est pas utilisé, la variable de direction "direction" est affichée. Et les mêmes données s'exécutent sous la forme d'un flux d'octets vers le panier. Cependant, en raison du fait que le flux est purement octet, il serait difficile de déterminer où serait la commande "forward" ou "stop". C'est ce que j'ai fait: chaque direction et angle d'inclinaison a sa propre plage de nombres. En gros, 1-20 est "en avant" avec la vitesse correspondante, 21-40 est "en arrière" et ainsi de suite. Bien sûr, il serait possible de transmettre uniquement des données via UDP, et les commandes de contrôle elles-mêmes devraient être définies via le protocole TCP, et ce serait certainement plus correct. Mais pour cela, vous devez modifier le programme sur l'ESP8266 lui-même, ce que je ne veux pas encore.

Ainsi, le chariot roule autour de l'appartement, réagissant avec sensibilité aux pentes de mon GalaxyS7, mais même cela, comme le disait la célèbre Venya, n'est toujours pas cela.

«Maintenant, je vous offre le dernier et le meilleur. "La couronne du travail, surtout des récompenses", comme l'a dit le poète. Bref, je vous propose le cocktail «Offal Off», une boisson qui éclipse tout. Ce n'est plus une boisson - c'est la musique des sphères. „

À l'ère de Siri et d'Alexa, y a-t-il quelque chose pour faire tournoyer vos mains? Laissez la commande vocale obéir!

Et maintenant, écoutez-moi!



Je cite:

En fait, travailler avec la reconnaissance vocale et la synthèse vocale dans Android est très simple. Tous les calculs complexes nous sont cachés dans une bibliothèque assez élégante avec une API simple. Vous pouvez maîtriser cette leçon même si vous avez une connaissance très superficielle de la programmation pour Android.

En fait, tout s'est avéré assez maladroit pour moi, mais probablement parce que j'ai utilisé l'option la plus simple et que je n'ai pas creusé correctement dans cette API. Tout se fait également à travers des intentions, à l'aide desquelles nous nous tournons vers le moteur vocal de Google, à savoir sa fonction de reconnaissance vocale. Par conséquent, vous avez besoin d'un Internet fonctionnel.

Encore une fois, seul MainActivity.java change, même si j'ai changé un peu plus la disposition (quatre boutons sont maintenant complètement inutiles, un suffit).

Les éléments suivants ont été ajoutés à MainActivity.java:

La même intention:

 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); 

Et ce qu'il retourne:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { //    : if (requestCode==Print_Words && resultCode==RESULT_OK) { //     ,   : ArrayList<String>result=data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); //     TextView: stroka_otveta = result.toString(); } 

Et il renvoie un tableau de mots similaires, et sous une forme plutôt "poubelle", avec toutes sortes de crochets et de virgules. Et il vous suffit de choisir un mot similaire à celui que vous avez dit. Eh bien et en conséquence, si le mot «en avant» est pris, alors nous allons de l'avant, si «à droite», puis à droite et ainsi de suite. Bien sûr, nous devons prendre en compte où à travers "E", où la virgule supplémentaire est attachée (j'ai coupé les crochets, mais je n'avais pas assez de force pour les virgules).

Au total, le texte de MainActivity.java lui-même est devenu
 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); // EnteredText2 = (TextView) findViewById(R.id.textViewY); // EnteredText3 = (TextView) findViewById(R.id.textViewZ); // 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){ if(HTTP_client.ok){ // RecognizerIntent        : EnteredText3.setText(" http  "); 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); } else { EnteredText3.setText("  "); } } if (event.getAction() == MotionEvent.ACTION_UP ){ } return false; } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { //    : if (requestCode==Print_Words && resultCode==RESULT_OK) { //     ,   : ArrayList<String>result=data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); //     TextView: stroka_otveta = result.toString(); } StringBuffer sb = new StringBuffer(stroka_otveta); sb.deleteCharAt(stroka_otveta.length()-1); sb.deleteCharAt(0); stroka_otveta=sb.toString(); String[] words = stroka_otveta.split("\\s"); //        () //    for(int i = 0; i< words.length;i++) { if(words[i].equals(",")||words[i].equals("")) { direction = 1; slovo_raspoznano=true; stroka_otveta=words[i]; } if(words[i].equals(",")||words[i].equals("")){ direction=2; slovo_raspoznano=true; stroka_otveta=words[i]; } if(words[i].equals(",")|| words[i].equals("")){ direction=4; slovo_raspoznano=true; stroka_otveta=words[i]; } if(words[i].equals(",")|| words[i].equals(",")|| words[i].equals("") || words[i].equals("")){ direction=3; slovo_raspoznano=true; stroka_otveta=words[i]; } if(words[i].equals(",")|| words[i].equals(",")|| words[i].equals("") || words[i].equals("")){ direction=100; slovo_raspoznano=true; stroka_otveta=words[i]; } } if(!slovo_raspoznano){ direction=100; stroka_otveta=" ,   ... "; } EnteredText1.setText(" "+direction+" " +stroka_otveta); slovo_raspoznano=false; super.onActivityResult(requestCode, resultCode, data); } } 

Eh bien, jusqu'à la mise en page du tas avec un seul bouton

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> 

La chose la plus étonnante est qu'elle monte vraiment et écoute la voix (en règle générale). Mais, bien sûr, l'interface de freinage; pendant que vous dites, jusqu'à ce qu'il soit reconnu et revienne; Bref, choisissez une petite vitesse à l'avance ou la pièce est inversement plus large.

C'est tout pour aujourd'hui, je serai content si je l'ai aimé.

Source: https://habr.com/ru/post/fr409107/


All Articles