在上一篇文章Unity 串列埠連接Arduino:測試(二),已經將Arduino與Unity的專案連接成功,可以透過Arduino端的搖桿來控制Unity中的物件移動與旋轉。接著在本篇文章中我們兩個目標要達成:
夏虫之私人筆記
2023年5月12日 星期五
Unity 串列埠連接Arduino:測試(三)
2023年5月7日 星期日
Unity 串列埠連接Arduino:測試(二)
在上一篇文章Unity 串列埠連接Arduino:測試(一),雖然已經將Arduino與Unity的專案連接成功,可以透過Arduino端的搖桿來控制Unity中的物件旋轉與否;表面上成功,但實際上資料傳送有不少問題存在。
在Arduino傳送資料與Unity中C#讀取資料的過程中,實際上有產生錯誤。但在上篇文章的測試中,僅傳輸0或1,不容易觀察到資料錯誤的狀況。
在本篇文章,我們將Arduino程式修改如下:
-----------------------------------------------------
Serial.println("B,"+SSK+","+SSX+","+SSY+",D");
傳送SSK、SSX、SSY這3個資料,分別對應按鈕、搖桿左右搖、搖桿前後搖三個資料,以","隔開,並在前面加入一個開始字元B,在結束加入一個結束字元D。
在Serialsetup.cs中修改如下:
----------------------------------------------------------------
sp.DiscardInBuffer()先不執行,觀察每一筆資料,在Console視窗有時可以看到錯誤資料
如上圖紅框中所示。(但不確定什麼原因造成,有可能是Arduino端造成的)
由於我們採用的傳送是固定時間間隔傳送和接收,如果Aruino傳送時間間隔太短,Unity這端讀取資料時間間隔為0.02sec(FixedUpdate()設定為每0.02秒執行一次),資料累積的結果,將造成Unity在後續應用這些資料做控制時有Lag的現象。但如果Arduino傳送資料的間隔太長,則會造成Unity讀不到資料(這裡利用例外處理避免掉錯誤引起的一些困擾)。
因此,我們採用的方式是Arduino的dealy設為7。並且在ReadLine讀取成功之後,將inBuffer的資料丟掉(sp.DiscardInBuffer())。不過,使用DiscardInBuffer()後,資料讀取不正確的比例上升很多。
為了避免資料不正確產生後續的錯誤,當讀取資料不正確,則再讀取下一行,最多讀取4次。利用Split來拆解字串,拆解後檢查第一個字串(words[0])和第五個字串(words[4]),如分別為B和D,視為正確。
----------------------------------------------------------------
由Console視窗觀察,最多讀取2次即可成功。(但仍然有產生錯誤的狀況)
讀取第一次即成功和讀取第二次成功的比例與Arduino的dealy時間(間隔)有關。
----------------------------------------------------------------
上面程式中,如果有某一次FixedUpdate()在執行ReadandSplit()、sp.DiscardInBuffer()失敗時,則顯示"not good"。
2023年5月6日 星期六
Unity 串列埠連接Arduino:測試(一)
底下三篇文章是要測試Arduino透過串列埠傳輸資料到PC,藉以控制Unity專案上的物件。
=====================================================================
在第一篇文章中,我們首先建立Arduino與Unity專案的串列埠連線的基本功能:
利用Arduino連接搖桿產生數據,一開始為簡化問題,先只傳送按鈕數據(1個字元),按鈕沒按下時傳送1,按下時傳送0。以Serial.println傳送。
S-K接Pin12=========================================
先利用Arduino IDE的Serial Monitor檢查資料是否正確
按鈕未按下時,傳輸1,按鈕按下時,傳輸0
測試完,記得關閉Serial Monitor。
==========================================
==========================================
Unity端
在場景中放置一個Cube
調整Main Camera高度與角度
目的:當Arduino端連接的搖桿未按下時,Cube不旋轉。搖桿按下時,Cube旋轉。
先在專案Asset視窗中新建一個C#檔ComData.cs,設定共用變數
=========================================
再建立一個腳本Ctrlmotion.cs,附加在Cube上。
可在inspector視窗調整rspeed數值,改變旋轉速度。
==========================================
接著在Hierarchy視窗中加入Canvas,在Canvas中加入2個按鈕、1個下拉式選單。
修改物件名稱如下
在下拉式選單的inspector視窗中,將Options先刪除。
其選項可在C#程式中,由SerialPort.GetPortNames()取得。
但SerialPort.GetPortNames()的資料型態是string陣列,
需再轉為List。
==========================================接著建立一個腳本Serialsetup.cs,附加在EventSystem上。
----------------------------------------------------------------
這邊須注意,如果無法加入System.IO.Ports,檢查Api Compatibility Level
是否設定為.Net 4.x
在Button1的inspector視窗中,將EventSystem拉入,選擇對應的function:
Button2和下拉式選單也是相同設定:
===============================================================
執行結果:
下拉式選單中選擇PortName2018年8月6日 星期一
青少年班
機械手臂自動控制設計班
機器手臂簡介ppt
材料:meArm組件,馬達建議使用MG90S,不要選用SG90
下載一
下載二
0.依照教材進行組裝
1.使用可變電阻操控伺服馬達轉動角度
馬達接在數位腳位第9腳、可變電阻中間腳接類比腳位A0。
小心轉動可變電阻,透過監控視窗,逐一測試所有伺服馬達的可轉動範圍,並紀錄上下限。
Servo myservo;
int potpin = 0;
int val;
void setup()
{
Serial.begin(9600);// 開啟 Serial Port,通訊速率為 9600
myservo.attach(9); // Servo 接在 pin 9
}
void loop()
{
val = analogRead(potpin);
val = map(val, 0, 1023, 0, 179);
Serial.println(val);
myservo.write(val); // 設定 Servo 旋轉角度
delay(100); // 等待
}
2.使用單顆可變電阻測試操控四顆伺服馬達轉動角度
夾爪馬達接在數位腳位第2腳,底部馬達、左馬達、右馬達分別接在3、4、5腳,可變電阻中間腳接類比腳位A0。
將步驟1所量測到的馬達轉動範圍填入程式中,利用可變電阻測試四顆馬達的轉動順暢性。
Servo myservo_B;
Servo myservo_L;
Servo myservo_R;
Servo myservo_H;
int potpin = 0;
int val,val_B,val_L,val_R,val_H;
int B_min=10;//底部馬達最小角度
int B_max=175;//底部馬達最大角度
int L_min=110;//左馬達最大角度 (此處反著寫)
int L_max=40;//左馬達最小角度 (此處反著寫)
int R_min=60;//右馬達最小角度
int R_max=160;//右馬達最大角度
int H_min=80;//夾爪馬達最小角度
int H_max=145;//夾爪馬達最大角度
int dt=50;
void setup()
{
//Serial.begin(9600);// 開啟 Serial Port,通訊速率為 9600
//myservo_B.attach(3); // Servo 接在 pin 3
myservo_L.attach(4); // Servo 接在 pin 4
myservo_R.attach(5); // Servo 接在 pin 5
myservo_H.attach(2); // Servo 接在 pin 2
}
void loop()
{
val = analogRead(potpin);
val_B = map(val, 0, 1023, B_min, B_max);
val_L = map(val, 0, 1023, L_min, L_max);
val_R = map(val, 0, 1023, R_min, R_max);
val_H = map(val, 0, 1023, H_min, H_max);
//Serial.println(val);
myservo_B.attach(3); // Servo 接在 pin 3
myservo_B.write(val_B); // 設定 Servo 旋轉角度
myservo_L.write(val_L); // 設定 Servo 旋轉角度
myservo_R.write(val_R); // 設定 Servo 旋轉角度
myservo_H.write(val_H); // 設定 Servo 旋轉角度
delay(dt); // 等待
myservo_B.detach();
delay(100-dt);
}
3.使用雙搖桿測試操控四顆伺服馬達轉動角度
左搖桿的S-X接A0,控制底部馬達,S-Y接A1,控制左馬達。
預設馬達角度為為最大與最小的平均值。當搖桿移動時,馬達就跟著轉動到對應角度,放開時回復到預設角度。
Servo myservo_B;
Servo myservo_L;
Servo myservo_R;
Servo myservo_H;
int B = 0;//左S-X接A0,控制底部馬達
int L = 1;//左S-Y接A1,控制左馬達
int H = 2;//右S-X接A2,控制夾爪馬達
int R = 3;//右S-Y接A3,控制右馬達
int val,val_B,val_L,val_R,val_H;
int B_min=10;//底部馬達最小角度
int B_max=175;//底部馬達最大角度
int L_min=110;//左馬達最大角度 (此處反著寫)
int L_max=40;//左馬達最小角度 (此處反著寫)
int R_min=60;//右馬達最小角度
int R_max=160;//右馬達最大角度
int H_min=80;//夾爪馬達最小角度
int H_max=145;//夾爪馬達最大角度
int dt=50;
void setup()
{
//Serial.begin(9600);// 開啟 Serial Port,通訊速率為 9600
//myservo_B.attach(3); // Servo 接在 pin 3
myservo_L.attach(4); // Servo 接在 pin 4
myservo_R.attach(5); // Servo 接在 pin 5
myservo_H.attach(2); // Servo 接在 pin 2
}
void loop()
{
val = analogRead(B);
val_B = map(val, 0, 1023, B_min, B_max);
val = analogRead(L);
val_L = map(val, 0, 1023, L_min, L_max);
val = analogRead(R);
val_R = map(val, 0, 1023, R_min, R_max);
val = analogRead(H);
val_H = map(val, 0, 1023, H_min, H_max);
//Serial.println(val);
myservo_B.attach(3); // Servo 接在 pin 3
myservo_B.write(val_B); // 設定 Servo 旋轉角度
myservo_L.write(val_L); // 設定 Servo 旋轉角度
myservo_R.write(val_R); // 設定 Servo 旋轉角度
myservo_H.write(val_H); // 設定 Servo 旋轉角度
delay(dt); // 等待
myservo_B.detach();
delay(100-dt);
}
4.使用雙搖桿操控meArm
與步驟3接法一致,但搖桿偏移時,馬達逐步轉動,搖桿回復時,馬達停止轉動。
#include <Servo.h>
Servo myservo_B;
Servo myservo_L;
Servo myservo_R;
Servo myservo_H;
int B = 0;//左S-X接A0,控制底部馬達
int L = 1;//左S-Y接A1,控制左馬達
int H = 2;//右S-X接A2,控制夾爪馬達
int R = 3;//右S-Y接A3,控制右馬達
int val_b,val_l,val_r,val_h,val_B,val_L,val_R,val_H;
int db,dl,dr,dh;
int B_min=30;//底部馬達最小角度
int B_max=160;//底部馬達最大角度
int L_min=40;//左馬達最小角度
int L_max=110;//左馬達最大角度
int R_min=50;//右馬達最小角度
int R_max=150;//右馬達最大角度
int H_min=60;//夾爪馬達最小角度
int H_max=150;//夾爪馬達最大角度
int dt=15;
void setup()
{
//Serial.begin(9600);// 開啟 Serial Port,通訊速率為 9600
myservo_B.attach(3); // Servo 接在 pin 3
myservo_L.attach(4); // Servo 接在 pin 4
myservo_R.attach(5); // Servo 接在 pin 5
myservo_H.attach(2); // Servo 接在 pin 2
val_B=(B_min+B_max)/2;
val_L=(L_min+L_max)/2;
val_R=(R_min+R_max)/2;
val_H=(H_min+H_max)/2;
myservo_B.write(val_B); // 設定 Servo 旋轉角度
myservo_L.write(val_L); // 設定 Servo 旋轉角度
myservo_R.write(val_R); // 設定 Servo 旋轉角度
myservo_H.write(val_H); // 設定 Servo 旋轉角度
delay(dt); // 等待
myservo_B.detach();
delay(dt);
}
void loop()
{
val_b = analogRead(B);
if (val_b >= 912)
db=1;
else if (val_b <= 312)
db=-1;
else
db=0;
val_l = analogRead(L);
if (val_l >= 912)
dl=-1;
else if (val_l <= 312)
dl=1;
else
dl=0;
val_r = analogRead(R);
if (val_r >= 912)
dr=1;
else if (val_r <= 312)
dr=-1;
else
dr=0;
val_h = analogRead(H);
if (val_h >= 912)
dh=5;
else if (val_h <= 312)
dh=-5;
else
dh=0;
if ((val_B+db)>= B_min && (val_B+db)<= B_max)
val_B=val_B+db;
if ((val_L+dl)>= L_min && (val_L+dl)<= L_max)
val_L=val_L+dl;
if ((val_R+dr)>= R_min && (val_R+dr)<= R_max)
val_R=val_R+dr;
if ((val_H+dh)>= H_min && (val_H+dh)<= H_max)
val_H=val_H+dh;
//Serial.println(val);
myservo_B.attach(3); // Servo 接在 pin 3
myservo_B.write(val_B); // 設定 Servo 旋轉角度
myservo_L.write(val_L); // 設定 Servo 旋轉角度
myservo_R.write(val_R); // 設定 Servo 旋轉角度
myservo_H.write(val_H); // 設定 Servo 旋轉角度
delay(dt); // 等待
myservo_B.detach();
delay(dt);
}
5.音效下載
6. 0810-1
7. 0810-2
2017年4月30日 星期日
C# IPCAM
尚未使用emgu(open cv)進行影像處理