Home e-Manual

Input/output error

Hello

We really enjoy using dynamixel motor xm430-w350-R. We would like to ask the question about what we observed during actuating 37 xm430-w350-R motors.

During the experiment, we sometimes observe the following warnings, which stop communication between the motors and the operation PC.

Here, I’d like to put the specification we are using:

  • We use the following setting for all 37 motors via R+ manager (of course, motor ids are different among different motors):

  • We use the following items to make communication between the computer and the motors: OpenCM 485 Expansion Board, U2D2.

  • The circuit works as follows:


    So, we have 4 parallel communication serial chains where each serial daisy chain is connected via RS485. From OpenCM 485 Expansion board to U2D2, it is connected via RS485. Then, U2D2 is connected to PC via USB.

  • We use 14.1 V as an input voltage to the OpenCM 485 Expansion board.

  • We use Python 3.

  • We use DEFAULT_BAUDRATE = 4000000 in port_handler.py in dynamixel_sdk.

  • We modify port_handler.py to play around LATENCY_TIMER. In our experience, if we set LATENCY_TIMER to relatively small values such as 1, 2, then we frequently observed this issue. If we set LATENCY_TIMER to relatively large values such as 7, 10, then we less frequently observed this issue but it did not go away.

So, could you tell us what’s going on? If possible, it’d be appreciated if you let us know how to fix this problem. Please let us know if you need more information/questions!

We look forward to hearing from you!
Best regards,

1 Like

Hi

Input/output error is too wide clues.

Can you make a brief source code and put it in here?

Maybe two DYNAMIXEL use code would be great as it seems that you are using Syncwrite.

Hello,

First of all, thank you so much for your help! Yes, let me share the following two scripts:

  1. This is the function calling groupSyncWrite

def set_command_position(id_position_list):

 if connected:
    ADDR_PRO_GOAL_POSITION = 116  # Control table address
    LEN_PRO_GOAL_POSITION = 4  # Data Byte Length: Note the unit is byte = 8 bits = 2 bits HEX

    # Wait until the USB port is released  =========================================================================
    ttyUSB_data = glob.read_one_data(glob.mem_ttyUSB_data, 'portOccupied')
    while ttyUSB_data[0]:
        ttyUSB_data = glob.read_one_data(glob.mem_ttyUSB_data, 'portOccupied')

    # Occupy the USB port  =========================================================================================
    data_usb_occupied = {}
    data_usb_occupied['portOccupied'] = np.array([1.0])
    glob.mem_ttyUSB_data.set(data_usb_occupied)

    lock.acquire()
    
    # compose sync_write package
    groupSyncWrite = GroupSyncWrite(portHandler, packetHandler,
                                    ADDR_PRO_GOAL_POSITION, LEN_PRO_GOAL_POSITION)

    num_of_motors = len(id_position_list)

    for iter in range(num_of_motors):
        DXL_ID = id_position_list[iter][0]
        dxl_goal_position = rad2tick(id_position_list[iter][1])

        # Allocate goal position value into byte array

        # A word = 4 digits HEX number = 16 bits binary number = 0 - 65535, thus 65536 has loword=0 and hiword=1
        # LOBYTE and HIBYTE separates low 4 digit HEX into 2 low + 2 high digits and express in DEX
        # e.g. 2047 has LOBYTE=255 and HIBYTE=7, since 15 + 15*16 = 255, 255 + 7*16^2 = 2047
        param_goal_position = [DXL_LOBYTE(DXL_LOWORD(dxl_goal_position)),
                               DXL_HIBYTE(DXL_LOWORD(dxl_goal_position)),
                               DXL_LOBYTE(DXL_HIWORD(dxl_goal_position)),
                               DXL_HIBYTE(DXL_HIWORD(dxl_goal_position))]

        # Add Dynamixel goal position values to the Syncwrite parameter storage
        dxl_addparam_result = groupSyncWrite.addParam(DXL_ID, param_goal_position)
        if not dxl_addparam_result:
            print("[ID:%03d] groupSyncWrite addparam failed" % DXL_ID)
            return False

    # Syncwrite goal position
    dxl_comm_result = groupSyncWrite.txPacket()
    if dxl_comm_result != COMM_SUCCESS:
        print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
        return False

    # Clear syncwrite parameter storage
    groupSyncWrite.clearParam()

    # Release the USB port =========================================================================================
    data_usb_occupied = {}
    data_usb_occupied['portOccupied'] = np.array([0.0])
    glob.mem_ttyUSB_data.set(data_usb_occupied)

    lock.release()
    #print("Lock released for send command ----------------------------------------------")

    return True
else:
    return False
  1. This is groupSyncWrite

#!/usr/bin/env python

-- coding: utf-8 --

################################################################################

Copyright 2017 ROBOTIS CO., LTD.

Licensed under the Apache License, Version 2.0 (the “License”);

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an “AS IS” BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

################################################################################

Author: Ryu Woon Jung (Leon)

from .robotis_def import *

class GroupSyncWrite:
def init(self, port, ph, start_address, data_length):
self.port = port
self.ph = ph
self.start_address = start_address
self.data_length = data_length

    self.is_param_changed = False
    self.param = []
    self.data_dict = {}

    self.clearParam()

def makeParam(self):
    if not self.data_dict:
        return

    self.param = []

    for dxl_id in self.data_dict:
        if not self.data_dict[dxl_id]:
            return

        self.param.append(dxl_id)
        self.param.extend(self.data_dict[dxl_id])

def addParam(self, dxl_id, data):
    if dxl_id in self.data_dict:  # dxl_id already exist
        return False

    if len(data) > self.data_length:  # input data is longer than set
        return False

    self.data_dict[dxl_id] = data

    self.is_param_changed = True
    return True

def removeParam(self, dxl_id):
    if dxl_id not in self.data_dict:  # NOT exist
        return

    del self.data_dict[dxl_id]

    self.is_param_changed = True

def changeParam(self, dxl_id, data):
    if dxl_id not in self.data_dict:  # NOT exist
        return False

    if len(data) > self.data_length:  # input data is longer than set
        return False

    self.data_dict[dxl_id] = data

    self.is_param_changed = True
    return True

def clearParam(self):
    self.data_dict.clear()

def txPacket(self):
    if len(self.data_dict.keys()) == 0:
        return COMM_NOT_AVAILABLE

    if self.is_param_changed is True or not self.param:
        self.makeParam()

    # =============================================== Xuan code to deal with input/output error ==================================================
    # ct = 0
    # ret = False
    #
    # while not ret or ct <= 100:
    #     try:
    #         ret = self.ph.syncWriteTxOnly(self.port, self.start_address, self.data_length, self.param,
    #                                 len(self.data_dict.keys()) * (1 + self.data_length))
    #     except:
    #         ct += 1
    #         print("Trial {}".format(ct))
    #
    # return ret
    #
    return self.ph.syncWriteTxOnly(self.port, self.start_address, self.data_length, self.param,
                                          len(self.data_dict.keys()) * (1 + self.data_length))

I’m sorry in advance since the code is a bit difficult to read it here. Ideally it’d be good if I can directly upload the files here but this community website does not allow me to do it…

I’m looking forward to hearing from you!
Best,

Hi, it’d be super appreciated if somebody answer my question. Thanks!

Hello,

Have you tried commenting in the code block at the bottom of your second code snippet?

That looks like an error handler that automatically retries to send the packet when that IO error occurs.
Try uncommenting it and setting

ret = True

then see if that works, or at least changes the error.

Hello,

Thanks for your reply!

That looks like an error handler that automatically retries to send the packet when that IO error occurs.
Try uncommenting it and setting

ret = True

then see if that works, or at least changes the error.

Actually, this is the error handler we created by ourselves which automatically retries to send the packet when that IO error occurs as you said.

The problem is, even if we activate (i.e., set

ret = True

)
, we still observed the input/output errors after

while not ret or ct <= 100:

That means, we think, that once the code detects error, we cannot resolve this issue even though we retry to send the packet.

Thanks again for your kind support. We still do not know why this is happening and do not know how to fix it. The thing is, this happens randomly so maybe hardware side issue?

Best,

When your error handler is running does it ever correctly reconnect after the warning?
What do you have to do to successfully reconnect to the port?

termios.tcdrain is the linux builtin for watching the specified output and waiting until data is finished being written, it is being called by the serial port handler to verify the data is finished sending before closing the port.

It could be that something else is reading or flushing the data that termios is trying to watch. Do you have anything else that might be reading or writing to that port?

It has also been reported that termios may throw that error when the terminal emulator output is busy due to trying to display the results of the command, in that case redirecting the output of the whole program to a file will solve the issue, so that could also be worth trying.

Thanks so much for your comments! Maybe we guess likely this is the reason:
It could be that something else is reading or flushing the

data that termios is trying to watch. Do you have anything else that might be reading or writing to that port?

I’ll report what will happen based on your comments. Thank you so much for your kind suggestion!

Best,