Skip to content

Abb motor Drive E530 cannot switch to OP #174

@jintaoChan

Description

@jintaoChan

Environment

igh ethercat:1.6.4
ubuntu:24.04
ros2: jazzy

Problem description

I found that ethercat_generic_cia402_drive cannot motivate my abb motor. Then I tested raw igh code to motivate the motor. It still didn't work. Then I use wireshark to grab the ethercat package then compare to a workable motor. I found that igh will request slaves to INIT initially. My workable motor get in INIT successfully and finish PDO configuration. However the ABB motor driver keep staying in PREOP.

wireshark files

wireshark.zip
For abb motor drive: start from index 3800

For my workable motor drive(Synapticon): start from index 2487

Raw igh code

#include <errno.h>
#include <malloc.h>
#include <sched.h> /* sched_setscheduler() */
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

/****************************************************************************/

#include "ecrt.h"

/****************************************************************************/

// Application parameters
#define FREQUENCY 1000
#define CLOCK_TO_USE CLOCK_MONOTONIC
// #define MEASURE_TIMING

/****************************************************************************/

#define NSEC_PER_SEC (1000000000L)
#define PERIOD_NS (NSEC_PER_SEC / FREQUENCY)

#define DIFF_NS(A, B) \
    (((B).tv_sec - (A).tv_sec) * NSEC_PER_SEC + (B).tv_nsec - (A).tv_nsec)

#define TIMESPEC2NS(T) ((uint64_t)(T).tv_sec * NSEC_PER_SEC + (T).tv_nsec)

/****************************************************************************/

// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};

static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};

static ec_slave_config_t *sc = NULL;
static ec_slave_config_state_t sc_state = {};

/****************************************************************************/

// process data
static uint8_t *domain1_pd = NULL;
int is_kill = 0;
int in_operational = 0;
#define DM_522EC 0, 0 /*EtherCAT address on the bus*/
#define VID_PID 0x000000b7, 0x000002c2 /*Vendor ID, product code*/

/*Offsets for PDO entries*/
static struct
{
    unsigned int ctrl_word;
    unsigned int operation_mode;
    unsigned int target_position;
    unsigned int target_velocity;
    unsigned int velocity_offset;
    unsigned int torque_offset;
    unsigned int status_word;
    unsigned int operation_mode_display;
    unsigned int current_velocity;
    unsigned int current_position;
    unsigned int current_torque;
} offset;

const static ec_pdo_entry_reg_t domain1_regs[] = {
    {DM_522EC, VID_PID, 0x6040, 0, &offset.ctrl_word},
    {DM_522EC, VID_PID, 0x6060, 0, &offset.operation_mode},
    {DM_522EC, VID_PID, 0x607A, 0, &offset.target_position},
    {DM_522EC, VID_PID, 0x60FF, 0, &offset.target_velocity},
    {DM_522EC, VID_PID, 0x6041, 0, &offset.status_word},
    {DM_522EC, VID_PID, 0x6061, 0, &offset.operation_mode_display},
    {DM_522EC, VID_PID, 0x6064, 0, &offset.current_position},
    {DM_522EC, VID_PID, 0x606C, 0, &offset.current_velocity},
    {}};

/***************************************************************************/
/*Config PDOs*/
static ec_pdo_entry_info_t device_pdo_entries[] = {
    /*RxPdo 0x1601*/
    {0x6040, 0x00, 16},
    {0x6060, 0x00, 8},
    {0x607A, 0x00, 32},
    {0x60FF, 0x00, 32},
    /*TxPdo 0x1A00*/
    {0x6041, 0x00, 16},
    {0x6061, 0x00, 8},
    {0x6064, 0x00, 32},
    {0x606C, 0x00, 32},
};

static ec_pdo_info_t device_pdos[] = {
    {0x1600, 4, device_pdo_entries + 0},
    {0x1A00, 4, device_pdo_entries + 4}};

static ec_sync_info_t device_syncs[] = {
    {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
    {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
    {2, EC_DIR_OUTPUT, 1, device_pdos + 0, EC_WD_DISABLE},
    {3, EC_DIR_INPUT, 1, device_pdos + 1, EC_WD_DISABLE},
    {0xFF}};

static unsigned int counter = 0;
const struct timespec cycletime = {0, PERIOD_NS};

/*****************************************************************************/

struct timespec timespec_add(struct timespec time1, struct timespec time2)
{
    struct timespec result;

    if ((time1.tv_nsec + time2.tv_nsec) >= NSEC_PER_SEC)
    {
        result.tv_sec = time1.tv_sec + time2.tv_sec + 1;
        result.tv_nsec = time1.tv_nsec + time2.tv_nsec - NSEC_PER_SEC;
    }
    else
    {
        result.tv_sec = time1.tv_sec + time2.tv_sec;
        result.tv_nsec = time1.tv_nsec + time2.tv_nsec;
    }

    return result;
}

/*****************************************************************************/

void check_domain1_state(void)
{
    ec_domain_state_t ds;

    ecrt_domain_state(domain1, &ds);

    if (ds.working_counter != domain1_state.working_counter)
        printf("Domain1: WC %u.\n", ds.working_counter);
    if (ds.wc_state != domain1_state.wc_state)
        printf("Domain1: State %u.\n", ds.wc_state);

    domain1_state = ds;
}

/*****************************************************************************/

void check_master_state(void)
{
    ec_master_state_t ms;

    ecrt_master_state(master, &ms);

    if (ms.slaves_responding != master_state.slaves_responding)
        printf("%u slave(s).\n", ms.slaves_responding);
    if (ms.al_states != master_state.al_states)
        printf("AL states: 0x%02X.\n", ms.al_states);
    if (ms.link_up != master_state.link_up)
        printf("Link is %s.\n", ms.link_up ? "up" : "down");

    master_state = ms;
}

/****************************************************************************/

void check_slave_config_states(void)
{
    ec_slave_config_state_t s;
    ecrt_slave_config_state(sc, &s);
    if (s.operational)
    {
        in_operational = 1;
    }
    else
    {
        in_operational = 0;
    }

    sc_state = s;
}

/****************************************************************************/

void signal_handler(int sig)
{
    is_kill = 1;
    // printf("\nReleasing master...\n");
    // ecrt_release_master(master);
    // pid_t pid = getpid();
    // kill(pid, SIGKILL);
}

void cyclic_task()
{
    uint16_t status;
    signal(SIGINT, signal_handler);

    struct timespec wakeupTime, time;

    clock_gettime(CLOCK_TO_USE, &wakeupTime);
    int kill_count = 100;
    int wait = 100;
    while (1)
    {
        wakeupTime = timespec_add(wakeupTime, cycletime);

        clock_nanosleep(CLOCK_TO_USE, TIMER_ABSTIME, &wakeupTime, NULL);
        ecrt_master_application_time(master, TIMESPEC2NS(wakeupTime));
        // receive process data
        ecrt_master_receive(master);
        ecrt_domain_process(domain1);
        
        // check process data state (optional)
        // check_domain1_state();
        check_slave_config_states();

        if (in_operational)
        {
            status = EC_READ_U16(domain1_pd + offset.status_word);
            if (is_kill)
            {
                EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x0006);
                // EC_WRITE_S8(domain1_pd + offset.operation_mode, 9);
                --kill_count;
                if (!kill_count)
                {
                    ecrt_release_master(master);
                    break;
                }
            }
            else
            {
                if ((status & 0x0008) == 0x0008)
                {
                    EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x0080);
                }
                else if ((status & 0x0040) == 0x0040)
                {
                    EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x0006);
                }
                else if ((status & 0x003F) == 0x0031)
                {
                    EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x0007);
                }

                else if ((status & 0x003F) == 0x0033)
                {
                    EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x000f);
                }
                // operation enabled

                else if ((status & 0x003F) == 0x0037)
                {
                    if (wait)
                    {
                        --wait;
                    }
                    else
                    {
                        // EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x000f);
                        // EC_WRITE_S8(domain1_pd + offset.operation_mode, 8);
                        // int actual_position = EC_READ_S32(domain1_pd + offset.current_position);
                        // int target_position = actual_position + 1;
                        // EC_WRITE_S32(domain1_pd + offset.target_position, target_position);
                        EC_WRITE_S8(domain1_pd + offset.operation_mode, 9);
                        EC_WRITE_S32(domain1_pd + offset.target_velocity, 0);
                    }

                }
            }
            printf("Status= %x\tMode= %x\tPosition=%d\tVelocity=%d\tTarget Position=%d\tTarget Velocity=%d\n",
                   EC_READ_U16(domain1_pd + offset.status_word),
                   EC_READ_S8(domain1_pd + offset.operation_mode_display),
                   EC_READ_S32(domain1_pd + offset.current_position),
                   EC_READ_S32(domain1_pd + offset.current_velocity),
                   EC_READ_S32(domain1_pd + offset.target_position),
                   EC_READ_S32(domain1_pd + offset.target_velocity));
        }

        ecrt_domain_queue(domain1);
        ecrt_master_send(master);
        clock_gettime(CLOCK_TO_USE, &time);

        ecrt_master_sync_reference_clock_to(master, TIMESPEC2NS(time));
        ecrt_master_sync_slave_clocks(master);
    }
}

/****************************************************************************/

int main(int argc, char **argv)
{
    if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
    {
        perror("mlockall failed");
        return -1;
    }
    master = ecrt_request_master(0);
    if (!master)
        return -1;

    domain1 = ecrt_master_create_domain(master);
    if (!domain1)
        return -1;

    // Create configuration for bus coupler
    sc = ecrt_master_slave_config(master, DM_522EC, VID_PID);
    if (!sc)
        return -1;

    printf("Configuring PDOs...\n");
    if (ecrt_slave_config_pdos(sc, EC_END, device_syncs))
    {
        fprintf(stderr, "Failed to configure slave PDOs!\n");
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("*Success to configuring slave PDOs*\n");
    }

    if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs))
    {
        fprintf(stderr, "PDO entry registration failed!\n");
        exit(EXIT_FAILURE);
    }

    if(ecrt_slave_config_dc(sc, 0x0300, PERIOD_NS, 62500, 0, 0)){
        fprintf(stderr, "DC configuration failed!\n");
        exit(EXIT_FAILURE);
    }

    printf("Activating master...\n");
    if (ecrt_master_activate(master))
        return -1;

    if (!(domain1_pd = ecrt_domain_data(domain1)))
    {
        return -1;
    }
    /* Set priority */

    struct sched_param param = {};
    param.sched_priority = sched_get_priority_max(SCHED_FIFO);

    printf("Using priority %i.", param.sched_priority);
    if (sched_setscheduler(0, SCHED_FIFO, &param) == -1)
    {
        perror("sched_setscheduler failed");
    }
    signal(SIGINT, signal_handler);

    printf("Starting cyclic function.\n");
    cyclic_task();

    return 0;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions