OpenEtherCATsociety / SOEM

Simple Open Source EtherCAT Master
Other
1.35k stars 686 forks source link

Unable to send commands or change modes with Kollmorgen AKD-P01206-NBCC motor controller #324

Closed paholden closed 4 years ago

paholden commented 5 years ago

I'm no longer getting the 0x11 error, but what I am seeing now with slaveinfo is very weird. I set 2 PDO mappings that I was using in TwinCat3 (using #300 as a template) :

static int akd_dc_setup(uint16 slave) { uint32_t long_val; uint16_t temp_val; uint8_t byte_val;

  printf ("AKD drive setup\n");
  // Set 0x1C12:01 to 0x1701 object index
  temp_val = 0x1701;
  ec_SDOwrite(slave, 0x1C12, 1, FALSE, sizeof(temp_val), &temp_val, EC_TIMEOUTRXM);
  // Set 0x1C13:01 to 0x1B01 object index
  temp_val = 0x1B01;
  ec_SDOwrite(slave, 0x1C13, 1, FALSE, sizeof(temp_val), &temp_val, EC_TIMEOUTRXM);

  /* Set a slave name */
  strncpy (ec_slave[slave].name, "AKDDC", EC_MAXNAME);
  return 0;

} void soem_ecat:: soem_do_akd_initialization() { uint32 data; int slave; int wkc; int chk;

cout << "Fix SM0/SM1 data length bug in EEPROM." << endl;
for (slave = 1 ; slave <= ec_slavecount ; slave++)
{
  /* wait for slaves to reach INIT state */
  soem_wait_for_state(slave, 200, EC_STATE_INIT + EC_STATE_ACK);
  wkc = ec_statecheck(slave, EC_STATE_INIT,  EC_TIMEOUTSTATE * 4);
  cout << "Slave " << slave << " state to INIT; wkc = " << wkc << endl;

  /* Set SM0 StartAddr & SMlength fields */
  ec_slave[slave].SM[0].StartAddr = AKD_SM0_STARTADDR;
  ec_slave[slave].SM[0].SMlength = AKD_REV2_SMLEN;
  /* store boot write mailbox address */
  ec_slave[slave].mbx_wo = (uint16)AKD_SM0_STARTADDR;
  /* store boot write mailbox size */
  ec_slave[slave].mbx_l = (uint16)AKD_REV2_SMLEN;

  /* Set SM1 StartAddr & SMlength fields */
  ec_slave[slave].SM[1].StartAddr = (uint16)AKD_SM1_STARTADDR;
  ec_slave[slave].SM[1].SMlength = (uint16)AKD_REV2_SMLEN;
  /* store boot read mailbox address */
  ec_slave[slave].mbx_ro = (uint16)AKD_SM1_STARTADDR;
  /* store boot read mailbox size */
  ec_slave[slave].mbx_rl = (uint16)AKD_REV2_SMLEN;

  cout << " SM0 A:" << setfill('0') << setw(4) << hex << ec_slave[slave].SM[0].StartAddr;
  cout << " L:" << setfill('0') << setw(4) << dec << ec_slave[slave].SM[0].SMlength;
  cout << " F:" << setfill('0') << setw(8) << hex << (int)ec_slave[slave].SM[0].SMflags << endl;
  cout << " SM1 A:" << setfill('0') << setw(4) << hex << ec_slave[slave].SM[1].StartAddr;
  cout << " L:" << setfill('0') << setw(4) << dec << ec_slave[slave].SM[1].SMlength;
  cout << " F:" << setfill('0') << setw(8) << hex << (int)ec_slave[slave].SM[1].SMflags << endl;

  /* program SM0 mailbox in for slave */
  ec_FPWR (ec_slave[slave].configadr, ECT_REG_SM0, sizeof(ec_smt), &ec_slave[slave].SM[0], EC_TIMEOUTRET);
  /* program SM1 mailbox out for slave */
  ec_FPWR (ec_slave[slave].configadr, ECT_REG_SM1, sizeof(ec_smt), &ec_slave[slave].SM[1], EC_TIMEOUTRET);

  // Wait for pre-op
  cout << "Request pre-op state for slave " << slave << endl;
  soem_wait_for_state(slave, 200, EC_STATE_PRE_OP + EC_STATE_ACK);

  /* wait for slave to reach PRE_OP state */
  wkc = ec_statecheck(slave, EC_STATE_PRE_OP,  EC_TIMEOUTSTATE * 4);
  cout << "Slave " << setfill('0') << setw(1) << dec << slave << " state to PRE_OP, wkc = ";
  cout << setfill('0') << setw(1) << dec << wkc << endl;

  // Add mappings
  if ((ec_slave[slave].eep_id == AKD_DCBRUSH_EEP_ID)
  && (ec_slave[slave].eep_man == AKD_DCBRUSH_EEP_MAN))
  {
cout << "Apply Startup commands to Slave " << slave << endl;
akd_dc_setup(slave);
  }
}

}

Then I run slaveinfo, with the EEPROM-fix in the code: PDO mapping according to CoE : SM2 outputs addr b index: sub bitl data_type name [0x0000.0] 0x6040:0x00 0x10 [0x0002.0] 0x6040:0x00 0x10 [0x0004.0] 0x6060:0x00 0x08 [0x0005.0] 0x6040:0x00 0x10 [0x0007.0] 0x607A:0x00 0x20 [0x000B.0] 0x6040:0x00 0x10 [0x000D.0] 0x60FF:0x00 0x20 SM3 inputs addr b index: sub bitl data_type name [0x0011.0] 0x6041:0x00 0x10 [0x0013.0] 0x6041:0x00 0x10 [0x0015.0] 0x6061:0x00 0x08 [0x0016.0] 0x6041:0x00 0x10 [0x0018.0] 0x6064:0x00 0x20 [0x001C.0] 0x6041:0x00 0x10 [0x001E.0] 0x606C:0x00 0x20 End slaveinfo, close socket

This does not look right & when I run Kollmorgen Workbench, it says that the target device config data has been corrupted, would I like to upload/download the data.

Perhaps something else is not correct in this EEPROM? I can try to decipher TwinCat's STARTUP & add all the mappings they set I guess.

If I just run "si_map_sii()" I get the following mappings for both my code & the slaveinfo (both are identical & look correct): PDO mapping according to SII : SM2 RXPDO 0x1701 Outputs addr b index: sub bitl data_type name [0x0000.0] 0x60C1:0x01 0x20 INTEGER32 1st set-point [0x0004.0] 0x6040:0x00 0x10 UNSIGNED16 Controlword SM3 TXPDO 0x1B01 Inputs addr b index: sub bitl data_type name [0x0011.0] 0x6063:0x00 0x20 INTEGER32 Position actual internal value [0x0015.0] 0x6041:0x00 0x10 UNSIGNED16 Statusword

Should I just ignore the COE PDO mapping I saw with slaveinfo?

nakarlsson commented 5 years ago

According to the EtherCAT standard you( given you don’t use complete access)

  1. first write 0 to 0x1c12:00/0x1c13:00 to notify the slave that you’ll write the PDO mappings.
  2. Write the mappings N to 0x1c12:xx/0x1c13:xx.
  3. Write N entries to 0x1c12:00/0x1c13:00 to complete the mapping.

See if it helps

paholden commented 5 years ago

I did try writing 0 to 1C12/1C13 first and the AKD faulted on that, but it did get to SAFE-OP, just not OPERATIONAL mode. The function I'm using to set the mappings is below. I think the problem now is addressed in red_test because the error I'm seeing on the AKD workbench software is about loss of cyclic messages from target. AKD forum is now finally assisting with this problem. They find the SOEM work I'm doing an interesting topic, they said.

static int akd_dc_setup(uint16 slave) { uint32_t long_val; uint16_t temp_val; uint8_t byte_val;

  printf ("AKD drive setup\n");
  // Clear SM PDOs 0x1C12 & 0x1C13
  long_val = 0;
  ec_SDOwrite(slave, 0x1C12, 0, FALSE, sizeof(long_val), &long_val, EC_TIMEOUTRXM);
  long_val = 0;
  ec_SDOwrite(slave, 0x1C13, 0, FALSE, sizeof(long_val), &long_val, EC_TIMEOUTRXM);
  // Set 0x1C12:01 to 0x1701 object index
  temp_val = 0x1701;
  ec_SDOwrite(slave, 0x1C12, 1, FALSE, sizeof(temp_val), &temp_val, EC_TIMEOUTRXM);
  // Set 0x1C12:00 to count of 1 object
  temp_val = 0x01;
  ec_SDOwrite(slave, 0x1C12, 0, FALSE, sizeof(temp_val), &temp_val, EC_TIMEOUTRXM);
  // Set 0x1C13:01 to 0x1B01 object index
  temp_val = 0x1B01;
  ec_SDOwrite(slave, 0x1C13, 1, FALSE, sizeof(temp_val), &temp_val, EC_TIMEOUTRXM);
  // Set 0x1C13:00 to count of 1 object
  temp_val = 0x01;
  ec_SDOwrite(slave, 0x1C13, 0, FALSE, sizeof(temp_val), &temp_val, EC_TIMEOUTRXM);

  // Set a slave name
  strncpy (ec_slave[slave].name, "AKDDC", EC_MAXNAME);
  return 0;

}

nakarlsson commented 5 years ago

Ok, you should check the result from SDOWrite, > 0 or it failed. Not sure if the slave trips on the fact that you write size 4 to 0x1c12,0x1c13 :00 that is uint8.

Also, you should get some AlStatusCode for the SAFEOP + Error when you fail to got to OP.

paholden commented 5 years ago

Oh man, my bad. Will fix that problem & add return for all my SDOwrite() calls. Poor form on my part, just being lazy when I shouldn't!

oguzdilmac commented 5 years ago

Hi, have you succeeded to run the drive? We can get into OP state and read the position etc from PDO but It seems, SM2 interrupt is not generated, and the drive complains about missing SYNC.

Interestingly if we try to configure the drive with IGH EtherCAT master, than we can operate it with SOEM too, until power off/on.

nakarlsson commented 4 years ago

Inactive?