質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

2回答

3597閲覧

AndroidアプリでArduino+Bluetoothの情報を”正しく”受け取りたい(言語:kotlin)

CrisisAnatres

総合スコア1

Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2022/05/26 08:59

したいこと

Arduinoのシリアル通信からBluetoothを通じてAndroidアプリで受け取り、Logcatに映し出したいです。受信はできているのですが、Arduino側で送信したものと全く同じものにして(型を整える、必要な情報だけ)受け取ることができません。方法を教えていただけますでしょうか。

構築したいシステムの概要図

イメージ説明

環境

  • Android Studio Bumblebee | 2021.1.1 Patch 3Build #AI-211.7628.21.2111.8309675, built on March 17, 2022
  • API:26 minSdk:23 targetSdk:32 compileSdk:32
  • Android端末 モデル名:Nexus7 Androidバージョン:6.0.1
  • Arduino IDE (Windows Store 1.8.57.0)
  • 使用マイコン基板Arduino Uno
  • 使用Bluetooth送信機(RN-42)詳細>https://akizukidenshi.com/catalog/g/gK-07378/

今できてること

この記事を元にArduino側で以下のプログラムを書き込み、Arduinoを接続したPC上のシリアルモニターから所望の文字や数字を送信します。

Arduino

1#include <SoftwareSerial.h> 2 3SoftwareSerial btSerial(2,3); 4char moji;//入力・送信する文字に応じて型を変更 5 6void setup () { 7 btSerial.begin(115200); 8 Serial.begin(115200); 9} 10 11void loop () { 12 if(Serial.available()){ 13 moji = Serial.read(); 14 btSerial.write(moji);//送信部分 15 } 16 delay(20); 17}

その送信したデータを下記のプログラム(MainActivity.kt)で作成した、AndroidアプリをインストールしたAndroid端末で受信、Logcatで確認するという流れです。

kotlin

1package com.mongodb.arduinoble 2 3import android.Manifest 4import android.bluetooth.BluetoothAdapter 5import android.bluetooth.BluetoothDevice 6import android.bluetooth.BluetoothSocket 7import android.content.Intent 8import android.content.pm.PackageManager 9import android.os.Bundle 10import android.util.Log 11import androidx.appcompat.app.AppCompatActivity 12import androidx.core.app.ActivityCompat 13import java.io.IOException 14import java.io.InputStream 15import java.io.OutputStream 16import java.nio.ByteBuffer 17import java.util.* 18 19const val TAG = "MainActivity" 20const val TARGET_DEVICE_NAME = "デバイス名(Android端末とペアリングしたRN-42のデバイス名)" 21const val REQUEST_ENABLE_BLUETOOTH = 1 22// Defines several constants used when transmitting messages between the 23// service and the UI. 24const val MESSAGE_READ: Int = 0 25const val MESSAGE_WRITE: Int = 1 26const val MESSAGE_TOAST: Int = 2 27//SPPを行うための専用UUID? 28val MYUUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") 29 30class MainActivity : AppCompatActivity() { 31 private val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter() 32 private var connectedThread: ConnectedThread? = null 33 private var connectThread: ConnectThread? = null 34 override fun onCreate(savedInstanceState: Bundle?) { 35 super.onCreate(savedInstanceState) 36 setContentView(R.layout.activity_main) 37 38 if (bluetoothAdapter == null) { 39 Log.d(TAG, "bluetooth is not supported.") 40 return 41 } 42 43 if (!bluetoothAdapter.isEnabled) { 44 val enableBluetoothIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) 45 startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BLUETOOTH) 46 } 47 48 val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter.bondedDevices 49 pairedDevices?.forEach { device -> 50 val deviceName = device.name 51 val deviceHardwareAddress = device.address // MAC address 52 if (device.name == TARGET_DEVICE_NAME) { 53 Log.d(TAG, "name = %s, MAC <%s>".format(deviceName, deviceHardwareAddress)) 54 device.uuids.forEach { uuid -> 55 Log.d(TAG, "uuid is %s".format(uuid.uuid)) 56 } 57 connectThread = ConnectThread(device) 58 connectThread?.start() 59 return 60 } 61 } 62 } 63 64 fun manageMyConnectedSocket(socket: BluetoothSocket) { 65 connectedThread = ConnectedThread(socket) 66 connectedThread?.start() 67 } 68 69 private inner class ConnectThread(device: BluetoothDevice) : Thread() { 70 private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) { 71 device.createInsecureRfcommSocketToServiceRecord(MYUUID) 72 } 73 74 public override fun run() { 75 // Cancel discovery because it otherwise slows down the connection. 76 bluetoothAdapter?.cancelDiscovery() 77 if (mmSocket == null) { 78 return 79 } 80 val socket = mmSocket 81 socket ?: return 82 socket.connect() 83 // The connection attempt succeeded. Perform work associated with 84 // the connection in a separate thread. 85 manageMyConnectedSocket(socket) 86 } 87 88 // Closes the client socket and causes the thread to finish. 89 fun cancel() { 90 try { 91 mmSocket?.close() 92 } catch (e: IOException) { 93 Log.e(TAG, "Could not close the client socket", e) 94 } 95 } 96 } 97 98 private inner class ConnectedThread(private val mmSocket: BluetoothSocket) : Thread() { 99 100 private val mmInStream: InputStream = mmSocket.inputStream 101 private val mmOutStream: OutputStream = mmSocket.outputStream 102 private val mmBuffer: ByteArray = ByteArray(1024) // mmBuffer store for the stream 103 private var message: Array<String?> = arrayOfNulls(10) 104 105 override fun run() { 106 var numBytes: Int // bytes returned from read() 107 Log.d(TAG, "connect start!") 108 // Keep listening to the InputStream until an exception occurs. 109 while (true) { 110 // Read from the InputStream. 111 numBytes = try { 112 mmInStream.read(mmBuffer) 113 } catch (e: IOException) { 114 Log.d(TAG, "Input stream was disconnected", e) 115 break 116 } 117 //message = arrayOf(ByteBuffer.wrap(mmBuffer).toString()) 118 if (mmBuffer[0].toString()!="10"){ 119 Log.d(TAG, mmBuffer[0].toString()+","+mmBuffer[1].toString()) 120 } 121 else{ 122 123 } 124// // Send the obtained bytes to the UI activity. 125// val readMsg = handler.obtainMessage( 126// MESSAGE_READ, numBytes, -1, 127// mmBuffer) 128// readMsg.sendToTarget() 129 } 130 } 131 132 // Call this method from the main activity to shut down the connection. 133 fun cancel() { 134 try { 135 mmSocket.close() 136 } catch (e: IOException) { 137 Log.e(TAG, "Could not close the connect socket", e) 138 } 139 } 140 } 141}

ManifestファイルでBluetoothに必要なuses-permissionは設定済みです。

実行結果

Android端末が接続されているPCのSerialモニターに、文字を打ち込み送信(Enter)を押すと、
イメージ説明
Android studio上のlogcat上には「97」と「10」が表示されます。
この場合、aの情報が97で改行?の情報が10だと思います。この数値を97と10でなくて、しっかりとaと表示させ、不要な情報である10は条件分岐などで消せればよいと考えてます。

やったこと

自分なりに考えてみたのですが下のコードで情報を受け取っていると思いました。このmmBufferに最終的に情報が入っていると考察しています。

kotlin

1 numBytes = try { 2 mmInStream.read(mmBuffer) 3 }

このmmBufferは ByteArray型(バイト配列?)であると出てきたので、型変換を行うために後ろに変換したい所望の型を付け加えたりしました。
例:整数なら.toInt()
しかし、結果は変わらずでした。
また、この記事を元にByteBuffer.wrap(longBytes).getLong()なども付け加えたりしたのですが、こちらも結果は変わりませんでした。

応用について

もし、上記の問題が解決できた場合でさらなる応用をしたいと思っています。
Arduino側で,区切りで複数のデータを送信してそのデータを受信側で区別する方法はありますでしょうか?送信側のArduinoのプログラム↓

Arduino

1 btSerial.write(mojia); 2 btSerial.write(","); 3 btSerial.write(mojib); 4 btSerial.write(","); 5 btSerial.write(mojic); 6 btSerial.write("\n");

以上です。
ここで質問するのは初めてなので、冗長で分かりづらい文章になってしまいましたがご助言やコード例、考え方などを教えていただけますと幸いです。
kotlinも始めて数か月ですので、まだまだ初歩的なこともわかっていません()...
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2022/05/26 10:21

97 と 10 は a と改行の文字コードなので、普通にそのバイト列を文字列に変換すれば良いかと。
guest

回答2

0

ベストアンサー

kotlin知らないので原則論だけ。

文字/文字コードとかその辺がなにかというと...コンピュータ上では基本的には数値しか扱えないので、数値と文字の対応表を使用者共通のお約束として持って、必要な場面ではその数値と文字を互いに読み替えて使う、ということにするわけです。この対応表が「文字コード表」で、文字に対応する数値が「文字コード」。
で、シリアルの通信路も(8bitであれば)0~255の数値データしか送れないので、もし文字を送りたいのならここに文字コードを載せることになります。で、'a'であれば16進数で0x61,10進数なら97、改行コードがLFであれば0x0a/10。
(ただし、ArduinoIDEの改行がCRおよびLFになっているのなら、CR(0xd/13)LF(0xa/10)が続いて送られるはずなのですが...)
とりあえず、受け取った「値」を表示することはできているということになるかと思います。
あとは、kotlin側でその値が文字コードであることを正しく扱えばいいだけ。そうすれば、97は'a'に、LFは、MS-DOS系の改行であるCRLFをunix系のLFに勝手に自動で変換したのでしょうか、形のある「文字」ではなく改行という動作になるはずです。
byteArrayで[97][10]という配列を文字列に変換すればいいわけで、私はkotlin知らないのでGoogle先生に'kotlin byteArray 文字列 変換'でどうですか、と聞いてみてとりあえずトップでヒットしたサイトをみてみると、

fun main(args: Array<String>) { val charset = Charsets.UTF_8 val b1 = byteArrayOf(-29, -127, -126, 65, 49) // バイト配列を文字列に変換 val str1 = String(b1, charset) //UTF-8 println(str1) //あA1 }

なんていう例も出てくるので、これが参考になるのではないでしょうか? (しかし「復号化して」という言葉はどうかな。「復号」だけでサ変名詞だから「復号して」でいいような気がするのだけど。まぁこれはオフトピ)

カンマ区切りは...最近の言語なら文字列クラスにsplitとかいうメソッドがあって、一発で区切って配列に仕立ててくれるんじゃないかと想像しますけど、kotlinはそういうのはないのですか?
またまたGoogle先生に'kotlin 文字列 split'で聞いてみると、とりあえずトップでヒットしたサイトを見るといろいろ書いてあるようですが。

投稿2022/05/26 23:02

thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

CrisisAnatres

2022/06/03 10:56

回答ありがとうございます。 返信が遅れてしまいました! その他の皆様も対応いただき本当にありがとうございました! 型など理論的な説明をしていただきましたので、ベストアンサーとさせていただきました! 現在は一応、10進数のデータを取得することができるようになりました! ここから応用もやっていきます! 以上、本当にありがとうございました!!!
guest

0

if (mmBuffer[0].toString()!="10"){

そりゃtoStringすりゃ数値が文字列に変換されてしまいます
これつけないで直接シリアル送信しましょう

if (mmBuffer[0]!=10){

投稿2022/05/26 10:42

編集2022/05/26 10:58
y_waiwai

総合スコア88024

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2022/05/26 13:21

mmBuffer[0] は byte なので、これを ToString() した場合、10 なら "10" になります。 確かに迂遠な方法ではありますが、mmBuffer[0] != 10 との差はこの場合ありません。 またこの部分はシリアル送信ではなく、受信後の条件分岐です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問