Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profile position mode #73

Closed
Phiraos opened this issue Jul 4, 2022 · 3 comments
Closed

Profile position mode #73

Phiraos opened this issue Jul 4, 2022 · 3 comments

Comments

@Phiraos
Copy link

Phiraos commented Jul 4, 2022

Hi,

I follow up on my project (using a C1250-DS-XC-1S with standard ASIC ET1100 and CiA402 Protocol).
Now that I can realize a home, I would like to move the actuator according to my input.

I try a simple single target but nothing happen.

Here is the code :

import time
import pysoem
import ctypes

class InputPdo(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        ('statusword', ctypes.c_uint16),
        ('position_actual_value', ctypes.c_int32),
        ('demand_position', ctypes.c_int32),
        ('demand_current', ctypes.c_int32),
        ('modes_of_operation_display', ctypes.c_int8),
        ('byte_padding', ctypes.c_int8),
    ]


class OutputPdo(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        ('controlword', ctypes.c_uint16),
        ('target_position', ctypes.c_int32),
        ('target_velocity', ctypes.c_int32),
        ('modes_of_operation', ctypes.c_int8),
        ('byte_padding', ctypes.c_int8),
    ]


modes_of_operation = {
    'No mode': 0,
    'Profile position mode': 1,
    'Profile velocity mode': 3,
    'Homing mode': 6,
    'Cyclic synchronous position mode': 8,
    'Cyclic synchronous velocity mode': 9,
    'Cyclic synchronous torque mode': 10,
}

master = pysoem.Master()
output_data = OutputPdo()

print('opening connection')

master.open('eno1')

if master.config_init() > 0:
    master.read_state()
    for device in master.slaves:
        print('Found Device: {},'.format(device.name))
        print('Manufacturer id: {}'.format(hex(device.man)))
        print('Id: {}'.format((hex(device.id))))
        print('state: {}'.format(hex(device.state)))

    print('Transition system to SAFEOP_STATE')
    io_map_size = master.config_map()
    print('IOMap Size: {}'.format(io_map_size))
    
    if master.state_check(pysoem.SAFEOP_STATE, 50000) != pysoem.SAFEOP_STATE:
        master.read_state()
        if not device.state == pysoem.SAFEOP_STATE:
                print('{} did not reach SAFEOP state'.format(device.name))
                print('al status code {} ({})'.format(hex(device.al_status), pysoem.al_status_code_to_string(device.al_status))
                )
        
        raise Exception('not all slaves reached SAFEOP state')
    else:
            print('Device in SAFEOP state: {}'.format(hex(device.state)))

# Send and receive process data to have valid data at all outputs before transistioning to OP_STATE
    print('Send and receive process data to have valid data at all outputs before transitioning to OP_STATE')
    master.send_processdata()
    actual_wkc = master.receive_processdata(2000)
    if not actual_wkc == master.expected_wkc:
        print('incorrect wkc')

# Transition MASTER to OP_STATE (Slave should follow)
    print('Transitioning system to OP_STATE')
    master.state = pysoem.OP_STATE
    master.write_state()

    if master.state_check(pysoem.OP_STATE, 50000) != pysoem.OP_STATE:
        master.read_state()
        if not device.state == pysoem.OP_STATE:
                print('{} did not reach OP state'.format(device.name))
                print('al status code {} ({})'.format(hex(device.al_status), pysoem.al_status_code_to_string(device.al_status)))
        raise Exception('Not all slaves reached OP state')

        # Read state of all slaves at start-up
    master.read_state()
    print('Device in OP state: {}'.format(hex(device.state)))
    """output_data.modes_of_operation = modes_of_operation['Homing mode']
    for control_cmd in [6,7,15,0x1F]:
        print('{}'.format(control_cmd))
        output_data.controlword = control_cmd
        device.output = bytes(output_data)
        master.send_processdata()
        master.receive_processdata(1000)
        time.sleep(0.05)
        print('{}'.format(device.output))
    time.sleep(5) """

    output_data.modes_of_operation = modes_of_operation['Profile position mode']
    output_data.target_position = 200
    output_data.target_velocity = 1
    for control_cmd in [6,7,15,0x3F]:
        print('{}'.format(control_cmd))
        output_data.controlword = control_cmd
        device.output = bytes(output_data)
        master.send_processdata()
        master.receive_processdata(1000)
        time.sleep(1)
        print('{}'.format(device.output))
    time.sleep(5)
else:
    print('no device found')
master.slaves[0].output = bytes(len(master.slaves[0].output))
master.send_processdata()
master.receive_processdata(1000)

master.close()
@Phiraos
Copy link
Author

Phiraos commented Jul 12, 2022

I solved my problem.

I use the cyclic synchronous position mode (mode 8) instead of the profile position (mode 1).

And, most important, something I miss or not really explicit, the PDO streaming has to be stricly cyclic. If not, the buffer suffers an underflow and motor stop working.

So, as in the basic_example.py, I implement a thread for processdata in order to satisfy the cyclic condition.

@DHavron
Copy link

DHavron commented Jul 21, 2022

tell me how you changed mode 8 to mode 1. Can I see the correct code?

@Phiraos
Copy link
Author

Phiraos commented Jul 21, 2022

tell me how you changed mode 8 to mode 1. Can I see the correct code?

Aye @DHavron,

I changed the mode 1 to mode 8.

To do this, I juste changed the parameter in this line

    output_data.modes_of_operation = modes_of_operation['Profile position mode']

I use now "Cyclic synchronous position mode".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants