> -----Original Message-----
> From: Rahul Deshpande [mailto:[email protected]] 
> Sent: Friday, 4 August 2017 4:17 a.m.
> To: Graeme Foot <[email protected]>
> Subject: Yaskawa sigma 5 application
> 
> Hi Graeme,
> 
> Building up on the previous mail. I made a few changes to my application. 
> I am still an amateur at this and have just been introduced to motion 
> control last month. I have modified the example/xenomai/main.c file to 
> suit my needs. I have attached the file. I am setting the PDOs as you had 
> mentioned. I read on some of the etherlab group archive mails that I need 
> to set the sdo's as well.
> 
> My understanding is that the SDO's consist of the data that needs to be 
> processed and the PDO's are just a way to communicate this data from slave 
> to master and vice versa. Is there any specific way to configure these ?. 
> I just intend to write a simple application.
> 
> Thank you,
> Rahul
>


Hi,

Note: Remember to always post to the etherlab forum.


1) From you attached file it looks like you have a sigma 7 rather than sigma 5 
amp.  I haven't got my hands on one yet (in the pipeline) but should be similar 
to the sigma 5.  To make sure you have the correct PDO structures use the 
"ethercat struct" command.  It will output the currently configured (or default 
if not changed) structures to work with the device.  (The items below are for 
sigma 5, but should be similar.)


2) PDO's vs SDO's:
- PDO's are the workhorse of EtherCAT.  The PDO data is communicated every 
cycle.  PDO's are realtime.  
- SDO's are generally just used to set up initial configuration parameters.  
They can be used to read/write non-PDO parameters while running, but they are 
not realtime and take multiple cycles to be sent and be returned.  They should 
also only be used for values that do not change often. 


3) You don't need to call these:
ecrt_slave_config_sdo8( sc_dig_out_01, 0x1C12, 0, 0 ); /* clear sm pdo 0x1c12 */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C12, 1, 0x1601 ); /* download pdo 
1C12 index */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C12, 2, 0x1602 ); /* download pdo 
1C12 index */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C12, 3, 0x1606 ); /* download pdo 
1C12 index */
ecrt_slave_config_sdo8( sc_dig_out_01, 0x1C12, 0, 3 ); /* set number of RxPDO */
ecrt_slave_config_sdo8( sc_dig_out_01, 0x1C13, 0, 0 ); /* clear sm pdo 0x1c12 */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C13, 1, 0x1A01 ); /* download pdo 
1C13 index */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C13, 2, 0x1A03 ); /* download pdo 
1C13 index */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C13, 3, 0x1A06 ); /* download pdo 
1C13 index */
ecrt_slave_config_sdo8( sc_dig_out_01, 0x1C13, 0, 3 ); /* set number of TxPDO */

That’s what ecrt_slave_config_pdos() does.


4) There are some settings that you need to set and flash before running the 
drive (and repower the drive after flashing them).
- If it's an absolute motor that you will be running in incremental mode, you 
need to (0x2002.1 = 1)
- If you do not have limit switches you will need to disable them (in 0x250a.3 
and 0x250b.0)
- If you have external regen resistors, you need to set 0x2600
- possibly some others I forget


5) You are blinking the first 8 bits of 0x6040.  That won't be doing much of 
anything that you can see.
- First thing is, is the slave in Operational mode when you go to realtime?
- Second, to enable the drive you need to go through a state machine of setting 
control bits and confirming each state with status bits

set: Control.EnableVoltage & Control.QuickStop
wait until: Status.ReadyToSwitchOn
set: Control.SwitchOn
wait until: Status.SwitchedOn
set: Control.EnableOperation
wait until: Status.OperationEnabled

You will need to set 0x6060:00 (Mode of operation) to the mode you want to run 
with (e.g. 8=cyclic position)

You should now be good to send target position values (0x607a:00).  I you don't 
have a position generator they you could try velocity mode (Mode of operation 
9) and ramp up and down the value (for acceleration / deceleration).


Regards,
Graeme.





/******************************************************************************
 *
 *  $Id: main.c,v 3bdd7a747fae 2012/09/20 13:28:25 fp $
 *
 *  Copyright (C) 2009-2010  Moehwald GmbH B. Benner
 *                     2011  IgH Andreas Stewering-Bone
 *                     2012  Florian Pose <[email protected]>
 *
 *  This file is part of the IgH EtherCAT master
 *
 *  The IgH EtherCAT Master is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License version 2, as
 *  published by the Free Software Foundation.
 *
 *  The IgH EtherCAT master is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 *  Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with the IgH EtherCAT master. If not, see <http://www.gnu.org/licenses/>.
 *
 *  ---
 *
 *  The license mentioned above concerns the source code only. Using the
 *  EtherCAT technology and brand is only permitted in compliance with the
 *  industrial property and similar rights of Beckhoff Automation GmbH.
 *
 *****************************************************************************/

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <rtdm/rtdm.h>
#include <native/task.h>
#include <native/sem.h>
#include <native/mutex.h>
#include <native/timer.h>
#include <rtdk.h>
#include <pthread.h>

#include "ecrt.h"

#include <time.h>


RT_TASK my_task;

static int run = 1;

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

// 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 uint8_t *domain1_pd = NULL;

static ec_domain_t *domain2 = NULL;
static ec_domain_state_t domain2_state = {};
static uint8_t *domain2_pd = NULL;


static ec_slave_config_t *sc_dig_out_01 = NULL;

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

// process data

#define Drive01_Pos         0, 0
//#define BusCoupler01_Pos  0, 0
#define DigOutSlave01_Pos 0, 1

#define Yaskawa_Sigma7  0x00000539, 0x02200001

// offsets for PDO entries
static unsigned int off_dig_out0      = 0;
static unsigned int off_dig_out1      = 0;
static unsigned int off_dig_in0       = 0;
static unsigned int off_dig_in1       = 0;

const static ec_pdo_entry_reg_t domain1_regs[] = {
   {Drive01_Pos, Yaskawa_Sigma7, 0x6040, 0, &off_dig_out0, NULL},
   {Drive01_Pos, Yaskawa_Sigma7, 0x607a, 0, &off_dig_out1, NULL},
   {}
};


const static ec_pdo_entry_reg_t domain2_regs[] = {
   {Drive01_Pos, Yaskawa_Sigma7, 0x6041, 0, &off_dig_in0, NULL},
   {Drive01_Pos, Yaskawa_Sigma7, 0x6064, 0, &off_dig_in1, NULL},
   {}
};



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

/* Slave 0, "Yaskawa Sigma 7"
 * Vendor ID:       0x00000539   (1337 decimal)
 * Product code:    0x02200301
 * Revision number: 
 */

//initialize pdos

static ec_pdo_entry_info_t yaskawa_sigma7_pdoEntries[] = {

{0x6040, 0x00, 16},   // pg 8-21  control (rw)

{0x607a, 0x00, 32},   // pg 8-30  target position (rw) (for cyclic sync pos 
mode)

{0x60b1, 0x00, 32},   // pg 8-37  velocity offset (rw) (for cyclic sync pos 
mode)

{0x6072, 0x00, 16},   // pg 8-40  max torque (rw) in 0.1% increments, what is 
+ve torque lim and - torque lim? pdo or sdo??

{0x60fe, 0x01, 32},   // pg 8-44  outputs (rw) (bits 17, 18, 19 control outputs 
1, 2, 3)

{0x60b8, 0x00, 16},   // pg 8-41  latchControl (rw) (bits: 0 enable latch, 1 
single/continuous trigger,
                          //                             2 0=latch on S14 | 
1=latch on C, 4 enable latch sampling???)

{0x6060, 0x00, 8},    // pg 8-28  mode of operation (rw) (8=cyclic pos, 
9=cyclic vel)

 

{0x6041, 0x00, 16},   // pg 8-23  status (r)

{0x6064, 0x00, 32},   // pg 8-34  actual position (r)

{0x606c, 0x00, 32},   // pg 8-38  actual velocity (r) required??

{0x6077, 0x00, 16},   // pg 8-39  actual torque (r)

{0x60f4, 0x00, 32},   // pg 8-35  actual following error (r)

{0x60fd, 0x00, 32},   // pg 8-43  inputs (r) (available inputs: 0 (rev lim), 1 
(fwd lim), 2 (hm),

                          //                      16 - 22 (via CN1), 25 - 25 
(via base block))

{0x60ba, 0x00, 32},   // pg 8-42  latchPos (r) (via touch probe 1)

{0x60b9, 0x00, 16},   // pg 8-42  latchStatus (r) (bits: 0 latch enabled, 1 
latched, 7 latched toggle (for continuous mode))

{0x6061, 0x00, 8},    // pg 8-28  current mode of operation

{0x6098, 0x00, 8},    // pg 8-32  homing mode (rw) note: rw but we only want to 
read current value (setting new value by sdo)

{0x603f, 0x00, 16},   // pg 8-21  last error code

{0x6062, 0x00, 32},   // pg 8-34  position demand value (r)

};

static ec_pdo_info_t yaskawa_sigma7_pdos[] = {

{0x1600, 7, yaskawa_sigma7_pdoEntries + 0},

{0x1a00, 8, yaskawa_sigma7_pdoEntries + 7},

{0x1a01, 4, yaskawa_sigma7_pdoEntries + 15},

};

static ec_sync_info_t yaskawa_sigma7_syncs[] = {

//##################
   {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
   {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
   {2, EC_DIR_OUTPUT, 1, yaskawa_sigma7_pdos + 0, EC_WD_ENABLE},
   {3, EC_DIR_INPUT, 2, yaskawa_sigma7_pdos + 1, EC_WD_DISABLE},
   {0xff}

};

static unsigned int sync_ref_counter = 0;
//Not used anywhere
/*
#define FREQUENCY 1000
#define NSEC_PER_SEC (1000000000L)
#define PERIOD_NS (NSEC_PER_SEC / FREQUENCY)
#define TIMESPEC2NS(T) ((uint64_t) (T).tv_sec * NSEC_PER_SEC + (T).tv_nsec)
#define EL70X1_STEPSPERREV 200
*/
/*****************************************************************************
 * Realtime task
 ****************************************************************************/

void rt_check_domain_state(void)
{
    ec_domain_state_t ds = {};

        ecrt_domain_state(domain1, &ds);

    if (ds.working_counter != domain1_state.working_counter) {
        rt_printf("Domain1: WC %u.\n", ds.working_counter);
    }

    if (ds.wc_state != domain1_state.wc_state) {
        rt_printf("Domain1: State %u.\n", ds.wc_state);
    }

    domain1_state = ds;
}

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

void rt_check_master_state(void)
{
    ec_master_state_t ms;

        ecrt_master_state(master, &ms);

    if (ms.slaves_responding != master_state.slaves_responding) {
        rt_printf("%u slave(s).\n", ms.slaves_responding);
    }

    if (ms.al_states != master_state.al_states) {
        rt_printf("AL states: 0x%02X.\n", ms.al_states);
    }

    if (ms.link_up != master_state.link_up) {
        rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");
    }

    master_state = ms;
}

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

void my_task_proc(void *arg)
{
        int cycle_counter = 0;
   unsigned int blink = 0;
        unsigned int pos = 0;
        unsigned int status = 0;
        struct timespec time;


        rt_task_set_periodic(NULL, TM_NOW, 10000000); // ns

        while (run) {
                rt_task_wait_period(NULL);

                cycle_counter++;

                // receive EtherCAT frames
                ecrt_master_receive(master);
                ecrt_domain_process(domain1);
                ecrt_domain_process(domain2);

                rt_check_domain_state();

                if (!(cycle_counter % 1000)) {
                        rt_check_master_state();
                }
/*#####
                if (!(cycle_counter % 500)) {
                        pos = EC_READ_U32(domain1_pd + off_dig_in1);
                        status = EC_READ_U32(domain1_pd + off_dig_in0);
                   printf("Position = %d, status = %04Xh\n", pos, status);
                }
*/
/*
                // write application time to master
                clock_gettime(CLOCK_REALTIME, &time);
                ecrt_master_application_time(master, TIMESPEC2NS(time));

                if (sync_ref_counter) {
                        sync_ref_counter--;
                } else {
                        sync_ref_counter = 1; // sync every cycle
                        ecrt_master_sync_reference_clock(master);
                }
                ecrt_master_sync_slave_clocks(master);
*/

                if(!(cycle_counter % 200)){
                                blink = !blink;
                        }

                //EC_WRITE_U8(domain1_pd +  )
                EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0x0 : 0x0F);
                // send process data
                ecrt_domain_queue(domain1);
                ecrt_domain_queue(domain2);
                ecrt_master_send(master);

        }
}

/****************************************************************************
 * Signal handler
 ***************************************************************************/

void signal_handler(int sig)
{
    run = 0;
}

/****************************************************************************
 * Main function
 ***************************************************************************/

int main(int argc, char *argv[])
{
    ec_slave_config_t *sc;
    int ret;

    /* Perform auto-init of rt_print buffers if the task doesn't do so */
    rt_print_auto_init(1);

//    signal(SIGTERM, signal_handler);
//    signal(SIGINT, signal_handler);

    mlockall(MCL_CURRENT | MCL_FUTURE);

    printf("Requesting master...\n");
    master = ecrt_request_master(0);
    if (!master) {
        return -1;
    }

    printf("Create domain1\n");
    domain1 = ecrt_master_create_domain(master);
    if (!domain1) {
        return -1;
    }

    printf("Create domain2\n");
    domain2 = ecrt_master_create_domain(master);
    if (!domain2) {
        return -1;
    }


    printf("ecrt_master_slave_config() for yaskawa\n");

        sc = ecrt_master_slave_config(master, Drive01_Pos, Yaskawa_Sigma7);
                if (!sc) {
                        printf("Unable to configure slave\n");
                        return -1;
                }


        //getting slave configuration
        printf("Trying to get slave config");

        sc_dig_out_01 = ecrt_master_slave_config(master, DigOutSlave01_Pos, 
Yaskawa_Sigma7);
                if (!sc_dig_out_01) {
                        fprintf(stderr, "Failed to get slave configuration.\n");
                        return -1;
                }

/*
 printf("Configure 1C12\n");

ecrt_slave_config_sdo8(sc, 0x1c12, 0, 0);

    printf("ec_slave_config_pdos()\n");

    if (ecrt_slave_config_pdos(sc, EC_END, yaskawa_sigma7_syncs)) {
        fprintf(stderr, "Failed to configure PDOs.\n");
    }

*/

        //configure PDOs
        printf("Configure the PDOs\n");

    if (ecrt_slave_config_pdos(sc_dig_out_01, EC_END, yaskawa_sigma7_syncs)) {
        fprintf(stderr, "Failed to configure PDOs.\n");
        return -1;
    }

        //According to graeme, ecrt slave_config_pdos must be followed by 
create sdo request (this step is optional)
        
        // Create ecrt_slave_config_reg_pdo_entry - one call per pdo entry you 
want to interact

        if(ecrt_slave_config_reg_pdo_entry(sc_dig_out_01, Drive01_Pos, domain1, 
NULL)){
                printf("Failed to register pdo entry\n");
        return -1;
        }
        // or the below method can be used.     
         printf("ecrt_domain_reg_pdo_entry_list()\n");

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


//########################
        // Configuration entries go here

         ecrt_slave_config_sdo8( sc_dig_out_01, 0x1C12, 0, 0 ); /* clear sm pdo 
0x1c12 */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C12, 1, 0x1601 ); /* download pdo 
1C12 index */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C12, 2, 0x1602 ); /* download pdo 
1C12 index */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C12, 3, 0x1606 ); /* download pdo 
1C12 index */
ecrt_slave_config_sdo8( sc_dig_out_01, 0x1C12, 0, 3 ); /* set number of RxPDO */

ecrt_slave_config_sdo8( sc_dig_out_01, 0x1C13, 0, 0 ); /* clear sm pdo 0x1c12 */
    ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C13, 1, 0x1A01 ); /* download 
pdo 1C13 
index */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C13, 2, 0x1A03 ); /* download pdo 
1C13 index */
ecrt_slave_config_sdo16( sc_dig_out_01, 0x1C13, 3, 0x1A06 ); /* download pdo 
1C13 index */
    ecrt_slave_config_sdo8( sc_dig_out_01, 0x1C13, 0, 3 ); /* set number of 
TxPDO */

//
// Register startup configuration for the hardware
//
// Set the maximum current for the drive
// Unit: 1 mA
ecrt_slave_config_sdo16( sc_dig_out_01, 0x8010, 0x01, 4630 );

// Set the holding current
// Unit: 1 mA
  ecrt_slave_config_sdo16( sc_dig_out_01, 0x8010, 0x02, 500 );

// Set the nominal voltage
// Unit: 1 mv / 1000
ecrt_slave_config_sdo16( sc_dig_out_01, 0x8010, 0x03, 48000 );
// Set motor coil resistance
// Unit: 0.01 ohm
ecrt_slave_config_sdo16( sc_dig_out_01, 0x8010, 0x04, 104 );
// Set Motor full steps per revolution
// unit: steps
ecrt_slave_config_sdo16( sc_dig_out_01, 0x8010, 0x06, EL70X1_STEPSPERREV );


// Set Kp Factor
// Unit: 0.001
ecrt_slave_config_sdo16( sc_dig_out_01, 0x8011, 0x01, 200);

// Set filter limit frequencey of the current controller (low-pass)
// Unit: 1hz
ecrt_slave_config_sdo16( sc_dig_out_01, 0x8011, 0x06, 0);


//###################
/*   
 printf("ecrt_domain_reg_pdo_entry_list()\n");

    if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
        fprintf(stderr, "PDO entry registration failed!\n");
        return -1;
    }
*/

    // configure SYNC signals for this slave
    ecrt_slave_config_dc(sc, 0x0, 10000000, 0, 0, 0);

    printf("Activating Master\n");
    if (ecrt_master_activate(master)) {
      printf("Could not activate Master\n");  
                return -1;
    }

    printf("ecrt_domain_get_data()\n");
    if (!(domain1_pd = ecrt_domain_data(domain1))) { 
        fprintf(stderr, "Failed to get domain1 data pointer.\n");
        return -1;
    }

// domain 2 not yet configured

    ret = rt_task_create(&my_task, "my_task", 0, 80, T_FPU);
    if (ret < 0) {
        fprintf(stderr, "Failed to create task: %s\n", strerror(-ret));
        return -1;
    }

    printf("Starting my_task...\n");
    ret = rt_task_start(&my_task, &my_task_proc, NULL);
    if (ret < 0) {
        fprintf(stderr, "Failed to start task: %s\n", strerror(-ret));
        return -1;
    }

        while (run) {
                sched_yield();
        }

    printf("Deleting realtime task...\n");
    rt_task_delete(&my_task);

    printf("End of Program\n");
    ecrt_release_master(master);

    return 0;
}

/****************************************************************************/
_______________________________________________
etherlab-users mailing list
[email protected]
http://lists.etherlab.org/mailman/listinfo/etherlab-users

Reply via email to