1297.26 범위 검사 조건 노드의 구현
1. 범위 검사의 정의
범위 검사 조건 노드(range check condition node)는 블랙보드에서 읽은 값이 지정된 하한(lower bound)과 상한(upper bound) 사이에 있는지를 판정하는 조건 노드이다. 값 v, 하한 l, 상한 u에 대하여 l \leq v \leq u이면 SUCCESS를, 그렇지 않으면 FAILURE를 반환한다(Colledanchise & Ogren, 2018).
범위 검사는 로봇공학에서 센서 값의 정상 범위 확인, 관절 각도의 허용 한계 확인, 속도/고도/온도 등의 운용 범위 검증에 광범위하게 사용된다. 단일 임계값 비교(부등호 비교)와 달리, 상한과 하한을 동시에 검사하므로 하나의 노드로 양방향 경계를 검증할 수 있다.
2. 폐구간 범위 검사 구현
가장 일반적인 형태인 폐구간(closed interval) 범위 검사 [l, u]의 구현이다. 경계값 자체가 허용 범위에 포함된다.
class IsValueInRange : public BT::ConditionNode
{
public:
IsValueInRange(const std::string& name, const BT::NodeConfig& config)
: BT::ConditionNode(name, config) {}
BT::NodeStatus tick() override
{
double value;
auto result = getInput("value", value);
if (!result)
{
return BT::NodeStatus::FAILURE;
}
double min_val, max_val;
getInput("min", min_val);
getInput("max", max_val);
return (value >= min_val && value <= max_val)
? BT::NodeStatus::SUCCESS
: BT::NodeStatus::FAILURE;
}
static BT::PortsList providedPorts()
{
return {
BT::InputPort<double>("value", "검사 대상 값"),
BT::InputPort<double>("min", "하한값"),
BT::InputPort<double>("max", "상한값")
};
}
};
3. 개구간 및 반개구간 범위 검사
경계값의 포함 여부에 따라 네 가지 구간 유형이 존재한다:
| 구간 유형 | 수학 표기 | 조건 | 경계값 포함 |
|---|---|---|---|
| 폐구간 | [l, u] | l \leq v \leq u | 양쪽 포함 |
| 개구간 | (l, u) | l < v < u | 양쪽 제외 |
| 반개구간 (좌개) | (l, u] | l < v \leq u | 상한만 포함 |
| 반개구간 (우개) | [l, u) | l \leq v < u | 하한만 포함 |
구간 유형을 매개변수로 지정할 수 있는 확장 구현은 다음과 같다:
class IsValueInRangeEx : public BT::ConditionNode
{
public:
IsValueInRangeEx(const std::string& name, const BT::NodeConfig& config)
: BT::ConditionNode(name, config) {}
BT::NodeStatus tick() override
{
double value, min_val, max_val;
auto result = getInput("value", value);
if (!result)
{
return BT::NodeStatus::FAILURE;
}
getInput("min", min_val);
getInput("max", max_val);
bool include_min, include_max;
getInput("include_min", include_min);
getInput("include_max", include_max);
bool above_min = include_min ? (value >= min_val) : (value > min_val);
bool below_max = include_max ? (value <= max_val) : (value < max_val);
return (above_min && below_max)
? BT::NodeStatus::SUCCESS
: BT::NodeStatus::FAILURE;
}
static BT::PortsList providedPorts()
{
return {
BT::InputPort<double>("value", "검사 대상 값"),
BT::InputPort<double>("min", "하한값"),
BT::InputPort<double>("max", "상한값"),
BT::InputPort<bool>("include_min", true, "하한 포함 여부 (기본값: true)"),
BT::InputPort<bool>("include_max", true, "상한 포함 여부 (기본값: true)")
};
}
};
4. XML에서의 활용
<Sequence>
<!-- 온도가 10~40°C 범위인지 확인 -->
<Condition ID="IsValueInRange"
value="{temperature}" min="10.0" max="40.0"/>
<!-- 고도가 10~120m 범위인지 확인 -->
<Condition ID="IsValueInRange"
value="{altitude}" min="10.0" max="120.0"/>
<!-- 속도가 0~2.0 m/s 범위인지 확인 -->
<Condition ID="IsValueInRange"
value="{speed}" min="0.0" max="2.0"/>
<Action ID="Execute"/>
</Sequence>
동적 범위 설정이 필요한 경우 하한과 상한을 블랙보드 키로 매핑한다:
<Condition ID="IsValueInRange"
value="{joint_angle}"
min="{joint_min_limit}"
max="{joint_max_limit}"/>
5. 범위 외 검사 (Out-of-Range)
값이 범위 밖에 있는지를 판정하는 역조건도 필요한 경우가 있다. 이는 범위 검사 노드에 Inverter 데코레이터를 적용하여 구현할 수 있다:
<Inverter>
<Condition ID="IsValueInRange"
value="{temperature}" min="0.0" max="80.0"/>
</Inverter>
또는 전용 범위 외 검사 노드를 구현할 수 있다:
class IsValueOutOfRange : public BT::ConditionNode
{
public:
IsValueOutOfRange(const std::string& name, const BT::NodeConfig& config)
: BT::ConditionNode(name, config) {}
BT::NodeStatus tick() override
{
double value, min_val, max_val;
auto result = getInput("value", value);
if (!result)
{
return BT::NodeStatus::FAILURE;
}
getInput("min", min_val);
getInput("max", max_val);
return (value < min_val || value > max_val)
? BT::NodeStatus::SUCCESS
: BT::NodeStatus::FAILURE;
}
static BT::PortsList providedPorts()
{
return {
BT::InputPort<double>("value", "검사 대상 값"),
BT::InputPort<double>("min", "하한값"),
BT::InputPort<double>("max", "상한값")
};
}
};
6. 비정상 입력 처리
6.1 NaN 및 Inf 검사
부동소수점 값이 NaN이나 Inf인 경우, 범위 검사 전에 유효성을 확인해야 한다. NaN과의 비교는 IEEE 754 표준에 따라 항상 거짓을 반환하므로 범위 검사가 의도대로 동작하지 않을 수 있다.
BT::NodeStatus tick() override
{
double value, min_val, max_val;
auto result = getInput("value", value);
if (!result)
{
return BT::NodeStatus::FAILURE;
}
// NaN 및 Inf 검사
if (std::isnan(value) || std::isinf(value))
{
return BT::NodeStatus::FAILURE;
}
getInput("min", min_val);
getInput("max", max_val);
return (value >= min_val && value <= max_val)
? BT::NodeStatus::SUCCESS
: BT::NodeStatus::FAILURE;
}
6.2 역전된 범위 검사
하한이 상한보다 큰 경우(l > u)는 범위가 역전된 비정상 상태이다. 이 상황을 방어적으로 처리한다:
if (min_val > max_val)
{
return BT::NodeStatus::FAILURE;
}
7. 정수형 범위 검사
정수(int) 타입에 대한 범위 검사도 동일한 패턴으로 구현된다. 부동소수점 오차 문제가 없으므로 경계값 처리가 명확하다.
class IsIntInRange : public BT::ConditionNode
{
public:
IsIntInRange(const std::string& name, const BT::NodeConfig& config)
: BT::ConditionNode(name, config) {}
BT::NodeStatus tick() override
{
int value, min_val, max_val;
auto result = getInput("value", value);
if (!result) return BT::NodeStatus::FAILURE;
getInput("min", min_val);
getInput("max", max_val);
return (value >= min_val && value <= max_val)
? BT::NodeStatus::SUCCESS
: BT::NodeStatus::FAILURE;
}
static BT::PortsList providedPorts()
{
return {
BT::InputPort<int>("value", "검사 대상 정수 값"),
BT::InputPort<int>("min", "하한값"),
BT::InputPort<int>("max", "상한값")
};
}
};
8. 로봇공학에서의 범위 검사 적용 사례
| 적용 분야 | 검사 대상 | 하한 | 상한 | 단위 |
|---|---|---|---|---|
| 관절 제어 | 관절 각도 | 관절 최소 한계 | 관절 최대 한계 | rad |
| 내비게이션 | 로봇 속도 | 0.0 | 최대 허용 속도 | m/s |
| 드론 비행 | 비행 고도 | 최저 안전 고도 | 최대 허용 고도 | m |
| 환경 감시 | 센서 온도 | 운용 최저 온도 | 운용 최고 온도 | °C |
| 전원 관리 | 공급 전압 | 최소 동작 전압 | 최대 허용 전압 | V |
| 매니퓰레이션 | 파지 힘 | 최소 파지 힘 | 최대 안전 힘 | N |
이러한 범위 검사는 로봇 시스템의 안전 운용을 보장하는 핵심 조건으로, 행동 트리의 ReactiveSequence와 결합하여 실시간으로 지속 감시되는 것이 일반적이다.
9. 참고 문헌
- Colledanchise, M., & Ogren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
- Faconti, D., & Colledanchise, M. (2022). BehaviorTree.CPP Documentation. https://www.behaviortree.dev/
version: 0.1.0