モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

地球規模で遠隔操作できるブルドーザー(インターネット経由でスマホによるラジコン操作)

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2016/05/17
最終更新最終更新
2024/07/05
記事区分記事区分
一般公開

目次

    博士課程学生です。電子工作はただの趣味です。

    スマートフォンから操作できるブルドーザーロボットです。前進、後退、回転が可能です。Qoosky WebSocket API を利用しています。制作費は Raspberry Pi が既に手元にあれば追加でおおよそ 1 万円です。センサー機能が搭載されていないため正確な操作はできませんが、学校や職場から自宅のロボットを動かすこともできます。

    パーツを購入して大まかな部品を組み立てる (1日目)

    必要な部品リスト

    Raspberry Pi 一式が既に手元にある場合、工作に必要な部品リストは以下のとおりです。

    部品名 参考価格 個数
    2チャンネルリモコン ブルドーザー工作基本セット 1,800 円 1個
    Grove I2C モータードライバモジュール 1,740 円 1個
    I2C 接続キャラクタ LCD モジュール ACM1602NI 1,280 円 1個
    cheero Canvas 3200mAh IoT 機器対応 モバイルバッテリー 3,240 円 1個
    9V形 乾電池 300 円 (使い捨ての場合) 1個
    10k 半固定抵抗 30 円 1個
    1k 抵抗 20 円 1個
    ユニバーサル基板 200 円 1個
    画像ネットプリント 30 円 (写真サイズ) 5個
    1.0mm プラ板 二枚入り 418 円 1個
    5.0mm プラ棒 515 円 1個
    セメダイン ホビー用 20ml CA-221 182 円 1個
    セメダイン 貼ってはがせる粘着材 448 円 1個
    合計 10,323 円 -

    手元に届いたので早速工作キットを組み立ててみます。

    付属の説明書を読みながら組み立てます。後にプラ板で作るボックスがやや重たいため、モーターの負荷を考慮してブルドーザーの部品が上下に稼動しないモードで組み立てました。8 コマのベルトが不要であったりする等、数カ所つまずきポイントがありました。なお、コントローラはスマートフォンで代用するため、組み立て不要です。

    細かいパーツを除くと、おおよそこれらのモジュールを組み合わせれば完成します。

    ブレッドボードを用いて I2C デバイスの動作設定を行う (2日目)

    ブレッドボードで回路を組む

    以下のように回路を組みます。動作検証ですので、ブレッドボードを利用します。

    ACM1602NI と Grove I2C モータードライバモジュールの動作電圧が 3.3v および 5v と異なるため、厳密に作るならば I2C の電圧レベルを変換する必要がありますが、今回のような簡単な回路ではあまり気にせずにそのまま接続しても動きます。

    Connecting the 5V Arduino directly to a single 3.3V-powered I2C chip usually works, even though it violates official specifications in multiple ways.
    http://playground.arduino.cc/Main/I2CBi-directionalLevelShifter

    ピン配置の参考資料

    I2C デバイスの動作確認

    事前設定

    制御プログラムを動作させるための Raspberry Pi 設定を事前に行います。

    • IP 固定: 無線 LAN 接続の設定を行ったら IP を固定しておきます。
    • パッケージの管理情報を最新にする: apt-get` コマンドでパッケージの管理情報を最新にしておきます。
    sudo apt-get update
    
    • I2C 設定を有効にしておきます。

    I2C デバイスの動作検証

    ACM1602NI の動作検証を行っておきます。以下のコマンドで、モータードライバの出力電圧が制御できることを確認します。

    出力電圧 0V

    i2cset -y 1 0x0f 0x82 0x00 0x00 i
    

    出力電圧 2.5V (9V 電源の場合。M1、M2、両方)

    i2cset -y 1 0x0f 0x82 0x46 0x00 i
    i2cset -y 1 0x0f 0x82 0x00 0x46 i
    i2cset -y 1 0x0f 0x82 0x46 0x46 i
    

    電圧の向きが左右同じ (前進、後退)

    i2cset -y 1 0x0f 0xaa 0x0a 0x01 i
    i2cset -y 1 0x0f 0xaa 0x05 0x01 i
    

    電圧の向きが左右逆 (右回転、左回転)

    i2cset -y 1 0x0f 0xaa 0x09 0x01 i
    i2cset -y 1 0x0f 0xaa 0x06 0x01 i
    

    参考資料

    注意事項

    • モータードライバモジュールの上部にある、リセットボタンを押してから実行してください (モータードライバの電源を入れてから Raspberry Pi の電源を入れてください)
    • モーターの耐電圧は 3.0V です。誤って高電圧をかけないように電圧レベルの設定値に注意してください。
    • 電圧レベルと向きの両方を指定する必要があります。片方だけでは出力に失敗します。

    制御プログラムを作る (3日目)

    制御プログラム

    websocket_clients のうち、Ruby のサンプルコードをもとにしました。ruby はバージョンが 2.1.3 のものを使用しました。依存 Gem が一つだけありますので、事前にインストールしておきます。

    sudo gem install websocket-client-simple -v 0.3.0
    

    bulldozer.rb

    #!/usr/bin/ruby
    # -*- coding: utf-8 -*-
    require 'json'
    require 'logger'
    require 'websocket-client-simple'
    
    API_TOKEN = 'XXXX-XXXX-XXXX-XXXX'
    API_ENDPOINT = 'wss://api.qoosky.io/v1/controller/actuator/ws'
    LCD_PIN = 4
    
    $logger = Logger.new STDOUT
    $last_time = Time.now
    
    $speed = 70 # 9V 電源で 2.5V 程度の計算になります。
    
    def lcd_update(key)
      line1 = ["0x00 0x01", # クリア
               "0x00 0x02", # HOME
               "0x80 0x6b", "0x80 0x65", "0x80 0x79", # key
               "0x80 0x#{(48+key).to_s(16)}",
               "0x80 0x20", "0x80 0x#{($speed/70.0*2.5 + 48).round.to_s(16)}", "0x80 0x76", # 0-9v
               "0x00 0xc0"] # 改行
      case key
      when 3
        line2 = %w(73 70 65 65 64 20 75 70) # speed up
      when 4
        line2 = %w(73 70 65 65 64 20 64 6f 77 6e) # speed down
      when 5
        line2 = %w(66 6f 72 77 61 72 64) # forward
      when 8
        line2 = %w(62 61 63 6b 77 61 72 64) # backward
      when 6
        line2 = %w(6c 65 66 74) # left
      when 7
        line2 = %w(72 69 67 68 74) # right
      else
        line2 = %w(75 6e 64 65 66 69 6e 65 64) # undefined
      end
      line1.each{|ch| system "i2cset -y 1 0x50 #{ch}"}
      line2.each{|ch| system "i2cset -y 1 0x50 0x80 0x#{ch}"}
    end
    
    def motor_drive(key)
      hex = $speed.to_s(16)
      case key
      when 3 # speed up
        $speed += 10
        hex = '00'
      when 4 # speed down
        $speed -= 10
        hex = '00'
      when 5 # forward
        system "i2cset -y 1 0x0f 0xaa 0x05 0x01 i"
      when 8 # backward
        system "i2cset -y 1 0x0f 0xaa 0x0a 0x01 i"
      when 6 # left
        system "i2cset -y 1 0x0f 0xaa 0x09 0x01 i"
      when 7 # right
        system "i2cset -y 1 0x0f 0xaa 0x06 0x01 i"
      else
        hex = '00'
      end
      system "i2cset -y 1 0x0f 0x82 0x#{hex} 0x#{hex} i"
    end
    
    begin
      # WebSocket SSL クライアント
      ws = WebSocket::Client::Simple.connect API_ENDPOINT
    
      # コネクション確立時のイベント
      ws.on :open do
        if ws.handshake.valid?
          $logger.info 'Successfully connected to the API server.'
          ws.send({ token: API_TOKEN }.to_json)
          # LCD バックライト ON
          system "gpio -g mode #{LCD_PIN} out"
          system "gpio -g write #{LCD_PIN} 1"
          # LCD 初期化
          system "i2cset -y 1 0x50 0x00 0x01"
          system "i2cset -y 1 0x50 0x00 0x38"
          system "i2cset -y 1 0x50 0x00 0x0f"
          system "i2cset -y 1 0x50 0x00 0x06"
        else
          ws.emit :error, 'websocket handshake failed.'
        end
      end
    
      # エラー時のイベント
      ws.on :error do |err|
        $logger.error "An unexpected error has occurred: #{err}"
        ws.emit :close
      end
    
      # コネクション切断時のイベント
      ws.on :close do |e|
        raise "Connection closed."
      end
    
      # メッセージ受信時のイベント
      ws.on :message do |msg|
        $logger.info "received: #{msg}"
        json = JSON.parse msg.to_s
        if key = json['pushedKey']
          lcd_update(key)
          motor_drive(key)
        end
        $last_time = Time.now
      end
    
      # メインスレッド待機
      timer = 100
      loop do
        if (timer == 0)
          timer = 100
          msg = "keep-alive message."
          ws.send msg
          $logger.info "sent: #{msg}"
        else
          timer -= 1
          if Time.now - $last_time > 0.5
            $logger.info("motor stop")
            system "i2cset -y 1 0x0f 0x82 0x00 0x00 i"  # モーター停止
          end
        end
        sleep 0.1
      end
    
    rescue => e
      $logger.warn "An error occurred: #{e}\nretrying..."
      sleep 5
      retry # 再試行
    
    ensure
      # 終了時に消灯して初期化
      system "gpio -g write #{LCD_PIN} 0"
      system "i2cset -y 1 0x50 0x00 0x01"
    end
    

    実行方法

    ruby bulldozer.rb
    

    動作概要: ボタン番号に応じて以下の動作をします。

    ボタン番号 動作
    1 未定義
    2 未定義
    3 加速 (初期値は 9V 電源でモーター電圧 2.5V)
    4 減速 (初期値は 9V 電源でモーター電圧 2.5V)
    5 前進
    6 左回転
    7 右回転
    8 後退

    10 秒毎に keep-alive メッセージを送信してサーバーからの切断を防ぎます。ネットワーク障害などが原因でコネクションが切断された時は自動で再接続します。加速と減速は電源電圧が低下してきた場合に利用します。加速しすぎるとモーターが故障する原因になりますので注意してください。

    試験的に操作してみます。

    前進、後退、右回転、左回転の操作ができることを確認します。回線速度に依存する部分もありますが、反応もリアルタイムです。

    バッテリーや回路を格納するボックスを作る (4日目)

    プラ板でボックスを作る

    1.0mm 厚のプラ版で Raspberry Pi やバッテリーを格納するボックスを作ります。プラ版はハサミやカッターで簡単に加工できます。

    骨組みを作る

    洗濯挟みなどで固定してセメダインが乾くのを待ちます。LCD 用の窓を切り取っておきます。

    プラ版ボックスを乗せる柱を二本用意しておく

    プラ棒を利用して、ボックスを乗せる柱を二本立てておきます。こちらもセメダインで固定します。

    ネットプリントしたフィルムで装飾

    ボックスの骨組みができたら、セブンイレブン等でプリントアウトしたフィルムで装飾します。フリー素材の迷彩柄を利用しました。

    洗濯挟みで固定してセメダインが固まるのを待ちます。

    LCD 用の窓を切り取ります。

    本体に乗せる

    便利な商品「貼って剥がせるセメダイン」を利用してボックスを本体に乗せます。モーターが故障したときにも取り外せるので安心です。

    側面から

    別の角度から

    回路作り (5日目)

    はんだづけ

    LCD をのせるための回路を作ります。ブレッドボードで動作検証した回路です。

    裏面です。配線の固定方法が少し残念なことになっていますが、簡単な回路なのでこのままで。

    完成 (6日目)

    ボックスの中にモジュールを設置する

    個別に動作検証してきたモジュールを、ボックスの中に設置します。

    別の角度から

    ふたを閉じて完成です。

    Raspberry Pi 起動時の設定

    好みに応じて rc.local に nohupを用いたコマンドを登録すれば Raspberry Pi 起動時に自動で WebSocket 通信が開始できます。または tmux を用いて、ターミナルを終了してもプログラムの実行が継続されるようにしておきます。

    $ tmux new
    $ ruby bulldozer.rb  ←実行後にターミナルを閉じる
    

    Likeボタン(off)0
    詳細設定を開く/閉じる

    記事内で用いられたハードウェア

    • 名称個数商品リンク
    • ハードウェア画像-0I2C 接続キャラクタ LCD モジュール ACM1602NI1ハードウェアWebリンク秋月電子通商
    • ハードウェア画像-1cheero Canvas 3200mAh IoT 機器対応 モバイルバッテリー1ハードウェアWebリンクAmazon
    • ハードウェア画像-22チャンネルリモコン ブルドーザー工作基本セット1ハードウェアWebリンクAmazon
    • ハードウェア画像-3Raspberry Pi3 Modle B+1ハードウェアWebリンクAmazon
    • ハードウェア画像-4Grove I2C モータードライバモジュール1ハードウェアWebリンクスイッチサイエンス

    記事内で用いられたソフトウェア (電子回路図、CAD、ソースコード等)

    • ファイル名種別サイズアップロード日時
    • bulldozer.rbソースコード4KB2024/07/04 21:03
    • bulldozer-schematic.jpg電子回路図133KB2024/07/04 21:21
    アカウント プロフィール画像

    博士課程学生です。電子工作はただの趣味です。

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    >>さらに詳しくステッカーを贈る
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      ログインする

      関連記事