0
votes

Hello software developers. I am new in programming and ROS. I am working now with servo motors and want to make the controlling node to rotate motor into some degrees like from 0 --> 90--> 180-->0 degrees. there is a main code and I would like to add def function into the main node:

#!/usr/bin/env python

import os
import rospy
from std_msgs.msg import String
from controller_motor.msg import Motor
from controller_motor.srv import Motor2


if os.name == 'nt':
    import msvcrt
    def getch():
        return msvcrt.getch().decode()
else:
    import sys, tty, termios
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    def getch():
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

from dynamixel_sdk import *                    # Uses Dynamixel SDK library


class DynamixelController(object):
    def __init__(self):
        #print("1")

        self.motor_sub = rospy.Subscriber("/motor_topic", Motor, self.motor_callback)
        self.test_motor_client(1)                #here we can put request order as 1 for the using id=14 and position= 1500; or as 2 is id same and position is 2500. The cases could be found in the server.py node
    
    def motor_callback(self, data):
        _id = data.id
        _position = data.position

        print("_id : {0}, _position : {1}".format(_id, _position))
        self.read_write(_id, _position)

    def test_motor_client(self, request):
        print("2")
        rospy.wait_for_service('test_motor_service')
        try:
            proxy = rospy.ServiceProxy('test_motor_service', Motor2)
            response = proxy(request)
            print("response is id : {} position : {}".format(response.id, response.position))

            self.read_write(response.id, response.position)

        except rospy.ServiceException as e:
            print("Service call failed: %s"%e)

    def new_rotation(self, response):
        print("3")
        rospy.wait_for_service('test_mototr_rotation')
        try:
            proxy = rospy.ServiceProxy('test_motor_rotation', Motor2)
            response = proxy(request)
            self.read_write(response.id, response.position(arg[0]))
            sleep(2)
            self.read_write(response.id, response._position(arg[1]))
            sleep(2)
            self.read_write(response.id, response._position(arg[2]))
            sleep(2)
        except rospy.ServiceException as e:
            print("Service call failed: %s"%e)
    

    
    def read_write(self, _id, _position):
        print("Start the node")
     

        # Control table address
        ADDR_PRO_TORQUE_ENABLE      = 64                  # Control table address is different in Dynamixel model
        ADDR_PRO_GOAL_POSITION      = 116
        ADDR_PRO_PRESENT_POSITION   = 132
       
        # Protocol version
        PROTOCOL_VERSION            = 2.0                 # See which protocol version is used in the Dynamixel

        # Default setting
        DXL_ID                      = _id                 # Dynamixel ID : 14
        BAUDRATE                    = 1000000             # Dynamixel default baudrate : 1000000
        DEVICENAME                  = '/dev/ttyUSB0'      # Check which port is being used on your controller
                                                          # ex) Windows: "COM1"   Linux: "/dev/ttyUSB0" Mac: "/dev/tty.usbserial-*"

        TORQUE_ENABLE               = 1                 # Value for enabling the torque
        TORQUE_DISABLE              = 0                 # Value for disabling the torque
        DXL_MINIMUM_POSITION_VALUE  = 10                # Dynamixel will rotate between this value
        DXL_MAXIMUM_POSITION_VALUE  = _position         # The position here is already in the degree measurement; and this value (note that the Dynamixel would not move when the position value is out of movable range. Check e-manual about the range of the Dynamixel you use.)
        DXL_MOVING_STATUS_THRESHOLD = 20                # Dynamixel moving status threshold
        

        index = 0
        dxl_goal_position = [DXL_MINIMUM_POSITION_VALUE, DXL_MAXIMUM_POSITION_VALUE]         # Goal position
        


        # Initialize PortHandler instance
        # Set the port path
        # Get methods and members of PortHandlerLinux or PortHandlerWindows
        portHandler = PortHandler(DEVICENAME)

        # Initialize PacketHandler instance
        # Set the protocol version
        # Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
        packetHandler = PacketHandler(PROTOCOL_VERSION)

        # Open port
        if portHandler.openPort():
            print("Succeeded to open the port")
        else:
            print("Failed to open the port")
            print("Press any key to terminate...")
            getch()
            quit()


        # Set port baudrate
        if portHandler.setBaudRate(BAUDRATE):
            print("Succeeded to change the baudrate")
        else:
            print("Failed to change the baudrate")
            print("Press any key to terminate...")
            getch()
            quit()

        # Enable Dynamixel Torque
        dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)
        if dxl_comm_result != COMM_SUCCESS:
            print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
        elif dxl_error != 0:
            print("%s" % packetHandler.getRxPacketError(dxl_error))
        else:
            print("Dynamixel has been successfully connected")

        while 1:
            print("Press any key to continue! (or press ESC to quit!)")
            if getch() == chr(0x1b):
                break

            # Write goal position
            dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL_ID, ADDR_PRO_GOAL_POSITION, dxl_goal_position[index])
            if dxl_comm_result != COMM_SUCCESS:
                print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
            elif dxl_error != 0:
                print("%s" % packetHandler.getRxPacketError(dxl_error))

            while 1:
                # Read present position
                dxl_present_position, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL_ID, ADDR_PRO_PRESENT_POSITION)
                if dxl_comm_result != COMM_SUCCESS:
                    print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
                elif dxl_error != 0:
                    print("%s" % packetHandler.getRxPacketError(dxl_error))

                print("[ID:%03d] GoalPos:%03d  PresPos:%03d" % (DXL_ID, dxl_goal_position[index], dxl_present_position))

                if not abs(dxl_goal_position[index] - dxl_present_position) > DXL_MOVING_STATUS_THRESHOLD:
                    break

            # Change goal position
            if index == 0:
                index = 1
            else:
                index = 0


        # Disable Dynamixel Torque
        dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
        if dxl_comm_result != COMM_SUCCESS:
            print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
        elif dxl_error != 0:
            print("%s" % packetHandler.getRxPacketError(dxl_error))

        # Close port
        portHandler.closePort()
if __name__ == '__main__':
    rospy.init_node('read_write', anonymous=True)
    controller = DynamixelController()

and here is the server node:

#!/usr/bin/env python
import rospy
from controller_motor.srv import Motor2, Motor2Response


def motor_info(req):
    print("receive the request : {}".format(req.order))
    if req.order == 1:
        _id = 14
        #_position = 1500
        _positiondegree = 180                 # change it degree value
        _position = (11.4 * (_positiondegree))  # here is using there 11.4 the number which helps rotate the motor in the correct degree; We get the number encoder number/degree we want to rotate the motor.
              
    elif req.order == 2:
        _id = 14
        #_position = 2047.5
        _positiondegree = 180
        _position = (11.4 * (_positiondegree))
       

    print("Response to this request id : {} and postiion : {}".format(_id, _position))
    return Motor2Response(_id, _position)
   

    
def motor_info_server():

    rospy.init_node('test_motor_service')
    s = rospy.Service('test_motor_service', Motor2, motor_info)
    print("Ready to response some id and position")

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

if __name__ == '__main__':
    motor_info_server()

Now when running the motor it rotates to the degree I would like it to rotate. And now I would like to know how could I give some degrees to make motor rotates from 0 to some other degrees and go back to the 0 degree position again.

I guess there might be applied the list and args for some degrees. But I am not well-known how I could do this :) I would like to get some advice from professionals like you ,guys :)

I know my question could be obvious for professionals. I would like to get experience in the programming and ROS as much as I can :)

I will be so thankful for any help and advise how I could do this :)

Thank to everyone who will share his/her idea:)

I wish you have a good day :)

1
I don't know much about ROS, but as a general tip - you've posted too much code. I would estimate that at least 90% of the code you show have nothing to do with the issue (motor rotation). Chances of getting an answer improve if you cut down the code sample to the minimum (minimal reproducible example). Usually that means rewriting it from scratch so it does nothing but the thing you have a question about. - Tomalak

1 Answers

0
votes

You have to add a new function to your code in the client file:

def rotate_bot(self,degree):
     rospy.wait_for_service('rotate_motor')
     try:
         proxy = rospy.ServiceProxy('test_motor_rotation', Motor2)
         response = proxy(degree)
     except rospy.ServiceException as e:
         print("Service call failed: %s"%e)

This function basically calls a Service and gives him the amount of degrees the robot has to turn. Also add this function to call the roate function:

def test_rotate(self):
       rotate_bot(90)
       rotate_bot(90)
       rotate_bot(-180)

Now the robot turns from 0 --> 90 --> 180 --> 0 In your server file you have to add the service in the motor_info_server() method:

s = rospy.Service('test_motor_rotation', Motor2, rotate_motor)

and also add the method:

def rotate_motor(req):
    print("received the request : {}".format(req.order))
    degree = req.order
    _id = 14
    _positiondegree = degree                 
    _position = (11.4 * (_positiondegree))  

    return Motor2Response(_id, _position)

If you want to pass doubles as degrees you have to change your message datatype from Motor2 to something else...