記事公開日

ハンドエレキを改造!コントローラーで操縦できるようにしてみた

「エレキがリモコン操作できたら便利だよなぁ~」と思い、作ってみました。

十字キーの左または右を押している間、アームが動き、進行方向を変えられます。

ボタンはスピードの切り替え。

一段ずつアップ・ダウンするだけでなく、一気に最高スピードまでアップできるところがポイントです。

コントローラーのボタン割り当て

ハンドエレキを直接手で操作していたときは、後にのけ反る姿勢を取らないといけなかったので、ずいぶんと操縦がラクになりました。

ハンドエレキを改造してコントローラーで操縦

ただ、構想段階では、もっとカンタンにできると思っていたんですけどね・・・

思いのほか、ロボットになってしまいました。

改造したハンドエレキ(斜め下から)

改造したハンドエレキ(後ろから)

改造したハンドエレキ(下向き)

改造したハンドエレキ(フローター全体)

掛かった費用・使用したもの

同じものを作ろうと思う人はいないでしょうが、何か作るときのヒントになればと思うので、情報を残しておきます。

総費用:約10,000円

制御のコアとなる手のひらサイズのラズパイ

手のひらサイズのラズパイ

メインの制御システムに、Raspberry Pi(通称:ラズパイ)を使いました。

ラズパイは、小さいパソコンです。

なんと、手のひらに収まるサイズ!

しかも、1,000円ちょっとで買えちゃいます。

Raspberry Pi Zero W – スイッチサイエンス

値段も安いので、ラズパイの処理能力はそれほど高くありません。

しかし、無線通信やモーター制御などの面倒な処理を担ってくれるので、必要なパーツやプログラムもぐーんと少なくて済みます。

そしてもう一つ、ラズパイを使うことでの大きなメリットがあります。

それは、『操縦プログラム』が可能になること。

現段階ではまだ組み込んでいませんが、GPSデータを使って、目的のポイントまで自動操縦することだって可能です。

スーファミにそっくりなワイヤレス・コントローラー

スーファミにそっくりなワイヤレス・コントローラー

普通にリモコン付けるだけじゃあ、フットコンと同じで面白くない。

そこで、ワイヤレスタイプのコントローラーを使用しました。

2.4GHz帯の無線コントローラーなので、最大約10m(障害物があるときは約3m)まで電波が届きます。

アルミボートの後部座席からでも操縦が可能ですよ。

ただし、ワイヤレスコントローラーには、一つ注意点があります。

それは、一定時間操作しないと『スリープ状態』になってしまうこと。

このコントローラーの場合、約3分間、何もボタン操作が無いと、スリープしてしまいます。

STARTボタンを押せば、すぐに再接続されますが、やや面倒です。

充電ケーブルを使って有線にしておけばスリープにはなりませんので、フローターの場合、有線タイプのコントローラーで十分かもしれませんね。

なお、このコントローラーは、中国の通販サイト『AliExpress(通称:アリエク)』で購入しました。

スーパーファミコン ワイヤレスゲームパッド – AliExpress

やっぱスーファミ世代の僕には、このコントローラーが手に馴染みます。

モバイルバッテリー

モバイルバッテリー(黒)Anker Anker PowerCore II 6700、(白)ELECOM DE-M01L-6400

今回、電源にはモバイルバッテリーを2つ使ってます。

一つはラズパイ用(黒)、もう一つがモーター用(白)です。

  • 黒:Anker Anker PowerCore II 6700 2A / 5V
  • 白:ELECOM DE-M01L-6400 6400mAh 2.6A / 5V

本当はモバイルバッテリー1つだけで補いたかったのですが、手持ちのモバイルバッテリーでは出力電流が足りなかったので、今の段階では2つ使ってます。

※ラズパイとそれぞれのモーターで、各1.2Aぐらいの電流が必要です。

本来、モバイルバッテリーはスマホなどの”充電”に使用するものなので、少しでも電流が流れていない時間が続くと、出力が止まってしまう仕様になっています。

そこで、ずっとある程度の電流を引っぱり出しておく回路が必要でした。

「どれくらいの電流があれば、ずっと出力し続けるか?」はモバイルバッテリーの種類によって違うので、可変抵抗によって引っ張る電流を変更できるようにしています。

参考:回路図

ちなみに、今回使用しているモーター用のモバイルバッテリー(白)では、100mA以上の電流を流し続ける必要があった為、可変抵抗の値は「40Ω」に設定しています。

5V ÷ 40Ω= 0.125A = 125mA

なお、ラズパイ用のモバイルバッテリーは(黒)、もう少し低い電流で出力するので、ラズパイ用としました(ラズパイの待機時消費電流:80mA)

もしかしたら、電源はモバイルバッテリーではなく、エレキを動かすための鉛バッテリーから電気を引っ張ってくる方が簡略化できたかもしれませんね。

※鉛バッテリーを使用する場合は、12V→5Vに降圧するための回路が必要になります(使用してるエレキの定格電圧が12Vの場合)

サーボモーター

サーボモーター(MG996R)

『スピードを切り替えるためのモーター』と『方向を変えるためのアームのモーター』、両方ともサーボモーターという指定した位置で止められる特殊なモーターを使用しています。

基本的に、値段が高いほど、回す力(トルク)が大きいです。

今回は『10kgf』のトルクを持つサーボモーターを使用しました。

しかし、単純に力のあるモーターを使えば良いわけではなく、”力の働き”を考えないといけないのが大変ですね。

トルクがあるモーターは重いので、その分、フレームに掛かる負担も大きくなってしまいます。

すると、フレームが歪む・・・

じゃあ、フレームの負担を減らすために、モーターの取り付け位置を変えようとすると、今度は回転軸がズレるから、ギアやプーリーが必要になってしまう。

しかも、ギアやプーリーを使うと、もっと大きな動力が必要になってきます。

結局、軸の位置も変えずに、重量もできるだけ軽いモーターを選び、バランスを取って、この形になりました。

フレーム用の資材(アルミ・木材・ネジ等)

アルミ資材

フレームに使用したアルミ・木材などの資材は、すべてハンズマン(ホームセンター)で揃えました。

一個のアルミパーツが10円~30円ぐらいで変えるので、パズル感覚で組み立てられます。

あまり加工は得意でないので、基本的には穴を空けるとか、アルミ板を折り曲げる程度のことしかしてません。

ただ、「エレキ本体に穴はあけたくない」というこだわりがあったので、クランプで固定したり、機構を工夫する必要がありました。

この装置、防水性は全くないのですからね・・・

雨の日の釣行のために、ネジ数本で取り外しができるようになってます↓

取り外し可能なフレーム

ボタンを押して、エレキを水面から持ち上げる部分はよく稼働させるので、突っ張り棒方式で固定しました↓

エレキを水面から持ち上げる部分のフレーム

水中でのモーターの高さを調整させる部分は、手動で回せるネジを使用しました↓

水中でのモーターの高さを調整する部分のフレーム

電源スイッチ

電源スイッチ

電源スイッチとしてトグルスイッチを取り付けました。

  • スイッチを上にすると、通電(各モバイルバッテリーで電源ON)
  • スイッチを下にすると、モーターとラズパイの電源がOFF
  • スイッチを真ん中にすると、モーターのみ電源がオフ

『モーターのみ電源オフ』の目的は、手動操作を可能にするためです。

モーターに通電していると、その位置でモーターが固定されてしまうため、手で動かすことができません。

入り組んだ狭いところでは、手動で操作する方がやりやすいかもしれないので、一応、余地を残しておきました。

回路図

エレキモーターをコントローラーで操縦するための回路図

ラズバイZERO用ユニバーサル基板を使った回路(部品実装面)

ラズバイZERO用ユニバーサル基板を使った回路(配線面)

LEDはステータス確認用です。

通電しているときは、緑が点灯。

プログラムが正常に動いているときは、黄色が点灯。

コントローラーからの信号を受信したときは、黄色が点滅します。

電源スイッチとラズパイのGPIO16間にある1KΩの抵抗は、ラズパイに電源オフを伝えるための信号に使っています。

ラズパイに流していい電流は上限20mAと決まっているので、抵抗によって5mA程度だけ流れるよう制御しています。

今回、サーボモーターを動かすために『ハードウェアPWM』という制御方法を使用しました。

ラズパイでPWM信号を出力できるGPIOピンは、12Pin・13Pin(もしくは、18Pin・19Pin)と決まっています。

プログラム(Python)

#!/usr/bin/python

import time
import threading
import pigpio
import struct
import subprocess

# Device Input Directory
device_path = "/dev/input/js0"

# L(time)   : unsigned long
# h(value)  : unsigned short
# B(type)   : unsigned char
# B(number) : unsigned char
EVENT_FORMAT = "LhBB";
EVENT_SIZE = struct.calcsize("LhBB")

# PWM Pin Set
gpio_pin0 = 12
gpio_pin1 = 13

# Make Instance : pigpio.pi
servo = pigpio.pi()

# GPIO12 : ALT0(PWM0)
servo.set_mode(gpio_pin0, pigpio.ALT0)
# GPIO13 : ALT0(PWM1)
servo.set_mode(gpio_pin1, pigpio.ALT0)

# Initial Speed
speed = 0

# Save Previous Speed
pre_speed = 0

# Initial Pulse
pulse = 50000

# Default Motor Status
flag = False

# Power Off (Switch)
sw_pin = 16
servo.set_mode(sw_pin, pigpio.INPUT)
servo.set_pull_up_down(sw_pin, pigpio.PUD_DOWN)

def power_off(gpio, level, tick):
        print(gpio, level, tick)
        if level == 1:
                #subprocess.call("sudo shutdown -h now", shell=True)
                subprocess.call("sudo poweroff", shell=True)

servo.callback(sw_pin, pigpio.EITHER_EDGE, power_off)

# Test LED (Yellow)
chk_pin = 4
servo.set_mode(chk_pin, pigpio.OUTPUT)
servo.write(chk_pin, 1)

# Controller Input Func
def con_input():

        # Device Path Open
        with open(device_path, "rb") as device:

                # Device Input Data Read (1st Time)
                event = device.read(EVENT_SIZE)

                # Exists [event] Data
                while event:

                        # Fromat Convert
                        (con_time, con_val, con_type, con_num) = struct.unpack(EVENT_FORMAT, event)
                        print( "{0}, {1}, {2}, {3}".format(con_time, con_val, con_type, con_num ) )

                        global flag
                        global pre_speed
                        global speed
                        global pulse

                        # CROSS KEY Push
                        if con_type == 2:

                                # LEFT / RIGHT KEY
                                if con_num == 0:

                                        # INITIAL
                                        if con_val == 0:
                                                flag = False

                                        # LEFT (MAX:-32767)
                                        elif con_val < 0:
                                                flag = 1

                                        # RIGHT (MAX:32767)
                                        elif con_val > 0:
                                                flag = 2

                        # BUTTON Push
                        elif con_type == 1:

                        # ---------------------------
                        #       BUTTON Setting
                        # ---------------------------

                                # X (Speed:4)
                                if con_num == 0:
                                        speed = 4

                                # A (Speed:1)
                                elif con_num == 1:
                                        speed = 1

                                # B (Speed:2)
                                elif con_num == 2:
                                        speed = 2

                                # Y (Speed:3)
                                elif con_num == 3:
                                        speed = 3

                                # L (Speed:-1)
                                elif con_num == 4:
                                        if con_val == 1:
                                                speed = pre_speed -1
                                                if speed < -1:
                                                        speed = pre_speed

                                # R (Speed:+1)
                                elif con_num == 5:
                                        if con_val == 1:
                                                speed = pre_speed +1
                                                if speed > 4:
                                                        speed = pre_speed

                                # SELECT (Speed:0)
                                elif con_num == 8:
                                        speed = 0

                                # START
                                #elif con_num == 9:
                                #       speed = 0

                                # ---------------------------
                                #        Pulse Setting
                                # ---------------------------

                                # Speed:0
                                if speed == 0:
                                        pulse_up = 60000
                                        pulse_down = 44000

                                # Speed:1
                                elif speed == 1:
                                        pulse_up = 85000
                                        pulse_down = 60000

                                # Speed:2
                                elif speed == 2:
                                        pulse_up = 95000
                                        pulse_down = 75000

                                # Speed:3
                                elif speed == 3:
                                        pulse_up = 110000
                                        pulse_down = 90000

                                # Speed:4
                                elif speed == 4:
                                        pulse_up = 125000
                                        pulse_down = 105000

                                # Back:1
                                elif speed == -1:
                                        pulse_up = 23000
                                        pulse_down = 23000

                                # ---------------------------
                                #         Send Pulse
                                # ---------------------------
                                if con_val == 1:

                                        if speed > pre_speed:
                                                pulse = pulse_up
                                        elif speed < pre_speed:
                                                pulse = pulse_down
                                        pre_speed = speed

                                        servo.hardware_PWM(gpio_pin1, 50, pulse)

                                        print (speed)

                        # Device Input Data Read (2nd Time)
                        event = device.read(EVENT_SIZE)

# Parallel Process Command
th = threading.Thread(target=con_input)
th.start()

# Default Motor Pulse
i = 80000

# Speed Adjust (Motor Step)
step = 200

# Speed Adjust (Wait Interval)
interval = 0.00001

# Motor Max Pulse
left_max = 40000
right_max = 107000

# Infinite loop
while True:

        # Controlle BUTTON ON
        if flag:

                # Test LED OFF (Yellow)
                servo.write(chk_pin, 0)

                # LEFT KEY ON
                if flag == 1:
                        i = i - step
                        if i < left_max:
                                i = left_max

                # RIGHT KEY ON
                elif flag == 2:
                        i = i + step
                        if i > right_max:
                                i = right_max

                # Motor Pulse Set
                servo.hardware_PWM(gpio_pin0, 50, i)

                # Motor Pulse Data
                print(i)

                # Speed Adjust
                time.sleep(interval)

        # Test LED ON (Yellow)
        servo.write(chk_pin, 1)

# Parallel Process End
th.join()

exit()

実際、触ってみないと分からないかもしれませんが、スピードを切り替えるとき、アップするときとダウンするときでは、モーターの停止位置を変える必要があります。

よって、アップとダウンでサーボに送るパルスが異なるコードとなっています。

2021年の初バス釣り

初夏の籾木池

2021年4月22日(木)籾木池 12:00~12:30

この日は、2021年初のバス釣り。

田植えの時期なので、かなり減水しています。

しかし、こんなに水が少ないと、魚影が濃いエリアはかなり絞られる。

正直、釣り堀レベルです。

ということで、今回は試運転がメインだったので、サクッと一匹だけ!

ネコリグで釣れたブラックバス

やっぱり、真っ昼間ということもあり、一番水深のあるポイントにいましたね。

減水した籾木池でブラックバスが釣れたポイント

無事、2021年の初バスを釣ることができました。

40アップのブラックバス

この記事のURLをコピー

メールアドレスは公開されませんのでご安心ください。また、* が付いている欄は必須項目となります。

内容に問題なければ、下記の「コメントを送信する」ボタンを押してください。

関連情報

運営者プロフィール
Kaz

熱狂的にフローターを愛す30代半ばの釣り人です。宮崎在住・バス釣り歴15年・フリーのITエンジニアとして働いています。

その他の運営サイト
  • バス釣り用フローター購入ガイド
  • ベイトフィネスリール購入ガイド
  • 実際にバスプロが使ってるロッドとリールの組み合わせを集めたタックルのデータベースサイト
  • 偏光グラスの選び方