OpenEtherCATsociety / SOEM

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

Problems communicating with actuator using SOEM #523

Closed ergial23 closed 3 years ago

ergial23 commented 3 years ago

Hi guys, since I'm new to SOEM and ethercat I'm a little bit lost in the way the IO map is updated and how I could send the target position to an actuator via etherCAT. Readind the tutorial and the issues closed, this is what I've been trying:

Executing the slaveinfo -map this is the output I get:

ec_init on enp2s0f2 succeeded.
1 slaves found and configured.
Calculated workcounter 3

Slave:1
 Name:JXCE1
 Output size: 288bits
 Input size: 160bits
 State: 4
 Delay: 0[ns]
 Has DC: 1
 DCParentport:0
 Activeports:1.0.0.0
 Configured address: 1001
 Man: 00000114 ID: 0100003f Rev: 00010001
 SM0 A:1000 L: 128 F:00010026 Type:1
 SM1 A:1200 L: 128 F:00010022 Type:2
 SM2 A:1400 L:  36 F:00010024 Type:3
 SM3 A:1600 L:  20 F:00010020 Type:4
 FMMU0 Ls:00000000 Ll:  36 Lsb:0 Leb:7 Ps:1400 Psb:0 Ty:02 Act:01
 FMMU1 Ls:00000024 Ll:  20 Lsb:0 Leb:7 Ps:1600 Psb:0 Ty:01 Act:01
 FMMUfunc 0:1 1:2 2:3 3:0
 MBX length wr: 128 rd: 128 MBX protocols : 04
 CoE details: 13 FoE details: 00 EoE details: 00 SoE details: 00
 Ebus current: 0[mA]
 only LRD/LWR:0
PDO mapping according to CoE :
  SM2 outputs
     addr b   index: sub bitl data_type    name
  [0x0000.0] 0x7010:0x00 0x10 UNSIGNED16   Output port to which signals are allocat
  [0x0002.0] 0x7011:0x00 0x10 UNSIGNED16   Controlling of the numerical data flag
  [0x0004.0] 0x7012:0x00 0x08 UNSIGNED8    Start flag
  [0x0005.0] 0x7020:0x00 0x08 UNSIGNED8    Operation Method
  [0x0006.0] 0x7021:0x00 0x10 UNSIGNED16   Speed
  [0x0008.0] 0x7022:0x00 0x20 INTEGER32    Target position
  [0x000C.0] 0x7023:0x00 0x10 UNSIGNED16   Acceleration
  [0x000E.0] 0x7024:0x00 0x10 UNSIGNED16   Deceleration
  [0x0010.0] 0x7025:0x00 0x10 UNSIGNED16   Pushing force
  [0x0012.0] 0x7026:0x00 0x10 UNSIGNED16   Trigger LV
  [0x0014.0] 0x7027:0x00 0x10 UNSIGNED16   Pushing speed
  [0x0016.0] 0x7028:0x00 0x10 UNSIGNED16   Pushing force for positioning
  [0x0018.0] 0x7029:0x00 0x20 INTEGER32    AREA1
  [0x001C.0] 0x702A:0x00 0x20 INTEGER32    AREA2
  [0x0020.0] 0x702B:0x00 0x20 INTEGER32    Positioning width
  SM3 inputs
     addr b   index: sub bitl data_type    name
  [0x0024.0] 0x6010:0x00 0x10 UNSIGNED16   Signal allocated to the input port
  [0x0026.0] 0x6011:0x00 0x10 UNSIGNED16   Controller information flag
  [0x0028.0] 0x6020:0x00 0x20 INTEGER32    Current position
  [0x002C.0] 0x6021:0x00 0x10 UNSIGNED16   Current speed
  [0x002E.0] 0x6022:0x00 0x10 UNSIGNED16   Current pushing force
  [0x0030.0] 0x6023:0x00 0x20 INTEGER32    Target position
  [0x0034.0] 0x6030:0x01 0x08 UNSIGNED8    Alarm1
  [0x0035.0] 0x6030:0x02 0x08 UNSIGNED8    Alarm2
  [0x0036.0] 0x6030:0x03 0x08 UNSIGNED8    Alarm3
  [0x0037.0] 0x6030:0x04 0x08 UNSIGNED8    Alarm4
End slaveinfo, close socket
End program

Therefore, in order to send the target position to the actuator I created the following structure:

typedef struct PACKED
{
        int16      output_port;
        int16      data_flag;
        int8       start_flag;
        int8       movement_mode;  
        int16      speed;
        int32      target_position;
        int16      accel;
        int16      decel;
        int16      pushing_force;
        int16      trigger;
        int16      pushing_speed;
        int16      moving_force;
        int32      area1;
        int32      area2;
        int32      in_pos;
} out_actuador;

out_actuador  *out_ac;

Then, once we are in SAFE-OP

out_ac = (out_actuador*) ec_slave[1].outputs; and finally, in order to send the target position we should send the next sequence:

               out_ac->start_flag = 0x00;
               ec_send_processdata();
               ec_receive_processdata(EC_TIMEOUTRET);

               out_ac->output_port=0x0201;
               ec_send_processdata();
               ec_receive_processdata(EC_TIMEOUTRET);

               out_ac->data_flag=0x0040;
               ec_send_processdata();
               ec_receive_processdata(EC_TIMEOUTRET);

               out_ac->target_position=0x00001388;
               ec_send_processdata();
               ec_receive_processdata(EC_TIMEOUTRET);

               out_ac->start_flag = 0x01;
               ec_send_processdata();
               ec_receive_processdata(EC_TIMEOUTRET);

I'm trying to adapt the simple_test code and introduce that in the cyclic loop but I have not been able to do that, since, in order to remain in OP state, I have to keep sending data to the actuator, I left the cyclic loop this way:

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

            while(1)
            {
               ec_send_processdata();
               ec_receive_processdata(EC_TIMEOUTRET);
           }

and then I created another thread in wich the IO map is updated but this doesn't work.

Sorry for the inconviniece. Since I'm a little bit lost here, any help would be great, thanks. This is the ESI file: SMC JXCE1_V10.txt

nakarlsson commented 3 years ago

Keep it simple and stick to a single thread to start with, check test/linux/red_test.c.

Below, implement your application state machine in that loop.
If that is not possible , you need to synchronize the access of the IOmap, since below functions will access the IOmap (read and write), if you access the IOmap from another thread you need to handle that.

           ec_send_processdata();
           ec_receive_processdata(EC_TIMEOUTRET)

OSAL_THREAD_FUNC_RT ecatthread(void *ptr)

     wkc = ec_receive_processdata(EC_TIMEOUTRET);

     dorun++;
     /* if we have some digital output, cycle */
     if( digout ) *digout = (uint8) ((dorun / 16) & 0xff);

     if (ec_slave[0].hasdc)
     {
        /* calulate toff to get linux time and DC synced */
        ec_sync(ec_DCtime, cycletime, &toff);
     }
     ec_send_processdata();
ergial23 commented 3 years ago

I have introduced the state machine in the cyclic loop but now, due to the wait time between states, the communication fails and there is an application watchdog failure. I understand that there is a synchronization problem so, should I introduce the ec_sync and ecatthread functions you mentioned, even if I use the ec_send_processdata in only one thread? It's being quite difficult for me to understand what is done in those functions so any help would be great. Thanks in advance.

nakarlsson commented 3 years ago

You need to keep the processdata loop going at < 100ms cycle time, otherwise the slaves watchdogs will trip and they'll enter SAFEOP, eg "outputs" get disabled.

ergial23 commented 3 years ago

Perfect, thanks but the data sheet of the actuator says that I must set the time more than twice the communication cycle time for the interval between the signals, when the signals are continuously input, so how can I manage that?

nakarlsson commented 3 years ago

Cycle time is relative, you conrtol what cycle time you'll run at.

nakarlsson commented 3 years ago

@ergial23 , can this issue be closed?

nakarlsson commented 3 years ago

close due to inactivity