Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

example ec400 stalling with slave state not switching to OP #21

Closed
jimy-byerley opened this issue Mar 14, 2023 · 12 comments
Closed

example ec400 stalling with slave state not switching to OP #21

jimy-byerley opened this issue Mar 14, 2023 · 12 comments

Comments

@jimy-byerley
Copy link

jimy-byerley commented Mar 14, 2023

Hello
This may be the first of a serie of stupid interogations for setting up a master using CoE

I'm trying to start a cyclic communication with PDO read/write on an omron servodrive (R88D-1SN04H-ECT), based on example/ec400.rs. While starting, the program stalls in the loop waiting for servo.tick(). The slave never switches to OP and then often after ~2min, the program panics with the following log:

ydejonghe@UBUNTU:~/ethercat/ethercrab$ sudo RUST_LOG=debug target/debug/examples/ec400
[2023-03-14T13:55:29Z INFO  ec400] Starting SDO demo...
[2023-03-14T13:55:29Z DEBUG ethercrab::slave] Slave 0x1000 name R88D-1SN04H-ECT
[2023-03-14T13:55:29Z DEBUG ethercrab::client] Configuring topology/distributed clocks
[2023-03-14T13:55:29Z DEBUG ethercrab::dc] Slave 0x1000 R88D-1SN04H-ECT has DC
[2023-03-14T13:55:29Z DEBUG ethercrab::dc] --> Times 39335733 (2139694680) 2179030413 (0) 0 (1819436374) 1819436374
[2023-03-14T13:55:29Z DEBUG ethercrab::dc] --> Propagation time None ns, child delay 0 ns
[2023-03-14T13:55:29Z DEBUG ethercrab::dc] Distributed clock config complete
[2023-03-14T13:55:29Z DEBUG ethercrab::dc] Performing static drift compensation using slave 0x1000 R88D-1SN04H-ECT as reference. This can take some time...
[2023-03-14T13:55:31Z DEBUG ethercrab::dc] Static drift compensation complete
[2023-03-14T13:55:31Z DEBUG ethercrab::slave_group::configurator] Going to configure group, starting PDI offset 0x000000
[2023-03-14T13:55:31Z DEBUG ethercrab::eeprom] Discovered sync managers:
    [
        SyncManager {
            start_addr: 0x1800,
            length: 0x0100,
            control: Control {
                operation_mode: Mailbox,
                direction: MasterWrite,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: MailboxWrite,
        },
        SyncManager {
            start_addr: 0x1c00,
            length: 0x0100,
            control: Control {
                operation_mode: Mailbox,
                direction: MasterRead,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: MailboxRead,
        },
        SyncManager {
            start_addr: 0x1100,
            length: 0x000c,
            control: Control {
                operation_mode: Normal,
                direction: MasterWrite,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: true,
            },
            enable: ENABLE,
            usage_type: ProcessDataWrite,
        },
        SyncManager {
            start_addr: 0x1200,
            length: 0x001c,
            control: Control {
                operation_mode: Normal,
                direction: MasterRead,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: ProcessDataRead,
        },
    ]
[2023-03-14T13:55:31Z DEBUG ethercrab::slave::configurator] Slave 0x1000 SM0: start 0x1800, size 0x0100 (256), direction MasterWrite, mode Mailbox, enabled
[2023-03-14T13:55:31Z DEBUG ethercrab::slave::configurator] Slave 0x1000 SM1: start 0x1c00, size 0x0100 (256), direction MasterRead, mode Mailbox, enabled
[2023-03-14T13:55:31Z DEBUG ethercrab::slave::slave_client] Set state Pre-Operational for slave address 0x1000
[2023-03-14T13:55:31Z INFO  ec400] Found "R88D-1SN04H-ECT\0\0\0\0\0"
[2023-03-14T13:55:31Z DEBUG ethercrab::eeprom] Discovered sync managers:
    [
        SyncManager {
            start_addr: 0x1800,
            length: 0x0100,
            control: Control {
                operation_mode: Mailbox,
                direction: MasterWrite,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: MailboxWrite,
        },
        SyncManager {
            start_addr: 0x1c00,
            length: 0x0100,
            control: Control {
                operation_mode: Mailbox,
                direction: MasterRead,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: MailboxRead,
        },
        SyncManager {
            start_addr: 0x1100,
            length: 0x000c,
            control: Control {
                operation_mode: Normal,
                direction: MasterWrite,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: true,
            },
            enable: ENABLE,
            usage_type: ProcessDataWrite,
        },
        SyncManager {
            start_addr: 0x1200,
            length: 0x001c,
            control: Control {
                operation_mode: Normal,
                direction: MasterRead,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: ProcessDataRead,
        },
    ]
[2023-03-14T13:55:31Z DEBUG ethercrab::eeprom] Discovered FMMUs:
    [
        Outputs,
        Inputs,
        SyncManagerStatus,
        Unused,
    ]
[2023-03-14T13:55:31Z DEBUG ethercrab::eeprom] FMMU mappings: []
[2023-03-14T13:55:31Z DEBUG ethercrab::slave::configurator] Slave 0x1000 has CoE: true
[2023-03-14T13:55:31Z DEBUG ethercrab::eeprom] Discovered PDOs:
    [
        Pdo {
            index: 0x1b01,
            num_entries: 9,
            sync_manager: 3,
            dc_sync: 0,
            name_string_idx: 3,
            flags: PDO_DEFAULT | PDO_FIXED_CONTENT,
            entries: [
                PdoEntry {
                    index: 0x603f,
                    sub_index: 0,
                    name_string_idx: 4,
                    data_type: U16,
                    data_length_bits: 16,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x6041,
                    sub_index: 0,
                    name_string_idx: 5,
                    data_type: U16,
                    data_length_bits: 16,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x6064,
                    sub_index: 0,
                    name_string_idx: 6,
                    data_type: I32,
                    data_length_bits: 32,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x6077,
                    sub_index: 0,
                    name_string_idx: 7,
                    data_type: I16,
                    data_length_bits: 16,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x60f4,
                    sub_index: 0,
                    name_string_idx: 8,
                    data_type: I32,
                    data_length_bits: 32,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x60b9,
                    sub_index: 0,
                    name_string_idx: 9,
                    data_type: U16,
                    data_length_bits: 16,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x60ba,
                    sub_index: 0,
                    name_string_idx: 10,
                    data_type: I32,
                    data_length_bits: 32,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x60bc,
                    sub_index: 0,
                    name_string_idx: 11,
                    data_type: I32,
                    data_length_bits: 32,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x60fd,
                    sub_index: 0,
                    name_string_idx: 12,
                    data_type: U32,
                    data_length_bits: 32,
                    flags: 0,
                },
            ],
        },
    ]
[2023-03-14T13:55:31Z DEBUG ethercrab::slave::configurator] Slave 0x1000 SM3: start 0x1200, size 0x001c (28), direction MasterRead, mode Normal, enabled
[2023-03-14T13:55:31Z DEBUG ethercrab::slave::configurator] Slave 0x1000 FMMU1: logical start 0x00000000:0, size 28, logical end bit 7, physical start 0x1200:0, RO, enabled
[2023-03-14T13:55:31Z DEBUG ethercrab::slave::configurator] Slave 0x1000 PDI inputs: PdiSegment { bytes: 0..28, bit_len: 224 } (28 bytes), outputs: PdiSegment { bytes: 0..0, bit_len: 0 } (0 bytes)
[2023-03-14T13:55:31Z DEBUG ethercrab::slave_group::configurator] Slave mailboxes configured and init hooks called
[2023-03-14T13:55:31Z DEBUG ethercrab::eeprom] Discovered sync managers:
    [
        SyncManager {
            start_addr: 0x1800,
            length: 0x0100,
            control: Control {
                operation_mode: Mailbox,
                direction: MasterWrite,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: MailboxWrite,
        },
        SyncManager {
            start_addr: 0x1c00,
            length: 0x0100,
            control: Control {
                operation_mode: Mailbox,
                direction: MasterRead,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: MailboxRead,
        },
        SyncManager {
            start_addr: 0x1100,
            length: 0x000c,
            control: Control {
                operation_mode: Normal,
                direction: MasterWrite,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: true,
            },
            enable: ENABLE,
            usage_type: ProcessDataWrite,
        },
        SyncManager {
            start_addr: 0x1200,
            length: 0x001c,
            control: Control {
                operation_mode: Normal,
                direction: MasterRead,
                ecat_event_enable: false,
                dls_user_event_enable: true,
                watchdog_enable: false,
            },
            enable: ENABLE,
            usage_type: ProcessDataRead,
        },
    ]
[2023-03-14T13:55:31Z DEBUG ethercrab::eeprom] Discovered FMMUs:
    [
        Outputs,
        Inputs,
        SyncManagerStatus,
        Unused,
    ]
[2023-03-14T13:55:31Z DEBUG ethercrab::eeprom] FMMU mappings: []
[2023-03-14T13:55:31Z DEBUG ethercrab::slave::configurator] Slave 0x1000 has CoE: true
[2023-03-14T13:55:32Z DEBUG ethercrab::eeprom] Discovered PDOs:
    [
        Pdo {
            index: 0x1701,
            num_entries: 4,
            sync_manager: 2,
            dc_sync: 0,
            name_string_idx: 13,
            flags: PDO_DEFAULT | PDO_FIXED_CONTENT,
            entries: [
                PdoEntry {
                    index: 0x6040,
                    sub_index: 0,
                    name_string_idx: 14,
                    data_type: U16,
                    data_length_bits: 16,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x607a,
                    sub_index: 0,
                    name_string_idx: 15,
                    data_type: I32,
                    data_length_bits: 32,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x60b8,
                    sub_index: 0,
                    name_string_idx: 16,
                    data_type: U16,
                    data_length_bits: 16,
                    flags: 0,
                },
                PdoEntry {
                    index: 0x60fe,
                    sub_index: 1,
                    name_string_idx: 17,
                    data_type: U32,
                    data_length_bits: 32,
                    flags: 0,
                },
            ],
        },
    ]
[2023-03-14T13:55:32Z DEBUG ethercrab::slave::configurator] Slave 0x1000 SM2: start 0x1100, size 0x000c (12), direction MasterWrite, mode Normal, enabled
[2023-03-14T13:55:32Z DEBUG ethercrab::slave::configurator] Slave 0x1000 FMMU0: logical start 0x0000001c:0, size 12, logical end bit 7, physical start 0x1100:0, W, enabled
[2023-03-14T13:55:32Z DEBUG ethercrab::slave::configurator] Slave 0x1000 PDI inputs: PdiSegment { bytes: 0..28, bit_len: 224 } (28 bytes), outputs: PdiSegment { bytes: 28..40, bit_len: 96 } (12 bytes)
[2023-03-14T13:55:32Z DEBUG ethercrab::slave::slave_client] Set state Safe-Operational for slave address 0x1000
[2023-03-14T13:55:32Z DEBUG ethercrab::slave_group::configurator] Slave FMMUs configured for group. Able to move to SAFE-OP
[2023-03-14T13:55:32Z DEBUG ethercrab::slave_group::configurator] Group PDI length: start 0, 40 total bytes (28 input bytes)
[2023-03-14T13:55:32Z DEBUG ethercrab::client] After group #0 offset: PdiOffset { start_address: 40, start_bit: 0 }
[2023-03-14T13:55:32Z DEBUG ethercrab::client] Total PDI 40 bytes
[2023-03-14T13:55:32Z INFO  ec400] Slaves moved to OP state
[2023-03-14T13:55:32Z INFO  ec400] Group has 1 slaves
[2023-03-14T13:55:32Z INFO  ec400] -> Slave 4096 R88D-1SN04H-ECT inputs: 28 bytes, outputs: 12 bytes
[2023-03-14T13:55:32Z INFO  ec400] Cycle time: 2 ms
[2023-03-14T13:55:32Z DEBUG ethercrab::ds402] Edge READY_TO_SWITCH_ON | SWITCHED_ON | WARNING | STO | REMOTE | TARGET_REACHED | INTERNAL_LIMIT | OP_SPECIFIC_1 | OP_SPECIFIC_2 | MAN_SPECIFIC_1 | MAN_SPECIFIC_2

<2min>

thread 'main' panicked at 'TX/RX: Pdu(InvalidFrameState)', examples/ec400.rs:188:36
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Here is the code I'm running:

use async_io::Timer;
use ethercrab::{
    ds402::{Ds402, Ds402Sm},
    error::Error,
    std::tx_rx_task,
    Client, PduLoop, PduStorage, SlaveGroup, SlaveState, SubIndex, Timeouts,
};
use futures_lite::StreamExt;
use smol::LocalExecutor;
use std::{
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    time::Duration,
};

#[cfg(target_os = "windows")]
// ASRock NIC
// const INTERFACE: &str = "TODO";
// // USB NIC
// const INTERFACE: &str = "\\Device\\NPF_{DCEDC919-0A20-47A2-9788-FC57D0169EDB}";
// Lenovo USB-C NIC
const INTERFACE: &str = "\\Device\\NPF_{CC0908D5-3CB8-46D6-B8A2-575D0578008D}";
// Silver USB NIC
// const INTERFACE: &str = "\\Device\\NPF_{CC0908D5-3CB8-46D6-B8A2-575D0578008D}";
#[cfg(not(target_os = "windows"))]
const INTERFACE: &str = "eno1";

const MAX_SLAVES: usize = 16;
const MAX_PDU_DATA: usize = 1100;
const MAX_FRAMES: usize = 16;
const PDI_LEN: usize = 256;

static PDU_STORAGE: PduStorage<MAX_FRAMES, MAX_PDU_DATA> = PduStorage::new();
static PDU_LOOP: PduLoop = PduLoop::new(PDU_STORAGE.as_ref());

async fn main_inner(ex: &LocalExecutor<'static>) -> Result<(), Error> {
    log::info!("Starting SDO demo...");

    let client = Arc::new(Client::new(&PDU_LOOP, Timeouts::default()));

    ex.spawn(tx_rx_task(INTERFACE, &client).unwrap()).detach();

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();

    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
    })
    .expect("Error setting Ctrl-C handler");

    // let num_slaves = client.num_slaves();

    let groups = SlaveGroup::<MAX_SLAVES, PDI_LEN>::new(|slave| {
        Box::pin(async {
            // --- Reads ---

            // // Name
            // dbg!(slave
            //     .read_sdo::<heapless::String<64>>(0x1008, SdoAccess::Index(0))
            //     .await
            //     .unwrap());

            // // Software version. For AKD, this should equal "M_01-20-00-003"
            // dbg!(slave
            //     .read_sdo::<heapless::String<64>>(0x100a, SdoAccess::Index(0))
            //     .await
            //     .unwrap());

            // --- Writes ---

            log::info!("Found {:?}", slave.name());

//             if slave.name() == "R88D-1SN04H-ECT\0\0\0\0\0" {
			if slave.name() == "ZeroErr Driver" {
				log::info!("  using it");
                // CSV described a bit better in section 7.6.2.2 Related Objects of the manual
                slave.write_sdo(0x1600, SubIndex::Index(0), 0u8).await?;
                // Control word, u16
                // NOTE: The lower word specifies the field length
                slave
                    .write_sdo(0x1600, SubIndex::Index(1), 0x6040_0010u32)
                    .await?;
                // Target velocity, i32
                slave
                    .write_sdo(0x1600, SubIndex::Index(2), 0x60ff_0020u32)
                    .await?;
                slave.write_sdo(0x1600, SubIndex::Index(0), 2u8).await?;

                slave.write_sdo(0x1a00, SubIndex::Index(0), 0u8).await?;
                // Status word, u16
                slave
                    .write_sdo(0x1a00, SubIndex::Index(1), 0x6041_0010u32)
                    .await?;
                // Actual position, i32
                slave
                    .write_sdo(0x1a00, SubIndex::Index(2), 0x6064_0020u32)
                    .await?;
                // Actual velocity, i32
                slave
                    .write_sdo(0x1a00, SubIndex::Index(3), 0x606c_0020u32)
                    .await?;
                slave.write_sdo(0x1a00, SubIndex::Index(0), 0x03u8).await?;

               // commented to avoid too big frame issue
//                 slave.write_sdo(0x1c12, SubIndex::Index(0), 0u8).await?;
//                 slave.write_sdo(0x1c12, SubIndex::Index(1), 0x1600).await?;
//                 slave.write_sdo(0x1c12, SubIndex::Index(0), 1u8).await?;
// 
//                 slave.write_sdo(0x1c13, SubIndex::Index(0), 0u8).await?;
//                 slave.write_sdo(0x1c13, SubIndex::Index(1), 0x1a00).await?;
//                 slave.write_sdo(0x1c13, SubIndex::Index(0), 1u8).await?;

                // Opmode - Cyclic Synchronous Position
                // slave.write_sdo(0x6060, SubIndex::Index(0), 0x08).await?;
                // Opmode - Cyclic Synchronous Velocity
                slave.write_sdo(0x6060, SubIndex::Index(0), 0x09u8).await?;
            }

            Ok(())
        })
    });

    let group = client
        .init::<16, _>(groups, |groups, slave| groups.push(slave))
        .await
        .expect("Init");

    client
        .request_slave_state(SlaveState::Op)
        .await
        .expect("OP");

    log::info!("Slaves moved to OP state");

    log::info!("Group has {} slaves", group.len());

    for slave in group.slaves() {
        let (i, o) = slave.io();

        log::info!(
            "-> Slave {} {} inputs: {} bytes, outputs: {} bytes",
            slave.configured_address,
            slave.name,
            i.len(),
            o.len(),
        );
    }

    // Run twice to prime PDI
    group.tx_rx(&client).await.expect("TX/RX");

    let cycle_time = {
        let slave = group.slave(0).unwrap();

        let base = slave
            .read_sdo::<u8>(&client, 0x60c2, SubIndex::Index(1))
            .await?;
        let x10 = slave
            .read_sdo::<i8>(&client, 0x60c2, SubIndex::Index(2))
            .await?;

        let base = f32::from(base);
        let x10 = 10.0f32.powi(i32::from(x10));

        let cycle_time_ms = (base * x10) * 1000.0;

        Duration::from_millis(unsafe { cycle_time_ms.round().to_int_unchecked() })
    };

    log::info!("Cycle time: {} ms", cycle_time.as_millis());

    // AKD will error with F706 if cycle time is not 2ms or less
    let mut cyclic_interval = Timer::interval(cycle_time);

    let slave = group.slave(0).expect("No servo!");
    let mut servo = Ds402Sm::new(Ds402::new(slave).expect("Failed to gather DS402"));

    let mut velocity: i32 = 0;

    // let mut slave = group.slave(0, &client).unwrap();

    let accel = 300;

    while let Some(_) = cyclic_interval.next().await {
        group.tx_rx(&client).await.expect("TX/RX");

        if servo.tick() {
            // // Opmode - Cyclic Synchronous Position
            // servo
            //     .sm
            //     .context()
            //     .slave
            //     .write_sdo(&client, 0x6060, SubIndex::Index(0), 0x08u8)
            //     .await?;

            let status = servo.status_word();
            let (i, o) = servo.slave().io();

            let (pos, vel) = {
                let pos = i32::from_le_bytes(i[2..=5].try_into().unwrap());
                let vel = i32::from_le_bytes(i[6..=9].try_into().unwrap());

                (pos, vel)
            };

            println!(
                "Position: {pos}, velocity: {vel}, status: {status:?} | {:?}",
                o
            );

            let pos_cmd = &mut o[2..=5];

            pos_cmd.copy_from_slice(&velocity.to_le_bytes());

            if running.load(Ordering::SeqCst) {
                if vel < 200_000 {
                    velocity += accel;
                }
            } else if vel > 0 {
                velocity -= accel;
            } else {
                break;
            }
        }
    }

    log::info!("Servo stopped, shutting drive down");

    while let Some(_) = cyclic_interval.next().await {
        group.tx_rx(&client).await.expect("TX/RX");

        if servo.tick_shutdown() {
            break;
        }

        let status = servo.status_word();
        let (i, o) = servo.slave().io();

        let (pos, vel) = {
            let pos = i32::from_le_bytes(i[2..=5].try_into().unwrap());
            let vel = i32::from_le_bytes(i[6..=9].try_into().unwrap());

            (pos, vel)
        };

        println!(
            "Position: {pos}, velocity: {vel}, status: {status:?} | {:?}",
            o
        );
    }

    Ok(())
}

fn main() -> Result<(), Error> {
    env_logger::init();
    let local_ex = LocalExecutor::new();

    futures_lite::future::block_on(local_ex.run(main_inner(&local_ex))).unwrap();

    Ok(())
}

Do you think I am doing something wrong ?

@jimy-byerley
Copy link
Author

jimy-byerley commented Mar 14, 2023

I can see on wireshark, that the slave actually received the request for mode OP and answered two successive state changes as expected: SafeOP then OP

Here is the transmission capture: issue-21.pcapng.zip

image

So why is the program blocked ?

@jamwaffles
Copy link
Collaborator

jamwaffles commented Mar 14, 2023

Thanks for the bug report and Wireshark dump. A few things:

  • You're still checking for if slave.name() == "ZeroErr Driver" {, which means the drive won't be configured correctly to go into OP. I don't see using it printed in the logs which confirms this. If you have no other slaves on the network, try removing the if and doing the SDO writes unconditionally.
  • I noticed the slave name is "R88D-1SN04H-ECT\0\0\0\0\0" which looks like a bug in either EtherCrab or the drive firmware. Could you please rerun your program with EtherCrab on the trace level (e.g. RUST_LOG=ec400=debug,ethercrab=trace) and attach the resulting output as a file - it will be very long - so I can debug this name reading issue please?
  • The packets you've highlighted in wireshark are EtherCAT's AL (Application Layer) statuses. DS402 has its own status on top of this which, confusingly, uses a lot of the same names. AFAIK DS402 isn't decoded by Wireshark so you'll just get raw LRW packet data there. Your drive is going into EtherCAT OP which then allows the DS402 state machine to start attempt to put the drive into DS402 OP state, where it's failing for some reason. You should be seeing DEBUG ethercrab::ds402] Edge ... spewing everywhere but I'm not sure why it's hanging.

As mentioned above, a trace level log and a new wireshark capture if you've changed anything would be appreciated, e.g. RUST_LOG=ec400=debug,ethercrab=trace

My best guess right now is that the drive isn't configured at all as none of the SDOs are written in the init closure. Try removing the if that checks for the slave name and see if you get any SDOs written by looking at Wireshark or the log output. Have a look at your drive's manual on correct values for CSV as well - the EC400 examples uses values specific to that drive.

It's late for me here but tomorrow I'll test master branch with my EC400 drive to check if there have been any regressions since I ran it last - it's strange that you're only seeing one DS402 tick.

@jimy-byerley
Copy link
Author

Oops I was running the test agains the two types of servodrives, and I copy-pasted the wrong code here it seems. I ran the program again with the good condition: mention using it is present this time and the same stall occurs.
(For the coming tests I will remove the name condition to avoid any possible problem with it).

I noticed that strange name issue, not sure if it is a bug in the firmware or not, but etherlab-rs doesn't seems to suffer from it.
Here is the full trace: issue-21-2.zip

I will check for the drives actual pdo addresses. But shouldn't the drive raise errors if I'm using wrong PDOs ?

@jamwaffles
Copy link
Collaborator

Hey, the string name issue should be fixed in #23 but it would be great if you could confirm if it fixed it for you or not. I don't have access to my test gear right now, but none of them showed the bug anyway...

But shouldn't the drive raise errors if I'm using wrong PDOs?

I don't think so - I think they just fail to go into DS402 OP if I remember what my drives do correctly.

@jimy-byerley
Copy link
Author

I confirm #22 is fixed in my case :)

@jimy-byerley
Copy link
Author

Have a look at your drive's manual on correct values for CSV as well - the EC400 examples uses values specific to that drive.

You were right, I did paid attention to that my PDO addresses were right (they are the same for omron drives and leadshine drives), but forgot to check the SDO selecting the PDO to receive (those are differents between omron and leadshine)
I will try with the correct ones

@jamwaffles
Copy link
Collaborator

I just ran the ec400 demo on my servo drive and it still works, so no regressions 🎉

You might find it useful to look for Discovered PDOs in the logs - the list of PDOs and their values are listed below that message. The manual is probably a better source of truth, but it might be useful for cross checking.

@jimy-byerley
Copy link
Author

jimy-byerley commented Mar 17, 2023

Well my tests gets weirds ...
I spent the last day checking the SDO and PDO addresses and those used in ec400.rs are the same for leadshine and omron (how cumbersome it is with the XML dumb syntax !).
Maybe what was wrong in my test was that I commented the writing of SDOs 0x1c12 and 0x1c13 however they are assigning the PDOs to the sync managers. So I guess that was pretty regular that the servodrive was not sending frames.
What is weird is that when I uncomment the writing of these two registers, It gets refused by the servodrive:

slave.write_sdo(0x1c12, SubIndex::Index(0), 0u8).await?;
slave.write_sdo(0x1c12, SubIndex::Index(1), 0x1600).await?;
slave.write_sdo(0x1c12, SubIndex::Index(0), 1u8).await?;
thread 'main' panicked at 'Init: Mailbox(Aborted { code: General, address: 7186, sub_index: 1 })', examples/ec400.rs:129:10
// 7186 = 0x1c12

Despite 0x1c12 is present in omron's ESI file

...
<Object>
	<Index>#x1C12</Index>
	<Name LcId="1033">Sync Manager 2 PDO Assignment</Name>

	<Type>DT1C12</Type>
	<BitSize>64</BitSize>
	<Info>
		<SubItem>
			<Name>SubIndex 000</Name>
			<Info>
				<MinValue>#x00</MinValue>
				<MaxValue>#x03</MaxValue>
				<DefaultValue>#x01</DefaultValue>
			</Info>
		</SubItem>
		<SubItem>
			<Name>1st PDO Mapping Object Index of assigned PDO</Name>
			<Info>
				<MinValue>#x0000</MinValue>
				<MaxValue>#x17FF</MaxValue>
				<DefaultValue>#x1701</DefaultValue>
			</Info>
		</SubItem>
		...

@jimy-byerley
Copy link
Author

You might find it useful to look for Discovered PDOs in the logs - the list of PDOs and their values are listed below that message. The manual is probably a better source of truth, but it might be useful for cross checking.

I think that will be of great help in further steps of my project, but yet I'm struggling even at triggering the PDOs 😓

@jimy-byerley
Copy link
Author

jimy-byerley commented Mar 17, 2023

I found the cause of my problem: I wasn't sending the right subitem size:

// was doing this:  implicitely a usize I guess, implying u64
slave.write_sdo(0x1c12, SubIndex::Index(1), 0x1600).await?;
// instead of this: u16
slave.write_sdo(0x1c12, SubIndex::Index(1), 0x1600_u16).await?;

So ec400.rs is working now on my omron servodrive 😃

@jamwaffles
Copy link
Collaborator

Great to hear! SDO issues are pretty hard to debug so well done figure it out :). I'm not sure it's possible but if it is, I'll look at having an error to report incorrect data types because this is a pretty mean gotcha in the current API.

@jimy-byerley
Copy link
Author

jimy-byerley commented Mar 17, 2023

The SDO abort code helped me actually
In the wireshark log, there was a field Abort code: 0x06070010 . Refering to the canopen communication profile, I found

Abort code Description
0607 0010 h Data type does not match, length of service parameter does not match

Since these error codes are part of the canopen specifications, it could be great to mention the received error code and eventually its string message in the error returned by write_sdo():

Mailbox(Aborted {
   code: General, address: 7186, sub_index: 1 
   errcode: ...,  // maybe even implement Display so it can be printed with the error message provided by the canopen specs
   })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants