長穴減速をProcessingでシミュレート



![SS 192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/a41cd967-f549-8677-1efa-2e99bf69518d.png) 検算の意味を込めて長穴減速をシミュレート

##やること
[前回記事の長穴減速](https://qiita.com/Ninagawa_Izumi/items/0b1d607e41396d3fc307
)について、Processingでシミュレートしてみます。

![SS 907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/1245d79e-11f0-bc83-e226-100964ede63b.png)


長穴減速（揺動スライダクランク）の減速比の求め方については前回記事にまとめてあります。
[前回記事:長穴減速を解く](https://qiita.com/Ninagawa_Izumi/items/0b1d607e41396d3fc307
)

2種類のスケッチを用意しました。
1:リンクAの角度を変化させてそれに追従するリンクBの角度を求めるスケッチ
2:リンクBの角度を変化させてそれに追従するリンクAの角度を求めるスケッチ


##　1: リンクAを決め、リンクBを追従させるスケッチ

```c++:Processing3
//長穴減速、揺動スライドクランクについて、リンクAの角度からリンクBの角度を求めて描写する
//円の上部の頂点を0度とする表示

import controlP5.*; //スライダー用のライブラリをインポート
ControlP5 cp5;

float link_a_length ; //リンクAの円の中心からスライドピンまでの長さ
float link_b_length ; //円の中心からリンクBのフリー軸までの長さ
float link_a_angle; //リンクAの角度
float link_b_angle; //リンクBの角度

void setup() {
  size(400, 400); //画面サイズ
  strokeWeight(4); //リンク描画の線の太さ

  cp5 = new ControlP5(this); //スライダーを導入

  cp5.addSlider("link_a_angle") //リンクAの角度を決めるスライダー
    .setRange(2*PI, -2*PI)//スライダーの範囲
    .setValue(0)//スライダーの初期値
    .setPosition(60, 330)//スライダーの座標
    .setSize(200, 20);//スライダーのサイズ

  cp5.addSlider("link_a_length") //リンクA用の長さを決めるスライダー
    .setRange(10, 200) 
    .setValue(80)
    .setPosition(60, 360) 
    .setSize(70, 20); 

  //円の中心からリンクBのフリー軸までの長さを決めるスライダー
  cp5.addSlider("link_b_length") 
    .setRange(10, 200)
    .setValue(150)
    .setPosition(200, 360)
    .setSize(70, 20);
}

void draw() {

  background(128); //背景はグレー

  float x0 = width/2;// 画面の中心をx=0とした時の原点
  float y0 = height/3;// 画面の中心をy=0とした時の原点
  float x = mouseX-x0; // 画面の中心を0とした時のマウスのx座標
  float y =mouseY-y0;// 画面の中心を0とした時のマウスのy座標

  // スライドピンが動ける範囲をグレーで表示
  stroke(230); // 線の色はグレー
  strokeWeight(1); // 線の太さは1
  noFill();
  ellipse(x0, y0, 2*link_a_length, 2*link_a_length); //スライドピンが動ける円

  //リンクBの角度の算出
  link_b_angle = atan(link_a_length*sin(link_a_angle) / (link_a_length*cos(link_a_angle) + link_b_length));


  //リンクAを描画
  stroke(255, 0, 0); //線の色はレッド
  strokeWeight(1); //線の太さは1
  line(x0, y0, x0+link_a_length*cos(link_a_angle+PI/2), y0-link_a_length*sin(link_a_angle+PI/2));

  //リンクBを描画
  stroke(0, 255, 0); //線の色はグリーン
  strokeWeight(5); //線の太さは5
  line(x0, y0+link_b_length, x0 + (link_b_length*cos(PI/2+link_b_angle))*1.8, y0+link_b_length - (link_b_length*sin(PI/2+link_b_angle))*1.8);

  //各ポイントを描画
  stroke(255, 0, 0); //点の色はレッド
  //リンクAの中心点
  point(x0, y0);
  //リンクBの支点
  point(x0, y0+link_b_length);
  //スライダピンの位置
  point(x0+link_a_length*cos(link_a_angle+PI/2), y0-link_a_length*sin(link_a_angle+PI/2));

  //各アングル、減速比をモニタリング
  println("link_a_angle:", link_a_angle);
  println("link_b_angle:", link_b_angle);
  println("link_b_angle/link_a_angle:", link_b_angle/link_a_angle);
  println();
}

```
####実行結果
![SS 905.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/a85e7034-6051-598c-d4ca-1eb3d1b931a2.png)

スライダーを操作することで、入力角度、リンクAの長さ(a)、円の中心からリンクBのフリー軸までの長さ(b)を変更できます。

##　2: リンクBを決め、リンクAを追従させるスケッチ

```c++:Processing3
//長穴減速、揺動スライドクランクについて、リンクBの角度からリンクAの角度を求めて描写する
//円の上部の頂点を0度とする表示

import controlP5.*; //スライダー用のライブラリをインポート
ControlP5 cp5;

float link_a_length ; //リンクAの円の中心からスライドピンまでの長さ
float link_b_length ; //円の中心からリンクBのフリー軸までの長さ
float link_a_angle; //リンクAの角度
float link_b_angle; //リンクBの角度

void setup() {
  size(400, 400); //画面サイズ
  strokeWeight(4); //リンク描画の線の太さ

  cp5 = new ControlP5(this); //スライダーを導入

  cp5.addSlider("link_b_angle") //リンクB用の角度を決めるスライダー
    .setRange(PI/2, -PI/2)//スライダーの範囲
    .setValue(0)//スライダーの初期値
    .setPosition(60, 330)//スライダーの座標
    .setSize(200, 20);//スライダーのサイズ

  cp5.addSlider("link_a_length") //リンクA用の長さを決めるスライダー
    .setRange(10, 200) 
    .setValue(80)
    .setPosition(60, 360)
    .setSize(70, 20); 

  //円の中心からリンクBのフリー軸までの長さを決めるスライダー
  cp5.addSlider("link_b_length") /
    .setRange(10, 200)
    .setValue(150)
    .setPosition(200, 360)
    .setSize(70, 20);
}

void draw() {

  background(128); //背景はグレー

  float x0 = width/2;// 画面の中心をx=0とした時の原点
  float y0 = height/3;// 画面の中心をy=0とした時の原点
  float x = mouseX-x0; // 画面の中心を0とした時のマウスのx座標
  float y =mouseY-y0;// 画面の中心を0とした時のマウスのy座標

  // スライドピンが動ける範囲をグレーで表示
  stroke(230); // 線の色はグレー
  strokeWeight(1); // 線の太さは1
  noFill();
  ellipse(x0, y0, 2*link_a_length, 2*link_a_length); //スライドピンが動ける円

  //リンクAの角度を算出
  link_a_angle = PI/2 +  link_b_angle + asin(link_b_length*sin(link_b_angle)/link_a_length); 
  //link_a_angle = PI/2 -  link_b_angle - asin(link_b_length*sin(link_b_angle)/link_a_length); 

  //リンクAを描画
  stroke(255, 0, 0); //線の色はレッド
  strokeWeight(1); //線の太さは5
  line(x0, y0, x0+link_a_length*cos(link_a_angle), y0-link_a_length*sin(link_a_angle));

  //リンクBを描画
  stroke(0, 0, 255); //線の色はブルー
  strokeWeight(5); //線の太さは5
  line(x0, y0+link_b_length, x0 + (link_b_length*cos(PI/2+link_b_angle))*1.8, y0+link_b_length - (link_b_length*sin(PI/2+link_b_angle))*1.8);

  //各ポイントを描画
  stroke(255, 0, 0); //線の色はレッド
  //サーボの中心点
  point(x0, y0);
  //リンクBの支点
  point(x0, y0+link_b_length);
  //スライダピンの位置
  point(x0 + link_a_length*cos(link_a_angle), y0-link_a_length*sin(link_a_angle));

 //各アングル、減速比をモニタリング
  println("link_a_angle:", link_a_angle-PI/2);
  println("link_b_angle:", link_b_angle);
  println("link_b_angle/link_a_angle:", link_b_angle/(link_a_angle-PI/2));
  println();    
}
```
目的である減速後の角度から、回転させるサーボ量を決めるためのプログラムになります。

####実行結果
![SS 906.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/bb5ea665-fd99-eee5-d613-ad84e208c34e.png)


##次回
スライダの溝がbと並行にオフセットした場合の計算式にも挑戦してみようと思います。

へんなところがあったらご指摘ください。