現代のセーフティ・クリティカルなシステム(自動車、医療機器、産業ロボットなど)において、C++17をベースとした最新のガイドライン MISRA C++:2023(Guidelines for the use of C++17 in critical systems)への対応は必須となりつつあります。
本記事では、この厳格な規約を遵守しながら、組み込み制御の要である「振動抑制制御(バイブレーション制御)」をいかに実装すべきか、具体的なコード例と共に解説します。
1. MISRA C++:2023 の設計思想と主要な制約
MISRA C++:2023は、C++17の強力な機能を活用しつつ、予測不能な動作(Undefined Behavior)や複雑性によるバグを排除することを目指しています。本稿のサンプルコードでは、以下の主要制約を反映しています。
- 動的メモリ確保の禁止 (Rule 21.3): new / delete は使用せず、静的配置またはスタック利用に限定。
- 例外処理の不使用 (Directive 4.6.1): 実行時の不確定性を避けるため、throw / catch を排除し noexcept を徹底。
- 浮動小数点演算の制限 (Rule 0.3.1): 決定論的な動作のため、可能な限り Q形式固定小数点演算 を採用。
- 型安全性の強化: std::uint16_t 等の固定幅整数型を使い、 implicit conversion(暗黙の型変換)を抑制。
- リソース管理: 仮想関数は必要最小限に留め、final や override を明示。
2. 実装:完全固定小数点版 振動抑制コントローラ
加速度センサ(ADC)からの入力を元に、モータ駆動アクチュエータへPWM出力を行う、単軸振動抑制(ダンパ)制御の例です。ここでは精度と計算負荷のバランスに優れた Q15.16形式 を採用しています。
Q15.16形式の特性
- 整数部: 15ビット(±32768の範囲をカバー)
- 小数部: 16ビット(分解能:約0.000015)
- データ型: std::int32_t に適合し、多くの32bit MCUで高速処理が可能。
サンプルコード
//============================================================================
// File: vibration_damper_fixed.hpp
// Description: MISRA C++:2023 準拠志向の固定小数点振動抑制コントローラ
//============================================================================
#include <cstdint>
#include <cstddef>
#include <cmath>
namespace control {
// Q15.16 固定小数点型の定義
using q15_16_t = std::int32_t;
// 算術ヘルパー(インライン関数による副作用の排除)
constexpr q15_16_t to_q15_16(float v) noexcept {
return static_cast<q15_16_t>(v * 65536.0f + ((v >= 0.0f) ? 0.5f : -0.5f));
}
// 飽和演算付き乗算
constexpr q15_16_t mul_q15_16(q15_16_t a, q15_16_t b) noexcept {
const std::int64_t prod = static_cast<std::int64_t>(a) * b;
const std::int64_t scaled = prod >> 16;
// 飽和処理 (Rule 10.1.1: 符号付き整数のオーバーフロー防止)
if (scaled > 0x7FFFFFFFLL) return 0x7FFFFFFF;
if (scaled < -0x80000000LL) return -0x80000000;
return static_cast<q15_16_t>(scaled);
}
// ハードウェア抽象化レイヤー (HAL)
class ActuatorInterface {
public:
virtual ~ActuatorInterface() = default;
virtual void set_pwm(std::uint16_t duty_pos, std::uint16_t duty_neg) noexcept = 0;
virtual std::uint16_t read_adc() const noexcept = 0;
};
// 振動抑制コントローラ本体
class VibrationDamper final {
public:
explicit VibrationDamper(ActuatorInterface& iface) noexcept : hw(iface) {}
void update() noexcept {
const std::uint16_t raw_adc = hw.read_adc();
// 1. 範囲チェック (入力バリデーション)
if (raw_adc > 4095U) [[unlikely]] {
hw.set_pwm(0U, 0U);
return;
}
// 2. 偏差計算 (ターゲット 0 との比較)
const q15_16_t current_pos = static_cast<q15_16_t>(raw_adc - 2048U) << 5; // 簡易スケール
const q15_16_t error = target_pos - current_pos;
// 3. PD制御則
const q15_16_t p_term = mul_q15_16(error, kp);
const q15_16_t d_term = mul_q15_16(error - prev_error, kd);
q15_16_t output = p_term + d_term;
// 4. 出力リミッタ
if (output > max_output) { output = max_output; }
else if (output < -max_output) { output = -max_output; }
else { /* 範囲内 */ }
// 5. PWM変換
const auto abs_output = (output < 0) ? -output : output;
const auto duty = static_cast<std::uint16_t>((static_cast<std::uint64_t>(abs_output) * 10000U) >> 16);
if (output >= 0) {
hw.set_pwm(duty, 0U);
} else {
hw.set_pwm(0U, duty);
}
prev_error = error;
}
private:
ActuatorInterface& hw;
q15_16_t prev_error{0};
static constexpr q15_16_t target_pos{0};
static constexpr q15_16_t kp{to_q15_16(2.4f)};
static constexpr q15_16_t kd{to_q15_16(0.18f)};
static constexpr q15_16_t max_output{to_q15_16(0.85f)};
};
} // namespace control
