-
Notifications
You must be signed in to change notification settings - Fork 75
Open
Description
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, ¶m) == -1)
{
perror("sched_setscheduler failed");
}
signal(SIGINT, signal_handler);
printf("Starting cyclic function.\n");
cyclic_task();
return 0;
}
Metadata
Metadata
Assignees
Labels
No labels