0

Android SPP Bluetoothソケットインターフェイスを使用して、Androidフォンからモーターを「できるだけ近い」リアルタイムで制御/操作しようとしています。モーターは、いわゆる「デッドマン」動作モードで動作する必要があります。そのため、アンドロイドアプリのボタンに触れた場合にのみモーターが回転し、タッチを離すとすぐに停止するはずです。

これを実装するには、約 20 ミリ秒ごとに 20 バイトの「回転し続ける」テレグラムを連続的に送信して、モーターの回転を維持し、テレグラムが受信されなくなるか、または STOP テレグラムが受信されるとすぐにモーターを停止させます。

これは、一部の電話では問題なく機能しているように見えますが、MotionEvent.ACTION_UP イベントが処理されてデータが送信されなくなった後でも、「回転し続ける」テレグラムを送信し続ける電話もあります。

これは、送信データをキャッシュし、バッファが空になるまで送信を続ける内部バッファが原因であると考えられます。

簡単な質問:

  • BT ストリーム送信バッファを消去して、すべてのデータ転送をすぐに停止する方法はありますか?
  • または、送信バッファのフィル レベルを取得できますか?
  • または、ストリームを開くときにバッファ サイズを指定する方法はありますか?

ネットを検索しても、バッファ管理の BT ストリーム バッファ サイズに関する記述は見つかりませんでした。

そして、はい、読み取りおよび書き込み機能をスレッドとして実装しました。すべてのテレグラムの読み取りに問題はありません。テレグラムをリアルタイムで配信する必要はありませんが、「回転し続ける」テレグラムの送信を停止できるはずです。 50~100ms。

どんなヒントでも大歓迎です。

4

1 に答える 1

0

コードを追加しなかったことをお詫びします。次のように簡単なので必要ないかもしれないと思いました。

    @Override
    public boolean onTouch(final View v,MotionEvent event) {
        int eventAction = event.getAction();

        switch (eventAction) {
            case MotionEvent.ACTION_DOWN:
                if (v == btnUp || v == btnDown) {

                    // Start a thread that sends the goUP or DOWN command every 10 ms until
                    // btnUp released

                    tvCounter.setText("----");
                    action_touched = true;

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            int counter = 1;

                            // Disable heart beat
                            ServiceRequest.send(EnRequest.REQ_SET_HEARTBEAT,0);

                            // Send GoUp command plus a wrapping counter byte every nn ms
                            // until the button is released

                            while (action_touched) {
                                try {
                                    setDeadmanMove(v==btnUp,counter);
                                    Thread.sleep(20);
                                    ++counter;
                                }
                                catch (InterruptedException ex) {
                                    action_touched = false;
                                }
                                catch (Exception ex) {
                                    action_touched = false;
                                }
                            }

                            // Send a STOP command
                            setDeadmanStop();

                            // Enable heart beat again
                            ServiceRequest.send(EnRequest.REQ_SET_HEARTBEAT,1);

                            // We are done
                        }
                    }).start();
                }
                break;

            case MotionEvent.ACTION_UP:
                // Stop Thread
                action_touched = false;
                break;
        }
        return true;
    }

以下の抜粋は、Bluetooth シリアル通信を管理する通信クラスの一部です。

 public void btWrite(DeviceRecord message) {
     if (runBTreceiver) {

         if (message.isValidRecord()) {
             try {

                 lock.lock();
                 ++lockCounter;
                 mmBufferedOut.write(message.getFullRecord());
                 mmBufferedOut.flush();
             }
             catch (IOException e) {
                 if (GlobalData.isDebugger) Log.i(TAG, "Failed sending " + message + " " + e.getMessage());
                 ServiceResponse.send(EnEvent.EVT_BT_RECEIVER_ERROR, "Error data send: " + e.getMessage());
                 resetConnection();
                 runBTreceiver=false;
             }
             finally {
                 --lockCounter;
                 lock.unlock();
             }
         }
     }
 }

Bluetooth 接続を割り当てて開くために切り取られたコード

try {
    // Set up a pointer to the remote node using it's address.
    BluetoothDevice device = myBluetoothAdapter.getRemoteDevice(myBluetoothMacId);
    if (device != null)
    {
        // Two things are needed to make a connection:
        // A MAC address, which we got above.
        // A Service ID or UUID. In this case we are using the
        // UUID for SPP.

        try {
            myBluetoothSocket = device.createRfcommSocketToServiceRecord(GlobalData.MY_UUID);
        }
        catch (IOException e) {
            sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,
                    String.format(GlobalData.rString(R.string.srv_failcrt),BTERROR_CREATE,e.getMessage()));
        }

        // Establish the connection. This will block until it connects or
        // timeout?

        try {
            if (! myBluetoothSocket.isConnected()) {
                myBluetoothSocket.connect();
            }
        }
        catch (IOException e) {
            try {
                Log.e("","trying fallback...");

                myBluetoothSocket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
                myBluetoothSocket.connect();
            }
            catch (IOException e2) {
                sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,e2.getMessage());
            }
        }
    }
    else {
        sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,
                String.format(GlobalData.rString(R.string.srv_failcrt),BTERROR_DEVICE,"getRemoteDevice failed"));
    }
}
catch (Exception e) {
    sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL, e.getMessage());
    return;
}
InputStream tmpIn = null;
OutputStream tmpOut = null;

mmSocket = socket;

// Get the input and output streams, using temp objects because
// member streams are final

try {
    tmpIn = socket.getInputStream();
    tmpOut = socket.getOutputStream();
}
catch (IOException e) {
    ServiceResponse.send(EnEvent.EVT_ERROR, GlobalData.rString(R.string.srv_failcst) + e.getMessage());
    resetConnection();
    runBTreceiver=false;
}
mmInStream = tmpIn;
// mmOutStream = tmpOut;
mmBufferedOut = new BufferedOutputStream(tmpOut,80);

// Initial request
btWrite(new DeviceRecord(0, 4));

このコードを介してデータを送受信する際の問題を発見したことはありません。すべてのレコードが適切に送受信されます。唯一の問題は、操作ボタンを放した瞬間に送信バッファをパージできないことでした。

この問題を克服するために、一度に 1 つの「回転し続ける」テレグラムのみが送信されるようにプロトコルを変更し、次のテレグラムは相手側からの応答の後に送信されます (ある種のハンドシェイク)プログラムは、ボタンが離されるまで、この ping/pong を実行し続けます。この方法は、送信バッファが一度に複数のテレグラムを保持しないため、非常にうまく機能します。

上記の問題は解決されましたが、送信バッファをパージできるかどうかはまだわかりません

于 2015-01-11T13:02:01.963 に答える