Raspberry PiでQtを使うUDPソケット通信 ~ QUdpSocket

2021年10月16日

スマートフォンからデータをRaspberry Piへ送る場合、UDPソケット通信を使う方法があります。これは以前の投稿でやっています。

以前の例では、Raspberry Piの受信プログラムがターミナル用でした。そこで今回はフォーム版で作ります。そしてフォーム版ということで、Qtを使います。

そのQtのプログラムですが、UDPソケットを扱うクラス「QUdpSocket」を使うことにしました。ターミナル版のロジックをそのまま使うと、いろいろ問題がありました。

それでは、プログラムを紹介します。

1.スマートフォン側プログラム

スマートフォン側のデータ送信を行うプログラムは、0から1000の数値をテキストでRaspberry Piに送ります。値はボタンの+ーで調節します。また、Raspberry PiIPアドレスを入力します。

Androidmanifest.xml

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

権限を加えてください

プログラム

public class MainActivity extends AppCompatActivity {
    private EditText IpAddressInput ;

    private final Handler handler = new Handler();

    private String wkstr ;
    private String clientIPAddress ;
    private int power = 0 ;

    private Button plusbutton ;
    private Button minusbutton ;
    private TextView powertext ;

    public MainActivity() {
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        clientIPAddress = "192.XXX.XXX.XXX" ;

        plusbutton = (Button) findViewById(R.id.plusbutton);
        minusbutton = (Button) findViewById(R.id.minusbutton);
        powertext = (TextView) findViewById(R.id.powertext);

        IpAddressInput = (EditText) findViewById(R.id.ipaddress) ;

        plusbutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                power += 10;

                if (power > 1000) {
                    power = 1000;
                }

                wkstr = String.valueOf(power);
                powertext.setText(wkstr);

                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        try {

                            clientIPAddress = IpAddressInput.getText().toString() ;

                            DatagramSocket sendUdpSocket = new DatagramSocket();
                            InetAddress IPAddress = InetAddress.getByName(clientIPAddress);

                            byte[] strByte = wkstr.getBytes("UTF-8");

                            DatagramPacket sendPacket = new DatagramPacket(strByte, strByte.length, IPAddress, 60000);

                            sendUdpSocket.send(sendPacket);
                            sendUdpSocket.close();

                        } catch (IOException e) {

                            System.out.println(e.getMessage());
                        }
                    }
                }).start();

            }
        });

        // マイナスボタン処理は省略
    }
}

UDPソケット通信は別スレッドで行うことに注意してください。

2.Raspberry Pi側プログラム

Raspberry Pi側のプログラムは、Qt Creatorを使って作成します。

フォーム

フォームエディタで画面を作成します。スマートフォンから送られてきたデータを表示するようにします。

プロジェクトファイル

QT += network

今回、QUdpSocketクラスを使うので、プロジェクトファイルに上記の記述を追加します。「QT += core gui」の行の下に追加すると良いでしょう。

ヘッダファイル

以下の記述をしました。説明はコメントにしています。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtNetwork/QUdpSocket>
#include <QDebug>

#define PORT_NUMBER 60000

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void udpupdate() ; // データを受信した時の関数
    void on_pushButton_clicked(); // 終了ボタンが押された時

private:
    Ui::MainWindow *ui;
    QUdpSocket udpSocket; // QUdpSocketインスタンス

};
#endif // MAINWINDOW_H

ソースファイル

以下の記述をしました。QUdpSocketクラスのおかげで、すごく簡単なソースになりました。

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    udpSocket.bind( PORT_NUMBER );
    connect( &udpSocket, SIGNAL( readyRead() ),
             this, SLOT( udpupdate() ) );
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::udpupdate()
{
    QByteArray byteArray;
    QString recieveStr;

    byteArray.resize( udpSocket.pendingDatagramSize() );
    udpSocket.readDatagram( byteArray.data(), byteArray.size() );

    ui->le_Power->setText(QString::fromUtf8(byteArray)) ;
}

void MainWindow::on_pushButton_clicked()
{
    close() ;
}

3.スマートフォンでRaspberry Piをコントロールしよう!

今回、とても簡単にスマートフォンからRaspberry Piへデータを送ることができました。UDPソケットを使えば、スマートフォンをコントローラにしたRaspberry Piのシステムを簡単に実現できると思います。

ひとつ、Raspberry PiIPアドレスを取得しなければなりませんが、今回フォームプログラム化したことでデスクトップが表示されているはずなので、IPアドレスの確認は簡単でしょう(Wi-Fiのアイコンにカーソルを置けば表示される)。

それに、スマートフォンテザリング環境で動作させることを前提としているので、IPアドレスが変わることは少ないと思います。

今回のプログラムは、先に予定している投稿のシステムの一部になります。よろしくお願いします。