基本上,把撲克牌放兩邊,模擬我們人的手洗牌的樣子。
而機構本身利用輪胎來推進撲克牌至中間的凹槽,馬達轉動的速度無需過快,以免撲克牌卡紙而破壞了牌紙。
且程式也止不過幾行,其中主要用以啟動馬達轉動的程式碼:
OnFwd(OUT_AB,50);
以下是洗牌機的影片片段:
『電腦鼠從起點到終點所經過的所有途徑,記錄所經過的座標之後,自動篩選及簡化路徑,進而尋找最短途逕從起點直至終點。』
#define blue_tap1 3
#define blue_tap2 4
#define red_tap 9
#define factor 2
#define LMotor OUT_A
#define RMotor OUT_C
#define Motors OUT_AC
#define LightSensor1Port IN_1
#define LightSensor2Port IN_2
#define ColorSensorPort IN_4
int x[10];
int y[10];
int x_fix[10];
int y_fix[10];
int i,j,k=0;
int D;
int colornum;
int black,white,light1_value,light2_value;
int Lpower=0,Rpower=0;
long tick;
string code;
void WaitSEC3()
{
tick=CurrentTick();
while(CurrentTick()<(tick+3000))
{
PlayTone(880,50);
Wait(950);
}
Wait(1000);
}
void InitialLightSensor()
{
while(!ButtonPressed(BTNCENTER,false))
{
TextOut(0,LCD_LINE3,"Light at black..");
black=Sensor(LightSensor1Port);
}
ClearScreen();
Wait(1000);
while(!ButtonPressed(BTNCENTER,false))
{
TextOut(0,LCD_LINE3,"Light at white..");
white=Sensor(LightSensor1Port);
}
ClearScreen();
WaitSEC3();
}
void LoopAdjust()
{
for(i=0; i<ArrayLen(x); i++)
{
x_fix[k]=x[i];
y_fix[k]=y[i];
for(j=i; j<ArrayLen(x); j++)
{
if((x[j]==x[i])&&(y[j]==y[i]))
{
x_fix[i]=x[j];
y_fix[i]=y[j];
i=j;
}
}
k++;
}
}
void BotWalking()
{
light1_value=Sensor(LightSensor1Port);
Rpower=(light1_value-black)*factor;
Lpower=(white-light1_value)*factor;
OnFwd(LMotor,Lpower);
OnFwd(RMotor,Rpower);
}
void LightSensorTouchLine() //讓bot的兩個light往前推進一小步,直至壓線
{
tick=CurrentTick();
while(CurrentTick()<tick+800)
{
OnFwdSync(Motors,25,0);
}
}
void TireTouchLine(int n) //讓bot往前移動,直至前輪壓線
{
tick=CurrentTick();
while(CurrentTick()<tick+n)
{
OnFwd(LMotor,25);
OnFwd(RMotor,25);
}
}
void BotRightTurn() //讓bot右轉
{
LightSensorTouchLine();
Off(Motors);
Wait(SEC_1);
TireTouchLine(500);
tick=CurrentTick();
while(CurrentTick()<tick+2050)
{
OnFwd(LMotor,25);
OnFwd(RMotor,-25);
}
}
void BotLeftTurn() //讓bot左轉
{
LightSensorTouchLine();
Off(Motors);
Wait(SEC_1);
TireTouchLine(1400);
tick=CurrentTick();
while(CurrentTick()<tick+1600)
{
OnFwd(LMotor,-25);
OnFwd(RMotor,25);
}
}
void ShortLoopGo() //Result: (0,1)-->(-1,1)-->(-1,0)-->(-2,0)
{
string prev_axis="Y" ;
i=1;
while(i<=k)
{
colornum=SensorHTColorNum(ColorSensorPort);
//NumOut(0,LCD_LINE1,D);
if((colornum!=blue_tap1)||(colornum!=blue_tap2))
{
if(colornum==red_tap)
{
StopAllTasks();
}
BotWalking();
}
if((colornum==blue_tap1)||(colornum==blue_tap2))
{
Off(Motors);
Wait(SEC_1);
if((x_fix[i]-x_fix[i-1])!=0)
{
if(((x_fix[i]-x_fix[i-1])>0)&&(prev_axis=="Y"))
{
D=1;
}
if(((x_fix[i]-x_fix[i-1])>0)&&(prev_axis=="-Y"))
{
D=2;
}
if(((x_fix[i]-x_fix[i-1])<0)&&(prev_axis=="Y"))
{
D=3;
}
if(((x_fix[i]-x_fix[i-1])<0)&&(prev_axis=="-Y"))
{
D=4;
}
if(((x_fix[i]-x_fix[i-1])>0)&&(prev_axis=="-X"))
{
D=5;
}
if(((x_fix[i]-x_fix[i-1])<0)&&(prev_axis=="X"))
{
D=6;
}
}
if((y_fix[i]-y_fix[i-1])!=0)
{
if(((y_fix[i]-y_fix[i-1])>0)&&(prev_axis=="X"))
{
D=7;
}
if(((y_fix[i]-y_fix[i-1])>0)&&(prev_axis=="-X"))
{
D=8;
}
if(((y_fix[i]-y_fix[i-1])<0)&&(prev_axis=="X"))
{
D=9;
}
if(((y_fix[i]-y_fix[i-1])<0)&&(prev_axis=="-X"))
{
D=10;
}
if(((y_fix[i]-y_fix[i-1])>0)&&(prev_axis=="Y"))
{
D=11;
}
if(((y_fix[i]-y_fix[i-1])<0)&&(prev_axis=="-Y"))
{
D=12;
}
}
NumOut(0,LCD_LINE1,D);
switch(D)
{
case 1:
BotRightTurn();
prev_axis="-X";
break;
case 2:
BotLeftTurn();
prev_axis="-X";
break;
case 3:
BotLeftTurn();
prev_axis="X";
break;
case 4:
BotRightTurn();
prev_axis="X";
break;
case 5:
LightSensorTouchLine();
Off(Motors);
Wait(SEC_1);
TireTouchLine(500);
BotWalking();
prev_axis="-X";
break;
case 6:
LightSensorTouchLine();
Off(Motors);
Wait(SEC_1);
TireTouchLine(1400);
BotWalking();
prev_axis="X";
break;
case 7:
BotRightTurn();
prev_axis="Y";
break;
case 8:
BotLeftTurn();
prev_axis="Y";
break;
case 9:
BotLeftTurn();
prev_axis="-Y";
break;
case 10:
BotRightTurn();
prev_axis="-Y";
break;
case 11:
LightSensorTouchLine();
Off(Motors);
Wait(SEC_1);
TireTouchLine(500);
BotWalking();
prev_axis="Y";
break;
case 12:
LightSensorTouchLine();
Off(Motors);
Wait(SEC_1);
TireTouchLine(1400);
BotWalking();
prev_axis="-Y";
break;
}
i++;
}
}
Off(Motors);
}
task main()
{
SetSensorLowspeed(ColorSensorPort);
SetSensorLight(LightSensor1Port,true);
SetSensorLight(LightSensor2Port,true);
ArrayBuild(x,0,-1,-1,-1,-2,-2,-2,-1,-1,-2);
ArrayBuild(y,1, 1, 2, 3, 3, 2, 1, 1, 0, 0);
LoopAdjust();
InitialLightSensor();
while(!ButtonPressed(BTNCENTER,false));
ClearScreen();
ShortLoopGo();
}
#define LMotor OUT_A
#define RMotor OUT_C
#define Motors OUT_AC
#define LightSensor1Port IN_1
#define LightSensor2Port IN_2
#define ColorSensorPort IN_4
#define factor 2
#define black_tap 0
#define blue_tap1 3
#define blue_tap2 4
#define red_tap 9
int colornum; //彩色感應器讀值
int black,white,light1_value,light2_value; //光感器讀值
int Lpower=0,Rpower=0;
long tick=0;
//紀錄車子移動方位
int x=0,y=0;
int D=1; //初始放在y軸上
byte fileHandle;
short bytesWritten;
string str_log;
string str_x;
string str_y;
void InitialLightSensor()
{
while(!ButtonPressed(BTNCENTER,false))
{
TextOut(0,LCD_LINE3,"Light at black..");
black=Sensor(LightSensor1Port);
}
ClearScreen();
Wait(1000);
while(!ButtonPressed(BTNCENTER,false))
{
TextOut(0,LCD_LINE3,"Light at white..");
white=Sensor(LightSensor1Port);
}
ClearScreen();
tick=CurrentTick();
while(CurrentTick()<(tick+3000))
{
PlayTone(880,50);
Wait(950);
}
Wait(1000);
}
void BotWalking()
{
light1_value=Sensor(LightSensor1Port);
Rpower=(light1_value-black)*factor;
Lpower=(white-light1_value)*factor;
OnFwd(LMotor,Lpower);
OnFwd(RMotor,Rpower);
}
void LightSensorTouchLine() //讓bot的兩個light往前推進一小步,直至壓線
{
tick=CurrentTick();
while(CurrentTick(){
OnFwdSync(Motors,25,0);
}
}
void TireTouchLine(int n) //讓bot往前移動,直至前輪壓線
{
tick=CurrentTick();
while(CurrentTick(){
OnFwd(LMotor,25);
OnFwd(RMotor,25);
}
}
void BotRightTurn() //讓bot右轉
{
tick=CurrentTick();
while(CurrentTick(){
OnFwd(LMotor,25);
OnFwd(RMotor,-25);
}
}
void BotLeftTurn() //讓bot左轉
{
tick=CurrentTick();
while(CurrentTick(){
OnFwd(LMotor,-25);
OnFwd(RMotor,25);
}
}
void BotTurning()
{
Off(Motors);
Wait(1000);
LightSensorTouchLine();
Off(Motors);
Wait(1000);
light1_value=Sensor(LightSensor1Port);
light2_value=Sensor(LightSensor2Port);
colornum=SensorHTColorNum(ColorSensorPort);
if(light1_value>light2_value) //可右轉
{
TireTouchLine(500);
BotRightTurn();
D=D+1;
if(D>4) D=1;
}
if(light1_value<=light2_value) //可左轉
{
if(colornum==black_tap) //彩色感應器偵測到前方有黑線,可前行
{
BotWalking();
D=D;
}
if(colornum!=black_tap)
{
TireTouchLine(1400);
BotLeftTurn();
D=D-1;
if(D<1) D=4;
}
}
}
void AxisRecord()
{
if(D==1)
{
y=y+1;
}
if(D==2)
{
x=x+1;
}
if(D==3)
{
y=y-1;
}
if(D==4)
{
x=x-1;
}
str_x=NumToStr(x);
str_y=NumToStr(y);
str_log=str_x+" "+str_y;
WriteLnString(fileHandle,str_log,bytesWritten);
}
void IfEndTask()
{
Off(Motors);
tick=CurrentTick();
while(CurrentTick(){
PlayTone(880,20);
Wait(450);
}
AxisRecord();
StopAllTasks();
}
task main()
{
DeleteFile("DataLog.txt");
CreateFile("DataLog.txt",10000,fileHandle);
SetSensorLowspeed(ColorSensorPort);
SetSensorLight(LightSensor1Port,true);
SetSensorLight(LightSensor2Port,true);
InitialLightSensor();
}
task BotWalkTask()
{
Follows(main);
while(true)
{
colornum=SensorHTColorNum(ColorSensorPort);
if((colornum!=blue_tap1)||(colornum!=blue_tap2)) //判斷是否遇到叉路
{
if(colornum==red_tap)
{
IfEndTask();
}
BotWalking();
}
if((colornum==blue_tap1)||(colornum==blue_tap2))
{
AxisRecord();
BotTurning();
}
}
}
task main()
{
ResetRotationCount(OUT_A);
long readvalue=0;
long DesirePosition=180;
long err=0,prev_err=0;;
long cerr=0;
float S=0;
float Ud=0,Ueq=0;
int U=0;
byte fileHandle;
short bytesWritten;
DeleteFile("DataLog.txt");
CreateFile("DataLog.txt",10000,fileHandle);
string str_position;
string str_err;
string str_cerr;
string str_log;
while(!ButtonPressed(BTNCENTER,true))
{
str_position=NumToStr(readvalue);
str_err=NumToStr(err);
str_cerr=NumToStr(cerr);
str_log= str_position+" " +str_err+ " " +str_cerr;
WriteLnString(fileHandle,str_log,bytesWritten);
readvalue=MotorRotationCount(OUT_A);
err=DesirePosition-readvalue;
cerr=(err-prev_err);
S=0.7*(err)+(cerr);
prev_err=err;
if(S*err>0)
{
Ud=2*err;
}
if(S*err<0) { Ud=-2*err; } Ueq= -0.5*err; U=Ud+Ueq; if(U>100) U=100;
if(U<-100) U=-100; OnFwd(OUT_A,U); TextOut(0,LCD_LINE1,"degree="); NumOut(6*8,LCD_LINE1,readvalue); Wait(50); Off(OUT_A); ClearScreen(); } CloseFile(fileHandle); }
#define GyroScopePort IN_3
#define sample_size 100
#define GyroScale 4
#define t_scale 1e+6
//Define gyro offset parameters
float gyro_sum=0, gyro_avg=0;
int gyro_value=0;
int offset=0;
int i;
//Define Kalman filter parameter
float P=10; //Process state covariance
float Kgain; //The Kalman Filter Gain
float X_old=0;
float X_curr;
float Q=0.0001; //The Probability of process noise w ,P(w)~N(0,Q)
float R=0.1; //The Probability of measurement noise v, P(v)~N(0,R)
//Define BodyTiltTheta parameters
float theta=0,prev_theta=0;
float f1=0,f2=0;
float aa=0.001;
float theta_bias=0;
long prev_tick;
int KalmanFilter(int gyro_value)
{
X_curr=X_old;
P=P+Q;
Kgain=P/(P+R);
X_curr=X_curr+Kgain*(gyro_value-X_curr);
P=(1-Kgain)*P;
X_old=X_curr;
return (X_curr);
}
void CalcGyroOffset()
{
for(i=0;i<sample_size;i++)
{
gyro_value=SensorHTGyro(GyroScopePort);
gyro_sum+=gyro_value;
Wait(4);
}
gyro_avg=gyro_sum/sample_size;
offset=gyro_avg+0.5;
}
void ShowLCD()
{
TextOut(0,LCD_LINE1,"theta=");
NumOut(6*6,LCD_LINE1,theta-theta_bias);
Wait(20);
ClearScreen();
}
task main()
{
SetSensorHTGyro(GyroScopePort);
CalcGyroOffset();
prev_tick=CurrentTick();
while(true)
{
gyro_value=SensorHTGyro(GyroScopePort,offset);
f2=KalmanFilter(gyro_value)/GyroScale;
Wait(1);
theta=prev_theta+(f1+2*f2)*(CurrentTick()-prev_tick)/t_scale;
prev_theta=theta;
gyro_value=SensorHTGyro(GyroScopePort,offset);
f1=KalmanFilter(gyro_value)/GyroScale;
prev_tick=CurrentTick();
theta_bias=(1-aa)*theta_bias+aa*theta;
ShowLCD();
}
}