2014年3月25日 星期二

超音波傳感器記錄 Ultrasonic sensor data logging

利用陣列儲存每0.01秒的超音波值,當記錄結束後,使用左右鍵觀看資料。

It saves the ultrasonic sensor data with array per 0.01 seconds, and the left and right buttons can be used to view the data after the logging.

task main()
{
SetSensorUltrasonic(S4); //設定超音波感應器為 四 號
int value[100]; //設定要存 100 個值→編號 0~ 99
int i = 0;  //計數用變數

while(i < 100)//存 100 個值
 {
  value[i] = SensorUS(S4); //存當下的感應器值到變數第 i 個
  Wait(10);                //等0.01秒→結束迴圈後為 0.01*100 = 1 秒
  i++;                     //計數加一
 }

i = 0;                   //為顯示,計數歸零,從 0~7 開始顯示
while(1)
 {

  if(ButtonPressed(BTNLEFT,true))//按左鍵→顯示前 8 個值
   {
    if(i > 0)i--;// 沒有負的編號
   }
  else if(ButtonPressed(BTNRIGHT,true))//按右鍵→顯示後 8 個值
   {
    if(i < 13)i++;//每次八個→100除8 = 12...4→有十三頁
   }

//八個值,以第一次為但→i = 0→0,0+1,0+2,0+3,0+4,0+5,0+6,0+7 = 0,1,2,3,4,5,6,7
  NumOut(0,LCD_LINE1,value[i]);
  NumOut(0,LCD_LINE2,value[i+1],false);
  NumOut(0,LCD_LINE3,value[i+2],false);
  NumOut(0,LCD_LINE4,value[i+3],false);
  if(i<13)//每次八個→100除8 = 12...4→有十三頁,第十三頁只有四個值
   {
    NumOut(0,LCD_LINE5,value[i+4],false);
    NumOut(0,LCD_LINE6,value[i+5],false);
    NumOut(0,LCD_LINE7,value[i+6],false);
    NumOut(0,LCD_LINE8,value[i+7],false);
   }
 }
}

不使用「內建畫圓」來畫圓 Drawing a circle without "drawing circle command"

圓的方程式是:
座標 x 的平方+ 座標 y 的平方 = 半徑 r 的平方

而由三角函數定義,我們可以得知 x,y 可由角度代表,故我們個得圓的參數式為:

x = rcos(theta)、y = rsin(theta)

將其代入原式可得 
rcos(theta)平方 + rsin(theta)平方 = r平方

= r 平方(cos(theta)平方+sin(theta)平方)

 = r 平方

左式的 cos(theta)平方+sin(theta)平方 = 1,故左式=右式

使用 PointOut(x,y,options)去在螢幕上畫點

範例:

task main()
{

float thata = 0;

int r = 1;


while(theta < 2*PI)
{

PointOut(r*cos(theta),r*sin(theta),false);
theta = theta + 0.01;

}
while(1){}
}

2013年7月10日 星期三

輸入數字組 Inputting set of numbers

我們將輸入一組數字並顯示在螢幕上。應用左鍵作「減」、右鍵作「加」及中鍵作「確定」並利用陣列的方式來讓我們可以使用迴圈四次來輸入四個數字,最後使用螢幕顯示指令來將輸入結果輸出。

We will input a set of numbers and display the set.  We can apply the left button to be "minus", right button to be "plus" and center button to be "confirm".  We can use the array to let us to apply loop for 4 times to input 4 numbers and output the result with display command finally.

Example:  

task main()
{
int a[4]={0,0,0,0},i=0;
while(i<4)
{
while(!ButtonPressed(BTNCENTER,true))
{
if(ButtonPressed(BTNRIGHT,true))a[i]++;
if(ButtonPressed(BTNLEFT,true))a[i]--;
NumOut(i*10,0,a[i]);
}
while(ButtonPressed(BTNCENTER,true))
i++;
}
while(i>0)
{
NumOut(i*10,10,a[i]);
i--;
}
Wait(5000);
}

比例控制 Proportional control (P)

我們可以使用比例控制去讓機器人滑順地停止。概念是將電力和差距呈比例關係。差距是目標位置減現在位置(測量值)。電力大小為差距的大小的比例值而機器人移動方向為差距的正負。當差距等於零時,機器人靜止。當差距為正時,機器人向前。當差距為負時,機器人向後。我們使用角度感應器來測量差距。

電力式:電力 = 常數×差距 = 常數×(目標 - 測量) = K * (target - measurement)

We can use the Proportional control (P) to let the robot smooth stop.  The concept is that we can let the power be controlled proportionally by distance(error).  The distance is defined as the target position minus now position(measurement).  The magnitude of power is proportion of the magnitude of distance and The direction of the robot is the direction of distance.  If the distance is zero, the robot is static.  If the distance is positive, the robot moves forward.  If the distance is negative, the robot moves backward. We use degrees sensor to measure the distance.

The power formula is:  Power = constant × distance = K * (target - measurement)

Example:

task main()
{
int power,K,target,measurement;
K = 1;
target = 1000;
measurement = MotorRotationCount(OUT_A);
while(1)
{
measurement = MotorRotationCount(OUT_A);
power = K * (target - measurement);
OnFwd(OUT_AC,power);
}
}

2013年7月9日 星期二

Avoiding wall with ultrasonic

We can avoid the wall with touch sensor or ultrasonic sensor.  We can install a ultrasonic sensor on the front of a car.  When the sensor senses a wall, the car turns right to avoid the wall.


Example:

task main()
{
SetSensorUltrasonic(S1);
while(1)
{
if(SensorUS(S1) < 20)
{
OnFwd(OUT_A,100);
OnFwd(OUT_C,-100);
}
else
{
OnFwd(OUT_AC,100);
}
}

}

The tracking line car

We can create a car which can follow a line with light sensor.  The car moves right and the sensor installed on the left front of the car.  When the sensor senses the line, the car turns left to correct the direction.

Example:

task main()
{

SetSensorLight(S1);
while(1)
{
if(Sensor(S1)< 40)
{
OnFwd(OUT_A,-100);
OnFwd(OUT_C,100);
}
else
{
OnFwd(OUT_A,100);
OnFwd(OUT_C,80);
}
}

}

The avoiding wall car

We can use a touch sensor to avoid a wall.  A touch sensor can be installed on the front of a car. When the sensor touches a wall, the car turn right to avoid the wall.

Example:

task main()
{
SetSensorTouch(S1);
while(1)
{
if(Sensor(S1))
{
OnFwd(OUT_A,100);
OnRev(OUT_C,100);
}
else
{
OnFwd(OUT_AC,100);
}

}

}

2012年12月20日 星期四

Spin the car with NXC

Spin the car with NXC


Please building a basic car first.

We will let the car spin in this project by NXC. The basic method is letting the left motor and right motor turn inversely.  The function: OnFwd can control the motor to turn inversely by letting the power be negative.  In the example, we will let the motor A and C turn inversely for 1 second.

task main(){}, OnFwd(P,p), Wait(ms), Off(P) will be use in this project.

Example:


task main()
{
OnFwd(OUT_A,100);
OnFwd(OUT_C,-100);
Wait(1000);
Off(OUT_AC);
}

Car motion with NXC

Car motion with NXC

Please building a basic car before we write the code.

In this project, we will let the car forward for 1 second. This program will use the functions : task main(){}, OnFwd(Ports, Power), Wait(ms), Off(Ports).

task main(){}

This is the main function for a NXC program. The program begin from the function.

task main()
{

statements.

}

OnFwd(Port/s, Power)

This will control the car to forward if you build the orientation of motor as same as the NXC.
Ports: setting the port or ports (OUT_A,OUT_B,OUT_C,OUT_AB,OUT_AC,OUT_BC,OUT_ABC,) which you want to control.
Power: setting the power of the motor or motors.

OnFwd(Ports, Power)

Wait(ms)

This will let the car pause for the time which you set.

Wait(ms)

Off(Port/s)

This will turn off the motor or motors.
Ports: setting the port or ports (OUT_A,OUT_B,OUT_C,OUT_AB,OUT_AC,OUT_BC,OUT_ABC,) which you want to control.

Off(Ports)

Example:


task main()
{
OnFwd(OUT_AC,100);
Wait(1000);
Off(OUT_AC);
}

2012年5月4日 星期五

足球機器人 – 射門 Soccer Robot - Shoot


足球機器人  射門 Soccer Robot - Shoot

球門以障礙物作為守門員,所以是一個比較簡單的守門員,一臺機器人使用超音波感應器掃描,找到沒有守門員的地方後射門。



  
機器人機結構

機器人必須能夠掃描到沒有守門員的地方,所以裝超音波的地方必須可以旋轉或移動,射門的時候必須是與超音波同方向,所以機器人可以是一台車子再加上一個射門的裝置或直接用機器人撞球。

機器人程式

機器人的動作必須先向一個方向掃描,找到沒有守門員的地方,然後射門。

主程式

每一個機器人的程式內都必須有一個主工作(程式),這是啟動後第一個執行的程式,就像樹的主幹一樣主導整個程式。機器人可以多工處理(多個程式幾乎同時執行),「task」表示這是一個工作,「main()」表示為主工作,其他工作自定名稱,例如「second()」的second是這個工作的名稱,如同樹的其中一個分枝,大括弧{}內是這個工作的內容。

task main()
{
程式碼
}

等待Wait

程式會卡在「等待」這個指令,直到設定的毫秒數過去
Wait(毫秒);

範例:十秒後程式結束

task main()
{
Wait(10000);
}

資料型態 Data Type

機器人可以處理的資料型態,也就是資料的種類,一般有數值、字元等,數值又有可以放不同大小資料的型態。

型態
內容
關聯性
int
整數
-32768~32767
long
長整數
-2147483648~2147483647
float
浮點數(有小數點的數)
32bits
bool
布林值(邏輯值)
/
char
字元
8bits
string
字串
一串字元

範例:十秒後程式結束

task main()
{
Wait(10000);
}

運算

運算子(符號)
內容
關聯性
限制
範例
絕對值
n/a

abs(x)
回傳正負號
n/a

sign(x)
++, --
後置增/
只有變數
x++
++, --
前置增/
只有變數
++x
-

-x
~
位元 

~123
!
邏輯 

!x
*, /, %
乘、除、係數

x * y
+, -
加、減

x + y
<<, >>
位元移動左與右

x << 4
<, >, <=, >=
關係運算子

x < y
==, !=
等於、不等於(比較)

x == 1
&
位元 

x & y
^
位元 互斥或

x ^ y
|
位元 或

x | y
&&
邏輯 且

x && y
||
邏輯 或

x || y
?:
三元值

x==1 ? y : z

條件迴圈 while

當「條件」成立時重覆執行大括弧{}內的程式碼,例如條件是「還沒走十公分」而程式碼是「走」,機器人就會一直走,直到走了十公分,也就是「還沒走十公分」已經不對了。

while(條件)
{
程式碼
}

範例:走十秒後結束程式

task main()
{
Int a;
a = 0;
while(a < 10)
{
Wait(1000);
a = a + 1;
}
}

感應器

運用感應器時必須先設定哪個感應器接口連什麼感應器,這裡我們使用超音波感應器及角度感應器,而這次使用馬達內建的角度感應器,不用另外設定,可以直接使用讀取指令。

設定超音波感應器

設定一、二、三或四號為超音波感應器(Ultrasonic Sensor)
SetSensorUltrasonic(S1/S2/S3/S4);

範例:設定一號為超音為感應器(S1/S2/S3/S4=一號/二號/三號/四號)

因為S1是一號,所以在括弧中打上S1
SetSensrUltrasonic(S1);
其他還有觸碰感應器、光學感應器及聲音感應器等…
SetSensorTouch("port");/SetSensor("port", SENSOR_TOUCH);
SetSensorLight("port");
SetSensorSound("port");

讀取超音波感應器的值

讀取「感應器」一、二、三或四號的值
Sensor(S1/S2/S3/S4)


讀取「超音波感應器」一、二、三或四號的值
SensorUS(S1/S2/S3/S4)

範例:讀取在「一號」的超音波感應器的值

因為我們設定一號是超音波感應器,所以讀取一號的值就是讀超音波感應器的值。
SetSensrUltrasonic(S1);
SensorUS(S1);

讀取角度感應器的值

因為角度感應器的值從一啟動程式後就開始累計,不想使用累計值或為求保險就必須歸零。
ResetRotationCount(OUT_A/OUT_B/OUT_C);
讀取ABC的角度感應器值
MotorRotationCount(OUT_A/OUT_B/OUT_C);

範例:對 歸零後讀取 的值

若無錯誤,應是讀到「0
ResetRotationCount(OUT_A);
MotorRotationCount(OUT_A);

感應器應用範例 擊棒球

利用超音波感應器偵測球是否進入擊球區,當超音波感應器讀而小於六公分時表示進入擊球區,此時馬達轉動超過一百八十度後停止。

task main()
{
SetSensrUltrasonic(S1);
while(SensorUS(S1) > 6)
{
}
OnFwd(OUT_A,100);
ResetRotationCount(OUT_A);
while(MotorRotationCount(OUT_A) < 180)
{
}
}

*前後值比較

要找到障礙物,就必須不斷的比較「之前」測到的超音波值及「之後」測到的沼音波值,如果前比後小,就表示超音波的距離值由大到小,也就是從球門轉到障礙物的那一瞬間,這時就找到了障礙物的左邊界(此處是由左向右),而後比前小就代表從障礙物轉到球門的那一瞬間,此時找到了障礙物的右邊界。

dist0代表「前」值,dist1代表「後」值,deg0記錄「左邊界」,deg1記錄「右邊界」。

 
 





//找障礙物
 while(MotorRotationCount(OUT_A) < 180)//轉完這個角度後即是描完球門
 {
  //轉彎
  OnFwd(OUT_A,40);          //A
  OnRev(OUT_C,40);          //C
  //取得距離
  dist0 = SensorUS(S1);       //取得第一個值
  Wait(2);                  //等 毫秒
  dist1 = SensorUS(S1);       //第二個值
  //取得障礙物開始及結束位置
  if(dist1 < dist0)         //後比前小的話,就是找到障礙物的開始
  {
  deg0 = MotorRotationCount(OUT_A);//錄障礙物的開始
  }
  if(dist1 > dist0)
  {
  deg1 = MotorRotationCount(OUT_A);//錄障礙物的結束
  }
  
 }

 Off(OUT_AC);               //停止

射門

這時轉()回起點,此時因為已記錄了有障礙物的位置範圍,我們只要在程式寫「當超音波還在障礙物的位置範圍內就不射門」就可以達到在空處射門。

while(MotorRotationCount(OUT_A) < deg1 && MotorRotationCount(OUT_A) > deg0)//如果在障礙物範圍內就繼續轉
 {
 //反轉彎
 OnRev(OUT_A,40);          //C
 OnFwd(OUT_C,40);          //A
}

NXC 足球機器人射門範例

task main()
{
SetSensorUltrasonic(S1);  //設定 Port 1 是超音波感應器
int deg0,deg1,dist0,dist1; //找到障礙物的開始角度,找到障礙物的結束角度,前一個距離,後一個距離
ResetRotationCount(OUT_A);//Port A 角度感應器歸零
 //找障礙物
 while(MotorRotationCount(OUT_A) < 180)//轉完這個角度後即是描完球門
 {
  //轉彎
  OnFwd(OUT_A,40);          //A
  OnRev(OUT_C,40);          //C
  //取得距離
  dist0 = SensorUS(S1);       //取得第一個值
  Wait(2);                  //等 毫秒
  dist1 = SensorUS(S1);       //第二個值
  //取得障礙物開始及結束位置
  if(dist1 < dist0)         //後比前小的話,就是找到障礙物的開始
  {
  deg0 = MotorRotationCount(OUT_A);//錄障礙物的開始
  }
  if(dist1 > dist0)
  {
  deg1 = MotorRotationCount(OUT_A);//錄障礙物的結束
  }
  
 }

 Off(OUT_AC);               //停止
 while(MotorRotationCount(OUT_A) < deg1 && MotorRotationCount(OUT_A) > deg0)//如果在障礙物範圍內就繼續轉
 {
 //反轉彎
 OnRev(OUT_A,40);          //C
 OnFwd(OUT_C,40);          //A
 }
 Off(OUT_AC);             //停止
 //射門
 OnFwd(OUT_B,100);            //射門機構轉
 Wait(200);
 Off(OUT_B);
}