2
3

ROS2とQt5を使って自作UIを作ろう!!(1)

Posted at

はじめに

ロボコンをしていると、強豪校は自作のコントロールUIを作ったりしているのをよく目にします。
今回私がUIを書こうと思ったのは、それが単純にかっこいいと思ったからです。しかし、いざ書こうとすると、どのように書いたらいいかわかんなくなると思います。そんな人のためにこの記事を書きました。少しでも役に立つと幸いです。思ったより長くなりそうなのでpartを分けます。今回はROS2とQt5の連携の仕方です。

今回の学ロボで作ったUIの機能(ざっくり)

今回のUIに求めた機能は以下のようになっています。

  • ロボットに乗せてあるカメラの画像の表示
  • ボタンによってロボットに司令を送信する
  • ロボットが今どこにいるのかの可視化
  • ロボットの状態の表示
    完成品はもう少しタイマー等の機能が増えて以下のようになりました。
    IMG_8558.jpg
    この記事ではこのUIで使った基本的な部分のみ抜粋して解説していきます。
    コードの全体はgithubに上げておきます。

ROS2とQt5の連携

最初の一歩はROS2とQt5の連携です。ボタンを押したら、ボタンを押した回数をpubするUIをつくります。実際に動かすと以下のようになります。
IMG_8185.jpg

実際のコードは以下のようです。
ui_test.pyは以下のようになっておりこのコードはボタンの配置とかを指定しています。

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'ui_test.ui'
#
# Created by: PyQt5 UI code generator 5.14.1
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(400, 300)
        self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setObjectName("label")
        self.horizontalLayout.addWidget(self.label)
        self.pushButton = QtWidgets.QPushButton(Dialog)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout.addWidget(self.pushButton)

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.label.setText(_translate("Dialog", "TextLabel"))
        self.pushButton.setText(_translate("Dialog", "PushButton"))

ROSとかの処理を書いている方(上のui_test.pyをimportして使ってます)

import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtGui import QPixmap,QIcon
from ui_test import *

import rclpy
from rclpy.node import Node
from std_msgs.msg import Int32

class MyForm(QDialog):
    def __init__(self,parent=None):
        super(MyForm,self).__init__(parent)
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)
        self.count =0
        self.ui.pushButton.clicked.connect(self.button_update)
        self.show()
        
        rclpy.init(args=None)
        self.node = Node('button_main')
        self.pub = self.node.create_publisher(Int32,'button_topic',10)
        
    def __del__(self):
        self.node.destroy_node()    
        
    def pub_int32(self,num: int):
        msg = Int32()
        msg.data=num
        self.pub.publish(msg)
        
         
    def button_update(self):
        self.count +=1
        self.pub_int32(self.count)
        print(f'{self.count}回目のボタンが押されました\n')
        
        

        

def main():
    app = QApplication(sys.argv)
    window = MyForm()
    window.show()
    sys.exit(app.exec_())

if __name__=="__main__":
    main()

解説

Qtの解説は長くなるので今回はrosに関するところを説明します。

  • コンストラクタでnodeを初期化してインスタンス化しています。
    その中にpablisherを宣言しています。
        rclpy.init(args=None)
        self.node = Node('button_main')
        self.pub = self.node.create_publisher(Int32,'button_topic',10)
  • デイストラクタではnodeを破棄しています。
def __del__(self):
        self.node.destroy_node() 
  • ボタンが押されたときのcallbackを宣言
self.ui.pushButton.clicked.connect(self.button_update)
  • ボタンが押されたときのcallback関数でbutton_updateがあります。
    この関数では押された回数を数えてそれをpublishしています。
def button_update(self):
        self.count +=1
        self.pub_int32(self.count)
        print(f'{self.count}回目のボタンが押されました\n')

終わりに

今回は主にros2側を解説しました。
この記事を書いていてQtの説明を入れるのが難しかったのでまたの機会にQtだけの記事も書いたほうがいいと感じました。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3