IGH Master 主站CSP - Detail-ASD-A2-E

贴出完整代码,适合新手入门学习demo

  • cmakeList
cmake_minimum_required(VERSION 3.27)
project(demo)

set(CMAKE_CXX_STANDARD 17)

find_package(EtherCAT REQUIRED)

add_executable(demo main.cpp)

target_link_libraries(demo PUBLIC EtherLab::ethercat)

  • demo.cpp
#include <iostream>
#include <algorithm>
#include <csignal>
#include "ecrt.h"

using namespace std;

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

/** 任务周期(ns)。 */
#define PERIOD_NS   (1000000) // 1ms

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






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

/* 常量 */
#define NSEC_PER_SEC (1000000000)

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




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

// EtherCAT
static ec_master_t *master = nullptr;
static ec_master_state_t master_state = {};

static ec_domain_t *domain1 = nullptr;
static ec_domain_state_t domain1_state = {};

static ec_slave_config_t *sc;
static ec_slave_config_state_t sc_state = {};

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






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

/*处理数据*/

static uint8_t *domain1_pd = nullptr;

/*总线耦合器位置*/
#define BusCouplerPos  0, 0
/*从站位置*/
#define Detail_ASD_A2_E_1_Pos  0x000001dd,0x10305070 /*Vendor ID, Product code*/

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







/****************************************************************************/
/*PDO 条目的偏移量*/

static struct {
    unsigned int operation_mode;
    unsigned int ctrl_word;
    unsigned int target_velocity;
    unsigned int status_word;
    unsigned int current_velocity;
    unsigned int current_position;
} offset;

const static ec_pdo_entry_reg_t domain1_regs[] = {
        {BusCouplerPos, Detail_ASD_A2_E_1_Pos, 0x6040, 0, &offset.ctrl_word},
        {BusCouplerPos, Detail_ASD_A2_E_1_Pos, 0x6041, 0, &offset.status_word},
        {BusCouplerPos, Detail_ASD_A2_E_1_Pos, 0x6064, 0, &offset.current_position},
        {BusCouplerPos, Detail_ASD_A2_E_1_Pos, 0x607A, 0, &offset.target_velocity},
        {}
};

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





/****************************************************************************/
/*Config PDOs*/

static ec_pdo_entry_info_t device_pdo_entries[] = {
        /*RxPdo 0x1600*/
        {0x6040, 0x00, 16}, /*Controlword*/
        {0x607A, 0x00, 32}, /*TargetPosition*/
        /*TxPdo 0x1A00*/
        {0x6041, 0x00, 16}, /*Statusword*/
        {0x6064, 0x00, 32}, /*ActualPosition*/
};

static ec_pdo_info_t device_pdos[] = {
        //RxPdo
        {0x1601, 2, device_pdo_entries + 0},
        //TxPdo
        {0x1A01, 2, device_pdo_entries + 2}
};

static ec_sync_info_t device_syncs[] = {
        {0, EC_DIR_OUTPUT, 0, nullptr,         EC_WD_DISABLE},
        {1, EC_DIR_INPUT,  0, nullptr,         EC_WD_DISABLE},
        {2, EC_DIR_OUTPUT, 1, device_pdos + 0, EC_WD_DISABLE},
        {3, EC_DIR_INPUT,  1, device_pdos + 1, EC_WD_DISABLE},
        {0xFF}
};

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

void check_domain1_state() {
    ec_domain_state_t ds;
    ecrt_domain_state(domain1, &ds);
    if (ds.working_counter != domain1_state.working_counter) {
        printf("Domain1: WC %u.\n", ds.working_counter);
    }
    if (ds.wc_state != domain1_state.wc_state) {
        printf("Domain1: State %u.\n", ds.wc_state);
    }
    domain1_state = ds;
}

void check_master_state() {
    ec_master_state_t ms;
    ecrt_master_state(master, &ms);
    if (ms.slaves_responding != master_state.slaves_responding) {
        printf("%u slave(s).\n", ms.slaves_responding);
    }
    if (ms.al_states != master_state.al_states) {
        printf("AL states: 0x%02X.\n", ms.al_states);
    }
    if (ms.link_up != master_state.link_up) {
        printf("Link is %s.\n", ms.link_up ? "up" : "down");
    }
    master_state = ms;
}

void check_slave_config_states() {
    ec_slave_config_state_t s;
    ecrt_slave_config_state(sc, &s);
    if (s.al_state != sc_state.al_state) {
        printf("slave: State 0x%02X.\n", s.al_state);
    }
    if (s.online != sc_state.online) {
        printf("slave: %s.\n", s.online ? "online" : "offline");
    }
    if (s.operational != sc_state.operational) {
        printf("slave: %soperational.\n", s.operational ? "" : "Not ");
    }
    sc_state = s;
}


template<typename type>
void sdoWrite(uint16_t slave, uint16_t index, uint8_t subIndex, const type value) {
    uint32_t abort_code;
    if (ecrt_master_sdo_download(master, slave, index, subIndex, (uint8_t *) &value, sizeof(type), &abort_code))
        cout << "ERROR: ecrt_master_sdo_download: " << abort_code << endl;
}

template<typename type>
type sdoRead(uint16_t slave, uint16_t index, uint8_t subIndex) {
    type value;
    size_t result_size;
    uint32_t abort_code;
    if (ecrt_master_sdo_upload(master, slave, index, subIndex, (uint8_t *) &value, sizeof(type), &result_size,
                               &abort_code) < 0) {
        cout << "ERROR: ecrt_master_sdo_upload: " << abort_code << endl;
        // 如果出现错误,可能需要返回一个默认值或者采取其他适当的错误处理措施
    }
    return value;
}

template<>
// 特化模板
std::string sdoRead<string>(uint16_t slave, uint16_t index, uint8_t subIndex) {
    const size_t maxStringLength = 256;
    uint8_t data[maxStringLength]; // 缓冲区用于存储字符串数据
    size_t resultSize;
    uint32_t abortCode;

    // 读取字符串数据
    if (ecrt_master_sdo_upload(master, slave, index, subIndex, data, maxStringLength, &resultSize, &abortCode) < 0) {
        std::cerr << "ERROR: ecrt_master_sdo_upload: " << abortCode << std::endl;
    }
    // 将字节流转换为字符串
    std::string str(data, data + resultSize);
    // 替换换行符为空字符
    str.erase(std::remove_if(str.begin(), str.end(), [](char c) { return c == '\0'; }), str.end());
    return str;
}

void cyclic_task() {


    /*接收过程数据*/
    ecrt_master_receive(master);
    ecrt_domain_process(domain1);
    /*检查过程数据状态(可选)*/
    check_domain1_state();

    //检查主状态
    check_master_state();
    //检查从站配置状态
    check_slave_config_states();

    /*Read Position*/
    //position = EC_READ_U32(domain1_pd + offset.current_position);
    //fprintf(stderr, "Position: %d\n", position);

    static uint16_t command = 0x004F;//用来帮助判断状态字的值
    int position;
    int status; 

    status = EC_READ_U16(domain1_pd + offset.status_word);
    //EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x06);
    //EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x07);
    //EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x0f);
    // 延时1ms
//    cout << hex << (status & 0x4f) << endl;
    if ((status & 0x4F) == 0x40) {
        EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x06);
        //printf("Status: 0x40\n");
        command = 0x006F;
    } else if ((status & 0x6F) == 0x21) {
        EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x07);
        //printf("Status: 0x21\n");
        command = 0x006F;
    } else if ((status & 0x6F) == 0x23) {
        EC_WRITE_U16(domain1_pd + offset.ctrl_word, 0x0f);
        //printf("Status: 0x23\n");
        command = 0x006F;
    } else if((status & command) == 0x27){
        position = EC_READ_S32(domain1_pd + offset.current_position);
        position += 25600;
        EC_WRITE_S32(domain1_pd + offset.target_velocity, position);
    }
    // 发送PDO

    /*发送过程数据*/
    ecrt_domain_queue(domain1);
    ecrt_master_send(master);
}

struct timespec calculate_next_wakeup(const struct timespec &current_time, long period_ms) {
    struct timespec next_wakeup = current_time;
    long sec_to_add = period_ms / 1000;
    long nsec_to_add = (period_ms % 1000) * 1000000;

    next_wakeup.tv_sec += sec_to_add;
    next_wakeup.tv_nsec += nsec_to_add;

    // Adjust tv_sec and tv_nsec if necessary
    if (next_wakeup.tv_nsec >= 1000000000) {
        next_wakeup.tv_sec += 1;
        next_wakeup.tv_nsec -= 1000000000;
    }

    return next_wakeup;
}

int main() {
    printf("Requesting master...\n");
    master = ecrt_request_master(0);
    if (!master) {
        exit(EXIT_FAILURE);
    }

    // 这里可以配置1C12,1C13等配置

    //int slave = 0;

    /* *//*RxPDO*//*
    sdoWrite<int8_t>(slave, 0x1C12, 0, 0);
    *//*TxPDO*//*
    sdoWrite<int8_t>(slave, 0x1C13, 0, 0);

    *//*RxPDO*//*
    sdoWrite<int8_t>(slave, 0x1600, 0, 0);
    sdoWrite<int32_t>(slave, 0x1600, 1, 0x60400010); // Controlword
    sdoWrite<int32_t>(slave, 0x1600, 2, 0x60710010); // Target torque
    sdoWrite<int32_t>(slave, 0x1600, 3, 0x607A0020); // Target position
    sdoWrite<int32_t>(slave, 0x1600, 4, 0x60FF0020); // Target velocity
    sdoWrite<int32_t>(slave, 0x1600, 5, 0x60600008); // Modes of operation display
    sdoWrite<int32_t>(slave, 0x1600, 6, 0x60B20010); // Torque offset
    sdoWrite<int8_t>(slave, 0x1600, 0, 6);

    *//*TxPDO*//*
    sdoWrite<int16_t>(slave, 0x1A00, 0, 0);
    sdoWrite<int32_t>(slave, 0x1A00, 1, 0x60410010); // Statusword
    sdoWrite<int32_t>(slave, 0x1A00, 2, 0x60640020); // Position actual value
    sdoWrite<int32_t>(slave, 0x1A00, 3, 0x606C0020); // Velocity actual value
    sdoWrite<int32_t>(slave, 0x1A00, 4, 0x60770010); // Torque actual value
    sdoWrite<int32_t>(slave, 0x1A00, 5, 0x60610008); // Modes of operation display
    sdoWrite<int8_t>(slave, 0x1A00, 0, 5);

    *//* write 0x1C12 and 0x1C13 (RxPDO and TxPDO) *//*
    sdoWrite<int16_t>(slave, 0x1C12, 1, 0x1600);
    sdoWrite<int8_t>(slave, 0x1C12, 0, 1);

    sdoWrite<int16_t>(slave, 0x1C13, 1, 0x1A00);
    sdoWrite<int8_t>(slave, 0x1C13, 0, 1);*/

    //sdoWrite<int16_t>(0, 0x6040, 0, 0x80);    //reset faluts
    //sdoWrite<int16_t>(0, 0x6040, 7, 0x1);    //reset faluts
    //sdoWrite<int8_t>(0, 0x6060, 0, 8);		//Modes of Operation: 8 [cyclic synchronous position mode]

    //sdoWrite<int8_t>(0, 0x60C2, 1, 4000/100);
    //sdoWrite<int8_t>(0, 0x60C2, 2, -4);

    //string deviceName = sdoRead<string>(slave, 0x1008, 0); // Device name
    //cout << "Device name: " << deviceName << endl;

    //sdoWrite<uint8_t>(0, 0x6060, 0, 8);
    //sdoWrite<uint8_t>(0, 0x60C2, 1, 1);

    domain1 = ecrt_master_create_domain(master);
    if (!domain1) {
        exit(EXIT_FAILURE);
    }
    if (!(sc = ecrt_master_slave_config(master, BusCouplerPos, Detail_ASD_A2_E_1_Pos))) {
        fprintf(stderr, "Failed to get slave configuration for slave!\n");
        exit(EXIT_FAILURE);
    }
    printf("Configuring PDOs...\n");
    if (ecrt_slave_config_pdos(sc, EC_END, device_syncs)) {
        fprintf(stderr, "Failed to configure slave PDOs!\n");
        exit(EXIT_FAILURE);
    } else {
        printf("*Success to configuring slave PDOs*\n");
    }

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

    ecrt_slave_config_dc(sc, 0x0300, 1000000, 0, 0, 0);
    ecrt_master_select_reference_clock(master, nullptr);
    //ecrt_master_application_time(master, 1);
    //ecrt_master_sync_reference_clock(master);
    //ecrt_master_sync_slave_clocks(master);

    ecrt_slave_config_sdo8(sc, 0x6040, 0, 0x80);

    ecrt_slave_config_sdo8(sc, 0x60C2, 1, 1);
    ecrt_slave_config_sdo8(sc, 0x6060, 0, 8);

    printf("Activating master...\n");
    if (ecrt_master_activate(master)) {
        exit(EXIT_FAILURE);
    } else {
        printf("*Master activated*\n");
    }
    if (!(domain1_pd = ecrt_domain_data(domain1))) {
        exit(EXIT_FAILURE);
    }

    printf("*It's working now*\n");

    struct timespec wakeup_time{};
    clock_gettime(CLOCK_MONOTONIC, &wakeup_time);

    const long PERIOD_MS = 1; // 1ms

    while (true) {
        //usleep(1000);
        //cyclic_task();
        wakeup_time = calculate_next_wakeup(wakeup_time, PERIOD_MS);
        //printf("Next wakeup: %ld.%09ld\n", wakeup_time.tv_sec, wakeup_time.tv_nsec);
        cyclic_task();
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wakeup_time, nullptr);
        //cyclic_task();
    }
    ecrt_release_master(master);
    return EXIT_SUCCESS;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在配置驱动伺服电机之前,需要确保已经将igh_master主站连接到系统网络,同时也需要了解相关的驱动器和伺服电机的型号及通信协议,并且具备一定的网络和电气知识。 首先,需要将驱动器连接到igh_master主站。通常情况下,驱动器会提供一个以太网接口或者其他类型的网络接口,通过网线将驱动器与主站连接在一起。确保连接的稳定性和正确性,可使用网络线缆进行测试。 其次,需要在igh_master主站的配置软件中进行相关配置。根据驱动器和伺服电机的型号和通信协议,选择正确的配置选项。通常,配置软件会提供一个界面,在这个界面中可以设置伺服电机的参数,如位置、速度、加速度等,也可以设置驱动器的通信参数。 在配置过程中,需要使用驱动器和伺服电机的说明书,查找相应的参数值和配置方式。根据应用需求,可以对一些特殊的参数进行调整,例如反馈装置类型、控制方式等。 配置完成后,需要对配置结果进行验证和测试。可以使用配置软件提供的监控功能,查看驱动器和伺服电机的状态和反馈信息,确认配置是否生效。可以通过手动操作(如启动、停止、定位)来测试伺服电机的工作情况,调整相关参数以达到期望的效果。 最后,需要对整个系统进行调试和优化。在实际应用中,可能会遇到一些问题,例如电机不稳定、控制精度不高等。通过实践和经验,需要逐步调整和优化系统的参数和控制策略,以满足实际需求。 总之,配置驱动伺服电机需要进行硬件连接、软件配置、验证测试和系统调试等多个步骤,需要理解相关的驱动器和伺服电机的特性,并具备一定的技术知识和实践能力。 ### 回答2: 要配置igh_master主站驱动伺服电机,首先需要确保主站已经正确连接到驱动器和电机。然后,通过在主站上进行参数设置和通信配置来实现驱动伺服电机的功能。 配置的第一步是设置主站的参数。这涉及到主站的通信速率、通信协议、ID地址等。通过设置这些参数,可以确保主站与驱动器和电机之间的通信正常进行。 接下来,需要对驱动器进行参数设置。这些参数包括电机型号、电机参数、运动模式、速度曲线等。设置这些参数可以确保驱动器能够正确驱动电机,实现预期的运动效果。 在配置完成后,需要对主站和驱动器进行通信配置。这涉及到主站发送指令给驱动器,以控制电机的运动。通信配置还包括主站接收从驱动器返回的状态信息,以便进行实时监控和反馈控制。 最后,需要进行驱动电机的测试和调试。通过发送指令和监控返回的状态信息,可以验证配置是否正确,并进行调整和优化。测试和调试包括检查电机运动是否符合预期、调整运动参数和速度等。 总结来说,配置igh_master主站驱动伺服电机需要进行参数设置、通信配置和测试调试。通过正确配置,可以实现对伺服电机的精确控制和运动管理。 ### 回答3: igh_master主站是一种控制系统,用于配置和驱动伺服电机。伺服电机是一种精密的电动机,能够根据输入的控制信号实现高精度的位置控制。而igh_master主站可以通过发送信号给伺服电机的驱动器来控制电机的运动。 首先,安装和配置igh_master主站是配置伺服电机的第一步。通过连接电源和网络连接,我们可以将一台计算机设置为igh_master主站。然后,我们需要安装相应的软件来确保主站与伺服电机之间的通信正常。这些软件可以包括设备配置工具和运动控制软件。 接下来,我们需要连接伺服电机和主站。通常,使用驱动器和编码器将伺服电机连接到主站。驱动器负责将主站发送的信号转换为电机运动,而编码器则用于提供电机位置和速度的反馈信号。 配置伺服电机的参数也是一个重要的步骤。我们需要根据具体的应用需求,设置伺服电机的加速度、减速度、速度限制等参数。这些参数将决定伺服电机的运动特性,如响应时间和精度。 最后,我们可以使用运动控制软件来对伺服电机进行控制。我们可以通过运动指令(如位置指令、速度指令)来控制电机的运动。同时,我们还可以监控电机的状态,如位置、速度和电流等。 综上所述,通过配置和驱动伺服电机,igh_master主站充当了控制和调节信号的中间件。它提供了一个有效的方式,可以在应用中实现对伺服电机的高精度控制和监控。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值