pythonservicerosrospy

How to create a ROS service to write at serial port [python]? [Problem with self as argument]


I have a node that has a serial connection. I want to create a service so other nodes can send requests for it to write at the serial.

This is the server:

import rospy
import serial
from my_package.srv import SerialData

class SerialServer:

    def __init__(self):

        # Initialize the node and name it.
        rospy.init_node('serial_server', anonymous=True)

        # Services
        rospy.Service('send_serial', SerialData, send_serial)

        # Serial connection
        self.ser = serial.Serial('/dev/ttyUSB0', baudrate=115200, timeout=1) 


def send_serial(self, req):
        try:
            self.ser.write(req)
            return 1
        except:
            rospy.loginfo('*** could not send ***')
            return 0

def main():
    try:
        #Initialize
        serial_server = SerialServer()
    except rospy.ROSInterruptException: pass

    #spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    main()


However, it needs self as an argument, which causes an error when I try to call the service from the client because I have no access to the server object from the client node.

send_serial(initCondition)

"error processing request: send_serial() missing 1 required positional argument:

import rospy
from ros_igtl_bridge.msg import igtlstring

class SerialClient:

    def __init__(self):

        # ROS Topics
        rospy.Subscriber('IGTL_STRING_IN', igtlstring, self.callbackString)

        # Initialize the node and name it.
        rospy.init_node('serial_client', anonymous=True)

    def callbackString(self, msg):
        if msg.name == 'INIT':
            initCondition = msg.data[4] + msg.data[5]
            rospy.wait_for_service('send_serial')
            try:
                send_serial = rospy.ServiceProxy('send_serial', SerialData)
                if (send_serial(initCondition)):
                    rospy.loginfo("Initialization successful")
                else:
                    rospy.loginfo("Could not initialize")
            except rospy.ServiceException as e:
                rospy.loginfo("Controller Service call failed: %s"%e)


def main():
    try:
        #Initialize
        serial_client = SerialClient()
    except rospy.ROSInterruptException: pass

    #spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    main()

Which is the appropriate way to implement this type of service in ROS?


Solution

  • The indentation is wrong in your first file. send_serial should be a attribute of the class; that way when it's called a reference to the instance(self) will be passed in too. You will then have to also change the code where you set up the service such as:

    rospy.Service('send_serial', SerialData, self.send_serial)