17.状态模式--State

状态模式解析
本文详细介绍了状态模式的概念及其应用场景,展示了如何通过状态模式简化对象状态转换的复杂逻辑,并提供了具体的实现代码示例。此外,还对比了状态模式与策略模式之间的区别。
 

State模式:
State模式当一个对象的内在状态改变时允许改变其行为,这个对象看起来好像是改变了其类

State模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没必要使用State模式了。

State模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。通过把各种状态转移逻辑分布到State的子类之间来减少互相间的依赖。当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。

State模式典型的结构图为:
 

State模式的实现代码如下:

//state.h
#ifndef _STATE_H_
#define _STATE_H_
class Context; //前置声明
class State
{
public:
    State();
    virtual ~State();
    virtual void OperationInterface(/*Context* */) = 0;
    virtual void OperationChangeState(Context*) = 0;
protected:
    bool ChangeState(Context* con,State* st);
};

class ConcreteStateA:public State
{
public:
    ConcreteStateA();
    virtual ~ConcreteStateA();
    virtual void OperationInterface(/*Context* */);
    virtual void OperationChangeState(Context*);
protected:
private:
};

class ConcreteStateB:public State
{
public:
    ConcreteStateB();
    virtual ~ConcreteStateB();
    virtual void OperationInterface(/*Context* */);
    virtual void OperationChangeState(Context*);
protected:
private:
};
#endif //~_STATE_H_


//State.cpp
#include "State.h"
#include "Context.h"
#include <iostream>
using namespace std;
State::State()
{
}
State::~State()
{
}
void State::OperationInterface(/*Context* con*/)
{
    cout<<"State::.."<<endl;
}
bool State::ChangeState(Context* con,State* st)
{
    con->ChangeState(st);
    return true;
}
void State::OperationChangeState(Context* con)
{
}
ConcreteStateA::ConcreteStateA()
{
}
ConcreteStateA::~ConcreteStateA()
{
}
void ConcreteStateA::OperationInterface(/*Context* con*/)
{
    cout<<"ConcreteStateA::OperationInterface......"<<endl;
}
void ConcreteStateA::OperationChangeState(Context* con)
{
    OperationInterface(/*con*/);
    this->ChangeState(con,new ConcreteStateB());
}
ConcreteStateB::ConcreteStateB()
{
}
ConcreteStateB::~ConcreteStateB()
{
}
void ConcreteStateB::OperationInterface(/*Context* con*/)
{
    cout<<"ConcreteStateB::OperationInterface......"<<endl;
}
void ConcreteStateB::OperationChangeState(Context* con)
{
    OperationInterface(/*con*/);
    this->ChangeState(con,new ConcreteStateA());
}


//context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
class State;
class Context
{
public:
    Context();
    Context(State* state);
    ~Context();
    void OprationInterface();
    void OperationChangState();
protected:
private:
    friend class State; //表明在State类中可以访问Context类的private字段
    bool ChangeState(State* state);
private:
    State* _state;
};
#endif //~_CONTEXT_H_


//context.cpp
#include "Context.h"
#include "State.h"
Context::Context()
{
}
Context::Context(State* state)
{
    this->_state = state;
}
Context::~Context()
{
    delete _state;
}
void Context::OprationInterface()
{
    _state->OperationInterface(/*this*/);
}
bool Context::ChangeState(State* state)
{
    this->_state = state;
    return true;
}
void Context::OperationChangState()
{
    _state->OperationChangeState(this);
}


//main.cpp
#include "Context.h"
#include "State.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
    State* st1 = new ConcreteStateA();   
    Context* con = new Context(st1);

    con->OprationInterface();
    st1->OperationChangeState(con);     // 改变状态
    con->OprationInterface();
    con->OprationInterface();

    return 0;
}

State模式和Strategy模式又很大程度上的相似:它们都有一个Context类,都是通过委托(组合)给一个具有多个派生类的多态基类实现Context的算法逻辑。两者最大的差别就是State模式中派生类持有指向Context对象的引用,并通过这个引用调用Context中的方法,但在Strategy模式中就没有这种情况。因此可以说一个State实例同样是Strategy模式的一个实例,反之却不成立。实际上State模式和Strategy模式的区别还在于它们所关注的点不尽相同:State模式主要是要适应对象对于状态改变时的不同处理策略的实现,而Strategy则主要是具体算法和实现接口的解耦(coupling),Strategy模式中并没有状态的概念(虽然很多时候有可以被看作是状态的概念),并且更加不关心状态的改变了。
State模式很好地实现了对象的状态逻辑和动作实现的分离,状态逻辑分布在State的派生类中实现,而动作实现则可以放在Context类中实现(这也是为什么State派生类需要拥有一个指向Context的指针)。这使得两者的变化相互独立,改变State的状态逻辑可以很容易复用Context的动作,也可以在不影响State派生类的前提下创建Context的子类来更改或替换动作实现。

State模式问题主要是逻辑分散化,状态逻辑分布到了很多的State的子类中,很难看到整个的状态逻辑图,这也带来了代码的维护问题。

root@AM64x-Tronlong:~# ./igh_ethercat_dc_motor -d 0 --> main: Request master success. --> main: Create domain succe[ 217.664211] EtherCAT: Requesting master 0... ss. --> main: Get slave configuration success. --> main: Confi[ 217.664242] EtherCAT: Successfully requested master 0. guration PDO success. --> main: success to register bunch of PD[ 217.664598] EtherCAT 0: Domain0: Lo. O entries for domain. --> main: Activate master success. --> m[ 217.664608] EtherCAT 0: Datagram domain0-0-main: Logical offset 0x000. ain: Get pointer to the process data memory success. --> main: [ 217.664689] EtherCAT 0: Master thread exited. Enter cycle task now... --> check_master_state: 1 slave(s). --[ 217.664700] EtherCAT 0: Stopping EoE thread. > check_master_state: AL states: 0x02. --> check_master_state: [ 217.664781] EtherCAT 0: EoE thread exited. Link is up. --> check_slave_config_state: slave[0]: State 0x02.[ 217.664786] EtherCAT 0: S. --> check_slave_config_state: slave[0]: online. --> check_sla[ 217.664989] EtherCAT 0: Starting EtherCAT-OP thread. ve_config_state: slave[0]: State 0x01. --> check_slave_config_state: slave[0]: State 0x02. --> check_domain_state: Domain: WC 3. --> check_domain_state: D[ 217.953212] EtherCAT 0: Domain 0: Working counter c3 omain: State 2. --> check_slave_config_state: slave[0]: State 0[ 217.953235] . x04. [ 217.972256] EtherCAT ERROR 0-0: Failed to set OP state, slave refused state . [ 217.977301] EtherCAT ERROR 0-0: AL status message 0x0027: "Freerun not suppo. --> check_master_state: AL states: 0x04. [ 217.981523] EtherCAT 0-0: Acknowledged state SAFEOP. [ 217.993912] EtherCAT 0: Slave states on main device: SAFEOP
最新发布
03-11
<think>好的,我现在需要分析用户提供的EtherCAT主站运行日志,找出错误原因并提供解决方案。首先,我需要仔细阅读日志中的关键信息,尤其是错误提示部分。 首先,用户执行的命令是`./igh_ethercat_dc_motor -d 0`,看起来是启动一个基于IgH EtherCAT主站的直流电机控制程序。日志中显示主站请求成功,创建域、配置PDO等步骤也成功完成,直到激活主站后开始进入周期任务。这时候开始出现错误。 在日志中,有几个关键的错误信息: 1. `EtherCAT ERROR 0-0: Failed to set OP state, slave refused state.` 2. `AL status message 0x0027: "Freerun not supported."` 3. 最后从站的状态停留在SAFEOP(安全运行)状态,无法进入OP(运行)状态。 首先,错误代码0x0027对应的AL状态码,查阅EtherCAT协议文档,状态码0x0027通常与从站不支持某种操作模式有关,这里的错误信息明确提到“Freerun not supported.”,说明从站不支持自由运行模式。可能主站尝试让从站进入OP状态时,配置了不支持的同步模式,比如自由运行(Freerun),而从站可能要求使用DC(分布式时钟)同步或其他模式。 接下来,检查主站和从站的配置是否正确。IgH EtherCAT主站通常需要正确配置从站的同步模式,尤其是在使用周期性任务时。如果从站是直流电机驱动器,通常需要配置为DC同步模式,而不是自由运行模式。因此,错误可能是由于主站配置的同步模式与从站支持的模式不匹配导致的。 另外,查看日志中从站的状态变化:从0x02(PREOP)到尝试进入OP状态时失败,停留在SAFEOP(0x04)。根据EtherCAT状态机,从站需要依次进入PREOP→SAFEOP→OP状态。如果从站拒绝进入OP,通常是因为配置错误或同步设置问题。 可能的解决方案包括: 1. 检查从站(电机驱动器)的文档,确认其支持的同步模式。如果它需要DC同步,则需在主站配置中启用DC模式。 2. 在IgH配置中,可能需要设置从站的DC参数,比如分配同步管理器、设置周期时间等。 3. 检查主站的配置文件(如`ethercat.conf`)或应用代码,确保同步模式设置为DC而非自由运行。 4. 验证从站的PDO映射是否正确,尤其是在SAFEOP状态下,可能需要重新配置PDO以确保所有必要的参数都已正确映射。 此外,还可以通过EtherCAT主站工具(如`ethercat`命令行工具)检查从站的状态和配置,例如使用`ethercat slaves`查看从站信息,或`ethercat cstruct`生成配置结构时是否包含正确的DC参数。 总结来说,问题根源在于同步模式不兼容,需要调整主站配置以匹配从站支持的同步模式,并确保所有参数正确设置。</think>以下是针对该EtherCAT主站运行问题的分析及解决方案: --- ### **问题分析** 1. **错误信息定位** - **关键报错**:`AL status message 0x0027: "Freerun not supported."` - **状态机中断**:从站停留在**SAFEOP**状态(`0x04`),无法进入**OP**状态。 - **直接原因**:从站(电机驱动器)不支持**自由运行模式(Freerun)**,而主站可能默认配置了此模式。 2. **EtherCAT同步模式** - **自由运行(Freerun)**:主站不提供同步信号,从站内部自由运行。某些从站(如高精度电机驱动器)需依赖**分布式时钟(DC)**同步。 - **DC同步模式**:需配置主站与从站的时钟同步参数(如周期时间、偏移补偿等)。 --- ### **解决方案** #### 步骤1:验证从站支持的同步模式 - **查阅从站文档**:确认电机驱动器是否仅支持**DC同步**。 - **通过命令行工具检查**: ```bash ethercat slaves -v # 查看从站支持的同步模式(检查ESC寄存器配置) ``` #### 步骤2:配置主站使用DC同步 - **修改主站配置**: - 在应用代码或配置文件中,强制启用**DC同步模式**。 - 示例代码片段(C语言): ```c ecrt_master_select_reference_clock(master, 0); // 选择从站0作为参考时钟(若支持) ecrt_master_activate(master); // 激活主站前配置同步模式 ``` - **设置DC参数**: - 周期时间(`cycle_time`)、偏移时间(`shift_time`)需与从站匹配。 ```c ecrt_master_application_time(master, cycle_time_ns); // 设置应用周期时间 ``` #### 步骤3:重新配置PDO映射 - **检查PDO配置**: - 在**SAFEOP**状态下,从站需正确映射PDO(过程数据对象)。 - 使用`ethercat cstruct`生成配置结构时,确保包含**DC相关参数**(如SYNC0周期)。 #### 步骤4:重启主站并验证 - 重新运行程序,观察日志: - 成功标志:从站进入**OP**状态(`0x08`),无`Freerun not supported`报错。 - 调试命令: ```bash ethercat states -p 0 # 监控从站0的状态变化 ``` --- ### **附加建议** - **使用EtherCAT调试工具**: ```bash ethercat debug 1 # 开启主站调试日志 ethercat graph # 查看拓扑结构 ``` - **检查电缆与拓扑**:物理层问题(如信号干扰)也可能导致状态切换失败。 --- 通过以上步骤调整同步模式及配置,可解决从站因不支持自由运行模式导致的OP状态切换失败问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值