Arduino Nanoで作るスマートペットフィーダー
部品と材料
| Arduino Nano R3 コンパクトな筐体に収めるならNanoが最適 | ×1 |
| Adafruit リアルタイムクロック (DS3231) | ×1 |
| 連続回転サーボ | ×1 |
| シリアルディスペンサー | ×1 |
| ホールセンサー (ユニポーラ) | ×1 |
| ロッド磁石 3mm径、5mm長 | ×6 |
| Adafruit RGBバックライトLCD - 16x2 | ×1 |
| LCD I2Cバックパック | ×1 |
| Apem 防水プッシュボタン IP67 | ×1 |
| 小型モーメンタリプッシュボタン | ×1 |
| LED (汎用) 赤2、緑3、黄1 | ×6 |
| Hammond ABSハウジング (フランジ付き) | ×1 |
アプリとオンラインサービス
| LCDキャラクタジェネレーター |
このプロジェクトについて
更新履歴: 2018-09-06
2台のペットフィーダーが過去7ヶ月間故障なく動作中。日中はもちろん世話をしていますが、決まった時刻に確実に餌を与えられます。システムに大満足!
なぜまたペットフィーダーを作ったのか?
私の版はArduinoマイコンベースです。材料は比較的安価で、構築も簡単だと思います。既存のプロジェクトは多いですが、私が必要とする機能をすべて備えた完成度の高いプロジェクトが見つからなかったため、ゼロから作りました。
主な機能
- 正確な分量を毎回供給!(ホールセンサー使用)
- 1日2回の給餌時刻設定
- 極めて高精度なリアルタイムクロック(純正DS3231チップ使用時)
- ディスプレイとLEDインジケーターで、両タイマーの次回給餌を個別にキャンセル可能。設定時刻が過ぎると自動的にキャンセル解除
- 手動給餌機能(ボタン1回押しで1分量)
- 各給餌時刻の分量を個別に調整可能(1〜9分量)
- メイン画面で全設定パラメータを一覧表示
- 操作しやすいメニューシステム
- 給餌成功時のLED表示
- LCDバックライトタイマー(30秒で消灯、ボタン押下で点灯)
- 時刻等の設定をEEPROMに安全保存
デモ動画
写真
必要な部品
- シリアルディスペンサー 1個(eBayで安価入手可)
- ディスペンサー取付用木材(端材でOK)
- Arduino Uno 1個
- I2C DS3231(極めて高精度)またはDS1307 RTC 1個
- 16文字×2行LCDディスプレイ 1個
- LCD用I2Cバックパック 1個
- 連続回転サーボ 1個(良質なものを購入!)
- Honeywell SS443R ユニポーラホールセンサー 1個
- 12V/1A 外部電源アダプター 1個
- モーメンタリプッシュボタン 7個
- LED 6個(赤2、緑3、黄1)
- 抵抗 1kΩ 2個(赤LED用)
- 抵抗 560Ω 4個(緑・黄LED用)
- 電子部品用エンクロージャー 1個
- 外部サーボ/ホールセンサー接続用電源プラグ(メス)とコネクター
- 大量のホットグルー
サーボにより高電圧を供給すればよりパワフル。私のHSR-2645CRHサーボは7.4V対応なので、以下を追加で用意すれば実現可能:
- ユニバーサル基板
- LM317T 可変電圧レギュレーター
- 出力電圧設定用抵抗3個(1kΩ、150kΩ、4.7kΩ)
- 電解コンデンサ 2個(220µF、10µF)
- ヒートシンク不要(サーボは1日1〜2秒しか動かないため)
オンラインでLM317計算ツールが見つかります。
ペットフード容器
最も安価で使いやすいのは、多くの店やeBayで売っているシリアルディスペンサーです。私はeBayでデュアルシリアルディスペンサーを送料込み15ユーロ(英国→オランダ)で購入。
課題はフィーダーのマウントを作ること。ネット検索してもあまり参考にならなかったので、物置を漁って見つけた美しい杉材を使用。ディスペンサーを支える木材は3cm厚でガタつきなし。穴(私のフィーダーベースは86mm)はきつめに、ドリルで小さめに開けてから調整するのがコツ。
サーボとディスペンサーパドルホイールへの取り付け
良質なサーボを購入してください。最初にMG996Rを買って連続回転改造しましたが無駄金でした。その後、HSR-2645CRHサーボのような高品質品を入手。
連続回転モデルでなければなりません! 通常サーボを改造しても、私の試みでは性能が全然足りず、停止も即座ではありませんでした。
サーボ試験動画: こちら
サーボとディスペンサーパドルホイールの接続
最初はここが最難関に見えましたが、実は非常にシンプルでした。
5mmポリカーボネート板から直径約6cmの円盤を糸鋸で切り出し、中心に8mm穴(フィーダー軸の太さ、このプラスチック軸はパドルホイールから取り外し可能)をあけました。
外周に磁石用の3mm穴を6個あけました。パドルホイールにゴムパドルが6個あるため、6個の磁石を円盤外周に等間隔(360°/6=60°)で配置。ロッド磁石はきつめにはまります。
ホールセンサーが6個の磁石をそれぞれ検知するため、パドルホイールの位置を精密に把握して停止制御できます。サーボ停止遅延時間変数で、給餌後、サーボ停止前の遅延を調整。この遅延でパドルホイールの正確な停止位置を微調整できます。停止位置がズレると餌がパドルホイールから完全に出ません。ホールセンサー位置が異なる場合も、この変数調整で解決。
パドルホイール軸をポリカーボネート円盤に接着。
白いサーボホーンをM3ボルト3本で円盤に固定。ナットをスペーサーとして使用、締めすぎ注意!
これでサーボがフィーダーアセンブリの一部になりました。木製マウントに組み込み、サーボ下の木材の高さを測定。
ホールセンサー
使用したホールセンサーはユニポーラタイプ。磁石が近づくとLOW出力し、逆極性の磁石なしで自動的にHIGHに戻ります。ユニポーラホールセンサーを使用すれば 훨씬 간단합니다。
!!! ホールセンサーには10kΩプルアップ抵抗が必要です。!!!
0805チップ抵抗をホールセンサー直上に実装しましたが、お好みの方法でOK。この抵抗を忘れないでください!
古いボールペンのプラスチック部分をセンサーホルダーとして利用。
電子部品ハウジング
Hammond ABSハウジング(フランジ付き)120×65×40mmを使用。
外部接続には安価な中国製ではなく、精密ソケットコネクタを使用。すべてのプロジェクトで愛用しています。不良接続による(見つけにくい)故障ほど最悪なことはありません。
Arduinoプログラミングを容易にするため、外部FTDI接続も設けました:
フロントパネル
安価で見栄えの良いフロントパネルを作るために色々試しました...
- Mod Podgeでレーザープリント用紙をハウジング前面に貼り、さらにMod Podgeでコーティング → 失敗
- ポリウレタンアクリレート分散系クリアラッカー。非常に耐久性が強い。用紙をしっかり貼り付け、表面をラッキングすると見栄え良好だが、レーザープリンタートナー部分にラッカーが密着しない → 失敗
- フロントパネル印刷の上面のみラミネートフィルムでラミネート。美しい仕上がりで色も鮮やか。ラミネート済み用紙をラッカーでハウジングに貼り付け。ラッカーが用紙に浸透して耐水性が出るはずだったが、厚紙を使ったため浸透せず、水濡れテストで用紙がカールして剥がれる → 部分的失敗、要検討
- レーザープリンター用特殊アルミ箔を購入(1枚2.25ユーロ)。結果は良好だが、トナー保護用クリアフィルムを貼ろうとしたら写真1のような気泡/不完全さが取れない → 失敗
クリアラッカーで保護しようとしたらアルミ箔が高光沢に!しかしまたトナーにラッカーが密着しないため、ラッカーは永久に諦めました...
最終的に... 保護なしのアルミ箔印刷を採用。頻繁に触ると指紋が目立ちます(このページトップの写真、BACKボタン下あたり、鶏餌の汚れ参照)が、私には十分です。
写真のアップロード制限があるためここまで。
以上です... 楽しんでください!
コード
Pet Feed-O-Matic v 1.1 - 20-02-2018 Arduino
v 1.1: Cancel1/2ボタン押下時に説明表示
// c++ stuff...
//#include <Arduino.h>
//#line 1
//#line 1 "/Users/Erik/Documents/PlatformIO/Projects/180202-151127-uno/src/Pet_Feeder_1_1_ENG.cpp"
////////////////////////////////////////////////////////////////////////////////
// ユーザー変更可能な変数
////////////////////////////////////////////////////////////////////////////////
// ホールセンサー故障時バックアップ機能用
// インターバル時間はフィーダーの60度回転(1分量)より少し長めに
#define HALL_SENSOR_BACKUP_VALUE 300
// 給餌後、フィーダーサーボ停止前の遅延。回転パドルホイールを正しい位置で停止させるため
#define FEEDER_STOP_DELAY 100
// ボタン押下後のLCDバックライト点灯時間
#define LCD_BACKLIGHT_ON_TIME 30000
// メニューで一定時間操作なしなら保存せず終了
#define MENU_TIMEOUT_VALUE 7000
////////////////////////////////////////////////////////////////////////////////
// ライブラリ
////////////////////////////////////////////////////////////////////////////////
// https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
#include <LiquidCrystal_I2C.h>
// https://github.com/JChristensen/Button
#include <Button.h>
// https://github.com/JChristensen/DS3232RTC
#include <DS3232RTC.h>
// https://www.arduino.cc/playground/Code/Time
#include <Time.h>
// https://arduino.cc/en/Reference/Wire (Arduino IDE同梱)
#include <Wire.h>
#include <EEPROM.h>
// 接続:
// LCD (I2Cモジュール):
// SCL - A5
// SDA - A4
// VCC
// GND
// ホールセンサー割り込みピン
#define HALL_SENSOR_PIN 3
#define BUTTON_BACK_PIN 4
#define BUTTON_UP_PIN 5
#define BUTTON_DOWN_PIN 6
#define BUTTON_SELECT_PIN 7
#define BUTTON_CANCEL1_PIN 8
#define BUTTON_CANCEL2_PIN 9
#define BUTTON_MANUAL_PIN 10
#define LED_CANCEL1_PIN A0
#define LED_CANCEL2_PIN A1
#define LED_SUCCESS1_PIN A2
#define LED_SUCCESS2_PIN A3
// フィーダーサーボ出力ピン
#define SERVO_OUTPUT_PIN 12
// ホールセンサー入力ピン
#define LED_HALL_SENSOR_PIN 13
// LCDアドレス(16x2) 0x27または0x3F
LiquidCrystal_I2C lcd(0x3F, 16, 2);
// ボタンライブラリ設定
// タクトスイッチには通常20msのデバウンス時間で十分
#define DEBOUNCE_MS 20
// 長押しリピート開始までの時間
#define REPEAT_FIRST 1000
// 長押しリピート間隔
#define REPEAT_INCR 200
// 内部プルアップ抵抗使用
#define PULLUP true
#define INVERT true
// ボタン宣言
Button buttonSelect (BUTTON_SELECT_PIN, PULLUP, INVERT, DEBOUNCE_MS);
Button buttonUp (BUTTON_UP_PIN, PULLUP, INVERT, DEBOUNCE_MS);
Button buttonDown (BUTTON_DOWN_PIN, PULLUP, INVERT, DEBOUNCE_MS);
Button buttonBack (BUTTON_BACK_PIN, PULLUP, INVERT, DEBOUNCE_MS);
Button buttonCancel1 (BUTTON_CANCEL1_PIN, PULLUP, INVERT, DEBOUNCE_MS);
Button buttonCancel2 (BUTTON_CANCEL2_PIN, PULLUP, INVERT, DEBOUNCE_MS);
Button buttonManual (BUTTON_MANUAL_PIN, PULLUP, INVERT, DEBOUNCE_MS);
// 調整中の数値
int count;
int lastCount = -1;
unsigned long rpt = REPEAT_FIRST;
unsigned long timeoutValue = 0;
// 手動キャンセル給餌時刻変数
boolean manualCancelFeed1 = false;
boolean manualCancelFeed2 = false;
// 手動給餌オプション
boolean manualFeed = false;
// 給餌量(分量単位)
int feedAmount1 = 1;
int feedAmount2 = 1;
bool feederSuccess = false;
// フィーダー分量
int portions = 0;
int turns = 0;
// 入力アクション
enum {btnSELECT, btnUP, btnDOWN, btnBACK, btnCANCEL1, btnCANCEL2, btnMANUAL, trigTIMEOUT};
// 有限ステートマシン(FSM)の状態
enum STATES {
MAIN,
MENU_EDIT_FEEDTIME1,
MENU_EDIT_FEEDTIME2,
MENU_EDIT_FEEDAMOUNT,
MENU_EDIT_TIME,
MENU_EDIT_DATE,
MENU_EDIT_SETTINGS,
EDIT_FEED_TIME1_HOUR,
EDIT_FEED_TIME1_MINUTE,
EDIT_FEED_TIME1_ON_OFF,
EDIT_FEED_TIME2_HOUR,
EDIT_FEED_TIME2_MINUTE,
EDIT_FEED_TIME2_ON_OFF,
EDIT_FEED_AMOUNT1,
EDIT_FEED_AMOUNT2,
EDIT_HOUR,
EDIT_MINUTE,
EDIT_DAY,
EDIT_MONTH,
EDIT_YEAR,
EDIT_SERVO_STOP_DELAY,
EDIT_SERVO_BACKUP_DELAY,
};
// システム現在状態
STATES state;
int8_t userInput;
int8_t trigger;
int Second, Minute, Hour, Day, Month, Year;
int8_t DoW;
String day_of_week;
unsigned char address, data;
int testt = 0;
int feed_time1_hour, feed_time1_minute;
bool feed_time1_active = false;
bool alarm1Activated = false;
int feed_time2_hour, feed_time2_minute;
bool feed_time2_active = false;
bool alarm2Activated = false;
// 点滅用
uint32_t blink_interval = 500;
uint32_t blink_previousMillis = 0;
uint32_t blink_currentMillis = 0;
boolean blink_state = false;
// スピニングホイール表示用
uint32_t spinningWheel_interval = 170;
uint32_t spinningWheel_previousMillis = 0;
uint32_t spinningWheel_currentMillis = 0;
int spinningWheelSymbol = 0;
// ホールセンサー故障バックアップ用
uint32_t hallSensorBackup_interval = HALL_SENSOR_BACKUP_VALUE;
uint32_t hallSensorBackup_currentMillis = 0;
boolean hallSensorFail = false;
// LCDバックライトタイマー用
uint32_t lcdBacklight_interval = LCD_BACKLIGHT_ON_TIME;
uint32_t lcdBacklight_currentMillis = 0;
boolean RTC_error = true;
boolean long_press_button = false;
// LCDカスタムシンボル定義
byte bell_symbol_Char[8] = {
B00100, B01110, B01110, B01110, B11111, B00100, B00000, B00000
};
byte inverted_one_Char[8] = {
0b11111, 0b11011, 0b10011, 0b11011, 0b11011, 0b11011, 0b10001, 0b11111
};
byte inverted_two_Char[8] = {
0b11111, 0b11011, 0b10101, 0b11101, 0b11011, 0b10111, 0b10001, 0b11111
};
byte arrow_up_Char[8] = {
0b00100, 0b01110, 0b11111, 0b01110, 0b01110, 0b01110, 0b01110, 0b00000
};
byte arrow_down_Char[8] = {
0b00000, 0b01110, 0b01110, 0b01110, 0b01110, 0b11111, 0b01110, 0b00100
};
byte inverted_p_Char[8] = {
0b11111, 0b10001, 0b10101, 0b10001, 0b10111, 0b10111, 0b11111, 0b00000
};
byte backslash_Char[8] = {
0b00000, 0b10000, 0b01000, 0b00100, 0b00010, 0b00001, 0b00000, 0b00000
};
byte thickDash_Char[8] = {
0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b00000
};
volatile boolean hallSensorActivated = false;
// 割り込み1: ホールセンサー
void HallSensorIsr() {
hallSensorActivated = true;
digitalWrite(LED_HALL_SENSOR_PIN, HIGH);
}
// C++ファイルとして認識させるための前方宣言(Atom+PlatformIO使用のため)
void HallSensorIsr();
void setup();
void loop();
void change_states();
void check_inputs();
void transition(int trigger);
void check_alarm();
void check_manual_feed();
void display_menu_option_set_feedtime1();
void display_menu_option_set_feedtime2();
void display_menu_option_set_feed_amount();
void display_menu_option_set_time();
void display_menu_option_set_date();
void midnight_reset();
void display_time();
void displayFeedingAmouts();
void displayFeedingTimes();
void set_feedAmount();
void set_time();
void set_date();
void set_feeding1_time();
void set_feeding2_time();
void get_time();
void get_date();
void write_time();
void write_date();
void write_feeding_time1();
void write_feeding_time2();
void write_feedamount();
void get_feedamount();
void get_feed_time1();
void get_feed_time2();
void check_RTC();
byte decToBcd(byte val);
byte bcdToDec(byte val);
void leading_zero(int digits);
void blinkFunction();
void displaySpinningWheel();
void startFeederServo();
void stopFeederServo();
void activateFeeder(int portions);
void check_LcdBacklight();
void lcd_backlight_ON();
void ledsAndLcdDisplayStartup();
void hallSensorCheck();
#line 355
// ******************************************************************************
// SETUP
// ******************************************************************************
void setup() {
lcd.begin();
lcd_backlight_ON();
Wire.begin();
pinMode(HALL_SENSOR_PIN, INPUT_PULLUP);
pinMode(LED_HALL_SENSOR_PIN, OUTPUT);
pinMode(SERVO_OUTPUT_PIN, OUTPUT);
pinMode(LED_CANCEL1_PIN, OUTPUT);
pinMode(LED_CANCEL2_PIN, OUTPUT);
pinMode(LED_SUCCESS1_PIN, OUTPUT);
pinMode(LED_SUCCESS2_PIN, OUTPUT);
digitalWrite(LED_CANCEL1_PIN, LOW);
digitalWrite(LED_CANCEL2_PIN, LOW);
digitalWrite(LED_SUCCESS1_PIN, LOW);
digitalWrite(LED_SUCCESS2_PIN, LOW);
digitalWrite(LED_HALL_SENSOR_PIN, LOW);
lcd.createChar(0, thickDash_Char);
lcd.createChar(1, bell_symbol_Char);
lcd.createChar(2, backslash_Char);
lcd.createChar(3, inverted_p_Char);
lcd.createChar(4, inverted_one_Char);
lcd.createChar(5, inverted_two_Char);
lcd.createChar(6, arrow_up_Char);
lcd.createChar(7, arrow_down_Char);
stopFeederServo();
Wire.begin();
setSyncProvider(RTC.get);
setSyncInterval(60);
RTC.squareWave(SQWAVE_NONE);
attachInterrupt(INT1, HallSensorIsr, FALLING);
ledsAndLcdDisplayStartup();
state = MAIN;
get_feed_time1();
get_feed_time2();
}
// ******************************************************************************
// LOOP
// ******************************************************************************
void loop() {
change_states();
check_inputs();
check_alarm();
check_manual_feed();
midnight_reset();
display_time();
displayFeedingAmouts();
displayFeedingTimes();
set_feedAmount();
set_time();
set_date();
set_feeding1_time();
set_feeding2_time();
get_time();
get_date();
write_time();
write_date();
write_feeding_time1();
write_feeding_time2();
write_feedamount();
get_feedamount();
get_feed_time1();
get_feed_time2();
check_RTC();
// ... (以下、関数定義が続く)
// ファイルが長いため省略。完全版はダウンロードしてご確認ください。
}
回路図
Arduinoベースのペットフィーダー
Arduino IDE 1.8.2を使用。ライブラリフォルダに同じライブラリの異なるバージョンが2つ存在しないよう注意してください!
arduino_pet_feeder_final_eng_v1_0-ino_hex_libraries_dsoo0HscCr.zip
製造プロセス
- ペットフード製造:原料から規制まで完全ガイド
- Arduino Nano RP2040で作るDIY Photoshopコントロールコンソール
- Bluetooth操作のArduinoスパイボットを自作する
- Arduino Nanoで作るウェアラブル心拍ドレス:CrazyCircuitsとDFRobotセンサーで自信を持ってプロジェクトを構築
- 自作16×8 LEDマトリックスでテトリスゲーム:Arduino Nano実装
- Arduinoで作る自作デジタルペット「Tamaguino」─ 3Dプリンター製ケース付き完全ガイド
- Arduino Nanoとジョイスティックで2軸ステッピングモーターを制御:Visuinoで簡単プログラミング
- Arduino製リモコン式ペットフィーダー:DIYキットと組み立てガイド
- Arduino Nanoで作る携帯型ガイガーカウンター
- Arduino Nano用 高性能2.8インチTFTシールド - 320×240 SPIディスプレイ
- Arduino Nano搭載 スマート3Dプリント自動ペットフィーダー