제조업에서 제어파트 및 비전 파트에서는 Sequence방식의 제어를 빈번하게 사용한다. switch-case문으로 구현 해왔고, 그렇게 배웠다.
사용하는 중에 명확한 코드 시인성이지만, 유지보수 측면에서 아쉬웠다. 수정 할 부분을 찾아야 하는 경우나, 모든 스탭에 반복적인 로직을 추가해야 하는 경우에 번거로웠다.
편리해진 AI기능을 사용하여 질의하여 더 나아 보이는 구조를 테스트 해보았다.
기존 구조는 C Style의 Enum과 Switch-Case를 사용한 구조이다. 장점은 코드 시인성이 좋고, 직관적이다. 스탭을 추가하거나 삭제하는 경우에 직관적으로 코드를 수정 할 수 있다. 단점은 유지보수 측면에서 아쉬웠다. 수정 할 부분을 찾아야 하는 경우나, 모든 스탭에 반복적인 로직을 추가해야 하는 경우에 번거로웠다.
enum EN_STEP
{
EN_STEP_IDLE = 0,
EN_STEP_MOVE_MOTOR,
EN_STEP_MOVE_MOTOR_CHECK,
EN_STEP_MOVE_CYLINDER,
EN_STEP_MOVE_CYLINDER_CHECK,
EN_STEP_DONE
}
void Update()
{
switch(step)
{
case EN_STEP::EN_STEP_IDLE:
break;
case EN_STEP::EN_STEP_MOVE_MOTOR:
// move motor
step++;
break;
case EN_STEP::EN_STEP_MOVE_MOTOR_CHECK:
// if move done
{
step++;
}
break;
case EN_STEP::EN_STEP_MOVE_CYLINDER:
// move cylinder
step++;
break;
case EN_STEP::EN_STEP_MOVE_CYLINDER_CHECK:
// if cylinder move done
{
step++;
}
break;
case EN_STEP::EN_STEP_DONE:
// step done.
break;
}
}
테스트 구조는 C++의 함수 포인터를 사용한 구조이다. 스탭 함수를 별도로 구현하여, 함수 포인터로 등록하여 반환 값에 따라 순차적으로 함수 포인터를 수행한다. GetStepName()을 통해 현재 스탭의 이름을 반환 받을 수 있다. Time-Out과 같은 로직은 Update함수에서 처리 할 수 있다.
using StepFunc = std::function<bool(void*)>;
class Sequence
{
private:
std::vector<std::tuple<int, StepFunc, std::string>> steps;
int currentStep;
public:
Sequence()
{
currentStep = 0;
}
~Sequence()
{
steps.clear();
}
void SetStep(int step)
{
currentStep = step;
}
void AddStep(StepFunc stepFunc, std::string stepName)
{
steps.push_back(std::make_tuple(steps.size(), stepFunc, stepName));
}
std::string GetStepName()
{
return std::get<2>(steps[currentStep]);
}
void Update()
{
if (currentStep < steps.size())
{
if (std::get<1>(steps[currentStep])())
{
currentStep++;
}
}
}
};