diff --git a/.vscode/settings.json b/.vscode/settings.json index b2987cc..b4f706c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,8 @@ "C_Cpp.doxygen.generatedStyle": "/**", "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", "editor.formatOnSave": true, - "files.encoding": "utf8" + "files.encoding": "utf8", + "files.associations": { + "cmath": "cpp" + } } diff --git a/CMakeLists.txt b/CMakeLists.txt index 08a5bb2..53d0305 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ if(DEFINED MBED_PATH) # mbed-os のビルドに影響を与えるため、最適化オプションを指定せず、警告をエラーにしない target_compile_options(spirit PUBLIC -Wall -Wextra -pedantic) elseif(MSVC) - target_compile_options(spirit PUBLIC /Wall /WX) + target_compile_options(spirit PUBLIC /W4 /WX /utf-8) else() # GCC or Clang target_compile_options(spirit PUBLIC -O2 -Wall -Wextra -pedantic-errors -Werror) endif() @@ -57,7 +57,7 @@ if(DEFINED MBED_PATH) add_library(spirit-platform-mbed STATIC) if(MSVC) - target_compile_options(spirit-platform-mbed PUBLIC /Wall) + target_compile_options(spirit-platform-mbed PUBLIC /W4) else() target_compile_options(spirit-platform-mbed PUBLIC -Wall -Wextra -pedantic) endif() diff --git a/src/spirit/include/Id.h b/src/spirit/include/Id.h index afcc626..1532924 100644 --- a/src/spirit/include/Id.h +++ b/src/spirit/include/Id.h @@ -17,7 +17,7 @@ static constexpr uint32_t motor_prefix = 0x1; static constexpr uint32_t motor_prefix_size = 2; /// spiritでCANでモーター制御に使う場合に使うIDのDIPスイッチの最大ビット幅 -static constexpr uint32_t dip_switch_size = 5; +static constexpr uint32_t dip_switch_width = 5; /** * @brief CAN通信時のモーターIDを取得する diff --git a/src/spirit/include/SpeedController.h b/src/spirit/include/SpeedController.h index 9e498a2..16f00d4 100644 --- a/src/spirit/include/SpeedController.h +++ b/src/spirit/include/SpeedController.h @@ -1,115 +1,115 @@ -#ifndef SPIRIT_SPEED_CONTROLLER_H -#define SPIRIT_SPEED_CONTROLLER_H - -#include - -#include "InterfaceInterruptIn.h" - -namespace spirit { - -class SpeedController { -public: - /** - * @brief コンストラクタ - * @param a_phase RotaryEncoder A phase pin - * @param b_phase RotaryEncoder B phase pin - */ - SpeedController(InterfaceInterruptIn& a_phase, InterfaceInterruptIn& b_phase); - - /** - * @brief 目標rpsを与えると速度制御の計算結果を返す - * @param target_rps 速度制御の目標rps - * @param dt 制御周期(s) - */ - float calculation(float target_rps, float dt); - - /** - * @brief 速度制御の計算結果にかける上限値と下限値を設定 - * @param high_limit 速度制御の計算結果の最大値 - * @param low_limit 速度制御の計算結果の最小値 - */ - void limit(float high_limit, float low_limit); - - /** - * @brief PID制御のゲイン係数を設定 - * @param kp 比例ゲイン - * @param ki 積分ゲイン - * @param kd 微分ゲイン - * @retval false ゲイン変更なし - * @retval true ゲイン変更あり - */ - bool pid_gain(float kp, float ki, float kd); - - /** - * @brief ロータリーエンコーダの計算値をリセット - */ - void reset(); - - /** - * @brief ロータリーエンコーダの角度を返す - */ - float angle(); - - /** - * @brief rpsを返す - * @return rps - */ - float rps(); - -private: - InterfaceInterruptIn& _a_phase; - InterfaceInterruptIn& _b_phase; - - float _kp{0.0f}; - float _ki{0.0f}; - float _kd{0.0f}; - - static constexpr int _ppr{200}; - static constexpr float _deg_unit{360.0f / _ppr / 4.0f}; - - int _angle_counter; - - bool first_loop; - - /// @note モータの最低回転速度によっては変更の余地あり(ppr=200で0.15[rps]以下が目安??) - static constexpr int _angle_buff_max{10}; - int _angle_buff_index; - int _angle_buff[_angle_buff_max]; - - float _rps{0.00f}; - - float _sum_error; - float _delta_error; - float _last_error; - - float _high_limit{0.00f}; - float _low_limit{0.00f}; - - /** - * @brief rpsを算出して返す - * @param dt rps - * @return 算出されたrps - */ - float rps_calculation(float dt); - - /** - * @brief 元の数値にリミッターをかける - * @param val 元の数値 - * @return リミッターをかけた数値 - */ - float limiter(float val); - - /** - * @brief ロータリーエンコーダのA相が変化した際の処理を行う - */ - void a_phase_interrupt(); - - /** - * @brief ロータリーエンコーダのB相が変化した際の処理を行う - */ - void b_phase_interrupt(); -}; - -} // namespace spirit - -#endif // SPIRIT_SPEED_CONTROLLER_H +#ifndef SPIRIT_SPEED_CONTROLLER_H +#define SPIRIT_SPEED_CONTROLLER_H + +#include + +#include "InterfaceInterruptIn.h" + +namespace spirit { + +class SpeedController { +public: + /** + * @brief コンストラクタ + * @param a_phase RotaryEncoder A phase pin + * @param b_phase RotaryEncoder B phase pin + */ + SpeedController(InterfaceInterruptIn& a_phase, InterfaceInterruptIn& b_phase); + + /** + * @brief 目標rpsを与えると速度制御の計算結果を返す + * @param target_rps 速度制御の目標rps + * @param dt 制御周期(s) + */ + float calculation(float target_rps, float dt); + + /** + * @brief 速度制御の計算結果にかける上限値と下限値を設定 + * @param high_limit 速度制御の計算結果の最大値 + * @param low_limit 速度制御の計算結果の最小値 + */ + void limit(float high_limit, float low_limit); + + /** + * @brief PID制御のゲイン係数を設定 + * @param kp 比例ゲイン + * @param ki 積分ゲイン + * @param kd 微分ゲイン + * @retval false ゲイン変更なし + * @retval true ゲイン変更あり + */ + bool pid_gain(float kp, float ki, float kd); + + /** + * @brief ロータリーエンコーダの計算値をリセット + */ + void reset(); + + /** + * @brief ロータリーエンコーダの角度を返す + */ + float angle(); + + /** + * @brief rpsを返す + * @return rps + */ + float rps(); + +private: + InterfaceInterruptIn& _a_phase; + InterfaceInterruptIn& _b_phase; + + float _kp{0.0f}; + float _ki{0.0f}; + float _kd{0.0f}; + + static constexpr int _ppr{200}; + static constexpr float _deg_unit{360.0f / _ppr / 4.0f}; + + int _angle_counter; + + bool first_loop; + + /// @note モータの最低回転速度によっては変更の余地あり(ppr=200で0.15[rps]以下が目安??) + static constexpr int _angle_buff_max{10}; + int _angle_buff_index; + int _angle_buff[_angle_buff_max]; + + float _rps{0.00f}; + + float _sum_error; + float _delta_error; + float _last_error; + + float _high_limit{0.00f}; + float _low_limit{0.00f}; + + /** + * @brief rpsを算出して返す + * @param dt rps + * @return 算出されたrps + */ + float rps_calculation(float dt); + + /** + * @brief 元の数値にリミッターをかける + * @param val 元の数値 + * @return リミッターをかけた数値 + */ + float limiter(float val); + + /** + * @brief ロータリーエンコーダのA相が変化した際の処理を行う + */ + void a_phase_interrupt(); + + /** + * @brief ロータリーエンコーダのB相が変化した際の処理を行う + */ + void b_phase_interrupt(); +}; + +} // namespace spirit + +#endif // SPIRIT_SPEED_CONTROLLER_H diff --git a/src/spirit/src/Id.cpp b/src/spirit/src/Id.cpp index 24e86aa..6a0f470 100644 --- a/src/spirit/src/Id.cpp +++ b/src/spirit/src/Id.cpp @@ -10,15 +10,16 @@ namespace { /** * @brief DIPスイッチの値がビット幅を超えていないかチェックする - * @param dip_switch_size DIPスイッチの値 + * @param value DIPスイッチの値 + * @param width DIPスイッチのビット幅 * @retval true ビット幅を超えていない (正常) * @retval false ビット幅を超えている (異常) */ -bool dip_switch_is_valid(uint32_t dip_switch, std::size_t dip_switch_size) +bool dip_switch_is_valid(uint32_t value, std::size_t width) { // DIPスイッチの値がビット幅を超えていないかチェックする // 例えば、DIPスイッチの値が0b1111で、ビット幅が3の場合、0b1111は3bitで表現できないため、エラーとする - return (dip_switch >> dip_switch_size) == 0; + return (value >> width) == 0; } /** @@ -75,10 +76,10 @@ uint32_t get_motor_id(const uint32_t motor_count, const uint32_t motor, const ui return 0; } - if (!dip_switch_is_valid(dip_switch, dip_switch_size)) { + if (!dip_switch_is_valid(dip_switch, dip_switch_width)) { Error::get_instance().warning(Error::Type::IllegalCombination, 0, __FILE__, __func__, __LINE__, "DIP switch value (%d) exceeds maximum bit width (%d)", dip_switch, - dip_switch_size); + dip_switch_width); return 0; } @@ -95,7 +96,7 @@ uint32_t get_motor_id(const uint32_t motor_count, const uint32_t motor, const ui id |= 0x00 << (can_id_size - motor_prefix_size - motor_count_prefix_size); // DIPスイッチの値をそのままIDに反映する - id |= dip_switch << (can_id_size - motor_prefix_size - motor_count_prefix_size - dip_switch_size); + id |= dip_switch << (can_id_size - motor_prefix_size - motor_count_prefix_size - dip_switch_width); return id; case 1: @@ -106,7 +107,7 @@ uint32_t get_motor_id(const uint32_t motor_count, const uint32_t motor, const ui id |= motor << (can_id_size - motor_prefix_size - motor_count_prefix_size - 1); // DIPスイッチの値をそのままIDに反映する - id |= dip_switch << (can_id_size - motor_prefix_size - motor_count_prefix_size - 1 - dip_switch_size); + id |= dip_switch << (can_id_size - motor_prefix_size - motor_count_prefix_size - 1 - dip_switch_width); return id; case 2: @@ -117,7 +118,7 @@ uint32_t get_motor_id(const uint32_t motor_count, const uint32_t motor, const ui id |= motor << (can_id_size - motor_prefix_size - motor_count_prefix_size - 2); // DIPスイッチの値をそのままIDに反映する - id |= dip_switch << (can_id_size - motor_prefix_size - motor_count_prefix_size - 2 - dip_switch_size); + id |= dip_switch << (can_id_size - motor_prefix_size - motor_count_prefix_size - 2 - dip_switch_width); return id; default: diff --git a/src/spirit/src/PwmDataConverter.cpp b/src/spirit/src/PwmDataConverter.cpp index 20240c5..3ab387a 100644 --- a/src/spirit/src/PwmDataConverter.cpp +++ b/src/spirit/src/PwmDataConverter.cpp @@ -57,7 +57,7 @@ void PwmDataConverter::set_duty_cycle(const float duty_cycle, uint8_t* buffer) c { /// @todo デューティー比がマイナスを取ることはないため、その場合はエラーにする - const uint16_t duty_cycle_16bit = 65535 * duty_cycle; // 2^16 - 1 = 65535 + const uint16_t duty_cycle_16bit = (uint16_t)(65535 * duty_cycle); // 2^16 - 1 = 65535 set_range_value(duty_cycle_16bit, 2, 16, 8, buffer); } diff --git a/src/spirit/src/SpeedController.cpp b/src/spirit/src/SpeedController.cpp index 55600d9..d6a709a 100644 --- a/src/spirit/src/SpeedController.cpp +++ b/src/spirit/src/SpeedController.cpp @@ -1,168 +1,168 @@ -#include "spirit/include/SpeedController.h" - -#include - -#include "spirit/include/Error.h" - -namespace spirit { - -SpeedController::SpeedController(InterfaceInterruptIn& a_phase, InterfaceInterruptIn& b_phase) - : _a_phase(a_phase), _b_phase(b_phase) -{ -#if defined(__MBED__) && !defined(ARDUINO) - _a_phase.rise(mbed::callback(this, &SpeedController::a_phase_interrupt)); - _a_phase.fall(mbed::callback(this, &SpeedController::a_phase_interrupt)); - _b_phase.rise(mbed::callback(this, &SpeedController::b_phase_interrupt)); - _b_phase.fall(mbed::callback(this, &SpeedController::b_phase_interrupt)); -#elif defined(ARDUINO) - // TODO Arduinoに対応 -#else - std::function func_a = std::bind(&SpeedController::a_phase_interrupt, this); - std::function func_b = std::bind(&SpeedController::b_phase_interrupt, this); - _a_phase.rise(func_a); - _a_phase.fall(func_a); - _b_phase.rise(func_b); - _b_phase.fall(func_b); -#endif - reset(); -} - -float SpeedController::calculation(float target_rps, float dt) -{ - if (target_rps < 0.0f) { - Error::get_instance().error(Error::Type::InvalidValue, 0, __FILE__, __func__, __LINE__, - "[target_rps = %g] value cannot be negative", target_rps); - return 0.0f; - } - - if (dt <= 0.0f) { - Error::get_instance().error(Error::Type::InvalidValue, 0, __FILE__, __func__, __LINE__, - "[dt = %g] value cannot be less than 0", dt); - return 0.0f; - } - - _rps = rps_calculation(dt); - - float error = target_rps - _rps; - _sum_error += error; - _delta_error = error - _last_error; - - float p = _kp * error; - float i = limiter(_ki * _sum_error * dt / 2.0f); - float d = _kd * _delta_error / dt; - - _last_error = error; - - return limiter(p + i + d); -} - -float SpeedController::rps_calculation(float dt) -{ - if (dt <= 0.0f) { - Error::get_instance().error(Error::Type::InvalidValue, 0, __FILE__, __func__, __LINE__, - "[dt = %g] value cannot be less than 0", dt); - return 0.0f; - } - - float rps; - _angle_buff_index++; - - if (_angle_buff_index == _angle_buff_max) { - _angle_buff_index = 0; - first_loop = false; - } else if (first_loop) { - rps = angle() / 360.0f / (dt * _angle_buff_index); - if (rps < 0.0f) { - rps *= -1; - } - return rps; - } - - float angle_diff = _angle_counter - _angle_buff[_angle_buff_index]; - _angle_buff[_angle_buff_index] = _angle_counter; - - rps = (angle_diff * _deg_unit) / 360.0f / (dt * _angle_buff_max); - if (rps < 0.0f) { - rps *= -1; - } - return rps; -} - -void SpeedController::limit(float high_limit, float low_limit) -{ - if (high_limit > low_limit) { - _high_limit = high_limit; - _low_limit = low_limit; - } else { - Error::get_instance().error(Error::Type::InvalidValue, 0, __FILE__, __func__, __LINE__, - "[high_limit = %g, low_limit = %g]The relationship between the upper limit value " - "and the lower limit value is strange", - high_limit, low_limit); - } -} - -bool SpeedController::pid_gain(float kp, float ki, float kd) -{ - if ((_kp == kp) && (_ki == ki) && (_kd == kd)) { - return false; - } - - _kp = kp; - _ki = ki; - _kd = kd; - - return true; -} - -void SpeedController::reset() -{ - _angle_counter = 0; - _angle_buff_index = 0; - _sum_error = 0.0f; - _last_error = 0.0f; - _rps = 0.0f; - for (int i = 0; i < _angle_buff_max; i++) { - _angle_buff[i] = 0; - } - first_loop = true; -} - -float SpeedController::limiter(float val) -{ - if (val > _high_limit) { - return _high_limit; - } else if (val < _low_limit) { - return _low_limit; - } - return val; -} - -void SpeedController::a_phase_interrupt() -{ - if (_a_phase.read() != _b_phase.read()) { - _angle_counter++; - } else { - _angle_counter--; - } -} - -void SpeedController::b_phase_interrupt() -{ - if (_a_phase.read() == _b_phase.read()) { - _angle_counter++; - } else { - _angle_counter--; - } -} - -float SpeedController::angle() -{ - return _angle_counter * _deg_unit; -} - -float SpeedController::rps() -{ - return _rps; -} - -} // namespace spirit +#include "spirit/include/SpeedController.h" + +#include + +#include "spirit/include/Error.h" + +namespace spirit { + +SpeedController::SpeedController(InterfaceInterruptIn& a_phase, InterfaceInterruptIn& b_phase) + : _a_phase(a_phase), _b_phase(b_phase) +{ +#if defined(__MBED__) && !defined(ARDUINO) + _a_phase.rise(mbed::callback(this, &SpeedController::a_phase_interrupt)); + _a_phase.fall(mbed::callback(this, &SpeedController::a_phase_interrupt)); + _b_phase.rise(mbed::callback(this, &SpeedController::b_phase_interrupt)); + _b_phase.fall(mbed::callback(this, &SpeedController::b_phase_interrupt)); +#elif defined(ARDUINO) + // TODO Arduinoに対応 +#else + std::function func_a = std::bind(&SpeedController::a_phase_interrupt, this); + std::function func_b = std::bind(&SpeedController::b_phase_interrupt, this); + _a_phase.rise(func_a); + _a_phase.fall(func_a); + _b_phase.rise(func_b); + _b_phase.fall(func_b); +#endif + reset(); +} + +float SpeedController::calculation(float target_rps, float dt) +{ + if (target_rps < 0.0f) { + Error::get_instance().error(Error::Type::InvalidValue, 0, __FILE__, __func__, __LINE__, + "[target_rps = %g] value cannot be negative", target_rps); + return 0.0f; + } + + if (dt <= 0.0f) { + Error::get_instance().error(Error::Type::InvalidValue, 0, __FILE__, __func__, __LINE__, + "[dt = %g] value cannot be less than 0", dt); + return 0.0f; + } + + _rps = rps_calculation(dt); + + float error = target_rps - _rps; + _sum_error += error; + _delta_error = error - _last_error; + + float p = _kp * error; + float i = limiter(_ki * _sum_error * dt / 2.0f); + float d = _kd * _delta_error / dt; + + _last_error = error; + + return limiter(p + i + d); +} + +float SpeedController::rps_calculation(float dt) +{ + if (dt <= 0.0f) { + Error::get_instance().error(Error::Type::InvalidValue, 0, __FILE__, __func__, __LINE__, + "[dt = %g] value cannot be less than 0", dt); + return 0.0f; + } + + float rps; + _angle_buff_index++; + + if (_angle_buff_index == _angle_buff_max) { + _angle_buff_index = 0; + first_loop = false; + } else if (first_loop) { + rps = angle() / 360.0f / (dt * _angle_buff_index); + if (rps < 0.0f) { + rps *= -1; + } + return rps; + } + + int angle_diff = _angle_counter - _angle_buff[_angle_buff_index]; + _angle_buff[_angle_buff_index] = _angle_counter; + + rps = (angle_diff * _deg_unit) / 360.0f / (dt * _angle_buff_max); + if (rps < 0.0f) { + rps *= -1; + } + return rps; +} + +void SpeedController::limit(float high_limit, float low_limit) +{ + if (high_limit > low_limit) { + _high_limit = high_limit; + _low_limit = low_limit; + } else { + Error::get_instance().error(Error::Type::InvalidValue, 0, __FILE__, __func__, __LINE__, + "[high_limit = %g, low_limit = %g]The relationship between the upper limit value " + "and the lower limit value is strange", + high_limit, low_limit); + } +} + +bool SpeedController::pid_gain(float kp, float ki, float kd) +{ + if ((_kp == kp) && (_ki == ki) && (_kd == kd)) { + return false; + } + + _kp = kp; + _ki = ki; + _kd = kd; + + return true; +} + +void SpeedController::reset() +{ + _angle_counter = 0; + _angle_buff_index = 0; + _sum_error = 0.0f; + _last_error = 0.0f; + _rps = 0.0f; + for (int i = 0; i < _angle_buff_max; i++) { + _angle_buff[i] = 0; + } + first_loop = true; +} + +float SpeedController::limiter(float val) +{ + if (val > _high_limit) { + return _high_limit; + } else if (val < _low_limit) { + return _low_limit; + } + return val; +} + +void SpeedController::a_phase_interrupt() +{ + if (_a_phase.read() != _b_phase.read()) { + _angle_counter++; + } else { + _angle_counter--; + } +} + +void SpeedController::b_phase_interrupt() +{ + if (_a_phase.read() == _b_phase.read()) { + _angle_counter++; + } else { + _angle_counter--; + } +} + +float SpeedController::angle() +{ + return _angle_counter * _deg_unit; +} + +float SpeedController::rps() +{ + return _rps; +} + +} // namespace spirit diff --git a/src/spirit/src/SpeedDataConverter.cpp b/src/spirit/src/SpeedDataConverter.cpp index c5a2a6f..a8e1d4d 100644 --- a/src/spirit/src/SpeedDataConverter.cpp +++ b/src/spirit/src/SpeedDataConverter.cpp @@ -58,7 +58,7 @@ float SpeedDataConverter::get_speed(const uint8_t* buffer) const { uint32_t speed_16bit = 0; get_range_value(buffer, 8, 2, 16, speed_16bit); - return bfloat16_to_float32(speed_16bit); + return bfloat16_to_float32((uint16_t)speed_16bit); } void SpeedDataConverter::set_speed(float speed, uint8_t* buffer) const @@ -75,11 +75,11 @@ void SpeedDataConverter::get_pid_gain_factor(const uint8_t* buffer, float& kp, f uint32_t kp_16bit = 0; get_range_value(buffer, 7, 18, 16, kp_16bit); - kp = bfloat16_to_float32(kp_16bit); + kp = bfloat16_to_float32((uint16_t)kp_16bit); uint32_t ki_16bit = 0; get_range_value(buffer, 7, 34, 16, ki_16bit); - ki = bfloat16_to_float32(ki_16bit); + ki = bfloat16_to_float32((uint16_t)ki_16bit); } void SpeedDataConverter::set_pid_gain_factor(float kp, float ki, float kd, uint8_t* buffer) const diff --git a/src/spirit/src/bfloat16.cpp b/src/spirit/src/bfloat16.cpp index 9ddbc70..cd040c0 100644 --- a/src/spirit/src/bfloat16.cpp +++ b/src/spirit/src/bfloat16.cpp @@ -28,7 +28,7 @@ float bfloat16_to_float32(const uint16_t bfloat16) constexpr uint32_t exponent_bias = 127 + 7; // 127: 指数部の0x7Fのオフセット, 7: 仮数部のビット数 const uint32_t actual_mantissa = mantissa + 128; // ケチ表現で省略された最上位ビットを復元 - return std::ldexp(actual_mantissa, exponent - exponent_bias) * sign; + return (float)std::ldexp(actual_mantissa, exponent - exponent_bias) * sign; } } @@ -54,7 +54,7 @@ uint16_t float32_to_bfloat16(const float value) mantissa = static_cast(std::ldexp(mantissa_float, 8)); } - return (sign << 15) | (exponent << 7) | mantissa; + return (uint16_t)((sign << 15) | (exponent << 7) | mantissa); } } // namespace spirit diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 15f6dbc..4dc491b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,8 +7,10 @@ FetchContent_Declare( URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.zip ) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") +if(NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") +endif() # 親プロジェクトのコンパイラ・リンカ設定を上書きするのを防ぐ(Windowsのみ) if(WIN32) @@ -23,9 +25,9 @@ function(add_gtest target_source) add_executable(${target} ${ARGV}) if(MSVC) - target_compile_options(${target} PUBLIC /W4) + target_compile_options(${target} PUBLIC /W4 /WX) else() - target_compile_options(${target} PUBLIC -O2 -Wall -Wextra) + target_compile_options(${target} PUBLIC -O2 -Wall -Wextra -pedantic-errors -Werror) endif() target_include_directories(${target} PUBLIC ../src/spirit/include) diff --git a/tests/integration_test.cpp b/tests/integration_test.cpp index e5ee019..cd124b6 100644 --- a/tests/integration_test.cpp +++ b/tests/integration_test.cpp @@ -18,7 +18,7 @@ TEST(IntegrationTest, 1) constexpr uint32_t dip_sw = 0x00; /// 送信側 - auto controller = [](const spirit::Motor &motor) { + auto controller = [&dip_sw](const spirit::Motor &motor) { spirit::FakeUdpConverter fake_udp; spirit::MotorDataConverter motor_data; const uint32_t can_id = spirit::can::get_motor_id(1, 0, dip_sw); @@ -50,7 +50,7 @@ TEST(IntegrationTest, 1) }; /// 受信側 - auto peripheral = [](const ::CANMessage &message) { + auto peripheral = [&dip_sw](const ::CANMessage &message) { spirit::FakeUdpConverter fake_udp; spirit::MotorDataConverter motor_data; diff --git a/tests/test_Id.cpp b/tests/test_Id.cpp index a062d82..0e4e41e 100644 --- a/tests/test_Id.cpp +++ b/tests/test_Id.cpp @@ -41,7 +41,7 @@ TEST(Id, IdCanMotorTest) // 本当のエラー時にエラー出力させたいので、異常系のテスト中は標準エラー出力をキャプチャする testing::internal::CaptureStderr(); - /// @test dip_switchの値がビット幅( dip_switch_size )を超えている場合 + /// @test dip_switchの値がビット幅( dip_switch_width )を超えている場合 EXPECT_EQ(0, can::get_motor_id(1, 0, 0x20)); /// @test motorの値がモーターの数を超えている場合 diff --git a/tests/test_Motor.cpp b/tests/test_Motor.cpp index fb118be..e2feca0 100644 --- a/tests/test_Motor.cpp +++ b/tests/test_Motor.cpp @@ -409,10 +409,10 @@ TEST(Motor, MaximumChangeDutyCycleTest) /// @test 設定値が範囲外(x < Motor::minimum_maximum_change_duty_cycle, 2.00 < x)の場合、エラーが発生することの確認 anomaly_test(Motor::ChangeLevelTarget::Rise, - Motor::minimum_maximum_change_duty_cycle - Motor::minimum_maximum_change_duty_cycle * 0.001); + Motor::minimum_maximum_change_duty_cycle - Motor::minimum_maximum_change_duty_cycle * 0.001F); anomaly_test(Motor::ChangeLevelTarget::Fall, - Motor::minimum_maximum_change_duty_cycle - Motor::minimum_maximum_change_duty_cycle * 0.001); + Motor::minimum_maximum_change_duty_cycle - Motor::minimum_maximum_change_duty_cycle * 0.001F); anomaly_test(Motor::ChangeLevelTarget::Rise, 2.01F); diff --git a/tests/test_SpeedController.cpp b/tests/test_SpeedController.cpp index c2b454b..55a7cc9 100644 --- a/tests/test_SpeedController.cpp +++ b/tests/test_SpeedController.cpp @@ -1,91 +1,91 @@ -#include - -#include "Error.h" -#include "SpeedController.h" -#include "tests/stubs.h" - -namespace { - -using namespace spirit; - -TEST(SpeedController, SpeedControllerTest) -{ - StubInterruptIn a_phase; - StubInterruptIn b_phase; - SpeedController speed_controller(a_phase, b_phase); - - // 計算しやすいようにゲインを設定 - speed_controller.pid_gain(1.00f, 1.00f, 1.00f); - speed_controller.limit(3.00f, 0.00f); - - /* エンコーダの仮想パルス生成 (1.8°回転) */ - a_phase.interrupt_rise(); - b_phase.interrupt_rise(); - a_phase.interrupt_fall(); - b_phase.interrupt_fall(); - /* ここまで */ - - // 角度 - EXPECT_FLOAT_EQ(speed_controller.angle(), 1.80f); - // PID計算(リミットなし) - EXPECT_FLOAT_EQ(speed_controller.calculation(1.005f, 1.00f), 2.5f); - // RPS - EXPECT_FLOAT_EQ(speed_controller.rps(), 0.005f); - - speed_controller.limit(1.00f, 0.00f); - - // PID計算(上限リミット) - EXPECT_FLOAT_EQ(speed_controller.calculation(1.00f, 1.00f), 1.00f); - - speed_controller.reset(); - - speed_controller.limit(1.00f, -1.00f); - - /* エンコーダの仮想パルス生成 (-1.8°回転) */ - b_phase.interrupt_rise(); - a_phase.interrupt_rise(); - b_phase.interrupt_fall(); - a_phase.interrupt_fall(); - /* ここまで */ - - // 角度(マイナス) - EXPECT_FLOAT_EQ(speed_controller.angle(), -1.80f); - // PID計算(リミットなし) - EXPECT_FLOAT_EQ(speed_controller.calculation(0.00f, 1.00f), -0.0125); - // RPS(マイナスなし) - EXPECT_FLOAT_EQ(speed_controller.rps(), 0.005f); - - speed_controller.limit(1.00f, 0.00f); - // PID計算(下限リミット) - EXPECT_FLOAT_EQ(speed_controller.calculation(0.00f, 1.00f), 0.00f); -} - -TEST(SpeedController, SpeedControllerErrorTest) -{ - StubInterruptIn a_phase; - StubInterruptIn b_phase; - SpeedController speed_controller(a_phase, b_phase); - - // Error時に標準エラー出力に文字列が出力される - // 本当のエラー時にエラー出力させたいので、異常系のテスト中は標準エラー出力をキャプチャする - testing::internal::CaptureStderr(); - - Error& error = Error::get_instance(); - EXPECT_EQ(error.get_status(), Error::Status::Normal); - speed_controller.limit(0.00f, 1.00f); - EXPECT_EQ(error.get_status(), Error::Status::Error); - - error.reset(); - EXPECT_EQ(error.get_status(), Error::Status::Normal); - speed_controller.calculation(-1.00f, 1.00f); - EXPECT_EQ(error.get_status(), Error::Status::Error); - - error.reset(); - EXPECT_EQ(error.get_status(), Error::Status::Normal); - speed_controller.calculation(1.00f, 0.00f); - EXPECT_EQ(error.get_status(), Error::Status::Error); - - testing::internal::GetCapturedStderr(); -} - -} // namespace \ No newline at end of file +#include + +#include "Error.h" +#include "SpeedController.h" +#include "tests/stubs.h" + +namespace { + +using namespace spirit; + +TEST(SpeedController, SpeedControllerTest) +{ + StubInterruptIn a_phase; + StubInterruptIn b_phase; + SpeedController speed_controller(a_phase, b_phase); + + // 計算しやすいようにゲインを設定 + speed_controller.pid_gain(1.00f, 1.00f, 1.00f); + speed_controller.limit(3.00f, 0.00f); + + /* エンコーダの仮想パルス生成 (1.8°回転) */ + a_phase.interrupt_rise(); + b_phase.interrupt_rise(); + a_phase.interrupt_fall(); + b_phase.interrupt_fall(); + /* ここまで */ + + // 角度 + EXPECT_FLOAT_EQ(speed_controller.angle(), 1.80f); + // PID計算(リミットなし) + EXPECT_FLOAT_EQ(speed_controller.calculation(1.005f, 1.00f), 2.5f); + // RPS + EXPECT_FLOAT_EQ(speed_controller.rps(), 0.005f); + + speed_controller.limit(1.00f, 0.00f); + + // PID計算(上限リミット) + EXPECT_FLOAT_EQ(speed_controller.calculation(1.00f, 1.00f), 1.00f); + + speed_controller.reset(); + + speed_controller.limit(1.00f, -1.00f); + + /* エンコーダの仮想パルス生成 (-1.8°回転) */ + b_phase.interrupt_rise(); + a_phase.interrupt_rise(); + b_phase.interrupt_fall(); + a_phase.interrupt_fall(); + /* ここまで */ + + // 角度(マイナス) + EXPECT_FLOAT_EQ(speed_controller.angle(), -1.80f); + // PID計算(リミットなし) + EXPECT_FLOAT_EQ(speed_controller.calculation(0.00f, 1.00f), -0.0125f); + // RPS(マイナスなし) + EXPECT_FLOAT_EQ(speed_controller.rps(), 0.005f); + + speed_controller.limit(1.00f, 0.00f); + // PID計算(下限リミット) + EXPECT_FLOAT_EQ(speed_controller.calculation(0.00f, 1.00f), 0.00f); +} + +TEST(SpeedController, SpeedControllerErrorTest) +{ + StubInterruptIn a_phase; + StubInterruptIn b_phase; + SpeedController speed_controller(a_phase, b_phase); + + // Error時に標準エラー出力に文字列が出力される + // 本当のエラー時にエラー出力させたいので、異常系のテスト中は標準エラー出力をキャプチャする + testing::internal::CaptureStderr(); + + Error& error = Error::get_instance(); + EXPECT_EQ(error.get_status(), Error::Status::Normal); + speed_controller.limit(0.00f, 1.00f); + EXPECT_EQ(error.get_status(), Error::Status::Error); + + error.reset(); + EXPECT_EQ(error.get_status(), Error::Status::Normal); + speed_controller.calculation(-1.00f, 1.00f); + EXPECT_EQ(error.get_status(), Error::Status::Error); + + error.reset(); + EXPECT_EQ(error.get_status(), Error::Status::Normal); + speed_controller.calculation(1.00f, 0.00f); + EXPECT_EQ(error.get_status(), Error::Status::Error); + + testing::internal::GetCapturedStderr(); +} + +} // namespace diff --git a/tests/test_adjust_duty_cycle.cpp b/tests/test_adjust_duty_cycle.cpp index 70487c9..8becc00 100644 --- a/tests/test_adjust_duty_cycle.cpp +++ b/tests/test_adjust_duty_cycle.cpp @@ -181,11 +181,11 @@ TEST(AdjustDutyCycle, SameState) // 最後にデューティー比が目標値に達していることを確認する(上昇) current_state = Motor::State::CW; current_duty_cycle = 0.60F; - std::size_t count = std::ceil(fabs(motor.get_duty_cycle() - current_duty_cycle) / - motor.get_maximum_change_duty_cycle(Motor::ChangeLevelTarget::Rise)); + uint32_t count = (uint32_t)std::ceil(fabs(motor.get_duty_cycle() - current_duty_cycle) / + motor.get_maximum_change_duty_cycle(Motor::ChangeLevelTarget::Rise)); // デューティー比が目標値に達するまでループ - for (std::size_t i = 0; i < count; i++) { + for (uint32_t i = 0; i < count; i++) { // ほんとはループ中にデューティー比が目標値に達しているか確認するべきだが、 // 浮動小数点の誤差があるので、最後の何回かはFAILしてしまう // なので、ループの最後でのみ確認する @@ -212,8 +212,8 @@ TEST(AdjustDutyCycle, SameState) // 最後にデューティー比が目標値に達していることを確認する(下降) current_state = Motor::State::CW; current_duty_cycle = 1.00F; - count = fabs(motor.get_duty_cycle() - current_duty_cycle) / - motor.get_maximum_change_duty_cycle(Motor::ChangeLevelTarget::Rise); + count = (uint32_t)(fabs(motor.get_duty_cycle() - current_duty_cycle) / + motor.get_maximum_change_duty_cycle(Motor::ChangeLevelTarget::Rise)); for (std::size_t i = 0; i < count; i++) { // ほんとはループ中にデューティー比が目標値に達しているか確認するべきだが、 // 浮動小数点の誤差があるので、最後の何回かはFAILしてしまう @@ -295,7 +295,7 @@ TEST(AdjustDutyCycle, Normal) Motor::State current_state_for_loop = current_state; float current_duty_cycle_for_loop = current_duty_cycle; Motor::State next_state; - float next_duty_cycle; + float next_duty_cycle = -1.00F; for (size_t i = 0; i < loop_count; i++) { adjust_duty_cycle(motor.get_state(), motor.get_duty_cycle(),