Another instance using the serial port

Hey!

Finally my servos arrived, I’m still trying to use pypot, but calling only the autodetect method from the dynamixel module ,eg. I make an empty .py file which only contains this:
robot = autodetect_robot()
will throw me a DxlError.

Trace:
Traceback (most recent call last): File "python_test.py", line 23, in <module> test_instance = Test() File "python_test.py", line 10, in __init__ self.core = Core() File "/Users/pszent/repos/io.payworks.mpos.robot/python_core.py", line 55, in __init__ self.robot = autodetect_robot() File "/Users/pszent/Library/Python/2.7/lib/python/site-packages/pypot/dynamixel/__init__.py", line 115, in autodetect_robot dxl_io = DxlIOCls(port) File "/Users/pszent/Library/Python/2.7/lib/python/site-packages/pypot/dynamixel/io/abstract_io.py", line 75, in __init__ self.open(port, baudrate, timeout) File "/Users/pszent/Library/Python/2.7/lib/python/site-packages/pypot/dynamixel/io/abstract_io.py", line 98, in open self._open(port, baudrate, timeout) File "/Users/pszent/Library/Python/2.7/lib/python/site-packages/pypot/dynamixel/io/abstract_io.py", line 120, in _open raise DxlError('Another instance of pypot use the port {}. You should restart your Python kernel to pass through this issue.'.format(port)) pypot.dynamixel.io.abstract_io.DxlError: Another instance of pypot use the port /dev/tty.usbmodem14111. You should restart your Python kernel to pass through this issue.

I’m using OS X Sierra, with the newest macbook pro, therefore I needed an USB hub connected to the Thunderbolt 3 type connectors to get the USB2AX working. That is connected to a power/serial hub, and the servo itself. Only 1 servo attached, I configured its ID already with the Dynamixel Configurator, it worked there.

Any tips?

Cheers,
Pali

Hi,

What usb2AX (version) ? What servos ?
Better to go step by step, so you could understand issues without difficulties.
Autodetect_robot() is an old function, not totally operationnel.
The problem is about your port (maybe autodetect use a wrong port)
What I recommend is to run the command here stept by step to catch the problem :

Starting with low level communication is a good option to understand.[quote=“pszent, post:1, topic:2879”]
I needed an USB hub
[/quote]

Normally the usb2AX doesn’t need any hub.

Hi,

  • Are you sure that your servo are powered (plugged to a 12V power) ?
  • Are you sure that you don’t have multiple servo with the same IDs on the bus ?

Maybe pypot try to open a port from another device which is used by your computer. You can scan the potential serial ports with

import pypot.dynamixel
pypot.dynamixel.get_available_ports()

the newest macbooks doesnt have normal usb ports, only usb c, so i need an usb hub which connects to the mac through that, and offers normal usb ports.

edit: sorry, I forgot to add the details you requested: Dynamixel AX-12A servos, usb2AX 3.2b, I use a 6 Port AX/MX Power Hub from Trossen Robotics to power the servos with a 12V5A DC PSU.

I spent days on understanding the low level communication, I’d say I’m at the point where I have a clear, thorough view about it. It causes me no issue to communicate, move and set register values on servos, however, I am only able to do this through the DxlIO instance because of this issue, which renders me unable to use any other higher level abstractions (eg. DxlAXRXMotor from motors, etc. I tried instantiating motors from config instead of autodetect, it gives me the same error.

Hey Theo!

As I mentioned in the reply to the previous suggestion, it causes me no issue to address the servos through the IO properly (eg. using the set_goal_position method on the DxlIO class). However I can’t use any higher level abstraction of the robot because of this error. I tried to instantiate the motors using a config files, got the same error.

Are you using low level on /dev/tty.usbmodem14111 port ? If not it can be another port created by your USB hub or a device (e.g. wirelmess mouse) with is used by another process of your computer.

Another solution could be to wrote your own configuration file take the old ergo as an example.

It is really weird that it works on low level and not with a config file. The high level is just a a loop on low level communication.
What is the port used (succesfully !) with low level communication ?
Can you post your configuration file to check what port you are using.

I haven’t touched the whole things for 2 weeks now, I can’t quite remember the actual config I used to reproduce the exact same issue, but with this piece of code (which includes the config too) I get an error which might be in connection with the autodetect issue (the config was something similar to this though):

import pypot.robot

my_config = {‘controllers’: {}}

my_config[‘controllers’][‘example_controller’] = {
‘port’: ‘/dev/tty.usbmodem14341’,
‘sync_read’: False,
‘attached_motors’: [‘example_motors’],
‘protocol’: 1,
}

my_config[‘motorgroups’] = {
‘example_motors’: [‘single_motor’],
# ‘torso’: [‘arms’, ‘head_x’, ‘head_y’],
# ‘arms’: [‘left_arm’, ‘right_arm’],
# ‘left_arm’: [‘l_shoulder_x’, ‘l_shoulder_y’, ‘l_elbow’],
# ‘right_arm’: [‘r_shoulder_x’, ‘r_shoulder_y’, ‘r_elbow’]
}

my_config[‘motors’] = {}
my_config[‘motors’][‘single_motor’] = {
‘id’: 1,
‘type’: ‘AX-12A’,
‘orientation’: ‘direct’,
‘offset’: 0.0,
‘angle_limit’: (-90.0, 90.0),
}

robot = pypot.robot.from_config(my_config)

for m in robot.example_motors:
print ‘moving to 90’
m.goal_position = 90.0
print 'current position is ', m.present_position
print ‘moving to 0’
m.goal_position = 0.0
print 'current position is ', m.present_position

To ensure I’m using the correct ports and ID (I used these in the config):

The issue is that if I don’t comment the move, it’ll return -0.15 degree (although I set the position to zero through the IO from the console previously) and if I comment it, it returns 0.15, but it doesn’t move one bit. I suspect this happens because the code subscribes something else on this bus and it returns with some garbage (although I haven’t been able to trace this theory back - I’m still novice at python).

I also tried unplugging every other device but the USB2AX, same issue.

It works properly, I think that your motor is compliant. It have to be stiff to be controlled by software.

You have to do something like

 motor_instance.compliant = False

Hey!

A little update: I got all my motors, so I was trying to use this config (based on the ergo jr config):

my_config = {
‘controllers’: {
‘my_dxl_controller’: {
‘sync_read’: False,
‘attached_motors’: [‘a’, ‘b’, ‘c’, ‘d’],
‘port’: ‘/dev/tty.usbmodem14331’
}
},
‘motorgroups’: {
‘a’: [‘m1’],
‘b’: [‘m2’],
‘c’: [‘m3’],
‘d’: [‘m4’, ‘m5’, ‘m6’]
},
‘motors’: {
‘m1’: {
‘orientation’: ‘indirect’,
‘type’: ‘AX-12A’,
‘id’: 1,
‘angle_limit’: [-90.0, 90.0],
‘offset’: 0.0
},
‘m2’: {
‘orientation’: ‘direct’,
‘type’: ‘AX-12A’,
‘id’: 2,
‘angle_limit’: [-90.0, 90.0],
‘offset’: 0.0
},
‘m3’: {
‘orientation’: ‘indirect’,
‘type’: ‘AX-12A’,
‘id’: 3,
‘angle_limit’: [-90.0, 90.0],
‘offset’: 0.0
},
‘m4’: {
‘orientation’: ‘direct’,
‘type’: ‘AX-12A’,
‘id’: 4,
‘angle_limit’: [-90.0, 90.0],
‘offset’: 0.0
},
‘m5’: {
‘orientation’: ‘indirect’,
‘type’: ‘AX-12A’,
‘id’: 5,
‘angle_limit’: [-90.0, 90.0],
‘offset’: 0.0
},
‘m6’: {
‘orientation’: ‘indirect’,
‘type’: ‘AX-12A’,
‘id’: 6,
‘angle_limit’: [-90.0, 90.0],
‘offset’: 0.0
}
}
}

Theos suggestion won’t work, because I can’t instantiate the motors. As soon as my code tries to execute

robot = pypot.robot.from_config(my_config)

I get the original error. However, if I use ‘port’: ‘auto’ instead of explicitly naming the port, I get a different error message:

available ids: [1, 3, 4, 5, 6]
Traceback (most recent call last):
File “asd.py”, line 70, in
robot = pypot.robot.from_config(my_config)
File “/Users/pszent/Library/Python/2.7/lib/python/site-packages/pypot/robot/config.py”, line 62, in from_config
dxl_io = dxl_io_from_confignode(config, c_params, attached_ids, strict)
File “/Users/pszent/Library/Python/2.7/lib/python/site-packages/pypot/robot/config.py”, line 160, in dxl_io_from_confignode
port = pypot.dynamixel.find_port(ids, strict)
File “/Users/pszent/Library/Python/2.7/lib/python/site-packages/pypot/dynamixel/init.py”, line 106, in find_port
ids, list(set(ids) - set(ids_founds))))
IndexError: No suitable port found for ids [2, 1, 3, 4, 5, 6]. These ids are missing [1, 2, 3, 4, 5, 6] !

Notice how I inserted a scan on the io before I instantiated the robot, the io accesses the servo ids, which the from_config method says are missing in the error message. Also notice, compared to the ergo config, i changed the order of the motors in the config (but they belong to the proper motor group, so I’m not sure this should be an issue).

The result of this test show that your motor is working, and I also think the motor doesn’t move because it was compliant.
Probably something is wrong in your config file.

Have you tried low level communication with your 6 motors ? If not better to do it and to check the response time of your 6 motors.

I tried setting compliance explicitly to false (as Theo previously suggested), with no result, it still gives back the same -0.15 and 0.15 degrees.
I can only communicate with the servos low level (using a DxlIO instance), how do you mean to check the response times? What do they have to do with the issue? On low level I can control and move (therefore it never was a question if the motors are working) my servos without an issue, are you suggesting if the response time is too high then the higher abstraction levels (eg. motor instances) won’t execute the commands?
I don’t understand properly what does compliant means, if it’s an issue, shouldn’t it render me unable to use the servos through low level as well?

I’m at the point currently where I feel it would be more helpful if someone could provide me a working config and a piece of code for one AX-12A (eg. turn +90 degrees).

You should not instanciate multiple time the serial port…
I see

And the traceback after, which means that you did a scan in low level and instantiate your robot after. If you didn’t close the DxlIO instance, it could be the reason of your problem.

On the scan you seems to not have motor with id 2, is it intentional ?

You should not instanciate multiple time the serial port…

I did it solely for the purpose of proving that I can see the servos on low level, it makes no difference if I delete that part. As I already stated in the OP, an empty file only containing the autodetect (or the instantiation from config) throws the error, normally I do not want to instantiate the DxlIO class. I figured out that this was a mistake, so instead of this, I used a for loop cycling through the motors in the robot, printing their ids, same result.

regarding to the list of servos: it seems strange, I definitely have one with the ID 2. I probably missed connecting it, but I just checked it with all connected, the list of IDs contains ID 2 now, still don’t move.

Although I did a rather interesting discovery: If I move the servos with 0 torque (eg. before I fire up the script) the position will change accordingly. This means the config I use and the way I use it works, now the only question is why don’t they move regardless of their compliance.

If you can move the servos by hands, this means that they are compliant.

What’s the return of :

robot.compliant

the return value is an empty list (by default, right after instantiation from config).

I still don’t understand why are we forcing this approach, I already tried modifying the compliance values and with no result. What does compliance do?

Dynamixel motors have 2 states :
_ State 1 compliant : you can move the motors by hands but motors can’t move with a goal_position statement
_ State 2 not compliant (or stiff) : you can not move motors by hands but motors move with a goal_position

Why forcing this approach : if I understood correctly what you meant, your only problem is motors which are not moving. So, your setup seems to be good it is why for us the compliance could be the problem.

To confirm your motors are stiff :

robot.m1.compliant

should return False and in this case it is normaly not possible to turn your motors by hands.

if I use low level io to move the motors I experience the effect you are describing, I’m not able to turn the servos by hand. if i instantiate them from config, it’s not happening, they are just slightly more difficult to turn than they are while not getting power (obviously). you can see that the robot.compliant returns an empty list, which then I suppose means that none of my motors are compliant, therefore they should move.

When you send an order to the motor :
robot.m1.goal_position = 90

They don’t move. Can you tel me what is the return of (after sending the goal_position = 90) :
> robot.m1.__dict__

sure, here you go:

{
    'safecompliance': ,
    'readsynchronous': defaultdict( < function at 0x75e0b0f0 > , {
        'present_temperature': False,
        'name': False,
        'present_voltage': False,
        'upper_limit': False,
        'lower_limit': False,
        'present_position': False,
        'angle_limit': False,
        'model': False,
        'id': False
    }),
    'direct': False,
    'present_load': 0.0,
    'id': 1,
    'present_temperature': 37.0,
    'compliant': False,
    'compliantbehavior': 'dummy',
    'moving_speed': 0,
    'compliance_slope': (32, 32),
    'defaultgoto_behavior': 'dummy',
    'writesynchronous': defaultdict( < function at 0x75e0b1f0 > , {
        'goal_position': False,
        'compliance_slope': False,
        'torque_limit': False,
        'moving_speed': False,
        'compliance_margin': False
    }),
    'torque_limit': 100.0,
    'broken': False,
    'goalposition': -90.0,
    'readsynced': defaultdict(, {
        'compliance_slope': ,
        'present_temperature': ,
        'present_voltage': ,
        'upper_limit': ,
        'lower_limit': ,
        'compliance_margin':
    }),
    'upper_limit': 89.88,
    'lower_limit': -89.88,
    'max_pos': 150,
    'offset': 0.0,
    'compliance_margin': (1, 1),
    'name': 'm1',
    'present_speed': 0.0,
    'present_voltage': 12.3,
    'present_position': -0.44,
    'writesynced': defaultdict(, {
        'compliance_slope': ,
        'compliance_margin':
    }),
    'model': 'AX-12A'
}