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結果

(影片中仍是用較易卡住的三軸加速器)

https://www.youtube.com/watch?v=uZpjlJUO9o0