LoginSignup
6
7

More than 3 years have passed since last update.

Fusion360用3Dマウスの自作

Posted at

背景

前回に続いて、Fusion360用のデバイスを制作しました。
作成に至った詳細やハードウエアについては、別のブログ記事に書いています。
こちらでは、電気回路とコード内容について書きました。

電気回路

使用した電気部品は次の通りです。

アイテム 数量 備考
マイコンProMicro 1個
ジョイスティックモジュールA 1個 傾けるタイプ
ジョイスティックモジュールB 2個 平行移動タイプ
タクトスイッチ 1個 リセット用

次のブレッドボード図を参考お願いします。

3Dマウス_パターン2_ブレッドボード.jpg

可変抵抗(ボリューム)が2個並んでいるのは、ジョイスティックB(平行移動タイプ)1個
の意味です。丁度良い素材が無く、回路的に等価なので、このような表現にさせて
いただきました。

コード内容

Arduino IDE 1.8.0 を使用しました。
スケッチ例 => 09.USB => Mouse => JoystickMouseControl を参考にしました。

以下、コードを少し区切って説明します。
順番に全てを繋げれば動くはずですが、必要に応じて適時修正お願いします。

#include "Keyboard.h"
#include "Mouse.h"

// set pin numbers for switch, joystick axes, and LED:
const int txAxis = A0;         // tilt joystick X axis
const int tyAxis = A1;         // tilt joystick Y axis
const int s1xAxis = A2;         // shift1 joystick X axis
const int s1yAxis = A3;         // shift1 joystick Y axis
const int s2xAxis = A6;         // shift2 joystick X axis(A6=4)
const int s2yAxis = A7;         // shift2 joystick Y axis(A7=6)
const int fitButton = 7;         // input pin for zoom fit mode

// parameters for reading the joystick:
int range = 30;               // output range of X or Y movement
int responseDelay = 40;        // response delay of the mouse, in ms
int threshold = range / 6;    // resting threshold
int center = range / 2;       // resting position value
int zmSens = 6;            // zoom sensitivity

int modeState = 0;          // effective mode state
int lastModeState = 0;      // previous mode state
int modeTimes = 10;         // reset at stated periods
int modeTime = 0;
int xMoved = 0;             // x moved total
int yMoved = 0;             // y moved total

void setup() {
  pinMode(fitButton, INPUT_PULLUP);
  // take control of the mouse:
  Mouse.begin();
  Keyboard.begin();
}

void loop() {

  // read and scale the two axes:
  int txMove = - readAxis(txAxis);
  int tyMove = - readAxis(tyAxis);
  int sxMove = - (readAxis(s1xAxis) + readAxis(s2xAxis) ) / 2;
  int syMove = (readAxis(s1yAxis) - readAxis(s2yAxis) ) / 2;
  int zmMove = (readAxis(s1yAxis) + readAxis(s2yAxis) ) / 2;
  int fitMode = digitalRead(fitButton);

冒頭は、I/Oピン定義、各変数の定義です。
全ての変数の意味は、すみませんが説明省略します。
loopの最初、各ジョイスティックの入力を変数に代入しています。
向きを間違えていたので、マウス座標に合わせるために正負符号付けました。

変数 目的 センサー 操作
t*Move 3Dモデル回転 ジョイスティックA 傾ける
s*Move 3Dモデル移動 ジョイスティックB 2個を同じ方向に動かす (=水平移動)
zmMove 拡大縮小 ジョイスティックB 2個を逆方向に動かす (=ひねる)
fitMode 全画面表示 ジョイスティックA 押し込む
  // mode select
  if (fitMode == 0){
    modeState = 1;
  }
  else if (txMove != 0 or tyMove != 0){
    if (modeTime > 0){
      modeState = 2;
      modeTime--;
    }
    else{
      modeState = 0;
    }
  }
  else if (sxMove != 0 or syMove != 0 or zmMove != 0){
    if (modeTime > 0){
      modeState = 3;
      modeTime--;
    }
    else{
      modeState = 0;
    }
  }
  else{
    modeState = 0;
  }

  // screen fit mode
  switch (modeState){
    case 1:
      if (lastModeState != 1){
        if (!Mouse.isPressed(MOUSE_MIDDLE)) {
          Keyboard.releaseAll();
          Mouse.release(MOUSE_MIDDLE);
        }
        delay(responseDelay);
        if (fitMode == 0){
          Mouse.press(MOUSE_MIDDLE);      // middle button double click
          delay(100);
          Mouse.release(MOUSE_MIDDLE);
          delay(100);
          Mouse.press(MOUSE_MIDDLE);
          delay(100);
          Mouse.release(MOUSE_MIDDLE);
          delay(500);
          lastModeState = 1;
        }
      }
      break;

    // tilt mode
    case 2:
      if (!Mouse.isPressed(MOUSE_MIDDLE)) {
        Keyboard.press(KEY_LEFT_SHIFT);
        Mouse.press(MOUSE_MIDDLE);
      }
      Mouse.move(txMove, tyMove, 0);
      xMoved += txMove;
      yMoved += tyMove;
      lastModeState = 2;
      break;

    // shift and zoom mode
    case 3:
      if (!Mouse.isPressed(MOUSE_MIDDLE)) {
        Keyboard.releaseAll();
        Mouse.press(MOUSE_MIDDLE);
      }
      Mouse.move(sxMove, syMove, 0);
      if (zmMove > zmSens){
        Mouse.move(0, 0, 1);
      }
      else if (zmMove < -zmSens){
        Mouse.move(0, 0, -1);
      }      
      xMoved += sxMove;
      yMoved += syMove;
      lastModeState = 3;
      break;

    // release and reset
    default:
      if (Mouse.isPressed(MOUSE_MIDDLE)) {
        Keyboard.releaseAll();
        Mouse.release(MOUSE_MIDDLE);
      }
      Mouse.move(-xMoved, -yMoved, 0);
      xMoved = 0;
      yMoved = 0;
      modeTime = modeTimes;
      lastModeState = 0;
      break;
  }
  delay(responseDelay);
}

各操作をswich文で切り替えています。

場合分け 目的 命令
case1 全画面表示 真ん中ダブルクリック
case2 3Dモデル回転 Shift+真ん中ボタン+マウス移動
case3 3Dモデル移動&拡大縮小 真ん中ボタン+マウス移動 or スクロール
その他 リセット キー&マウスボタン離す、マウスカーソル移動

3Dモデル「回転」と「移動」は命令が重複しており、同時に出せないので
(少なくとも私には方法が分からない....)、切り替えています。
また、画面のマウスカーソルも動いてしまうので、一定時間毎に戻しています。

int readAxis(int thisAxis) {
  // read the analog input:
  int reading = analogRead(thisAxis);

  // map the reading from the analog input range to the output range:
  reading = map(reading, 0, 1023, 0, range);

  // if the output reading is outside from the rest position threshold, use it:
  int distance = reading - center;

//  if (abs(distance) < threshold) {
//    distance = 0;
//  }
  if (distance > 0){
    distance = distance - threshold;
      if (distance < 0){
        distance = 0;
      }
  }
  else {
    distance = distance + threshold;
      if (distance > 0){
        distance = 0;
      }
  }

  // return the distance for this axis:
  return distance;
}

ジョイスティックのアナログ入力をデジタルに変換、処理しています。
中央位置の遊び(=threshold)をキャンセルする処理方法は少し変更しました。
元のスケッチ例をコメントアウトしているので参考ください。

最後に

最後まで読んでいただき、ありがとうございました。

末尾に参考にさせていただいたブログ記事リンクを記載しました。感謝いたします!
また、自作キーボード(Self-Made Keyboards in Japan)のDiscordにて、カテゴリ違い
気味にも関わらずアドバイスくださった有識者の方々にも、改めて感謝いたします!

◆Hobby Plus:第62回 USBデバイスが作れるArduino?Arduino Pro Micro(Leonardo)でHID機能を使ってみる
◆物を作る者:ジョイスティックとタクトスイッチでマウスを作る
◆K.H.WEBLOG:Arduino Micro を使って、試しに USB スライドパッド マウスを作ってみた(小型USBキーボード自作のための準備色々)

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7