OpenEtherCATsociety / SOEM

Simple Open Source EtherCAT Master
Other
1.34k stars 681 forks source link

Vaule of Reading actual position is not correct, when servo driver be Power On (Operation Enable) #415

Closed tuanakv closed 4 years ago

tuanakv commented 4 years ago

Hi all,

I tried using SOEM Ethercat master to control Omron R88D1SN 200W (COE profile). I can power on the driver by send control word to driver. And I also can read pdo value as "status word", "actual position". If I don't power on Driver I can read actual position correctly( I compared value with Twincat3 also), But when power on actual position value is not correct. (For status word always correct)

For reading PDO i use as: Typedef struct PACKED { Uint16 status_word; Int32 actualposition; ... } input; Input_ * inn And reading : Ec_send_processdata(); Int wkc = ec_receive_processdata(EC_TIMEOUTRET); If (wkc >= expectedWKC) { Cout<<" actual position: "inn->actual_position << endl; ...}

Can somebody can give me ideal to solve this problem ?

ArthurKetels commented 4 years ago

You do not give us much data to work with. What is your definition of "correct position"? Some wireshark data would also be helpful. What cycle time are you using? What is your device mapping (which objects are used in which order)? When using windows as OS you can not use PACKED but must use PACKED_BEGIN and PACKED_END.

tuanakv commented 4 years ago

Hi Below is PDO mapping infor PDO outputs:: [0x0000.0] 0x6040:0x00 0x10 [0x0002.0] 0x607A:0x00 0x20 [0x0006.0] 0x60B8:0x00 0x10 [0x0008.0] 0x60FE:0x01 0x20 PDO inputs addr b index: sub bitl data_type name [0x000C.0] 0x603F:0x00 0x10 [0x000E.0] 0x6041:0x00 0x10 [0x0010.0] 0x6064:0x00 0x20 [0x0014.0] 0x6077:0x00 0x10 [0x0016.0] 0x60F4:0x00 0x20 [0x001A.0] 0x60B9:0x00 0x10 [0x001C.0] 0x60BA:0x00 0x20 [0x0020.0] 0x60BC:0x00 0x20 [0x0024.0] 0x60FD:0x00 0x2

I also use PACKED_BEGIN and PACKED_END as your comments: PACKED_BEGIN typedef struct PACKED {
uint16_t control_word;
int32_t value_607A; uint16_t value_60B8;
uint32_t value_60FE; } output_omron; PACKED_END // using 0x1B01 mapping PACKED_BEGIN typedef struct PACKED {
uint16 value_603F;
uint16 status_word;
int32 actual_position;
int16 value_6077;
int32 value_60F4;
uint16 value_60B9;
int32 value_60BA;
int32 value_60BC;
uint32 value_60FD; } input_omron; PACKED_END

And this is code for cyclic: / cyclic loop /
for (i = 1; i <= 100000; i++) { // get status of slave status = in_omron->status_word;
bfirst = true;
if (bfirst) {
switch (state){
case 0: out_omron->control_word = 14;
if ((status == 568 ) || (status ==1592)) out_omron->control_word = 128;
if ((status == 561) || (status == 1585)) {
state = 1; }
break;
case 1: out_omron->control_word = 15;
if ((status == 3639) || (status == 2615) || (status == 5687) || (status == 4663)) {
state = 2;
bfirst = false; }
break;
case 2: out_omron->control_word = 15; break; } } ec_send_processdata();
int wkc = ec_receive_processdata(EC_TIMEOUTRET);
if (wkc >= expectedWKC) {
std::cout << in_omron->value_603F << std::endl;
std::cout << in_omron->status_word << std::endl;
std::cout << " actual position: " << in_omron->actual_position << std::endl << in_omron->value_6077 << std::endl; std::cout<< in_omron->value_60B9 << std::endl;
std::cout << in_omron->value_60BA << std::endl <value_60BC << std::endl;
std::cout << in_omron->value_60FD << std::endl; needlf = TRUE; }
osal_usleep(5000);

////////////////// I compare value read by Twincat 3 to know what is correct or not?

I already check via wireshark, if not power on I see data from WireShark and from SOEM is the same. But if I power on Driver, only status word is the same as data from WireShark.

Can anyone help me?

Thanks

tuanakv commented 4 years ago

wireshark.zip

I also attach 2 wireshark file: one file capture when power on Driver, other file just read actual position and data from driver

ArthurKetels commented 4 years ago

The wireshark trace looks ok. In both cases the slave is in OP mode because we see a WKC of 3. The PDO is what it is. If you do not see the data you expect then this is a slave configuration issue. As far as SOEM goes all is fine.

I would suggest to carefully look into the slave configuration. A lot of DS402 slaves need homing before operation. And if you select synchronous modes you first have to sync master with slave and start the SYNC0/1 as required. Look for other posts here how to do that.

tuanakv commented 4 years ago

Hi,

Thank for your feedback. I revised my code to meet your comment and re-check as below:

Example I set out_omron->value_607A = 10000; but when print out_omron->value_607A , value = 0.

Or //////////////////////// 18 command position: 0 actual checking 5687 -1: 1301 target checking 5687 : 0 actual checking 5687 -2: 1301 status: 4663 actual position: 1301 actual torque: 0 469762048 19

I don't know why is it? Can you help me to solve this problem ?

Below I show my code as: out_omron = (output_omron)ec_slave[0].outputs; in_omron = (input_omron)ec_slave[0].inputs;
uint16_t status; int8_t mode_display = 0; int8_t state = 0;

        if (slaves[0].state == EC_STATE_OPERATIONAL)
        {
            printf("Operational state reached for all slaves.\n");
            inOP = TRUE;                

            /* cyclic loop */

            for (i = 1; i <= 100000; i++)
            {
                // get status of slave
                status = in_omron->status_word;

                if (mode_display == 8) bfirst = TRUE;
                bfirst = true;
                //out_omron->control_word = 14;
                if (bfirst) {

                    switch (state)
                    {
                    case 0: out_omron->control_word = 14;
                        if ((status == 568) || (status == 1592)) out_omron->control_word = 128;
                        if ((status == 561) || (status == 1585)) {// || (status == 624) || (status == 1648)) {
                            state = 1;

                        }
                        break;
                    case 1: out_omron->control_word = 15;
                        if ((status == 3639) || (status == 2615) || (status == 5687) || (status == 4663)) {
                            state = 2;
                            std::cout << "actual checking 5687 -1: " << in_omron->actual_position << std::endl;
                            out_omron->value_607A = 10000;
                            std::cout << "target checking 5687 : " << out_omron->value_607A << std::endl;
                            std::cout << "actual checking 5687 -2: " << in_omron->actual_position << std::endl;

                        }
                        break;
                    case 2:
                        out_omron->control_word = 15;

                    }
                }

                //int tp = sdo_read16(1, 0x1C32, 0x01);
                //std::cout << "type is : "  << tp << std::endl;
                //int md = sdo_read16(1, 0x6061, 0x00);
                //std::cout << "mode is : " << md << std::endl;
                if (wkc >= expectedWKC)
                {
                    std::cout << "status: " << in_omron->status_word << " actual position: " << in_omron->actual_position << "  actual torque: " << in_omron->value_6077 << std::endl;
                    std::cout << "  " << in_omron->value_60FD << std::endl <<i << std::endl;
                    std::cout << " command position: " << out_omron->value_607A << std::endl;
                    needlf = TRUE;
                }

                osal_usleep(cycle_time);

            }
            inOP = FALSE;

/////////////////////////////////////////////////////////////////////// / most basic RT thread for process data, just does IO transfer / void CALLBACK RTthread(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { //IOmap[0]++;

ec_send_processdata();
wkc = ec_receive_processdata(EC_TIMEOUTRET);

//std::cout << " this is rt thread "  << rtcnt << std::endl;
rtcnt++;
/* do RT control stuff here */

///////////////////////// OSAL_THREAD_FUNC ecatcheck(void *lpParam) { int slave;

while (1)
{
    //std::cout << " this is ecat checking " << std::endl;
    if (inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate))
    {
        if (needlf)
        {
            needlf = FALSE;
            printf("\n");
        }
        /* one ore more slaves are not responding */
        ec_group[currentgroup].docheckstate = FALSE;
        ec_readstate();
        for (slave = 1; slave <= ec_slavecount; slave++)
        {
            if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL))
            {
                std::cout << "ecat checking : " << std::endl;
                ec_group[currentgroup].docheckstate = TRUE;
                if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR))
                {
                    printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave);
                    ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK);
                    ec_writestate(slave);
                }
                else if (ec_slave[slave].state == EC_STATE_SAFE_OP)
                {
                    printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave);
                    ec_slave[slave].state = EC_STATE_OPERATIONAL;
                    ec_writestate(slave);
                }
                else if (ec_slave[slave].state > EC_STATE_NONE)
                {
                    if (ec_reconfig_slave(slave, EC_TIMEOUTMON))
                    {
                        ec_slave[slave].islost = FALSE;
                        printf("MESSAGE : slave %d reconfigured\n", slave);
                    }
                }
                else if (!ec_slave[slave].islost)
                {
                    /* re-check state */
                    ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET);
                    if (ec_slave[slave].state == EC_STATE_NONE)
                    {
                        ec_slave[slave].islost = TRUE;
                        printf("ERROR : slave %d lost\n", slave);
                    }
                }
            }
            if (ec_slave[slave].islost)
            {
                if (ec_slave[slave].state == EC_STATE_NONE)
                {
                    if (ec_recover_slave(slave, EC_TIMEOUTMON))
                    {
                        ec_slave[slave].islost = FALSE;
                        printf("MESSAGE : slave %d recovered\n", slave);
                    }
                }
                else
                {
                    ec_slave[slave].islost = FALSE;
                    printf("MESSAGE : slave %d found\n", slave);
                }
            }
        }
        if (!ec_group[currentgroup].docheckstate)
            printf("OK : all slaves resumed OPERATIONAL.\n");
    }
    osal_usleep(cycle_time);
}

//return 0;

} }

ArthurKetels commented 4 years ago

A wireshark trace of your test run would be nice. Are you able to run a simple slave (for example digital I/O)? When something complex does not work, first try a simple set-up.

tuanakv commented 4 years ago

Hi ,

I solved this problem. Once status word of slave is at "Ready to Switch On" state , must set value of 0x607A first. if not set , target position =0, so slave move to 0 position.

nakarlsson commented 4 years ago

Good, please close the issue

ilovewall commented 4 years ago

HI,tuanakv,I worked on Omron R88D-1SN04H-ECT,and i met a problem .If i add code "ec_dcsync0(1, TRUE, cycle_ns, 0);",then the servo had a error 83-03,if i didnot use this code ,servo worked well.did you meet this issue?

tuanakv commented 4 years ago

Hi, As i know the error 83-03 just warning about lost ethercat master. But it is not problem when slave work. I use ec_dcsync0(1, TRUE, cycle_ns, cycle_ns/2) and slave work well.

ilovewall commented 4 years ago

HI,i am very glad to receive your letter,and my servo did not work when the error 83-03 dispalyed,so i didnot know why this happened.However,i used panasonic servo worked well used DC mode. How long had you used SOEM?i am a newer,i hope we can discuss on SOEM or ethercat master or everything if you like. this is my first time to  write email use english, please forgive me some Chinese English! Best wish!

------------------ 原始邮件 ------------------ 发件人: "OpenEtherCATsociety/SOEM" <notifications@github.com>; 发送时间: 2020年7月17日(星期五) 上午6:43 收件人: "OpenEtherCATsociety/SOEM"<SOEM@noreply.github.com>; 抄送: "阳依草 "<715297306@qq.com>;"Comment"<comment@noreply.github.com>; 主题: Re: [OpenEtherCATsociety/SOEM] Vaule of Reading actual position is not correct, when servo driver be Power On (Operation Enable) (#415)

Hi, As i know the error 83-03 just warning about lost ethercat master. But it is not problem when slave work. I use ec_dcsync0(1, TRUE, cycle_ns, cycle_ns/2) and slave work well.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

tuanakv commented 4 years ago

Hi,

You can conntact me

ilovewall commented 4 years ago

Hi,can you give me the demo about the R88D-1SN servo,I want to learn something on how to use DC mode on OMRON servo,i used the ecsync0,then the servo had an error that can not running.thank you Best Wishes!

------------------ 原始邮件 ------------------ 发件人: "OpenEtherCATsociety/SOEM" <notifications@github.com>; 发送时间: 2020年8月4日(星期二) 中午11:14 收件人: "OpenEtherCATsociety/SOEM"<SOEM@noreply.github.com>; 抄送: "阳依草 "<715297306@qq.com>;"Comment"<comment@noreply.github.com>; 主题: Re: [OpenEtherCATsociety/SOEM] Vaule of Reading actual position is not correct, when servo driver be Power On (Operation Enable) (#415)

Hi,

You can conntact me

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.