産業用ラインフォロワーロボット - 物資輸送用自律走行ロボット
必要なパーツと用品
| パーツ | 数量 | 備考 |
|---|---|---|
| SparkFun Arduino Pro Mini 328 - 5V/16MHz | 1 | |
| カスタムPCB | 1 | レイアウトは添付ファイル参照。なくても製作可能 |
| 超音波センサー HC-SR04 (汎用) | 1 | |
| RFIDモジュール (汎用) | 1 | |
| SparkFun RedBot ラインフォロワーセンサー | 3 | |
| Texas Instruments Hブリッジ モータードライバー 1A | 1 | L293D使用、互換品 |
| リチウムイオンバッテリー - 1000mAh 7.4V | 1 | 7.4V必須だがこの特定品である必要はなし |
| ホビーギアモーター - 140 RPM (ペア) | 1 | シャーシ接続用コネクタなし、3Dプリントで自作可能 |
| ホイール - 65mm | 1 | |
| ジャンパーワイヤー (汎用) | 1 | |
| トグルスイッチ | 1 | |
| RFIDタグ (汎用) | 4 | 4個使用。タスク数に応じて増減可能 |
| ブザー | 1 | |
| メスヘッダー 40ピン 1列 (2.54mm) | 1 |
必要な工具と機械
- 3Dプリンター (汎用)
- レーザーカッター (汎用) - 持っていないのでオンライン発注。高価な工具がなくても製作可能
- ハンダゴテ (汎用)
使用するアプリとオンラインサービス
- Arduino IDE
- Autodesk Fusion 360
プロジェクト概要
組立ラインで部品を運ぶあのファンシーなロボットがどう動いているか気になったことはありませんか? ポーランドのオペル工場でそんなロボットを見て、たくさん質問して仕組みを教えてもらいました。黒いテープの代わりに磁気ストリップ、光センサーの代わりに磁気センサー、さらに安全機能やスマート機能がたくさんありますが、本質は高度なラインフォロワーだと瞬時に理解。これがきっかけで、もっと小さく、安く、Arduinoベースでオープンソースな、賢く物資を運べるロボットを自作できないかと考えました。大きなチャレンジですが、それが好きなんです!
設計
まずは設計...紙に鉛筆で! なぜCADがあるのに紙か? いくつか利点があり、他の人から聞いて自分でも確認しました。制限がなく自由、気を散らすものがない、白紙と鉛筆だけで物事が簡単。寸法や最終形状を気にせず高速に描ける。気に入らなければ書き直せばよく、すべての図面を一度に見れば組み合わせて新しいアイデアが生まれます。紙で全体形状を決めてからCADで寸法を入れるのがおすすめ。私のスケッチ(右側のカラフルな線は甥っ子の創作活動の成果)

絵が下手なのはご愛嬌。5分でより良いものが描ける人もいるでしょうが、私は以前はひどく下手で、上記例でも私にとっては有望に見えました。これをベースにCAD設計。最初から一部は3Dプリント、でも100% 3Dプリントにはしたくなく、新しいことも試したかった。最終的に一部をレーザーカットすることに。レーザーカッターは持ってないし、レーザーカット用設計も初挑戦。やり方を学んでオンライン発注。材料は4mm合板(アクリル等も可)。ロボット前部は3Dプリントパーツで、全センサー、電子部品、バッテリーを収納。レンダリング画像は私の意見では素晴らしい出来!


レーザーカット発注。ポーランド在住なので送料節約のためポーランドの業者に依頼。近くの業者を探すなら「レーザーカット + 都市名」で検索。フィンガージョイントが完璧に嵌まるよう、業者にオフセット調整を依頼(カーフという現象のため、詳細はこちら)。幸運にも対応してくれる業者が見つかりました!

レーザーカット設計もパーツ使用も初体験で不安でしたが、綺麗に仕上がりました。DXFファイルは添付ファイルセクションにあります。
シャーシ完成のため、フロントパーツを3Dプリント。3Dプリンターは持っているので問題なし。持ってない場合は購入検討を(最近は安い)。学校や図書館、知り合いに3Dプリント愛好家がいるかも。STLファイルは添付ファイルセクションに。特別な設定は不要。2パリメーター、30%インフィル、0.2mm層高さ、サポート必要。約8時間かかるので気長に。
プリント完了後、後処理して合板パーツにネジ止め。でもさらに手を加えました。また未経験のことに挑戦。プリント品をサンディングして塗装、再度サンディングして塗装、パテで表面を完璧に、さらにサンディングと塗装。時間はかかったけど多くを学び、この光沢面を見てください! 3Dプリント品とは思えない完璧さ! 2日間の塗装とサンディング、絶対に価値あり。

レーザーカットパーツと3Dプリントパーツ、組み立て準備完了。

Arduino、センサー、モーター、PCB...

すべてを制御するのはArduino Pro Mini。Fritzingで設計したカスタムPCBに接続(PCBレイアウトと設計ファイルは添付)。人間の入力なしで自律動作するため、ラインセンサーとRFIDモジュールでライン沿いのタグを検知。モーター制御用Hブリッジは安価で人気のL293D。ブザーも追加し、特定RFIDタグ検知時にビープ音。全て2セルLiPoバッテリー(公称7.4V)で駆動。RFIDモジュールは3.3V駆動のため、PCB上にレギュレータを追加して適切な電圧を供給。障害物検知用超音波センサーも搭載(安全第一!)。HC-SR04での距離測定はマイクロコントローラーの観点から見るとかなり時間がかかるため、これを高速・容易にする別プロジェクトも作成(詳細はこちら)。必須ではないが、かなり楽になります。
PCB製作にはツールと部品(Arduino、L293D、ブレイクアウェイヘッダー、バッテリーコネクタ、ブザー、3.3Vレギュレータ)が必要。自宅PCB製作の詳細と必要ツールはこちら。

最初はCNCフライス盤でPCBを削ろうと思いましたが、慣れ親しんだトナートランスファー法を採用。銅板にトナー転写した様子。その後エッチングしてトナー除去。スルーホール部品用に穴あけ。

DIY PCBとしてはハンダ付けが驚くほど簡単。通常はハンダマスク*がないため難しいのですが。

PCB裏面に5本のジャンパーワイヤー(FritzingのPCBビューでは青いケーブルとして表示)。複雑な回路と片面基板では避けられません。

電源は2セルLiPoバッテリー。同等電圧なら他の電池も可。容量は任意(大きいほど長時間稼働)。バッテリー接続用ソケットもPCBにハンダ付け。

全てハンダ付け完了したらバッテリーを接続してテスト。Arduino LEDが点灯し、煙が出なければOK!

問題なければ最後のハンダ付け: モーターに後でハンダ付けするケーブルをPCBに接続。少し長めにして後でカットするのが無難。

PCB完成! PCB製作未経験でも挑戦してみてください。それほど難しくありません。ケーブルやユニバーサル基板で配線してもOKですが、ロボット前部に収めるのは大変かも。PCBなら簡単! まだセンサーをPCBに接続する必要がありますが、まずシャーシを組み立ててセンサーを取り付けます。
組み立て

レーザーカットパーツのフィンガージョイントは完璧に嵌まりますが、剛性と耐久性のために接着。合板なので木工用ボンドでOK。接着剤の使いすぎと漏れに注意。数時間乾燥させるので休憩。パーツが正しく配置されているか確認。乾燥後は修正不可。



数時間後、組み立て再開。3Dプリントフロントパーツを合板に取り付け。CITインターンシップで教わった通り「接着剤は非プロフェッショナル、忘れろ」(木材なら大丈夫かと希望)。ネジで固定。ロボット底面からネジを入れ、短め(6mm程度)にして内部回路とショートしないよう注意。この方法の利点は上面から見えないこと。ロボットの下を見ないとわからないので見栄えが良い。ワッシャー使用で合板変形防止を推奨。


ここまででこんな感じ。綺麗で完璧!

モーターと後輪をシャーシに取り付け。M3ネジが必要。ここでもワッシャー使用で合板保護。

センサー取り付け。ロボットをひっくり返し、M3ネジとドライバーで。

組み立て完了! 難しくなく純粋に楽しい。全センサーとモーターが配置されたロボットの形が見えます。最終テストの前に全センサーをPCBに接続。
配線接続

時間がかかるステップ。難しくないけど、3Dプリントフロントパーツの狭いスペースに全ケーブルを通すのがトリッキー。ベストな方法: 全センサー/モジュールにケーブルを接続し、フロントパーツの穴を通して、最後にPCBに接続。
全電子部品をフロントパーツ左側に配置したかったが、バッテリーが広告より少し大きく、左側にバッテリー、右側に電子部品という配置に変更。大した問題ではなく、全て完璧に収まりました。
超音波センサーの取り付けも忘れずに。
電源オン/オフしやすくするため、バッテリーコネクタにスイッチを追加。バックパネルにスイッチ用の穴もあります。


コード

フロントパーツの蓋を閉める前に、Arduino Pro Miniにコードをアップロード。PCBからArduinoを取り出し、USB-UARTコンバーターでPCに接続。コードは下記にあります。全てコメントと動画で説明。Web Editorでも確認可能。
このロボット用のタスクを生成するC#特別プログラム「タスクプランナー」も作成(.exeファイル参照)。ロボットのタスクを簡単に生成し、コピーしてArduino IDEに貼り付けてアップロード。タスク生成にはRFIDカードのIDが必要。取得方法はこちら。

ほぼ完成...

フロントパーツの蓋を2つのフラップで閉めてネジ止め。全コンポーネントを収めるのは少しトリッキー。配置を変えて蓋が閉まるように調整。


短いM3ネジで固定。ワッシャーは不要。これが最後の作業。いよいよ最終テスト! これほど時間をかけたプロジェクト、意図通り動くかワクワクします。

全コンポーネント配置済み、電子部品はフロントパーツ内部に隠蔽、センサーはロボットに搭載。唯一の欠点はバッテリー充電が困難なこと(バックフラップを開けて取り出す必要)。シンプルな解決策: 3Dパーツに穴を開けてバッテリーのバランサーケーブルを露出させる。

最終テスト!
どう見せるのが正解か迷いました。このプロジェクトの主目的は、組立ラインや工場で賢く物資を運べる安価なオープンソースロボットを作ること。簡易組立ラインをセットアップし、父と甥っ子に手伝ってもらいました。目標: アイテムをロボットに載せ、別ステーションで取り出し、シール済みのものを載せ、最後のステーションでシール付きアイテムを倉庫へ移動。組立ラインを模したシンプルなタスクで動作テスト。
床に黒テープを貼ろうとしましたが、センサーには反射率が足りず、段ボールを使用。テスト開始、動画で確認できます(プロジェクト冒頭)。

このプロジェクトでは多くのことが失敗する可能性がありましたが、全て完璧に機能。意図通りに動作し、初期アイデアから設計、組み立てまで全てスムーズかつ驚くほどうまくいきました。「失敗する可能性がたくさんあった」と言ったのは本当です。3Dプリント、プログラミング、Arduinoの経験は豊富ですが、紙に描くのは初めてで素晴らしいアイデアだと確信、レーザーカット設計も初挑戦、C#プログラマー資格持ちでも達人ではない。それら全てを繋ぎ合わせてこんなクールなロボットができました :) 気に入っていただけたらコメントで感想を。質問も大歓迎! お読みいただきありがとうございました。
Happy making!
コード
産業用ラインフォロワー Arduinoコード
/* * C by Nikodem Bartnik * https://NikodemBartnik.pl * https://www.youtube.com/user/nikodembartnik */ #include#include // ピン定義、回路図で変更した場合はここも変更 #define LINESENSOR1 6 #define LINESENSOR2 7 #define LINESENSOR3 8 #define BUZZER A0 #define MOTOR1A 2 #define MOTOR1B 3 #define MOTOR2A 4 #define MOTOR2B 5 #define RFID_SDA 10 #define RFID_SCK 13 #define RFID_MOSI 11 #define RFID_MISO 12 #define RFID_RST 9 #define DISTANCESENSOR A1 // 定数定義 #define STOP_TIME 3000 #define BEEP_LENGTH 200 #define MOTOR_SPEED 110 #define MINIMUM_TIME_BETWEEN_CARDS 2000 MFRC522 mfrc522(10, 9); long int last_card_read; // C#タスク生成プログラムから配列をペースト #define COMMANDS_LENGTH 4 char* Type[4] = {"Stop", "Beep&stop", "Beep&ignore", "Stop"}; int Value[4] = {3000, 1000, 0, 5000}; char* CardID[4] = {"12 14 B1 2F", "F6 34 F9 25", "ED B9 E0 2B", "83 87 3B 2E"}; void setup() { SPI.begin(); mfrc522.PCD_Init(); pinMode(LINESENSOR1, INPUT); pinMode(LINESENSOR2, INPUT); pinMode(LINESENSOR3, INPUT); pinMode(BUZZER, OUTPUT); pinMode(MOTOR1A, OUTPUT); pinMode(MOTOR1B, OUTPUT); pinMode(MOTOR2A, OUTPUT); pinMode(MOTOR2B, OUTPUT); pinMode(DISTANCESENSOR, INPUT); } void loop() { // ラインフォロー機能 if(digitalRead(LINESENSOR1) == LOW && digitalRead(LINESENSOR2) == HIGH && digitalRead(LINESENSOR3) == LOW){ Forward(); }else if(digitalRead(LINESENSOR1) == HIGH && digitalRead(LINESENSOR2) == LOW && digitalRead(LINESENSOR3) == LOW){ Left(); delay(20); }else if(digitalRead(LINESENSOR1) == LOW && digitalRead(LINESENSOR2) == LOW && digitalRead(LINESENSOR3) == HIGH){ Right(); delay(20); } // 前回カード検知から最小時間経過していれば次のカードをチェック if(millis() - last_card_read >= MINIMUM_TIME_BETWEEN_CARDS){ if ( ! mfrc522.PICC_IsNewCardPresent()){ return; } if ( ! mfrc522.PICC_ReadCardSerial()) { return; } String content = ""; for (byte i = 0; i < mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); Serial.print(mfrc522.uid.uidByte[i], HEX); content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ")); content.concat(String(mfrc522.uid.uidByte[i], HEX)); } content.toUpperCase(); content = content.substring(1); for(int a = 0; a < COMMANDS_LENGTH; a++){ last_card_read = millis(); if(content == CardID[a]){ if(Type[a] == "Stop"){ Stop(); delay(Value[a]); }else if(Type[a] == "Beep&stop"){ digitalWrite(BUZZER, HIGH); Stop(); delay(Value[a]); digitalWrite(BUZZER, LOW); }else if(Type[a] == "Beep&ignore"){ Stop(); digitalWrite(BUZZER, HIGH); delay(500); digitalWrite(BUZZER, LOW); }else if(Type[a] == "Ignore"){ } } } } } void Forward(){ digitalWrite(MOTOR1A, HIGH); analogWrite(MOTOR1B, 255 - MOTOR_SPEED); digitalWrite(MOTOR2A, HIGH); analogWrite(MOTOR2B, 255 - MOTOR_SPEED); } void Backward(){ digitalWrite(MOTOR1A, LOW); analogWrite(MOTOR1B, MOTOR_SPEED); digitalWrite(MOTOR2A, LOW); analogWrite(MOTOR2B, MOTOR_SPEED); } void Left(){ digitalWrite(MOTOR1A, LOW); analogWrite(MOTOR1B, MOTOR_SPEED); digitalWrite(MOTOR2A, HIGH); analogWrite(MOTOR2B, 255 - MOTOR_SPEED); } void Right(){ digitalWrite(MOTOR1A, HIGH); analogWrite(MOTOR1B, 255 - MOTOR_SPEED); digitalWrite(MOTOR2A, LOW); analogWrite(MOTOR2B, MOTOR_SPEED); } void Stop(){ digitalWrite(MOTOR1A, LOW); digitalWrite(MOTOR1B, LOW); digitalWrite(MOTOR2A, LOW); digitalWrite(MOTOR2B, LOW); }
タスクプランナー
ロボット用タスク生成C#プログラムのZIP。.exeファイルも下記にあります。
No preview (download only).
Task planner.exe
Windowsマシンでインストール不要で実行可能。
No preview (download only).
カスタムパーツとエンクロージャ
シャーシ用フロントパーツ。全センサーと電子部品を収納。白PLAでプリント後、サンディングと複数回塗装で光沢仕上げ。プリント約8時間、サポート必須
フロントパーツ左側を閉じるパーツ
フロントパーツ右側を閉じるパーツ
4mm材料(合板、アクリル)用レーザーカットDXFファイル
plateback_CLMFY08IX0.dxf platebottom_YXrDbx6Zxr.dxf plateleft_SWSXq4pbU1.dxf plateright_mRA9hd7Kp8.dxfFusion 360ファイル(編集用)
industrial_line_follower_design_vX9sr32Rar.f3d回路図
編集用Fritzingファイル
schematic_QjiJP4TLOo.fzz全接続を含む回路図
PCB製作用PDFファイル(片面基板なのでトップレイヤーなし)
製造プロセス