header image
  • プログラム・ソフト
  • 物理学・工学
  • ガジェット
  • 当サイトについて
  • お問い合わせ
  • プログラム・ソフト
  • 物理学・工学
  • ガジェット
  • 当サイトについて
  • お問い合わせ
  • HOME
  • プログラム・ソフト
  • マウスでロボットアームを制御してみる【Python】

マウスでロボットアームを制御してみる【Python】

投稿日:2020年10月14日 更新日:2022年3月18日

  • Tags: [Python], [Raspberry Pi], [ロボット],

nocap

Raspberry piを使ってサーボモータを動かしてみよう、そしてロボットアームを制御してみようと思いまして、作製した手順をまとめてみようと思います。ロボットアームはマウスで動くようにしてみました。

  • 構成
    • 材料
    • ソフトウェア
    • 全体像
  • 数値入力によるサーボモータの制御
    • pigpioのインストール
    • 配線
    • Pythonからpigpioを使ったサーボモータ動作
  • マウス操作によるサーボモータの制御
    • WebIOPiのインストール
    • WebIOPiの設定
    • プログラムの用意
    • プログラムの実行
      • WebIOPiの再起動
      • ブラウザ上で動作確認
  • マウスによるロボットアームの制御
    • プログラムの用意
    • 配線
    • ブラウザ上で動作確認
  • まとめ

構成

材料

  • Raspberry Pi 3 Model B
  • ロボットアーム 6軸
  • DC電源 5V

6軸ロボットアーム(DiyStudio)の部品
Fig.1. 6軸ロボットアーム(DiyStudio)の部品

今回使用したロボットアームは、MG995サーボ6個で構成されたものになります。Amazonから買いました(写真ではシルバーですが実際はブラックでした)。サーボモータ6つ付いて7500円ほどなので、お買い得です。サーボMG995は駆動電圧4.8~6.6Vなので、DC電源は1.5V電池4本でも一応動きますが、結構電力を使うようなのでコンセントから給電できるDC電源を用意すると安心です。私はタブレットに付属していた5V3A出力のDCアダプターを使用しています。

ソフトウェア

  • OS: Raspberry Pi OS (旧 Raspbian)
  • Python: version 3.7
  • ライブラリ
    • pigpio (サーボ制御のためのGPIO出力制御用)
    • WebIOPi(ブラウザからPythonの実行用)

pigpioとWebIOPiのインストール方法は以下の通りです。サーボモータへ入力するパルス信号の制御(PWM)用のモジュールは、wiringpiというのもありますが、pigpioの方が精度が高いようなのでpigpioを使っています。

全体像

マウスでサーボモータを動かす流れは、

  1. ブラウザでjavascriptを使ってマウス操作の情報を取得
  2. WebIOPiを使って、1で取得した値をPythonプログラムに渡す
  3. Pythonからpigpioを使ってラズパイのGPIOからパルス信号出力
  4. パルス信号を受け取ったサーボモータが動く

マウスでサーボモータを動かす流れ
Fig.2. マウスでサーボモータを動かす流れ

数値入力によるサーボモータの制御

pigpioのインストール

aptコマンドでpigpioをインストールできます。Raspberry Piの端末から以下を実行します。

sudo apt install pigpio

これでpigpioを使ったGPIO制御が可能になります。今回はPythonを使ってこのpigpioを使用します。

配線

Raspberry PiのGPIO、サーボモータ、DC電源の接続は下図の通りです。サーボモータには以下の3本の線を接続します。

  • 茶色:GND
  • 赤色:4.8 ~ 6.6V
  • 橙色:Raspberry PiのGPIO

Raspberry Piとサーボモータの接続
Fig.3. Raspberry Piとサーボモータの接続

Pythonからpigpioを使ったサーボモータ動作

pigpioをPythonで動かし、Raspberry PiのGPIOからパルス信号を出してみます。下記のようなPythonコードでファイルを作成します。ここでは例としてservo.pyというファイル名とします。

import time
import pigpio

pi = pigpio.pi()

try:
    while True:
        val = input('Enter number (0-180): ') # サーボモータの角度を入力
        val = int(val)
        val = int(1900/180*val) + 500   # 500 - 2400
        print(val)
        pi.set_servo_pulsewidth(21, val)  # gpio21からのパルス信号を設定
        time.sleep(0.25)

except KeyboardInterrupt: # Ctrl + c で停止
    pi.set_servo_pulsewidth(21, 0)
    pi.stop()
    print("stop") 

作成したPythonのプログラムをRaspberry Piの端末で実行します。

$ python3 servo.py

するとキーボード入力待ち状態になりますので、目的のサーボモータの角度(0~180度の間)を入力すると、サーボモータが動きます。 たとえば45度にしたいときは入力待ち状態で、”45″ + Enterキー と入力します。

マウス操作によるサーボモータの制御

数値入力によってサーボ角度の制御ができたので、次にマウスカーソルの座標からサーボモータを動かしたいと思います。マウス操作を取り扱うにはGUI(グラフィカル・ユーザー・インターフェイス)を用意しなければいけません。今回は手っ取り早くブラウザを使ってみます。ブラウザからマウスカーソルの座標を取得し、Pythonプログラムに受け渡してサーボモータを動かすという流れになります。配線は「数値入力によるサーボモータの制御」の時と同じで問題ありません。

WebIOPiのインストール

ブラウザからRaspberry Pi内にアクセスするのに、WebIOPiというのを使います。WebIOPiをインストールするには端末で以下を入力します。

$ cd ~
$ wget https://sourceforge.net/projects/webiopi/files/WebIOPi-0.7.1.tar.gz
$ tar xvzf WebIOPi-0.7.1.tar.gz
$ cd WebIOPi-0.7.1

ここで初期のRaspberry Pi向けであるWebIOPiをRaspbery Pi 3でも使用できるようにパッチを適用します。

$ wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi-pi2bplus.patch
$ patch -p1 -i webiopi-pi2bplus.patch
$ sudo ./setup.sh

「Do you want to access WebIOPi over Internet ? [y/n]」と聞かれたら「n」と入力すればよいです(「y」を選ぶと、外部ネットワークからRaspberry PiにアクセスできるWeavedのIoT Kitというものがインストールされるようです)。

続いてWebIOPiをサービスとしてsystemctlで操作できるようにします。

$ cd /etc/systemd/system/
$ sudo wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi.service

WebIOPiサービスの開始、自動起動ONにするには

$sudo systemctl start webiopi
$sudo systemctl enable webiopi

WebIOPiの設定

WebIOPiの設定ファイルの中身を書き加えます。

$ sudo vi /etc/webiopi/config

#でコメントアウトしてある部分を参考に、doc-rootとmyscriptのパスを指定します。doc-rootはブラウザ(html)ファイルを置く場所、myscriptはブラウザから実行するPythonプログラムを指定します。ここではユーザー名がpiで、ホームディレクトリの”webiopi”というディレクトリをプログラムの置く場所とした例を示しています。

・
・
[HTTP]
・
・
# Use doc-root to change default HTML and resource files location
#doc-root = /home/pi/webiopi/examples/scripts/macros
doc-root = /home/pi/webiopi/
・
・
・
[SCRIPTS]
・
・
#   each sourcefile may have setup, loop and destroy functions and macros
#myscript = /home/pi/webiopi/examples/scripts/macros/script.py
myscript = /home/pi/webiopi/pwmservo.py

プログラムの用意

ブラウザで表示させるindex.htmlファイルと、そこから実行させるサーバー上のPythonファイルを準備します。これらはWebIOPyの設定ファイルである/etc/webiopi/config内に記述したものと対応します。上での例にしたがって、index.htmlとPythonプログラムは/home/pi/webiopiディレクトリへ置くことにして、Pythonプログラム名はpwmservo.pyとしています。

<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>WebIOPi | Servo controller</title>
        <script type="text/javascript" src="/webiopi.js"></script>
        <script type="text/javascript">
           webiopi()
           var timer;
           
           window.addEventListener("load", function () {
              var cursorX = 0;
              var w = 0;

             // PWM値をpythonプログラムに渡す           
             function main() {
               var pwm1 = Math.round(1900 * cursorX/w) + 500;
               webiopi().callMacro("run_script", [pwm1], callbackGetValue);
             }
             
              // Window上のマウス座標を取得する
              var mouseMove = function (e) {
                 if (e) {
                  cursorX = e.pageX;
                 } else {
                  cursorX = event.pageX;
                 }
              }
             document.addEventListener("mousemove",mouseMove);
             
               
            // Windowサイズを取得する
             w = window.innerWidth;
            
            window.onresize = function (e) {
             w = window.innerWidth;
            }
           

             timer = setInterval(main, 550); // 550msごとにpythonプログラム実行
           })
           
           // ラズパイからの信号を止める
           function stopArm() {
               clearInterval(timer);
               webiopi().callMacro("run_script", [0], callbackGetValue);
           }
           function callbackGetValue(macro, args, data) {
               console.log(macro);
               console.log(args);
               console.log(data);
           }
        </script>
    </head>
    <body>
        <input type="button" value="stop" class="off" onClick="stopArm()">
        <p>再スタート:F5 or Ctrl+r</p> 
    </body>
</html>
import webiopi
import sys
import os
import time
import pigpio

sd = os.path.dirname(os.path.abspath(__file__))
sys.path.append(sd)

PIN1 = 21

SLEEP_TIME = 0.05
pi = pigpio.pi() # Connect to local Pi.

@webiopi.macro
def run_script(pwm1):
     pi.set_servo_pulsewidth(PIN1, pwm1)
     time.sleep(SLEEP_TIME)

大まかな動作の流れ

  1. 関数mouseMove(index.html):マウスカーソルのx座標を取得
  2. 変数pwm1(index.html):x座標から決めたPWM値(サーボMG995では500~2400が駆動範囲)
  3. webiopi().callMacro(…)(index.html):サーバ上のPythonコード中を実行
  4. pi.set_servo_pulsewidth(PIN1, pwm1)(pwmservo.py):GPIOのPIN1から周波数PWM1のパルス信号を出力
  5. timer = setInterval(main, 550);(index.html):1 ~ 4を500m秒間隔で繰り返し実行

index.html内に記述してあるjavascriptを使って、マウス座標を取得しPWM値を計算して、GPIOを動作させるPythonプログラムに渡すことで、マウスからサーボモータを操作できるようにしています。javascript上でPythonコードを実行しているのは

webiopi().callMacro(“実行するPythonの関数”, [Pythonの関数に渡す引数], Pythonの関数からのリターン値を渡すjavascript関数);

の部分です

プログラムの実行

WebIOPiの再起動

PythonコードをWebIOPiに反映させるには、webiopiサービスを再起動させる必要があるため端末上で

$sudo systemctl restart webiopi

と入力する必要があります。これはPythonのコードを書き換えるたびに必要です。

ブラウザ上で動作確認

実際に動かすには、Raspberry Pi自身のブラウザで”http://localhost:8000“にアクセスします。同じローカルネットワーク内のPCからも”http://<Raspberry PiのIPアドレス>:8000“で同様にアクセスできます。認証ダイアログが表示されたら

  • ユーザ名:webiopi
  • パスワード:raspberry

でログインでき、index.htmlにアクセスできます。

アクセスしてプログラムの読み込みが完了すると、サーボモータにPWMパルスを出力しだします。ブラウザ上でのマウスのx座標(横方向)を読み取り、その値に対応してサーボの角度が変化するはずです。

ブラウザ上の”stop”ボタンを押すとGPIOからパルス信号がでなくなり、サーボモータのパワーがオフになります。

マウスによるロボットアームの制御

ロボットアームとRaspberry Piの接続後
Fig.4. ロボットアームとRaspberry Piの接続後

マウスカーソル移動によって1軸のサーボモータを動かすことができました。次にこれを6軸に拡張して、ロボットアームを動かしてみます。

プログラムの用意

上記の1軸の時に使ったindex.htmlとpwmservo.pyの中身をそれぞれ以下のように書き換えます。

<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>WebIOPi | Servo control<</title>
        <script type="text/javascript" src="/webiopi.js"&<</script>
        <script type="text/javascript">
           webiopi()
           var timer;
           
           window.addEventListener("load", function () {
              var cursorX = 0, cursorY = 0;
              var wheelX = 0, wheelY = 0;
              var lClickX = 0, lClickY = 0;
              var w = 0, h = 0;

             // PWM値をpythonプログラムに渡す           
             function main() {
               var pwm1 = Math.round(1900 * cursorX/w) + 500;
               var pwm2 = Math.round(1900 * cursorY/h) + 500;
               var pwm3 = Math.round(1900 * wheelX / (w-17)) + 500;
               var pwm4 = Math.round(1900 * wheelY / (h-17)) + 500;
               var pwm5 = Math.round(1900 * lClickX/w) + 500;
               var pwm6 = Math.round(400 * lClickY/h) + 1700; // 1700 - 2100
               webiopi().callMacro("run_script", [pwm1,pwm2,pwm3,pwm4,pwm5,pwm6], callbackGetValue);
             }
             
              // Window上のマウス座標を取得する
              var mouseMove = function (e) {
                 if (e) {
                  cursorX = e.pageX - wheelX;
                  cursorY = e.pageY - wheelY;
                 } else {
                  cursorX = event.pageX;
                  cursorY = event.pageY;
                 }
              }
             document.addEventListener("mousemove",mouseMove);
             
              // ページスクロール量を取得する
              window.onscroll = function () {
               wheelX = document.documentElement.scrollLeft || document.body.scrollLeft;
               wheelY = document.documentElement.scrollTop || document.body.scrollTop;
            }
               
               
            // Windowサイズを取得する
             w = window.innerWidth;
             h = window.innerHeight;
            
            window.onresize = function (e) {
             w = window.innerWidth;
             h = window.innerHeight;
            }
           
            // 左クリック時にマウス座標取得
             document.onmousedown = function(event) {
               document.removeEventListener("mousemove",mouseMove);
               document.addEventListener("mousemove",onMouseMove);
             }
             var onMouseMove = function (e) {
                 if (e) {
                  lClickX = e.pageX - wheelX;
                  lClickY = e.pageY - wheelY;
                 } else {
                  lClickX = event.pageX;
                  lClickY = event.pageY;
                 }
             }
             document.onmouseup = function(event){
              document.addEventListener("mousemove",mouseMove);
              document.removeEventListener("mousemove",onMouseMove);
             }
           

             timer = setInterval(main, 550); // 550msごとにpythonプログラム実行
           })
           
           // ラズパイからの信号を止める
           function stopArm() {
               clearInterval(timer);
               webiopi().callMacro("run_script", [0, 0, 0, 0, 0, 0], callbackGetValue);
           }
           function callbackGetValue(macro, args, data) {
               console.log(macro);
               console.log(args);
               console.log(data);
           }
        </script>
        <style>
        <!--
           html {
               height: 100%;
           }
           
           body {
               height: 200%;
               margin: 0;
               width: 200%;
           }
        -->
        </style>
    </head>
    <body>
        <input type="button" value="stop" class="off" onClick="stopArm()">
        <p>再スタート:F5 or Ctr<</p> 
    </body>
</html>
import webiopi
import sys
import os
import time
import pigpio

sd = os.path.dirname(os.path.abspath(__file__))
sys.path.append(sd)

PIN1 = 21
PIN2 = 20
PIN3 = 16
PIN4 = 26
PIN5 = 19
PIN6 = 13

SLEEP_TIME = 0.05
pi = pigpio.pi() # Connect to local Pi.

@webiopi.macro
def run_script(pwm1, pwm2, pwm3, pwm4, pwm5, pwm6):
     pi.set_servo_pulsewidth(PIN1, pwm1)
     time.sleep(SLEEP_TIME)
     pi.set_servo_pulsewidth(PIN2, pwm2)
     time.sleep(SLEEP_TIME)
     pi.set_servo_pulsewidth(PIN3, pwm3)
     time.sleep(SLEEP_TIME)
     pi.set_servo_pulsewidth(PIN4, pwm4)
     time.sleep(SLEEP_TIME)
     pi.set_servo_pulsewidth(PIN5, pwm5)
     time.sleep(SLEEP_TIME)
     pi.set_servo_pulsewidth(PIN6, pwm6)
     time.sleep(SLEEP_TIME)

基本的なプログラムの流れは1軸制御の時と変わりません。異なる点はブラウザ上で読み取る値の数を増やしていることです。以下の6つを読み取るようにしています。

  • マウスカーソルのx座標
  • マウスカーソルのy座標
  • スクロールのx方向の量
  • スクロールのy方向の量
  • 左クリック時のマウスカーソルのx座標
  • 左クリック時のマウスカーソルのy座標

6つの値を読み取り、それぞれ6つのサーボへ信号を送るようになっています。左クリック時のマウスカーソルのy座標から取得しているpwm6は、他の5つよりも範囲を狭めて1700 ~ 2100となるようにしています(他の5つは500 ~ 2400の範囲)。pwm6のパルス信号を送るサーボモータは、ロボットアーム先端の物を挟むサーボモータであり、このサーボは180度全範囲動かすと非常にトルクを必要とすることから、可動範囲を狭めています。

Pythonコード(pwmservo.py)を書き換えた後は、端末上でwebiopiサービスの再起動を行うことを忘れないようにしてください。

配線

今回は6つのサーボモータを制御するので、6つ分の接続を行います。

Raspberry Piとサーボモータ(6個)の接続
Fig.5. Raspberry Piとサーボモータ(6個)の接続

今回のサーボモータ6個の番号
Fig.6. 今回のサーボモータ6個の番号

ブラウザ上で動作確認

1軸の時と同様に、ブラウザへアクセスした直後にロボットアームが動き出します。。 注意点としては、6軸全部動くのでロボットアーム全体からすると大きく動く可能性があることです。 ロボットアーム周辺に置いてある物やテーブルに当たったり、テーブルから落下することがあるので、ブラウザへアクセス(または再読み込み)する前にロボットアームの周辺が片付いているか、ロボットアームが机から落ちないように固定されているか確認しましょう。

まとめ

Raspberry Piを使って6軸のロボットアームを動かせるようにしてみました。コントローラーとしてマウスを使えるように、ブラウザからマウス情報を読み取り、サーバ(Raspberry Pi内部)にあるPythonプログラムを実行するようにしています。

コメントを残す コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


Vimのレジスタの種類とコマンドの使い方・構造

【超初心者向け】Vim(Vi)でなんとかファイル編集する方法

Vimの改行コマンドと改行コードの操作

Vimで便利な小技(よく使うコマンド集)

Raspberry Piで音楽サーバー(Rune Audio)

【初心者向け】FreeCADの基本的な使い方と手順の流れ

【動画あり】Vimのコマンドを一覧にまとめてみた

Vimの行番号の表示設定と移動方法

  • プロフィール

  • Yoshiharu

  • 現在、ひよっこ光学系エンジニアをやっている一般人です。我流でプログラムをいじったりしています。備忘録、知識整理を兼ねてアウトプットをしていく予定です。

    • 【ラズパイ】格安な抵抗式・静電容量式の土壌湿度センサーを実際に使って比較

      2022.11.23

      【ラズパイ】格安な抵抗式・静電容量式の土壌湿度センサーを実際に使って比較


    • ELEGOO Neptune 2Sをレビュー!2万円台3Dプリンターの実力を実際に使って評価!

      2022.11.03

      ELEGOO Neptune 2Sをレビュー!2万円台3Dプリンターの実力を実際に使って評価!


    • 自作ラズパイゼロケースを3Dプリンター用にモデリング【FreeCAD】

      2022.10.13

      自作ラズパイゼロケースを3Dプリンター用にモデリング【FreeCAD】


    • 【初心者向け】FreeCADの基本的な使い方と手順の流れ

      2022.10.11

      【初心者向け】FreeCADの基本的な使い方と手順の流れ


    • 【Python】ラズパイでLチカ:LEDの取り扱い~抵抗値の計算

      2022.09.07

      【Python】ラズパイでLチカ:LEDの取り扱い~抵抗値の計算


  • アーカイブ

    • 2022年11月
    • 2022年10月
    • 2022年9月
    • 2022年8月
    • 2022年5月
    • 2022年4月
    • 2022年3月
    • 2022年1月
    • 2021年11月
    • 2021年9月
    • 2021年8月
    • 2021年7月
    • 2021年2月
    • 2021年1月
    • 2020年12月
    • 2020年10月
    • 2020年9月
    • 2020年8月
    • 2020年7月
    • 2020年3月
    • 2020年2月
    • 2020年1月
  • カテゴリー

    • Vim
    • ガジェット
    • プログラム・ソフト
    • 光学
    • 情報処理
    • 物理学・工学
    • プログラム・ソフト
    • 物理学・工学
    • ガジェット
    • 当サイトについて
    • お問い合わせ
    Y Lab Desk

    Copyright © Y Lab Desk, 2022 All Rights Reserved.