Midterm Project Report - Holapoya/ee240500 GitHub Wiki
平面地圖探測機模擬
Objective
在網頁上做出地圖,並且利用三軸加速器操控模擬的探測車去探索地圖。
方法概念
操控車子
參考了網路上一篇利用鍵盤操控車子移動的網頁code,將其融合上課用過的code,將觸發車子前進、轉彎的條件換成由三軸加速器傳進來的值,並下載適合的圖片調整大小後,放進移動的block,便可做出由三軸加速器控制車子的效果。控制方法為:
三軸加速器前傾 – 前進
三軸加速器直立 – 煞車
三軸加速器後仰 – 倒車
壓住三軸加速器觸控板右側 – 右轉
壓住三軸加速器觸控板左側 – 左轉
模擬車圖:
Key code
%刷新車子所在位置
function draw(){
context = canvas.getContext("2d");
context.clearRect(0, 0, 819, 460);
context.fillStyle = "rgb(255, 255, 255)";
context.fillRect(0, 0, 819, 460);
x_old =x;
y_old =y;
var backgroundImage = new Image();
backgroundImage.src = 'pic2.png';
context.drawImage(backgroundImage, 0, 0);
var angle_new = angle + anglemod*2;
var x_new = x_old + (speed*mod) * Math.cos(Math.PI/180 * angle);
var y_new = y_old + (speed*mod) * Math.sin(Math.PI/180 * angle);
var moveable;
moveable = canMoveTo(x_new, y_new, angle_new);
if (moveable == 1){
x = x_new;
y = y_new;
angle = angle_new;
}
context.moveTo(x_old,y_old);
// context.lineTo(x,y);
context.lineWidth = 5;
context.strokeStyle = '#3271e7';
context.lineCap = 'round';
context.stroke();
context.save();
context.translate(x, y);
context.rotate(Math.PI/180 * angle);
// context.drawImage(car, x, y);
var ratio = 1;
//context.drawImage(car, -(car.width*ratio/2), -(car.height*ratio/2),ratio*car.width,ratio*car.height);
context.drawImage(car, 0, 0);
context.restore();
}
%canMoveTo是判定車子可否繼續進行下一步動作的function,下面會在解釋,若moveable為1則正常刷新車子座標;若為0則座標不變
%mod、speed和angle是決定車子目前狀態(動作)的變數
%判定車子現在狀態(動作)
function threeaxis__handler(d1, d2, d3){
//Prepare new file name to get from
// serverAddress=serverAddressBase+requestCounter;
//alert('Debug'+serverAddress);
//Save data from json object to the arrays
GetJsonData();
// console.log(d1, d2, d3);
if(d1== 0)
{
mod = 1;
speed =0;
}
if(d1== 1)
{
mod = 1;
speed =3;
}
if(d1 == 2)
{
mod = -1;
speed =3;
}
var angle_new;
if(d2== 0)
{
anglemod = 0;
}
if(d2== 1)
{
anglemod = -1;
}
if(d2 == 2)
{
anglemod = 1;
}
}
%d1、d2、d3為三軸加速器傳回來的data,d1是0表示三軸加速器接近垂直,是1表示前傾、是2表示後仰
%d2和d3其實一樣,只用一個就好,d2是0表示三軸上觸控感應板沒偵測到壓力,是1表示觸控感應板左邊被壓、是2表示觸控感應板右邊被壓
傳回三軸加速器的角度和觸控板data
因為在我設計的操控當中不需用到data_x、data_y、data_z(三軸的加速度值),需要的是三軸加速器的角度和觸控板data(theta、data_TSI,這兩個值在原本的kl25_sensors.c中已有計算得出),故我修改了kl25_sensors.c的部分code,並且已用theta、data_TSI計算出控制車子需要的值,也就是上面用過的d1、d2,寫進xdata檔案裡,以便判定時取用。
Key code
theta = acos(trunc_norm(acc_z, acc_z_abs_max)) * 180 / PI;
if (data_TSI > 0.5) way = 1;
else if (data_TSI > 0) way = 2;
else way = 0;
if (theta < 45) go = 1;
else if (theta > 120) go = 2;
else go = 0;
#ifdef DEBUG
#endif
if (i != sample-1) {
fprintf(xdata_fp, "[%d, %d, %d],\n", go, way, way);
}
else { // Last sample does not need a trailing comma for JSON format
fprintf(xdata_fp, "[%d, %d, %d],\n", go, way, way);
}
%go是0表示三軸加速器接近垂直,是1表示前傾、是2表示後仰
%way是0表示三軸上觸控感應板沒偵測到壓力,是1表示觸控感應板左邊被壓、是2表示觸控感應板右邊被壓
遇到障礙的停止判定
每次在刷新車子座標之前都會先確認車子可不可以進到下一個位子,而判定的function canMoveTo,input為車子中心點的下次座標以及那時的角度,偵測車子下一次出現的位置上有沒有和障礙物(黑色)疊到,若有,則return 0,若無,則return 1。 ket code
function canMoveTo(destX, destY, destangle) {
var x_front1 = destX + (car.width-1) * Math.cos(Math.PI/180 * destangle);
var x_front2 = x_front1 - (car.height-1) * Math.sin(Math.PI/180 * destangle);
var x_back = destX - (car.height-1) * Math.sin(Math.PI/180 * destangle);
var y_front1 = destY + (car.width-1) * Math.sin(Math.PI/180 * destangle);
var y_front2 = y_front1 + (car.height-1) * Math.cos(Math.PI/180 * destangle);
var y_back = destY + (car.height-1) * Math.cos(Math.PI/180 * destangle);
side1x = [];
side1y = [];
side2x = [];
side2y = [];
side3x = [];
side3y = [];
side4x = [];
side4y = [];
for(var i=0;i<5;i+=1){
side1x[i] = destX + 0.2 * i * (car.width-1) * Math.cos(Math.PI/180 * destangle);
side1y[i] = destY + 0.2 * i * (car.width-1) * Math.sin(Math.PI/180 * destangle);
side2x[i] = x_front1 - 0.2 * i * (car.height-1) * Math.sin(Math.PI/180 * destangle);
side2y[i] = y_front1 + 0.2 * i * (car.height-1) * Math.cos(Math.PI/180 * destangle);
side3x[i] = x_front2 - 0.2 * i * (car.width-1) * Math.cos(Math.PI/180 * destangle);
side3y[i] = y_front2 - 0.2 * i * (car.width-1) * Math.sin(Math.PI/180 * destangle);
side4x[i] = x_back + 0.2 * i * (car.height-1) * Math.sin(Math.PI/180 * destangle);
side4y[i] = y_back - 0.2 * i * (car.height-1) * Math.cos(Math.PI/180 * destangle);
// console.log("pp",line1y[i],p2y-p4y,i);
}
var canMove = 1;
var imgData1;
var imgData2;
var imgData3;
var imgData4;
var data1;
var data2;
var data3;
var data4;
for(var i=0;i<5;i+=1){
imgData1 = context.getImageData(side1x[i], side1y[i], 1, 1);
data1 = imgData1.data;
imgData2 = context.getImageData(side2x[i], side2y[i], 1, 1);
data2 = imgData2.data;
imgData3 = context.getImageData(side3x[i], side3y[i], 1, 1);
data3 = imgData3.data;
imgData4 = context.getImageData(side4x[i], side4y[i], 1, 1);
data4 = imgData4.data;
if (data1[0] === 0 && data1[1] === 0 && data1[2] === 0){
canMove = 0;
break;
}
if (data2[0] === 0 && data2[1] === 0 && data2[2] === 0){
canMove = 0;
break;
}
if (data3[0] === 0 && data3[1] === 0 && data3[2] === 0){
canMove = 0;
break;
}
if (data4[0] === 0 && data4[1] === 0 && data4[2] === 0){
canMove = 0;
break;
}
}
return canMove;
}
自己設計的地圖:
使用的設備及工具
Nitrogen6x board
3-axis accelerometers
C語言
Javascript
遇到的問題
一開始在測試的時候車子常常會時不時的不聽使喚,而三軸加速器也常常取data取到一半就卡住了,但是後來借了同學的三軸加速器就變得順暢許多,也可以成功長時間控制車子了。
Demo結果
(影片中仍是用較易卡住的三軸加速器)