Telefondan arduino'dan Bluetooth makinesi. Android'den Bluetooth üzerinden orantılı kontrole sahip araba. !!! terminaller, konektörler, kelepçeler değiştirilebilir

Android ve diğer faydalı bilgiler için kaynaklar da vardır. Bu yazımda Arduino platformu için CxemCAR'ın montajını göstereceğim. Hemen hemen tüm Arduino uyumlu kartlar, Arduino kartı olarak kullanılabilir: UNO, Nano, Mega, Leonardo ve hatta STM32 tabanlı Arduino DUE. eBay'den 9 dolara satın alınan bir Arduino Nano V3 kartı kullandım.

HC-06 Bluetooth modülüne ve L298N motor sürücüsüne Arduino bağlantı şeması:

Devrede jumper kullandım (Jmp1 devresinde), çünkü Bluetooth modülü bağlıyken, çizimi Arduino'ya yüklemek imkansızdı. Donanım yazılımı süresince, atlama telinin çıkarılması Bluetooth modülünün enerjisini keser.

Bir platform olarak, 25 dolara satın alınan küçük bir RC DIY platformu kullandım. Platformun kendisi, iki motorun, bir şanzımanın ve 4 tekerlek için 4 kardan dişlinin monte edildiği bir alüminyum tabandır. Yukarıda 3 raf üzerine bir breadboard yerleştirilmiştir.

Platform yüksek kaliteli işçilik değildir. Monte ettikten sonra gücü bağlamaya çalıştım - motorlar hareket etmedi bile, çok fazla bozulma, kusur vb. Her şeyi sökmek, bağlantı elemanlarını biraz gevşetmek, bazı yerlerde keskinleştirmek, her şeyi iyice yağlamak ve ayrıca ön akstan 2 üniversal mafsalı çıkarmak zorunda kaldım. Sonuç, makinenin arkadan çekişli versiyonuydu.

Bundan sonra Bluetooth modülünü Arduino'ya lehimledim ve bunun için bir durum LED'i gösterdim. Bluetooth modüllerinin türleri, Arduino ile bağlantıları, onlarla çalışma vb. bu makalede okuyabilirsiniz:. HC-06 modülü, 10 mm'lik ısıyla daralan bir tüpe yerleştirildi. Akım sınırlama direncine sahip Bluetooth durum LED'i de ısıyla daralan içine yerleştirildi, ancak daha ince - 5 mm.

Platformla birlikte gelen devre tahtasında delikler açtım ve L298N motor sürücüsünü taktım. Arduino kartını çift taraflı bantla yapıştırdım.

Makinenin alüminyum platformu ile breadboard arasına 3 adet Li-Po pil 3.7V 1100 mAh yerleştirdim. Kontrolör ve motorlara ayrı ayrı güç verilir: Arduino, tek bir 3.7V pil ile çalışır ve motorlar ve L298N sürücüsü, seri bağlı iki 3.7V pil ile çalışır. İki adet 2 konumlu güç anahtarı sağlanmıştır - bir konumda pillerden tüketicilere, diğer konumda şarj terminallerine güç sağlanır.

Şarj olurken makinenin fotoğrafı:

Yazılım

Program Arduino IDE 1.01'de yazılmıştır. Program kodu hakkında iyi yorum yapmaya çalıştım ama herhangi bir sorunuz varsa, forumda, .

#include "EEPROM.h" #define D1 2 // motor 1'in dönüş yönü #define M1 3 // Motor 1'i kontrol etmek için PWM pini (sol) #define D2 4 // motor 2'nin dönüş yönü #define M2 5 // motor dönüş yönü 2 (sağ) #define HORN 13 // ekle. kanal 1 pin 13'e bağlı //#define autoOFF 2500 // iletişim kesildiğinde robotun durduğu milisaniye sayısı #define cmdL "L" // Sol motor için UART komutu #define cmdR "R" // UART komutu sağ motor için #define cmdH "H" // ekleme için UART komutu. kanal 1 (örneğin Korna sinyali) #define cmdF "F" // Ayarları saklamak için MK EEPROM belleği ile çalışmak için UART komutu #define cmdr "r" // Ayarları saklamak için MK EEPROM belleği ile çalışmak için UART komutu (oku ) # define cmdw "w" // MK'nin EEPROM belleği ile çalışmak için UART komutu, ayarları saklamak (yazmak) char gelenByte; // gelen veri char L_Data; // sol motor verileri için dizi dizisi L bayt L_index = 0; // dizi indeks karakter R_Data; // sağ motor verileri için dizi dizisi R bayt R_index = 0; // dizi indeksi karakter H_Data; // ek için dize dizisi. kanal baytı H_index = 0; // dizi indeksi H char F_Data; // EEPROM baytı ile çalışmak için string veri dizisi F_index = 0; // dizi dizini F char komutu; // komut: R, L koordinatlarını veya satır sonu imzasız uzun currentTime, lastTimeCommand, autoOFF aktarın; void setup() ( Serial.begin(9600); // port başlatma pinMode(HORN, OUTPUT); // ek kanal pinMode(D1, OUTPUT); // motor dönüş yönünü ayarlamak için çıkış pinMode(D2, OUTPUT); // motor dönüş yönünü ayarlamak için çıkış /*EEPROM.write(0.255); EEPROM.write(1.255); EEPROM.write(2.255); EEPROM.write(3.255);*/ timer_init(); // yazılımı başlat timer) void timer_init() ( uint8_t sw_autoOFF = EEPROM.read(0); // EEPROM'dan "bağlantı kesildiğinde makineyi durdurma işlevidir" parametresini okuyun if(sw_autoOFF == "1")( // durdurma zamanlayıcı etkinleştirilirse char var_Data ; var_Data = EEPROM.read(1); var_Data = EEPROM.read(2); var_Data = EEPROM.read(3); autoOFF = atoi(var_Data)*100; // otomatik kapanma değişkeni ms sayısını saklamak için ) else if(sw_autoOFF == "0")( autoOFF = 999999; ) else if(sw_autoOFF == 255)( autoOFF = 2500; // EEPROM'a hiçbir şey yazılmazsa, varsayılan 2,5 sn'dir) currentTime = millis(); // m'den beri geçen süreyi oku programın başladığı an ) void loop() ( if (Serial.available() > 0) ( // UART verileri geldiyse incomingByte = Serial.read(); // baytı oku if(incomingByte == cmdL) ( // L motoru için veri geldiyse komut = cmdL; // mevcut komut memset(L_Data,0,sizeof(L_Data)); // diziyi temizleme L_index = 0; // dizi indeksini sıfırla ) else if(incomingByte == cmdR) ( // eğer motor R için veri geldiyse komut = cmdR; memset(R_Data,0,sizeof(R_Data)); R_index = 0; ) else if( incomingByte == cmdH) ( // eğer veri eklemek için. kanal 1 komutu = cmdH; memset(H_Data,0,sizeof(H_Data)); H_index = 0; ) else if(incomingByte == cmdF) ( // bellek ile çalışmak için veri geldiyse komut = cmdF; memset(F_Data,0,sizeof(F_Data)); F_index = 0; ) else if(incomingByte == "\r " ) komut="e"; // satır sonu başka if(incomingByte == "\t") komut = "t"; // bellek komutları için satır sonu if(command == cmdL && incomingByte != cmdL)( L_Data = incomingByte; // alınan her baytı L_index++ dizisinde depola; // mevcut dizi dizinini artır ) else if(command == cmdR && incomingByte != cmdR)( R_Data = incomingByte; R_index++; ) else if(command == cmdH && incomingByte != cmdH)( H_Data = incomingByte; H_index++; ) else if(command == cmdF && incomingByte) == cmdF && incomingByte)( F_= cmdH) incomingByte; F_index++; ) else if(command == "e")( // eğer satır sonu alınırsa Control4WD(atoi(L_Data),atoi(R_Data),atoi(H_Data)); delay(10); ) else if ( command == "t")( // Flash_Op(F_Data,F_Data,F_Data,F_Data,F_Data); ) lastTimeCommand = millis(); // programın başlamasından bu yana geçen süreyi oku ) if(millis() >= (lastTimeCommand + autoOFF))( // geçerli zamanlayıcıyı lastTimeCommand + autoOFF Control4WD(0,0,0); // makineyi durdur ) ) void Control4WD(int mLeft, int mRight, uint8_t Horn)( bool directionL, directionR; // L298N byte valueL, valueR için dönüş yönü; // PWM değeri M1, M2 (0-255) if(mLeft > 0)( değerL = mLeft; yönL = 0; ) else if(mLeft< 0){ valueL = 255 - abs(mLeft); directionL = 1; } else { directionL = 0; valueL = 0; } if(mRight >0)( değerR = mRight; yönR = 0; ) else if(mRight< 0){ valueR = 255 - abs(mRight); directionR = 1; } else { directionR = 0; valueR = 0; } analogWrite(M1, valueL); // задаем скорость вращения для L analogWrite(M2, valueR); // задаем скорость вращения для R digitalWrite(D1, directionL); // задаем направление вращения для L digitalWrite(D2, directionR); // задаем направление вращения для R digitalWrite(HORN, Horn); // дополнительный канал } void Flash_Op(char FCMD, uint8_t z1, uint8_t z2, uint8_t z3, uint8_t z4){ if(FCMD == cmdr){ // если команда чтения EEPROM данных Serial.print("FData:"); // посылаем данные с EEPROM Serial.write(EEPROM.read(0)); // считываем значение ячейки памяти с 0 адресом и выводим в UART Serial.write(EEPROM.read(1)); Serial.write(EEPROM.read(2)); Serial.write(EEPROM.read(3)); Serial.print("\r\n"); // маркер конца передачи EEPROM данных } else if(FCMD == cmdw){ // если команда записи EEPROM данных EEPROM.write(0,z1); // запись z1 в ячейку памяти с адресом 0 EEPROM.write(1,z2); EEPROM.write(2,z3); EEPROM.write(3,z4); timer_init(); // переинициализируем таймер Serial.print("FWOK\r\n"); // посылаем сообщение, что данные успешно записаны } }

Kod, AVR EEPROM belleğiyle çalışmak için bir kitaplık kullanır. Bellekte bir ayar saklanır: bağlantı kesildiğinde makinenin durduğu milisaniye sayısı. Bu ayarı programda "zor" olarak ayarlayabilirsiniz, bunu yapmak için #define autoOFF 2500 satırını kaldırın (2500 milisaniye sayısıdır). Bundan sonra, Flash_Op işlevi kaldırılabilir, ayrıca EEPROM belleği ile çalışmak için komutları almaktan sorumlu kodda küçük değişiklikler yapılması gerekecektir.

Bu makale, Android mobil işletim sistemi için küçük bir uygulamanın oluşturulmasını ve Arduino için bir eskizi ayrıntılı olarak anlatacaktır. Arduino Uno, Bluetooth modülüne sahip bir Kablosuz Kalkana sahip olacaktır. Uygulama Bluetooth modülüne bağlanacak ve bazı komutlar gönderecektir. Sırayla, bu komuttaki çizim Arduino'ya bağlı LED'lerden birini yakacak veya söndürecektir.

ihtiyacımız olacak

Android Uygulaması Oluşturma

boşluk

Android işletim sistemi için geliştirme, ADT geliştirme ortamı olan Android Geliştirme Araçları'nda gerçekleştirilir. Hangi Google Geliştirici Portalı'ndan indirilebilir. ADT'yi indirip yükledikten sonra, başlatmaktan çekinmeyin. Ancak, uygulamayı geliştirmeye başlamak için henüz çok erken. Ayrıca gerekli sürümün Android SDK'sını da indirmeniz gerekir. Bunu yapmak için Android SDK Yöneticisi "Pencere → Android SDK Yöneticisi"ni açmanız gerekir. Listede, bizim durumumuzda Android 2.3.3 (API 10) ihtiyacımız olan SDK'yı seçin. Telefon yoksa 2.3.3 veya üstünü seçin; ve varsa, telefonun işletim sisteminin sürümüyle eşleşen bir sürüm. Ardından, yükleme işlemini başlatmak için "Paketleri Kur" düğmesine tıklayın.

İndirme ve kurulum tamamlandıktan sonra uygulamayı oluşturmaya başlıyoruz. "Dosya → Yeni → Android Uygulama Projesi"ni seçin. Pencerenin içeriğini şekilde gösterildiği gibi doldurun.

    Uygulama Adı - Google Play Store'da gösterilecek uygulamanın adı. Ancak uygulamayı yüklemeyeceğiz, bu nedenle isim bizim için özellikle önemli değil.

    Proje Adı - ADT'deki projenin adı.

    Paket Adı - uygulama tanımlayıcısı. Şu şekilde oluşmalıdır: sitenizin adı tersten artı uygulamanın herhangi bir adı.

"Minimum Required SDK", "Target SDK", "Compile With" açılır listelerinde daha önce indirdiğimiz sürümü seçin. SDK'nın daha yeni sürümleri, uygulamalar için grafik temaları desteklerken, eski sürümler desteklemez. Bu nedenle, "Tema" alanında "Yok" seçeneğini seçin. Sonrakine tıkla".

"Özel başlatıcı simgesi oluştur" kutusunun işaretini kaldırın: Bu makalede, bir uygulama simgesi oluşturmaya odaklanmayacağız. Sonrakine tıkla".

Görünen pencerede, "Etkinlik" türünü seçebilirsiniz: uygulama başlatıldığında ekranda ne olacağının türü. Her şeye sıfırdan başlamak istediğimiz anlamına gelen "Boş aktivite"yi seçiyoruz. Sonrakine tıkla".

Uygulamamız sadece bir Aktiviteye sahip olacak, bu yüzden görünen pencerede hiçbir şeyi değiştiremezsiniz. Bu yüzden sadece "Bitir" e tıklayın.

Her şey, uygulamamız oluşturulur.

Öykünücüyü ayarlama

Android uygulamaları, gerçek bir cihazda veya yoksa bir emülatörde hata ayıklanır. Bizimkini yapılandıralım.

Bunu yapmak için "Pencere → Android Sanal Aygıt Yöneticisi"ni çalıştırın. Görünen pencerede "Yeni" ye tıklayın. Açılan formun alanlarını doldurun. Öykünücünün "telefona" ne kadar ve hangi kaynakları sağlayacağı onlara bağlıdır. Makul değerleri seçin ve Tamam'ı tıklayın.

Android Sanal Aygıt Yöneticisi penceresinde "Başlat" düğmesini tıklayın. Bu, öykünücüyü başlatacak. Başlatma birkaç dakika sürer. Bu yüzden sabırlı ol.

Sonuç olarak, buna benzer bir emülatör penceresi göreceksiniz:

Bir Aktiviteyi Doldurma

Etkinlik - uygulama başlatıldıktan sonra telefon ekranında görüntülenen budur. Üzerinde "Kırmızı LED'i yak" ve "Mavi LED'i yak" olmak üzere iki düğmemiz olacak. Onları ekleyelim. Paket Gezgini panelinde res/layout/activity_main.xml dosyasını açın. Görünümü, ekran görüntüsündeki ile yaklaşık olarak aynı olacaktır.

2 "ToggleButton" düğmesini ekran formuna sürükleyip bırakın. "activity_main.xml" sekmesine geçin ve aşağıdaki kodu görün:

aktivite_main_aiutogen.xml xmlns:araçlar = android:layout_width="match_parent" android:layout_height="match_parent" android:paddingbottom= android:paddingLeft = android:paddingRight= "@dimen/activity_horizontal_margin" android:paddingTop = "@dimen/activity_vertical_margin" araçlar:context=".MainActivity" > android:id="@+id/toggleButton1" android:layout_alignParentLeft="doğru" android:layout_alignParentTop ="true" android:text="ToggleButton" /> android:id="@+id/toggleButton2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/textView1" android:layout_alignParentRight="doğru" android:text="ToggleButton" /> >

Bu, grafik olarak gösterilmeyen, ancak XML biçiminde açıklanan Etkinliğimizden başka bir şey değildir.

Bileşen adlarını daha anlaşılır hale getirelim. Android:id alanlarını aşağıdaki gibi değiştirelim.

android:id="@+id/toggleRedLed" ... android:id="@+id/toggleGreenLed" ...

Ayrıca onlara başlıklar ekleyeceğiz, renklerini ve metin boyutlarını değiştireceğiz. Ortaya çıkan işaretleme kodu şöyle görünecektir.

aktivite_main.xml "http://schemas.android.com/apk/res/android" xmlns:araçlar = "http://schemas.android.com/tools" android:layout_width="fill_parent" android:paddingbottom= "@dimen/activity_vertical_margin" android:paddingLeft = "@dimen/activity_horizontal_margin" android:paddingRight= "@dimen/activity_horizontal_margin" android:paddingTop = "@dimen/activity_vertical_margin" araçlar:bağlam=".MainActivity" android:ağırlıkSum="2" android:orientation="yatay" > android:id="@+id/toggleRedLed" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1" android:background="#FF0000" android:textOff="KAPALI" android:textOn="AÇIK" android:textsize="30dp" /> android:id="@+id/toggleGreenLed" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1" android:background="#00FF00" android:textOff="KAPALI" android:textSize="30dp" android:textOn="AÇIK" /> >

Aynı değişiklikler, Anahat/Özellikler sekmesi kullanılarak grafik modunda da yapılabilir.

Deneme çalışma

Yeni oluşturduğumuz uygulamayı emülatör üzerinde çalıştırabiliriz. Başlatma ayarlarına gidin "Çalıştır" → Konfigürasyonları Çalıştır", sol tarafta "Android Uygulaması" üzerine tıklayın. Yeni bir konfigürasyon "New_configuration" belirir. Pencerenin sağ tarafında, "Hedef" sekmesini seçin ve "Tüm uyumlu cihazlarda/AVD'de başlat" seçeneğini seçin.

"Uygula" yı ve ardından "Çalıştır" ı tıklayın. Uygulama emülatörde çalışacaktır.

Düğmelere basabilirsiniz. Ancak tıklama işleyicileri henüz tarafımızdan yazılmadığı için hiçbir şey olmayacak.

Uygulamayı gerçek bir cihazda çalıştırmak için ayarlarında "USB hata ayıklama" seçeneğini etkinleştirmeniz ve bilgisayara bağlamanız gerekir.

Gerçek bir cihazda uygulama tamamen aynı görünüyor.

Android için kod yazma

Manifest düzenleme

Her Android uygulaması, sisteme hangi hakları vermesi gerektiğini söylemelidir. Haklar, sözde AndroidManifest.xml bildirim dosyasında listelenmiştir. İçinde, uygulamamızda Bluetooth kullanmak istediğimizi belirtmeliyiz. Bunu yapmak için sadece birkaç satır ekleyin:

AndroidManifest.xml "http://schemas.android.com/apk/res/android" package="tr.amperka.arduinoobtled" android:versionCode="1" android:versionName="1.0" > android:minSdkVersion="10" android:targetSdkVersion="10" /> "android.permission.BLUETOOTH"/> "android.permission.BLUETOOTH_ADMIN"/>
android:allowbackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > android:ad= "tr.amperka.arduinoobtled.MainActivity" android:label="@string/app_name" > > "android.intent.category.LAUNCHER" /> > > > >

Ana kodu ekleme

Uygulamamıza hayat vermenin zamanı geldi. MainActivity.java (src → ru.amperka.arduinobtled) dosyasını açın. Başlangıçta aşağıdaki kodu içerir:

MainActivityAutogen.java paketi en.amperka.arduinoobtled ; android.os.Bundle'ı içe aktar ; android.app.Activity'yi içe aktar ; android.view.Menu'yu içe aktar ; public class MainActivity, Activity'yi genişletir ( @Override protected void onCreate(Bundle saveInstanceState) ( super .onCreate (savedInstanceState) ; setContentView(R.layout .activity_main ); ) @Override public boolean onCreateOptionsMenu( Menü menu) ( getMenuInflater() .inflate (R.menu .main , menu) ; true döndür ; ) )

Kodu ihtiyacımız olana göre ekleyelim:

    Kapatılırsa Bluetooth'u açacağız.

    Düğme tıklamalarını işleyeceğiz

    Hangi düğmeye basıldığı hakkında bilgi göndereceğiz.

Arduino'ya iki basamaklı bir sayı ile bir bayt göndereceğiz. Sayının ilk hanesi, bu veya bu LED'in bağlı olduğu pimin numarasıdır, ikincisi LED'in durumudur: 1 - açık, 0 - kapalı.

Komut numarası çok basit bir şekilde hesaplanır: Kırmızı düğmeye basılırsa, 60 sayısı alınır (kırmızı LED için Arduino'nun 6. pinini seçtik) ve LED'in gerekip gerekmediğine bağlı olarak 1 veya 0 eklenir. şimdi olsun ya da olmasın. Yeşil buton için her şey aynı, 60 yerine sadece 70 alınır (yeşil led pin 7'ye bağlı olduğu için). Sonuç olarak, bizim durumumuzda 4 takım mümkündür: 60, 61, 70, 71.

Yukarıdakilerin hepsini uygulayan kodu yazalım.

MainActivity.java paketi en.amperka.arduinoctled ; java.io.IOException'ı içe aktarın; java.io.OutputStream'i içe aktarın; içe aktarmak java.lang.reflect.InvocationTargetException; java.lang.reflect.Method'u içe aktarın; android.app.Activity'yi içe aktar ; içe aktarmak android.bluetooth.BluetoothAdaptör; içe aktarmak android.bluetooth.BluetoothCihaz; içe aktarmak android.bluetooth.BluetoothSocket; android.content.Intent'i içe aktarın; android.os.Bundle'ı içe aktar ; android.util.Log'u içe aktar ; android.view.Menu'yu içe aktar ; android.view.View dosyasını içe aktarın; içe aktarmak android.view.View.OnClickListener; android.widget.Toast'ı içe aktar ; android.widget.ToggleButton'u içe aktarın; public class MainActivity, Activity uygulamalarını genişletir görüş.OnClickListener( // Düğme sınıflarımızın örnekleri ToggleButton redButton; ToggleButton yeşilButon; // Arduino'ya veri göndereceğimiz soket BluetoothSocket clientSocket; //Uygulama başladığında bu fonksiyon otomatik olarak çalışır@Override protected void onCreate(Bundle saveInstanceState) ( super .onCreate (savedInstanceState) ; setContentView(R.layout .activity_main ) ; // Uygulama penceresindeki düğme görünümünü uygulama ile "bağlayın" redButton = (ToggleButton) findViewById(R.id .toggleRedLed ) ; greenButton = (ToggleButton) findViewById(R.id .toggleGreenLed ) ; //Düğmeye bir "tıklama dinleyicisi" ekleyin redButton.setOnClickListener (bu); greenButton.setOnClickListener (bu); // bluetooth'u aç. Zaten etkinse, hiçbir şey olmayacak. Sicim enableBT = BluetoothAdapter.ACTION_REQUEST_ENABLE ; startActivityForResult(new Intent(enableBT), 0 ) ; //Varsayılan bluetooth adaptörünü kullanmak istiyoruz BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter(); //Bunları yapmaya çalışıyorum denemek( //Belirtilen adresteki cihaz bizim Bluetooth Bee'mizdir. //Adres şu şekilde tanımlanır: bağlantı kurun //PC ve modül arasında (pin: 1234) ve ardından ayarlara bakın //bağlantı modülü adresi. Büyük ihtimalle benzer olacaktır. BluetoothDevice device = bluetooth.getRemoteDevice("00:13:02:01:00:09" ) ; //Cihazla bağlantı başlat yöntem m = device.getClass() .getMethod ("createRfcommSocket", yeni Sınıf (int .class)); clientSocket = (BluetoothSocket) m.invoke (cihaz, 1 ) ; clientSocket.connect(); // Herhangi bir hata olması durumunda, günlüğe bir mesaj çıktısı) tutmak ( IOException Güvenlik İstisnası e) ( Log.d ("BLUETOOTH" , e.getMessage() ) ; ) catch ( NoSuchMethodException e) ( Log.d ("BLUETOOTH" , e.getMessage() ) ; ) catch ( IllegalArgumentException e) ( Log.d ("BLUETOOTH" , e.getMessage() ) ; ) catch ( IllegalAccessException e) ( Log.d ("BLUETOOTH" , e.getMessage() ) ; ) catch ( InvocationTargetException e) ( Log.d ("BLUETOOTH" , e.getMessage () ) ; ) // Başarılı bağlantı hakkında bir mesaj göster Toast.makeText (getApplicationContext() , "CONNECTED" , Toast.LENGTH_LONG ) .show() ; ) @Override public boole değeri onCreateOptionsMenu( Menü Menü) ( // Menüyü şişirin; bu, varsa, eylem çubuğuna öğeler ekler. getMenuInflater() .inflate(R.menu .main , menü) ; true döndür; ) // Sadece bu fonksiyon çağrılacak@Override public void onClick( görüş v)( //Veri göndermeye çalışıyorum denemek( //Veri aktarımı için çıktı akışını alın Çıktı Akışı outStream = clientSocket.getOutputStream(); int değeri = 0 ; //Hangi düğmeye basıldığına bağlı olarak, //gönderilecek verileri değiştir if (v == redButton) ( değer = (redButton.isChecked () ? 1 : 0 ) + 60 ; ) else if (v == greenButton) ( değer = (greenButton.isChecked () ? 1 : 0 ) + 70 ; ) // Çıktı akışına veri yaz outStream.write(değer) ; ) tutmak ( IOException e)( // Hatalar varsa, bunları günlüğe yazdırın Log.d ("BLUETOOTH" , e.getMessage (, OUTPUT) ; pinMode(7 , OUTPUT) ; ) void loop() ( //Veri geldiyse if (Serial.available() > 0 ) ( //Gelen baytı oku bayt gelenByte = Serial.read(); //Alınan baytın değerinin tamsayıya bölünmesiyle pin numarasını 10'a alın // ve bölmenin kalanını 2 ile alarak ihtiyacımız olan eylem: //(1 - aç, 0 - kapat) digitalWrite(incomingByte / 10 , gelenByte % 2 ) ; ))

Eskiz dolgu özellikleri

Denetleyici ile Bluetooth-Bee iletişimi için, bellenim için kullanılan aynı pinler (0 ve 1) kullanılır. Bu nedenle, denetleyiciyi programlarken, “Kablosuz Kalkan” üzerindeki “SERİ SEÇİMİ” anahtarı “USB” konumuna ayarlanmalı ve yanıp söndükten sonra “MİKRO” konumuna getirilmelidir.

Sonuç

Çözüm

Bu yazımızda Android işletim sistemi için uygulama oluşturmayı ve Bluetooth üzerinden veri aktarmayı öğrendik. Artık Android işletim sistemine sahip telefonun ekranındaki butona bastığınızda kart üzerindeki ledlerin durumu değişecek.

Bir fikir geliştirebilir ve Android'de daha kullanıcı dostu bir arayüz oluşturabilir, onunla çok daha karmaşık cihazları kontrol edebilir, Android Market'te harika uygulamalar yayınlayabilir ve çok, çok daha fazlasını yapabilirsiniz!

Bu, şimdiye kadar yaptığım ilk robotik proje ve hiç robot yapmayı denemediyseniz, muhtemelen bunun zor olduğunu düşünüyorsunuzdur. Ancak Arduino ve 2WD/4WD şasi, yapınızı çok daha kolay hale getirecek ve ilk Arduino RC robotunuzu herhangi bir acı çekmeden inşa edeceksiniz.


Yol boyunca, kendi ellerimle engelleri aşan radyo kontrollü bir araba yapma fikri aklıma geldi ve bu projeyi, aşağıda eklediğim video ve program dosyasını bir araya getirdim.

Dosyalar

Adım 1: Gerekli Parçalar ve Araçlar

Hazır çözümler kullandım ve tüm parçalar ve aletler çevrimiçi satın alındı.

Yedek parçalar:

  1. Robot 4WD Şasi Kiti (GearBest)
  2. Arduino Nano (GearBest)
  3. H-köprü modülü LM298 (GearBest)
  4. Bluetooth modülü HC-06 (Amazon)
  5. Li-ion piller 2 x 18650 (GearBest)
  6. Pil bölmesi 2x 18650 (GearBest)
  7. Küçük Breadboard (GearBest)
  8. 0,5 mm2 teller
  9. Erkek-dişi köprülü teller (Amazon)
  10. Dişi-dişi köprülü teller (Amazon)
  11. Maskeleme bandı, koli bandı veya benzeri (Amazon)

Engellerden kaçan bir robot için:

Ultrasonik Mesafe Ölçüm Modülü HC - SR04 (GearBest)

Gerekli araç:

  1. Havya (Amazon)
  2. Tel kesiciler (Amazon)
  3. Tel striptizci (GearBest)
  4. Tutkal tabancası (GearBest)

Adım 2: Robot nedir?

Bir robot, belirli hedeflere ulaşmak için çevreye bir şekilde tepki verebilen ve bağımsız kararlar veya eylemler alabilen elektromekanik bir cihazdır.

Robot aşağıdaki bileşenlerden oluşur:

  1. Yapı / Şasi
  2. Motor sürmek
  3. kontrolör
  4. Giriş Cihazları / Sensörler
  5. Güç kaynağı

Aşağıdaki adımlarda, her şeyi kolayca anlayabilmeniz için bu bileşenlerin her birini açıklayacağım.

Adım 3: Yapı / Şasi



Bir yapı fiziksel bileşenlerden oluşur. Bir robotun, bir görevi tamamlamak için bir şekilde hareket eden bir veya daha fazla fiziksel bileşeni vardır. Bizim durumumuzda robotun yapısı şasi ve tekerleklerdir.

4. Adım: Sürücüler



Bir sürücü, enerjiyi (robot biliminde enerji, elektrik enerjisi olarak anlaşılır) fiziksel harekete dönüştüren bir cihaz olarak anlaşılabilir. Çoğu aktüatör, döner veya doğrusal hareket üretir.

Bizim durumumuzda, sürücü 3000 rpm hıza ve 0,002 Nm torka sahip bir DC motordur.Şimdi buna 1:48 dişli oranına sahip bir dişli ekleyelim. Yeni hız 48 kat azaltılır (3000/44 = 68 rpm ile sonuçlanır) ve tork 48 kat artar (0,002 x 48 = 0,096 Nm ile sonuçlanır).

Adım 5: Motor Terminallerini Hazırlayın




Yaklaşık 12-15 cm uzunluğunda 4'er adet kırmızı ve siyah tel kesin, 0,5 mm2 kesitli teller kullandım. Tellerin uçlarını soyun. Kabloları motor terminallerine lehimleyin.

Motorların kutuplarını akü bölmesine bağlayarak kontrol edebilirsiniz. İleri yönde hareket ediyorsa (kırmızı kablo artı kutuplarda ve siyah kablo eksi kutuplardayken), bağlantı tamam demektir.

Adım 6: Motoru Kurun




Her motora iki uzun cıvata ve iki somun ile iki akrilik ara parçası takın. Netlik için videoyu izleyebilirsiniz.

Her motordaki kabloların kasanın merkezine gittiğine dikkat edin. Kasanın her iki tarafındaki motorlardan gelen hem kırmızı hem de siyah kabloları bağlayın. Bağlandıktan sonra, sol tarafta iki, sağ tarafta iki terminaliniz olacaktır.

Adım 7: Çatının Kurulması

4 motor kurduktan sonra bir çatı kurmanız gerekir. Somunlarla 6 bakır direk takın, kablo terminallerini çatıdaki delikten dışarı çıkarın.

Adım 8: Denetleyici

Şimdi kasayı ve sürücüleri kurduk, ancak denetleyici eksik. Kontrolörsüz kasa hiçbir yere gitmez. Robot yerinde kalacak, cansız kalacak. Dolayısıyla robotun hareket edebilmesi için bir beyne (kontrolör) ihtiyacımız var.

Kontrolör, belirli bir programa göre çalışabilen programlanabilir bir cihazdır ve tüm hesaplamalardan, karar verme ve iletişimden sorumludur. Bizim durumumuzda Arduino Nano mikro denetleyicisini denetleyici olarak kullanıyoruz.

Kontrolör giriş verilerini (sensörlerden, uzaktan vb.) alır, işler ve ardından sürücülere (motorlara) seçilen görevi gerçekleştirme talimatı verir.

Pozitif akü kablosunu motorun bir tarafına, ardından negatif akü kablosunu motorun diğer tarafına bağlarsanız, ileriye doğru dönecektir. Kabloları değiştirirseniz, motor ters yönde dönmeye başlayacaktır.

Motoru bir yöne çevirmek için bir mikrodenetleyici kullanılabilir, ancak motoru hem ileri hem de geri döndürmek için mikrodenetleyiciyi kullanmak istiyorsanız, o zaman ek bir devreye ihtiyacınız vardır - bir H köprüsü. Bir sonraki adımda, bunun ne olduğunu açıklayacağım.

Adım 9: H köprüsü (LM 298 modülü)




H köprüsü nedir?

H köprüsü terimi, bu devrenin tipik bir grafik gösteriminden türetilmiştir. Bu, motoru hem ileri hem de geri yönde döndürebilen bir devredir.

Çalışma prensibi:
H-köprü devresinin nasıl çalıştığını anlamak için ekteki resme bakın. Köprü 4 elektronik anahtar S1, S2, S3, S4'ten (transistörler / MOSFET / IGBTS) oluşur.

S1 ve S4 anahtarları kapalı ve diğer ikisi açık olduğunda, motordan pozitif voltaj geçecek ve ileri yönde dönecektir. Aynı şekilde S2 ve S3 anahtarları kapatılıp S1 ve S4 açıkken motora ters voltaj verilecek ve ters yönde dönmeye başlayacaktır.

Not: Bir koldaki anahtarlar (yani S1, S2 veya S3, S4) asla aynı anda kapanmaz - bu bir kısa devre oluşturacaktır.

H-köprüler entegre devreler olarak mevcuttur veya 4 transistör veya MOSFET ile kendi köprünüzü oluşturabilirsiniz. Benim durumumda, motorların hızını ve yönünü kontrol etmenizi sağlayan bir LM298 H-köprü entegre devresi kullanılıyor.

Pin Açıklaması:

Çıkış 1: DC motor 1 "+" veya step motor A+
Çıkış 2: DC motor 1 "-" veya step motor A-
Çıkış 3: DC motor 2 "+" veya step motor B+
Çıkış 4: Motor B çıkışı
12v: 12V giriş, ancak 7 ila 35V kullanılabilir
GND: Zemin
5v: 12V jumper yerindeyse 5V çıkış, Arduino'ya güç sağlamak için ideal (vb.)
EnA: Motor A için PWM sinyallerini almanızı sağlar (Lütfen Arduino Sketch Hususları bölümünü okuyun)
IN1: A motorunu açın
IN2: A motorunu açın
IN3: B motorunu açın
IN4: B motorunu açın
BENB: Motor B için PWM sinyallerini almanızı sağlar (Lütfen Arduino Sketch Hususları bölümünü okuyun)

Adım 10: Girişler / Sensörler

İnsanlardan farklı olarak robotlar görme, ses, dokunma, koku ve tat ile sınırlı değildir. Robotlar, dış dünyayla etkileşime geçmek için çeşitli sensörler kullanır.

Sensör, dış dünyadan belirli türde gelen bilgileri algılayan ve bunlara yanıt veren bir cihazdır. Bu bilgi ışık, ısı, hareket, nem, basınç veya diğer herhangi bir çevresel fenomen olabilir.

Gelen sinyaller sensörlerden, uzaktan veya akıllı telefondan gelebilir. Bu eğitimde, robotu kontrol eden sinyaller gönderen bir cihaz olarak bir akıllı telefon kullanıyorum.

Adım 11: Güç Kaynağı





Sürücüleri (motorları) kontrol etmek ve kontrolöre güç sağlamak için robotun bir güç kaynağına ihtiyacı vardır. Çoğu robot pillerle çalışır. Piller hakkında konuştuğumuzda, birçok seçeneği kastediyoruz:

  1. AA alkalin piller (şarj edilemez)
  2. AA nikel-metal hidrit veya nikel-kadmiyum piller (şarj edilebilir)
  3. Li-ion piller
  4. Lityum polimer piller

İhtiyaçlarınıza bağlı olarak, uygun pil tipini seçmeniz gerekir. Bence her zaman yeterli kapasitede şarj edilebilir piller seçmelisiniz. 2600mAh kapasiteli 2 adet Li-Ion 18650 pil kullandım. Özerklik için daha fazla güce ihtiyacınız varsa, 5A turnigy gibi büyük bir pil takımı kullanın.

Pil bölmesi:
Çin'den sipariş ettiğim pil kutusu düz pillere uymadığı için pilleri şekillendirmek için iki adet neodimyum mıknatıs kullandım.

Şarj cihazı:
Pilleri şarj etmek için iyi bir şarj cihazına ihtiyacınız var. Tecrübelerime göre, bu şarj cihazları iyi performans gösteriyor:

  1. PowerEx AA Şarj Analizörü (Amazon)
  2. XTAR LiIon Pil Şarj Cihazı (Amazon)
  3. Turnigy LiPo Pil Şarj Cihazı (Amazon)

Adım 12: Bileşenleri Yükleme


Tüm devre çatıya monte edilmiştir. Pil bölmesi, LM 298 motor sürücüsü ve sıcak tutkalla sabitlediğim küçük devre tahtası, ancak bunları vidalayabilirsiniz. Bluetooth modülü yapışkan bantla sabitlenmiştir. Arduino nano'yu devre tahtasına yerleştirin.

Adım 13: Kablolama






Modülleri bağlamak için jumper'lı kablolara ihtiyacınız olacak.
İki motorun kırmızı kablolarını (her iki tarafta) ve ardından siyah kabloları birbirine bağlayın. Sonuç olarak, her iki tarafta iki terminaliniz olacak.

MOTORA sırasıyla iki sağ motordan sorumludur, iki sol motor MOTORB'a bağlıdır.
Tüm bileşenleri bağlamak için talimatları izleyin:

Motor bağlantısı:

Out1 -> sol motorun kırmızı kablosu (+)
Out2 -> sol motorun siyah teli (—)
Out3 -> sağ motorun kırmızı kablosu (+)
Out4 -> sağ motorun siyah teli (—)
LM298 -> Arduino
IN1 -> D5
IN2->D6
IN2 ->D9
IN2->D10
Bluetooth modülü -> Arduino
Rx->Tx
Tx->Rx
GND -> GND
Vcc -> 3.3V
Beslenme
12V -> kırmızı akü kablosu
GND -> Arduino'da siyah pil kablosu ve GND pimi
5V -> Arduino 5V pinine bağlanın

Adım 14: Kontrol Mantığı

Nasıl çalıştığını anlamak için bu mantıksal tabloyu oluşturdum. Kod yazarken çok kullanışlı oluyor.

Adım 16: Test Etme



Robot arabayı test etmek için küçük bir karton kutunun üzerine koydum. Böylece tekerlekler dönecek, ancak araba yerinde kalacaktır. Mevcut tüm düğmelere basarak işlevselliği test edin. Her şey çalışıyorsa, gerçekten yönetebilirsiniz.

Not: Motorlar ters yönde dönüyorsa, kabloları değiştirmeniz yeterlidir.

Adım 17: Gelecek Planları




Bu rehberde basit bir arabanın nasıl oluşturulacağını anlattım. Ardından, ona bazı iyileştirmeler eklemek istiyorum. Buna çeşitli sensörler bağlayabilirsiniz, işte bazı fikirler:

  1. Engellerden Kaçınmak İçin Ultrasonik Sensör Ekleme
  2. Kontrol mesafesini uzatmak için Bluetooth yerine ESP8266 veya Node MCU gibi bir WiFi modülü kullanmak.
  3. Pilleri şarj etmek için bir güneş paneli ekleme.
Bir Arduino makinesinin Bluetooth aracılığıyla bir Android cihaz tarafından kontrol edilen üç motordan nasıl monte edildiğinin ayrıntılı bir geçmişi. Birkaç düzine paragrafta, her bir kablonun nereye bağlanacağını, tescilli bir uygulamanın nasıl yazılacağını ve bir haftadan fazla bir süre boyunca hangi çocukların tırmığına atlamam gerektiğini adım adım açıklamaya çalışacağım.

Seviye, yazar ve uyarılar hakkında biraz

Yazar olarak, Moskova yakınlarındaki bir köyden 16-17 yaşlarında bir çocuk olan ben, android uygulamaları yazma konusunda uzmanım (ve orada bir şeyler yakmak daha zor), bu yüzden sorunları çözmek için en uygun yaklaşımın sorumluluğunu alıyorum.

Görev

En kolay görev, arabayı Arduino sürücüsü ile kontrol etmek ve uzaktan kumandayı bir android ile değiştirmek. Ancak çoğu an, internette uygun bir çözüm bulunmadığı için tekerleği yeniden icat etmek zorunda kaldım.

Sürer

  1. Arduino
  2. Motor Kalkanı (benim durumumda iki tane)
  3. Bluetooth
  4. Android
  5. teller sıradan

Tasarım temeli

Lego Outdoor Challenger arabası temel alındı ​​(gerçekte daha az acıklı görünüyor). Ondan geriye kalan tek şey: gövde (tüm süslemeler kaldırıldı) ve üç motor.

Makinenin kendi kartı vardı, ancak görevlerden biri çok yönlülüğü ima ediyordu: Ben yaptım, diğerleri tekrar edebilir. Beyinleri çıkardım, Arduino Uno'yu koydum.

Arduino kurulumu

Yaratıcılar nedense Arduino için bir yer sağlamadılar, bu yüzden plastiği delerek vidalara sabitlediler. Hiçbir şeyin kısa devre yapmaması için tahtanın altına kontrplak koydum. Vidaların altına plastik bir şey (bir şişe parçası) kaydırmak daha iyidir, çünkü tahta demir cıvatalardan korunmaz.

Hemen kartın üstüne iki motor korumalı koydum, bu yüzden gerekli. İkincisini kontrol etmek için, herhangi bir dijital bağlantı noktasından bir kabloyu H1'e (yön) ve ikincisini şim destekli bir pimden (“~” ile işaretlenir, genellikle 10, 11) E1'e (hız) çalıştırmanız gerekir.

Dönme açısının belirlenmesi

Şaşırtıcı bir şekilde, makineyi döndürmekten bir servo sürücü değil, sıradan bir motor sorumludur. Bir sorun ortaya çıkıyor: yakmamak güzel olurdu, çünkü dönüş açısı sınırlıdır ve motor gerektiği kadar dönebilir.

Poking seçeneği söz konusu değil çünkü farklı pil seviyelerinde motora verilen akım miktarı değişerek sürekli değişen bir açıyla sonuçlanacak. Onu da tamamen çeviremezsin, er ya da geç dişliler parçalanacak.

Sorunun çözümü: açıyı bir kapaktan takip edin. Fotoğraf, döner mekanizmanın yanına takılan küçük bir şeyi göstermektedir. Motor tarafından sola / sağa tekerlekler ile dönen kısma demir kontaklı bir tarak takılır.

Çalışma prensibi: her hatta bir tel lehimlenir (toplamda dört tane vardır), alttaki artıya bağlanır (her zaman bir tarakla kenetlenir, resme bakın), tellerin geri kalanı eksiye gider . Tarak dişi hem alt sıraya hem de üçüncü sıraya çarptığında kısa devre oluşur, akım akar, bu Arduino tarafından fark edilir.

Üç şeridin çeşitli kombinasyonları sayesinde yedi köşeye kadar tanımlanabilir. Örneğin tüm hatlarda akım varken tekerlekler aşırı sağ konuma, sadece üstte akım varken tekerlekler maksimum sola çevrilir. Tablo tüm seçenekleri gösterir.

Köşe bağlantısı ve kodu

Her seviye için farklı bir renk seçildi: alttaki yeşil, alttan ilki kırmızı, ikincisi siyah, üçüncüsü beyaz. İlk aşamada görsel hata ayıklama için bir breadboard ve LED'ler kullanıldı.

Bağlantı şeması şekilde gösterilmiştir. Artı, yeşile çekiyoruz, gerisini eksiye uzatıyoruz. Girişimi ve kısa devre olmamasını ortadan kaldırmak için kurulan bir direnç aracılığıyla, kabloları A0-A2 çıkışlarına bağlarız. Sadece limanların geri kalanını kurtarmaktan seçilirler.

Kod yorumlarla birlikte verilir. Pinleri bağlayıp digitarRead() ile yoklıyoruz. Gerilim varsa, true döndürülür. Ardından, sonuç tekerleklerin aşırı konumlarda olduğu anlamına gelirse bakarız, bu yönde daha fazla dönüşü yasaklarız.

Küçük bir numara: Gelecekte 5V ve 3.3V çıkışlara ihtiyaç duyulacağından, dijital pinlerden birine artı koyabilirsiniz. Her açı kontrolünden önce, digitalWrite(whitePin) üzerinden akım çıkışı yapın, ardından açıyı kontrol edin ve akımı kaldırın.

int hızDönüş = 180; // dönüş hızı, 0'dan 255'e // dönüşü belirlemek için pinler int pinRed = A0; int pinBeyaz = A1; int pin Siyah = A2; int pinAngleStop = 12; //maksimum açıya ulaşılırsa akımı LED'e verir, //yalnızca void kurulumunda hata ayıklamak için gereklidir() ( //pinMode'u okumak için dönüş pinleri(pinRed, INPUT); pinMode(pinBlack, INPUT); pinMode(pinWhite, INPUT); //LED pinMode(pinAngleStop, OUTPUT); //motor sürücü pinleri, yön ve hız pinMode(angleDirection, OUTPUT); pinMode(angleSpeed, OUTPUT); Serial.begin(9600); ) //döngüden çağrılan fonksiyon (), androidden bir komut geldiğinde void turn(int angle) ( digitalWrite(pinAngleStop, HIGH); //artı gecikmesine bağlı kabloya akım verin(5); //akımın "sahip olması için biraz bekleyin" if(angle > 149 ) ( if(digitalRead(pinWhite) == HIGH && digitalRead(pinBlack) == LOW && digitalRead(pinBlack) == LOW) ( //en sağ konuma ulaşılırsa, //motor dönüşünü yakmamak için akım uygulamadan işlev; ) //açı maksimum değilse, digitalWrite(angleDirection, HIGH); analogWrite(angleSpeed, speedTurn); ) else if (angle) çevirin< 31) { if(digitalRead(pinRed) == HIGH && digitalRead(pinBlack) == HIGH && digitalRead(pinWhite) == HIGH) { //если достигнуто крайне левого положение, выйти из функции не подавая ток, чтобы не //сжечь мотор return; } //если угол не максимальный, поворачиваем digitalWrite(angleDirection, LOW); analogWrite(angleSpeed, speedTurn); } digitalWrite(pinAngleStop, LOW); //убираем ток с определителя угла delay(5); }

Seyahat tekerleklerinin paralelleştirilmesi

Başlangıçta, iki tahrik motoru birbirine bağlanır. İki nedenden dolayı bağlantılarını kestim: tekerlekler farklı yönlerde dönüyorsa dönüş daha verimlidir ve iki güçlü motor tek bir tahta tarafından çekilemez.

Sorun: Motor blendajının her biri 2 ampere kadar çıkış veren iki çıkışı vardır. Her motor 0.7A yiyor. Daha az görünüyor, ancak maksimum yüklerde değil. Diyelim ki makine kuma saplanmış veya dinlenmiş durumda, akım amperin üzerine çıkıyor. Kritik değil, ancak potansiyel olarak tehlikeli.

Ancak tahtanın ısıtılması kritik olduğu ortaya çıktı. Yarıştan bir buçuk dakika sonra motor kalkanı ısındı ve çirkin çalışmaya başladı: akımlar aynı değildi, tekerlekler dönmüyordu vb.

Her iki sorunun da çözümü: bir motor bir motor kalkanına, ikincisi diğerine bağlı. Garip bir şekilde, yardımcı oldu. Sıcaklık düştü, aşırı ısınma yok. Radyatör koymak mümkündü ama tamir etmesi zor.

Bluetooth bağlantısı

Ölümcül bir şaka yapan HC-05 modelini kullandım. Tüm bluetooth aynı şekilde bağlanır: 3.3V için bir kablo (bazen sadece 5V'den çalışmaya başlar), ikincisi eksi için, iki bağlantı noktası 0 ve 1 için (sırasıyla okuma ve gönderme). Bluetooth üzerindeki RXD imzalı tel arduino TXD'ye ve TXD'yi RXD'ye takılır (karıştırırsanız verileri göremezsiniz).

Bir uyarı var: 0 ve 1 numaralı bağlantı noktaları, çizimin yüklendiği Seri tarafından varsayılan olarak kullanılır. Yani bluetooth takılıyken kroki yüklenmeyecek. İki çıkış yolu vardır: doldurma süresi boyunca bluetooth'u kaldırın veya bluetooth'un giriş ve çıkışlarını yeniden atayın. İkinci seçenek iki satırda gerçekleştirilir

#Dahil etmek \\SoftwareSerial kitaplık bağlantısı BTSerial(8, 9); \\ 0 ve 1 yerine 8 ve 9 pinlerini ayarlama
Üç günlük çalışmamı yiyen tuzak, iletişimin hızıdır. Alışkanlık dışında 9600 kurdum ve denemeye gittim. Ya veriler gelmedi, sonra bir karakter karmaşası oldu. Ve sonunda cevap - HC-05 modeli 38400'de iletişim kurar! Setup() içinde, Serial.begin(9600) olsa bile BTSerial.begin(39400) dosyasını çalıştıracağıma kesinlikle dikkat edin.

Komut gönderme sistemi

Makale çok uzadı, bu yüzden Arduino ve Android kodunu ayrı bir ikinci bölümde ele alacağım ve şimdi prensibi anlatacağım.

Android cihazında bir joystick (uygulaması da ikinci bölümde olan bir daire) vardır. Android, ondan okumaları okur ve bunları arduino için uygun sayılara dönüştürür: piksellerden hızı -255 ila 255 (negatif - ters) arasında bir değere dönüştürür ve ayrıca açıyı belirler. Bu görevi kasıtlı olarak telefona verdim, çünkü çok daha güçlü ve saniyede birkaç yüz değer saymakla kolayca başa çıkabiliyor.

Soket kurulduktan sonra veriler şu biçimde gönderilir: @speed#*angle#. @ - aşağıdaki hanelerin hız içerdiğini gösterir, # - hız değerinin sonunu bildirir, * - açı değerinin başlangıcını, # - açıyı kaydetmeyi bitirir. Döngü sonsuzdur, komutlar her 100 milisaniyede bir gönderilir (şekil optimaldir). Android'de hiçbir şeye basılmazsa, hiçbir şey gönderilmez.

Veri alma algoritması, çizim kodunda ayrıntılı olarak açıklanmıştır. Bir kereden fazla yazıştı ve bana gelince, mükemmel çalışıyor.

İlk bölümün sonucu

Bu yazıda, makinenin fiziksel kısmı ile ilgili her şeyi ortaya koymaya çalıştım. Büyük olasılıkla, bir şeyi kaçırdım, bu yüzden sorduğunuzdan emin olun.

Ama benim için en ilginç olanı ikinciye kaldı - Arduino programı ve Android uygulaması, en azından genç ben için gerçek bir sihir var.

Herhangi bir kısmın cevabını bulamıyorsanız ve kişisel olarak eksikliklerimle beni dürtmek istiyorsanız, bekliyorum - [e-posta korumalı], .

UPD: ikinci bölüm zaten çıktı -

Çinlilerden kötü oyuncaklar almayalım, onlardan ucuz bir şasi üreticisi, birkaç modül alıp elimizi taşın altına koyalım!

Sonunda elde ettiğim şey şu: Geçersiz şasi, kontrollü - TA-YES !!! - Android akıllı telefonumdan.


"Ben düzüm, yanlarım,
Bir dönüşle ve bir sıçrama ile,
Ve bir koşudan ve yerinde,
Ve iki ayak birlikte ... "

Bugün Bluetooth üzerinden uzaktan kumandalı eğlenceli bir araba monte edeceğiz. Android için kontrol programının kaynakları dahildir.

İyi bir oyuncak örneği

İki çocuğum var, bir kızım ve bir oğlum. Her ikisine de doğum günleri için oyuncaklar verilir. Kızımın verdikleri, kural olarak, olumsuz tepkilerime neden olmaz. Ve oğula beklendiği gibi her türlü araba, tank ve diğer teçhizat verilir. Tüm bu Çinli uçurumdan, sadece kendim sunduğum oyuncak bir elektrikli testere herhangi bir şikayete neden olmaz.

Nedenmiş? Muhtemelen bu testere STIHL alet mağazasında satıldığı için. STIHL'nin küçük bir reklam çalışmasıyla ürünlerinin bir oyuncak benzerini yaptığına inanıyorum. Sonuç olarak, ağabeyine çok benzeyen tamamen aklı başında bir oyuncak doğdu. Lastik zincir dönüyor, kontrollerin yüzde 80'i uygulanıyor. Testereyi sarmak için kulplu bir kablo, bir anahtar, bir gaz düğmesi bile var. Yedek zincir ve zincir değiştirme aleti ile birlikte gelir.


İşte bir oyuncak testere

Ne hakkında konuşuyorum? Ah evet, mimari! Demek istediğim, dilerseniz mükemmel bir oyuncak yapabilirsiniz. Ve dört gözle beklenecek bir şey var.

Uzaktan kumandalı bir makine yapacağız!

Radyo kontrollü oyuncaklar pratik ve teknik açıdan ilgi çekicidir. Ancak 4-6 yaş arası bir çocuğa "yetişkin" orantı kontrollü oyuncaklar verilmeyecektir. Büyük olasılıkla, oyuncak kırılacak ve para atılacak.
Sonuç olarak, genellikle ucuz bir şey verirler. Tüm bunlardan - "ucuz" - arabalar ya çok hızlıdır ya da frenlidir; tanklar zayıf; ve diğer açık ve gizli eksiklikler. Ve kesinlikle orantısal kontrol yok.

Güzel bir gün, arabalardan biri sağ tekerleği döndürmeyi bıraktı. Demonte, motoru kontrol etti - servis yapılabilir.
Kontrol panosunda üç mikro devre var - Çin golem, aklı başında belgeler bulamadım. Bir çip, mantık çıkışları ve iki köprü motor sürücüsü olan bir radyo sinyali alıcısıdır. Sürücülerden biri başarısız oldu. Ayrık bileşenlerden bir köprü motor sürücüsü oluşturmayı hemen başaramadım.

Yerel radyo parçaları mağazasında uygun bir şey yoktu. Bu yüzden mucizevi mikro devreler için uzak ülkelere gittim. Eşyalarımı topladım, ceplerimi krakerle doldurdum, bir fincan kahve doldurdum, tarayıcıyı açtım ve gittim ... .
Parametrelere uygun bir motor sürücüsü buldum, aynı anda iki tane sipariş ettim. Her ihtimale karşı, aniden biri arızalanacak ya da kendimi yakacağım. İşte o zaman daktilo fikri ortaya çıkmaya başladı. Paket muhteşem Çin'den geldikten sonra sürücüyü başarıyla değiştirdim ve makine onarıldı.

Makinemin fikrini rafa kaldırmadan, temeli - gelecekteki makinenin şasisini - seçmeye tekrar eğildim. Kara taşımacılığı için şasi farklıdır: paletli, tekerlekli, iki, üç, dört tekerlekli vb.

Kasayı nasıl seçtim

İlk olarak, bir kara taşıma modu seçtim, bu da bir kara şasisine sahip olacağım anlamına geliyor. Paletli şasi daha pahalı olma eğilimindedir ve çok hızlı değildir. İki-üç tekerlekli olanlar bana fena halde fena görünüyor, böyle bir şasi sadece düz bir yüzeyde sürülebilir.
üzerine yerleştim. Bence böyle bir şasi mükemmel bir arazi kabiliyetine ve hıza sahip olacak.


Şasi dahil:
olası tüm sensörleri, kontrol panolarını ve diğer bileşenleri monte etmek için bir dizi teknolojik deliğe sahip iki akrilik plaka
4 tekerlek
4 tam tahrik (motor + şanzıman)
Her tekerlek için bir tane olmak üzere hız sensörleri için yuvalara sahip 4 disk
bağlantı elemanları
Evet, yine Çin. Evet, ucuz. Evet oldukça kaliteli. ANCAK! Önce denemek isteriz. Sonuçta, “yetişkin” şasi de yetişkin bir şekilde duruyor, henüz buna yetişmedik.

Düşünce bataklığı ve İş Tanımı

Elinizde, örneğin, her türlü sensör, servo vb. ile modelin gövde kitinin olanakları açısından umut verici bir şey tuttuğunuzda, bir düşünce bataklığına ve bir bakış açısı bataklığına boğulmaya başlarsınız. Ama kendimize diyelim - DUR! Ve tüm düğümlerin kısa bir açıklamasını içeren prototip için kendimizi mini bir TOR yapacağız.
Bluetooth üzerinden kontrol edilen, tekerleklerin dönüş hızını tersine çevirebilen ve sorunsuz bir şekilde kontrol edebilen bir kara aracının RC modelini almalıyız.

Makineyi monte etmek için neye ihtiyacımız var?

.


Döner tekerlek yoktur, bu da direksiyon kontrolünün paletli bir aracınki gibi olacağı anlamına gelir. Yani ileri/geri hareket için aktüatörlerin sağ ve sol tarafı aynı hızda döner. Ve dönüş yapabilmek için yanlardan birinin dönüş hızının az veya çok olması gerekir.


Makinenin uzaktan kumandası için Bluetooth kullanıyoruz. "HC-06" modülü, verilerin her iki yönde de aktarılmasına izin veren bir seri arabirim olan Bluetooth köprüsüdür. Girişte - mikrodenetleyiciye (hedef tahtası) bağlantı için "RxD" ve "TxD" seri arabiriminin TTL sinyalleri.
Bir Android cep telefonu uzaktan kumanda görevi görecektir. Programımızı yazalım!



Sürücü, sol ve sağ tekerlek çifti için iki kanallıdır. Sürücü, çıkışın (dönüş yönü) polaritesini değiştirmek için lojik girişlere ve bir PWM girişine sahiptir, dönüş hızını kontrol etmek mümkün olacaktır.


Bu tahta seçildi çünkü bir çekmeceye koyun ve amacımıza tamamen uygundur. Ayrık girişler/çıkışlar vardır, MK sinyalleri "RxD" ve "TxD" çıkıştır, "HC-06" bağlanacaktır.
İleriye baktığımda, Olimex MOD-IO ürününün zorlu bir baskın olduğunu söyleyeceğim. Hikayenin devamında tartışılacak olan olağan olanı uygulamak tamamen mümkün olacak!

Toplam: kasa + kontrol panosu + Bluetooth modülü + Android kontrol programı.

Genel bağlantı şeması

Saf haliyle bir devre değil, bir bağlantı şeması, çünkü sahip olduğumuz tüm panolar hazır ve onları birbirine bağlamak için kalıyor.

Proteus'taki Şema


Neyi ve nereye bağlandığımı tarif etmeyeceğim. Büyük olasılıkla farklı bir kontrol panosuna sahip olacaksınız. Donanım yazılımını düzenleyebilmeniz için kaynak kodlarını ekliyorum. Pekala, eğer biri anakartı için ürün yazılımını derleyemiyorsa, lütfen benimle iletişime geçin - boş zamanım olduğu kadar yardımcı olacağım.

mikrodenetleyici programı

MK programı, bir Bluetooth modülünden bir seri arabirim aracılığıyla komutları alabilir.
Ve komutlara göre, sol ve sağ sürücü çiftini kontrol edin. Geri ve hız kontrolü PWM ile çalışır.

Kod iyi yorumlanmıştır. Veri alışverişi uygulamam üzerinde ayrıca durmak istiyorum.
Bir halka arabelleği aracılığıyla veri alımını uyguladım. Şey yeni değil ve birçok uygulama var.

Halka arabelleği işlevlerim, aşağıdakilerden oluşan ayrı bir kitaplığa taşınır:
başlık dosyası ring_buffer.h ve işlev uygulama dosyası ring_buffer.c
Kütüphaneyi kullanmak için, onu main.c'ye dahil etmeniz gerekir.
#include "ring_buffer.h"

Ardından, başlık dosyasında kitaplığı yapılandırmanız gerekir. Yapılandırmak için yalnızca dört yönerge belirtmeniz gerekir:
#define RX_PACKET_SIZE 7 // RxD paket boyutu #define BUFFER_SIZE 16 // Alma arabelleğinin boyutu. İki katı olmalıdır RX_PACKET_SIZE #define START_BYTE "s" // Byte Başlat #define STOP_BYTE "e" // Byte'ı Durdur

Aslında yapılandırılacak başka bir şey yok.

kodu kullanma Main.c'de mikrodenetleyicinin USART'ını yapılandırıyoruz.
USART kurulum işlevini çağırma
USART_Init(MYUBRR);

#define BAUD 9600 #define MYUBRR F_CPU/16/BAUD-1 void USART_Init(unsigned int ubrr) ( /* baud hızını ayarla */ UBRRH = (işaretsiz karakter)(ubrr >> 8); UBRRL = (imzasız karakter)ubrr; /* Alıcı ve vericiyi etkinleştir */ UCSRB = (1<< TXCIE) | (1 << RXCIE)| (1 << TXEN) | (1 << RXEN); /* Set frame format: 8data, 2stop bit */ UCSRC = (1 << URSEL) | (0 << USBS) | (3 << UCSZ0); }

Bir veri paketi alma

USART alma bayt kesme işleyici işlevinde, yalnızca alınan baytı halka arabelleğine koymamız gerekir. Paketi daha sonra ayrıştıracağız.
ISR(USART_RXC_vect) ( uint8_t Veri = UDR; RB_push_char(Veri); // Alınan baytı halka arabelleğine ekleyin)
Evet, şimdiye kadar herhangi bir çerçeve kontrolünü ihmal ettim.

Şimdi, ara sıra arabelleğimizi kontrol etmek bize kalıyor. Bunu yapmak için, halka arabelleğini kontrol etmeye izin vermek için bayrağı ayarladığım bir zamanlayıcı başlattım.
ISR(TIMER0_OVF_vect) ( TCNT0 = 0x64; ReadRingBuffer = 1; )

Ana döngüde, bayrağı kontrol etmek için bir koşul ekliyoruz.
if (ReadRingBuffer) ( if (RB_read_buffer((uint8_t*)&RxPacket) == 1) Tamponu okuyun ( // Paketi ayrıştırın, bir şeyler yapın ) ReadRingBuffer = 0; )

İşlev RB_read_buffer paket boyutu, başlangıç ​​ve bitiş baytları yerlerindeyse halka arabelleğini kontrol eder - paket geçerli kabul edilir, işlev "1" döndürür.Bir argüman olarak, işlev alınan paketin nereye ekleneceğini gösteren bir işaretçi alır.
Daha fazla güvenilirlik için, pakete bir sağlama toplamı sağlanabilir, tam da bunu yaptığım ticari projelerimden birinde. Yani, boyutu kontrol etmek, baytları başlatmak / durdurmak için bir sağlama toplamı kontrolü eklenir. Ama şimdilik, onsuz yapalım.

Bir paketi nasıl açarım?

Şimdi en ilginç şey paketi nasıl sökeceğim. Bir bayttan büyük veriler, işaret verileri, kayan nokta verileri bir paket içinde iletilebilir.
Şasi yönetimi için bir paket örneğini kullanarak açıklayacağım. Başlatma ve durdurma baytlarına ek olarak, paketimde sürücülerin sol ve sağ tarafı için bir komut ve iki PWM değeri göndermem gerekiyor. Bir komut için bir bayt benim için yeterli ve her PWM değeri için gönderiyorum int16- 16 bit, imzalı tip. Yani, bir yön bayrağı (bayt/özellik) iletmiyorum. Yön değiştirmek için pozitif veya negatif bir PWM değeri geçiyorum.

Alıcı paket bir yapı şeklinde düzenlenir.
struct RxPacket ( uint8_t StartByte; uint8_t Komut; int16_t Left_PWM; int16_t Right_PWM; uint8_t StopByte; ) RxPacket;

Bir işlevi çağırmak RB_read_buffer ((uint8_t*)&RxPacket ), bir argüman olarak, alıcı paketin yapısına bir işaretçi iletiyoruz. Yani bir paket alındığında her şey RxPacket yapısında kendi raflarına sıralanacaktır. Ardından, yapıdan bu verileri okumak için kalır, örneğin şöyle:
lCmd = RxPacket.Command; lLPWM = RxPacket.Left_PWM; lRPWM = RxPacket.Right_PWM;

Veri paketi gönderme

Transfer programımda henüz kullanılmamış olsa da, yine de transfer imkanı uygulanmaktadır. Veri aktarımı daha kolaydır. Alıcı pakette olduğu gibi bir yapı oluşturalım:
struct TxPacket ( uint8_t StartByte; uint8_t Rc5System; uint8_t Rc5Command; uint8_t StopByte; ) TxPacket;

Nerede, bir başlatma ve durdurma baytı ve bir bilgi bölümü vardır. USART alıcısını zaten başlattık.
Bir paketin iletimini başlatmak için işlevi çağırırız.
void send_packet() ( // UDR kaydına başlangıç ​​baytı yaz UDR = START_BYTE; )
Bu örnekte, bu fonksiyonda sadece başlangıç ​​baytını UDR kaydına yazıyorum. Çok fazla değil gibi görünüyor, ancak aynı işlevde bir paketin veya başka bir yararlı şeyin hazırlanmasını uygulayabilirsiniz. Ve bu, bence, daha mantıklı. Kendi kendini belgeleyen kod açısından mantıklıdır. Yani, eğer kodun içindeysem, sadece UDR kaydına değeri yazarım, bu sadece bir bayt transfer etmek ve kendi kendine konuşan bir işlevi çağırmak olarak algılanabilir. send_packet()- Bir veri paketi gönderdiğimden bahsediyorum.

Ayrıca, USART vericisi UDR kaydından tüm baytı gönderdiğinde, iletim kesme işleyicisi çağrılır.
ISR(USART_TXC_vect) ( işaretsiz karakter *İşaretçi = (işaretsiz karakter *)&(TxPacket); statik imzasız karakter TxIndex = 1; if (TxIndex< sizeof(TxPacket)) { UDR = *(Pointer + TxIndex); TxIndex++; } else TxIndex = 1; }

İşleyicide, bir işaretçi değişkeni tanımlıyorum ve ona TxPacket yapısının adresini atıyorum. Ardından, statik bir değişken bildirilir - bildirildiğinde değer atanan iletilen baytın dizini 1 . Biriyle başlıyoruz çünkü yapıdan ilk baytı zaten gönderdik. Genel olarak yapıda start baytı olmadan da yapabilirsiniz zaten, ben ayrı ayrı gönderiyorum ama paketin nasıl göründüğünü anlamak için bu baytın bildirimi yapıda bırakılır.

koşul if (TxIndex< sizeof(TxPacket)) проверяет, что индекс меньше чем размер пакета. Если условие верно, то записываем байт в регистр UDR: UDR = *(Pointer + TxIndex);
TxIndex'i artırın. USART bir sonraki baytı gönderdiğinde, tekrar işleyiciye gireceğiz, ancak yapıdan bir sonraki bayt aktarılacak ve böylece yapının tüm baytları aktarılacak. TxIndex yapının boyutundan daha büyük olduğunda, koşul doğru olmayacak ve sonumuz else TxIndex = 1; TxIndex'in başlatılacağı, ancak sırasıyla UDR kaydına hiçbir şey yazılmadığı durumlarda, işleyici bir sonraki paket iletimi başlatılana kadar artık çağrılmayacaktır. Böylece transfer işlemi tamamen otomatiktir ve paket yapısını değiştirsek bile işleyicinin yeniden yazılmasına gerek kalmaz.

MK programının açıklamasının bir parçası olarak, sürücü yönetiminin uygulanması hakkında konuşmaya devam ediyor. Sürücü üç sinyalle kontrol edilir: A1 (B1), A2 (B2) ve PWMA (PWMB). A1 ve A2, sürücüyü açmak/kapatmak ve çıkışın polaritesini değiştirmek içindir. PWMA girişine MK'den bir PWM sinyali uygulanır - dönüş hızını kontrol edebilirsiniz. PWM sinyali için iki adet zamanlayıcı 1 donanım PWM'si kullandım.
#define _WGM13 0 #define _WGM12 1 #define _WGM11 0 #define _WGM10 1 // Zamanlayıcı 1 başlat TCCR1A = (1<< COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0) | (_WGM11 << WGM11) | (_WGM10 << WGM10); TCCR1B = (0 << CS12) | (0 << CS11) | (1 << CS10) | (_WGM13 << WGM13) | (_WGM12 << WGM12); TCNT1 =0x0000; OCR1A = 0; OCR1B = 0;

Zamanlayıcı 16 bittir, ancak PWM 8 bit olarak başlatılır. Ve muhtemelen zaten fark ettiğiniz gibi, alma paketinde sırasıyla sol ve sağ sürücüler için PWM'yi ayarlamak için iki değerim var. Değişkenler imzalı 16 bit.
Neden yaptığımı açıklayayım.

birinci olarak, Android programından çıktı. Gerçek şu ki, Java'da imzasız tür yoktur ve ben zaten bu komisyona bastım. Ve 0'dan 255'e bir sayı aktarmak için bir şekilde atlatmam gerekirdi. Daha basit bir yoldan gitmeye karar verdim - imzalı bir 16-bit numara gönderiyorum. Aynı zamanda, 16 bit işaretli tip -32786 ile 32768 arasındadır, bu bizim için yeterli.

ikinci olarak, bu yüzden bence daha şeffaf - dönüş hızı ve yön sadece bir değişken tarafından açıklanıyor.

ve üçüncüsü, ne derse desin, amaçlarımız için üç bayttan daha azını tutmak imkansızdır. Bir bayt daha feda edelim ama her şey netleşiyor, pozitif bir PWM değeri ileri dönüş, negatif bir değer ters dönüş.

Sürücüleri kontrol etmek için bir fonksiyon yazdım sürücü(int solPWM, int sağPWM);.
void drive(int leftPWM, int rightPWM) ( // (leftPWM > 0) ise sol tekerleği İLERİ hareket ettirin( ClearBit(A2_PORT, A2_PIN); SetBit(A1_PORT, A1_PIN); ) // (leftPWM ise sol tekerleği GERİ hareket ettirin)< 0){ ClearBit(A1_PORT, A1_PIN); SetBit(A2_PORT, A2_PIN); } // Движение ВПЕРЁД правое колесо if (rightPWM >0)( ClearBit(B2_PORT, B2_PIN); SetBit(B1_PORT, B1_PIN); ) // Eğer (sağPWM) sağ tekerde GERİ hareket< 0){ ClearBit(B1_PORT, B1_PIN); SetBit(B2_PORT, B2_PIN); } // Остановка if (leftPWM == 0){ ClearBit(A1_PORT, A1_PIN); ClearBit(A2_PORT, A2_PIN); } // Остановка if (rightPWM == 0){ ClearBit(B1_PORT, B1_PIN); ClearBit(B2_PORT, B2_PIN); } set_PWM((uint8_t)(abs(leftPWM)), (uint8_t)(abs(rightPWM))); }
PWM değerine göre A1 (B1), A2 (B2) sinyalleri kontrol edilir ve fonksiyon çağrılarak PWM değeri ayarlanır. set_PWM(solPWM, sağPWM).

Of, bir nefes al...
Özetlemek gerekirse: paketi aldık, ayrıştırdık, fonksiyona PWM değerini ilettik sürmek.

Arabalar için Android uygulaması

Hayır, MK için bir program gibi detaylı analiz yapmayacağım. Android için yazılım geliştirmede hâlâ yeniyim ve yeterince yetkin ve derinlemesine konuşmaya hazır değilim.

Programın ana işlevi- Bluetooth üzerinden HC-06 modülüne veri aktarımı. Program karmaşık olmayan bir arayüze sahiptir.

Yukarıda, bir modül seçmek için eşleştirilmiş Bluetooth cihazlarının bir açılır listesi bulunmaktadır. İlk başta, bu liste yoktu, ancak makale üzerindeki çalışmanın sonunda bunu insanca yapmaya karar verdim, çünkü herkes kaynak kodlarını anlayamayacak.

Ardından, "Kapalı" düğmesi - "HC-06" ile iletişimi etkinleştirir / devre dışı bırakır. Aşağıda soldan sağa: sol kanalın iletilen PWM değeri, sensör tipi, sağ kanalın değeri. Aşağıda hız ve dönüş hassasiyetini ayarlamak için iki kaydırıcı bulunmaktadır.

Program iki tür makine kontrolü uygular. Sensör türünü değiştirmek için sensör adının yazısına dokunmanız gerekir: "Eğim" veya "Karıştır".

1. Telefonunuzu eğerek makineyi kontrol edin. Telefonun sıfır konumu yataydır. Telefon öne eğildiğinde PWM değeri 0 ile 255 arasında değişen eğimle orantılı olarak artıyor. Telefon arkaya yatırıldığında 0 ile -255 aralığında eğimle orantılı olarak PWM değeri düşer.


Sola veya sağa çevirmek için - telefonu sırasıyla ileri veya geri ve aynı anda sola veya sağa yatırmanız gerekir. Evet, gerçek bir arabada olduğu gibi, siz gaza basana kadar dönüş yapılmaz.

2. Dokunmatik kontrol. Bu tür bir kontrol için ticari ismim "karıştırma"dır.


Dokunmatik yüzey olarak algılanabilir. Gri bir karede dokunulduğunda, PWM değeri dokunma yerine bağlı olarak artar / azalır, merkezden aşağı veya yukarı uzaklaştıkça değer büyür / küçülür.

"Güzel şeyler" ya da ziller ve ıslıklar yoktur. Hepsi bu gibi görünüyor.

"Kayak" üzerine biraz katran

Telefonumda bir sıkışma var. Evet, kayak telefonu LG G2 mini. Üzerinde, Bluetooth bağlantısı yeterince kurulmamış. Bağlantı, yalnızca uygulama başlatılmadan hemen önce Bluetooth açılmışsa normal olarak kurulur.
Bunu yaptım: Uygulamayı başlattığımda Bluetooth'un açık olup olmadığını kontrol ediyorum, kapalıysa açmak için istekte bulunuyorum. Ve "katladığımda", uygulamayı kapattığımda, Bluetooth'u zorla kapatıyorum.
Ve bir şey daha, ekran yönünü değiştirdiğinizde Bluetooth kapanıyor ve tekrar açmanız isteniyor, ekran döndürmenin otomatik geçişini kapatmanız gerekiyor.

Özet

Sanırım amacıma ulaştım! Fazla çaba harcamadan, aklı başında orantılı kontrole sahip bir RC modeli yarattım. Makine bir yetişkin tarafından bile coşkuyla çalınabilir, yerinde U dönüşleri yapabilir, karmaşık piruetler yazabilir, gerekirse yavaşlayabilir ve hızlanabilir.
Ve kırılırsa düzeltmek kolaydır.

Hala faaliyet alanı var, büyüme için yer var. Kasayı "sarabilirsin", telefonun yazılımını yükseltebilir ve iyileştirebilirsin.
Ve bu devam edecek!