Skip to content

Instantly share code, notes, and snippets.

@KeitetsuWorks
Last active November 24, 2021 14:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KeitetsuWorks/983e5bcb58e60b28b9ed47eceb684191 to your computer and use it in GitHub Desktop.
Save KeitetsuWorks/983e5bcb58e60b28b9ed47eceb684191 to your computer and use it in GitHub Desktop.
Arduino: ボタンスイッチでサーボモータの角度を切り替える
/**
* @file servo_button.ino
* @brief Servo Motor Controller
* @author Keitetsu
* @date 2021/09/29
* @copyright Copyright (c) 2021 Keitetsu
* @par License
* This software is released under the MIT License.
*/
#include <Servo.h>
#define SERVO_NUM 1 /**< サーボモータの数 */
#define BTN_NUM 1 /**< ボタンスイッチの数 */
#define BTN_COUNT_THRESH 2 /**< ボタンスイッチの状態の確定閾値 */
#define SERIAL_TX_BUF_SIZE 14 /**< シリアル通信の送信バッファのサイズ */
#define INTERVAL_TIME 20 /**< 周期実行の間隔 */
/**
* @struct button_st
* @brief ボタンスイッチ管理構造体
*
* @typedef BUTTON_T
* @brief ボタンスイッチ管理構造体
*/
typedef struct button_st
{
uint8_t pin; /**< 接続ピン */
uint8_t last_val; /**< 前回の入力値 */
uint8_t count; /**< 最後に入力値が変化してからのカウント値 */
uint8_t state; /**< 状態 */
} BUTTON_T;
BUTTON_T btns[BTN_NUM]; /**< ボタンスイッチ */
unsigned long prev_time; /**< 周期実行の前回実行時刻 */
unsigned long interval_time; /**< 周期実行の間隔 */
/**
* @brief サーボモータ
*/
Servo servos[SERVO_NUM];
/**
* @brief サーボモータの位置
*/
int servos_pos[SERVO_NUM];
/**
* @brief ボタンスイッチ管理構造体を初期化する
* @param[in,out] btn ボタンスイッチ管理構造体のポインタ
* @param[in] pin ボタンスイッチの接続ピン
*/
void initBtn(BUTTON_T *btn, uint8_t pin)
{
btn->pin = pin;
pinMode(btn->pin, INPUT);
btn->last_val = digitalRead(btn->pin);
btn->count = 0;
btn->state = btn->last_val;
return;
}
/**
* @brief ボタンスイッチの状態を更新する (周期実行)
* @param[in,out] btn ボタンスイッチ管理構造体のポインタ
* @retval true ボタンスイッチの状態に変化あり
* @retval false ボタンスイッチの状態に変化なし
*/
uint8_t updateBtnState(BUTTON_T *btn)
{
uint8_t is_changed;
uint8_t btn_val;
is_changed = false;
btn_val = digitalRead(btn->pin);
if (btn_val != btn->last_val)
{
// 入力値が変化した場合はカウント値を0にする
btn->last_val = btn_val;
btn->count = 0;
}
else
{
if (btn->count < 255)
{
// 入力値が変化していない場合はカウントアップ
btn->count++;
}
if (btn->count == BTN_COUNT_THRESH)
{
// 最後に入力値が変化してからのカウント値が
// BTN_COUNT_THRESHに達した場合,ボタンスイッチの状態を確定する
is_changed = true;
btn->state = btn_val;
}
}
return is_changed;
}
/**
* @brief ボタンスイッチの状態を取得する
* @param[in] btn ボタンスイッチ管理構造体のポインタ
* @return ボタンスイッチの状態
*/
uint8_t getBtnState(BUTTON_T *btn)
{
return btn->state;
}
/**
* @brief サーボモータの位置を更新する
*/
void update_servos_pos()
{
uint8_t i;
uint8_t btn_is_changed;
uint8_t btn_state;
char tx_buf[SERIAL_TX_BUF_SIZE];
// ボタンスイッチの状態に変化がある場合は,
// サーボモータの位置を変更し,サーボモータの位置をシリアル通信で送信する
for (i = 0; i < BTN_NUM; i++)
{
btn_is_changed = updateBtnState(&btns[i]);
btn_state = getBtnState(&btns[i]);
if (btn_is_changed && (btn_state == LOW))
{
servos_pos[i] = (servos_pos[i] != 0) ? 0 : 180;
servos[i].write(servos_pos[i]);
sprintf(tx_buf, "Servo[%1u]: %3u\n", i, servos_pos[i]);
Serial.print(tx_buf);
}
}
return;
}
/**
* @brief セットアップ関数
*/
void setup()
{
uint8_t i;
uint8_t btns_pin[BTN_NUM] = {2};
uint8_t servos_pin[SERVO_NUM] = {11};
// ボタンスイッチの初期化
for (i = 0; i < BTN_NUM; i++)
{
initBtn(&btns[i], btns_pin[i]);
}
// 各サーボモータの初期化
for (i = 0; i < SERVO_NUM; i++)
{
// 引数はピン番号,最小パルス幅,最大パルス幅
// パルス幅はサーボモータに合わせて調整する
servos[i].attach(servos_pin[i], 544, 2080);
servos_pos[i] = 0;
servos[i].write(servos_pos[i]);
}
// シリアル通信の初期化
Serial.begin(9600);
// 周期実行の初期化
prev_time = 0;
interval_time = INTERVAL_TIME;
}
/**
* @brief ループ関数
*/
void loop()
{
unsigned long curr_time;
// 現在時刻を取得する
curr_time = millis();
// 周期実行
if ((curr_time - prev_time) >= interval_time)
{
prev_time += interval_time;
update_servos_pos();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment