Search code examples
pythonlinuxros

How multiple run ros.init_node () in one python script?


I have written a program in python with ROS. It contains a GUI for "robot teleoperation", and in its MainWindow I added 3 widgets (rviz, joystick, button panel). When I start MainWindow I get the following error:

raise rospy.exceptions.ROSException("rospy.init_node() has already been called with different arguments: "+str(_init_node_args))

rospy.exceptions.ROSException: rospy.init_node() has already been called with different arguments: ('teleop_twist_keyboard', ['MainWindow.py'], False, None, False, False).

Joystick.py and Button.py contain ros.init_node() function. In MainWindow I instantiate Joystick and Button class and add them to MainWindow. I need to call ros.init_node() several times to communicate with various nodes.

directory structure

main window example

code main window

import sys
import PyQt5
import threading

from Joystick import Joystick
from QWidget_rviz import Rviz
from BaseArmPosition import BaseArmPosition

class MainWindow(PyQt5.QtWidgets.QMainWindow):

    def __init__(self,*args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.title = 'Robot teleoperation'
        self.left = 10
        self.top = 10
        self.width = 1920
        self.height = 1080

        self.joy = Joystick(maxDistance=50,MinimumSize=100,EclipseX=-20,EclipseY=40)
        self.rviz = Rviz()
        #self.arm_position = BaseArmPosition()


        self.initUI()

        
    def initUI(self):
        self.central_widget = PyQt5.QtWidgets.QWidget()
        self.setCentralWidget(self.central_widget)

        grid = PyQt5.QtWidgets.QGridLayout(self.centralWidget())

        grid.addWidget(self.joy, 0, 2)
        grid.addWidget(self.rviz, 0, 0)
        #grid.addWidget(self.arm_position, 0, 1)


        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.show() 

app = PyQt5.QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

code buttons widget, joistick.py has the same

import PyQt5
import rospy
from std_msgs.msg import String


class BaseArmPosition(PyQt5.QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super(BaseArmPosition, self).__init__(*args, **kwargs)            
        self.initUI()

    def initUI(self):
        self.pushButton_moveInit = PyQt5.QtWidgets.QPushButton("moveInit",self)
        self.pushButton_moveLeft = PyQt5.QtWidgets.QPushButton("moveLeft",self)
        self.pushButton_moveRight = PyQt5.QtWidgets.QPushButton("moveRight",self)

        layout = PyQt5.QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.pushButton_moveRight)
        layout.addWidget(self.pushButton_moveLeft)
        layout.addWidget(self.pushButton_moveInit)

        self.pushButton_moveInit.clicked.connect(self.moveInit)
        self.pushButton_moveLeft.clicked.connect(self.moveLeft)
        self.pushButton_moveRight.clicked.connect(self.moveRight)

        rospy.init_node("controller_ur")
        self.pub_arm = rospy.Publisher("/controller_ur/order",String,queue_size=1)

    def moveInit(self):
        moveInit = "moveInit"
        msg = String()
        msg.data = moveInit
        self.pub_arm.publish(moveInit)

    def moveLeft(self):
        moveInit = "moveLeft"
        msg = String()
        msg.data = moveInit
        self.pub_arm.publish(moveInit)

    def moveRight(self):
        moveInit = "moveRight"
        msg = String()
        msg.data = moveInit
        self.pub_arm.publish(moveInit)

Solution

  • A ROS node can only be initialized once in your program. You should centralize the initialization of the node at the beginning of the main script, and the rest of imported modules should not try to initialize a new node, as that is not allowed.

    If what you want is the different sub-modules to deal with different data, then you should just create separate topics within the same node.