4

我正在從一個項目中獲得電阻式觸摸屏的模擬值並將它們轉換爲交點。轉換交點區域以生成座標

下面是一個例子:enter image description here

這裏是我使用一個Arduino UNO和點的建設使用的工具,叫做處理的數據集合的代碼。

#define side1 2 
#define side2 3 
#define side3 4 
#define side4 5 
#define contact A0 

void setup() { 
    pinMode(contact, INPUT); 
    pinMode(side1, OUTPUT); 
    pinMode(side2, OUTPUT); 
    pinMode(side3, OUTPUT); 
    pinMode(side4, OUTPUT); 
    Serial.begin(9600); 
} 

void loop() { 
    int sensorValue1; 
    int sensorValue2; 
    int sensorValue3; 
    int sensorValue4; 

    // SENSOR VALUE 1: 
    digitalWrite(side1, LOW); 
    digitalWrite(side2, HIGH); 
    digitalWrite(side3, HIGH); 
    digitalWrite(side4, HIGH); 
    delay(5); 
    for (int i = 0; i < 10; i++){ 
    sensorValue1 = analogRead(contact); 
    } 


    // SENSOR VALUE 2: 
    digitalWrite(side2, LOW); 
    digitalWrite(side3, HIGH); 
    digitalWrite(side4, HIGH); 
    digitalWrite(side1, HIGH); 
    delay(5); 
    for (int i = 0; i < 10; i++){ 
    sensorValue2 = analogRead(contact); 
    } 


    // SENSOR VALUE 3: 
    digitalWrite(side3, LOW); 
    digitalWrite(side2, HIGH); 
    digitalWrite(side4, HIGH); 
    digitalWrite(side1, HIGH); 
    delay(5); 
    for (int i = 0; i < 10; i++){ 
    sensorValue3 = analogRead(contact); 
    } 


    // SENSOR VALUE 2: 
    digitalWrite(side4, LOW); 
    digitalWrite(side3, HIGH); 
    digitalWrite(side2, HIGH); 
    digitalWrite(side1, HIGH); 
    delay(5); 
    for (int i = 0; i < 10; i++){ 
    sensorValue4 = analogRead(contact); 
    } 

    Serial.print(sensorValue1); 
    Serial.print(","); 
    Serial.print(sensorValue2); 
    Serial.print(","); 
    Serial.print(sensorValue3); 
    Serial.print(","); 
    Serial.print(sensorValue4); 
    Serial.println(); 
} 

這是用於構建圖的處理代碼。

import processing.serial.*; 


Serial myPort; // The serial port 
int maxNumberOfSensors = 4; 
float[] sensorValues = new float[maxNumberOfSensors]; 
float sensorValueX; 
float sensorValueX1; 
float sensorValueY; 
float sensorValueY1; 
int scaleValue = 2; 

void setup() { 
    size(600, 600); // set up the window to whatever size you want 
    //println(Serial.list()); // List all the available serial ports 
    String portName = "COM5"; 
    myPort = new Serial(this, portName, 9600); 
    myPort.clear(); 
    myPort.bufferUntil('\n'); // don't generate a serialEvent() until you get a newline (\n) byte 
    background(255); // set inital background 
    smooth(); // turn on antialiasing 
} 


void draw() { 
    //background(255); 
    //noFill(); 
    fill(100,100,100,100); 
    ellipse(height,0, scaleValue*sensorValues[0], scaleValue*sensorValues[0]); 

    ellipse(0,width, scaleValue*sensorValues[1], scaleValue*sensorValues[1]); 
    ellipse(height,width, scaleValue*sensorValues[2], scaleValue*sensorValues[2]); 
    ellipse(0,0, scaleValue*sensorValues[3], scaleValue*sensorValues[3]); 
    //ellipse(sensorValueY, sensorValueX, 10,10); 
    //println(sensorValueY,sensorValueX); 
    sensorValueX = ((sensorValues[3]*sensorValues[3])-(sensorValues[2]*sensorValues[2])+600*600)/2000; 
    sensorValueX1 = ((sensorValues[0]*sensorValues[0])-(sensorValues[1]*sensorValues[1])+600*600)/2000; 
sensorValueY = ((sensorValues[3]*sensorValues[3])-(sensorValues[2]*sensorValues[2])+(600*600))/2000; 
    sensorValueY1 = ((sensorValues[1]*sensorValues[1])-(sensorValues[0]*sensorValues[0])+(600*600))/2000; 

    line(0, scaleValue*sensorValueX, height,scaleValue* sensorValueX); 
    line(scaleValue*sensorValueY, 0, scaleValue*sensorValueY, width); 
    ellipse(scaleValue*sensorValueY, scaleValue*sensorValueX, 20,20); 
    line(0, scaleValue*sensorValueX1, height,scaleValue* sensorValueX1); 
    line(scaleValue*sensorValueY1, 0, scaleValue*sensorValueY1, width); 
    ellipse(scaleValue*sensorValueY1, scaleValue*sensorValueX1, 20,20); 
    println(scaleValue*sensorValueX,scaleValue*sensorValueY); 
} 


void serialEvent (Serial myPort) { 
    String inString = myPort.readStringUntil('\n'); // get the ASCII string 

    if (inString != null) { // if it's not empty 
    inString = trim(inString); // trim off any whitespace 
    int incomingValues[] = int(split(inString, ",")); // convert to an array of ints 

    if (incomingValues.length <= maxNumberOfSensors && incomingValues.length > 0) { 
     for (int i = 0; i < incomingValues.length; i++) { 
     // map the incoming values (0 to 1023) to an appropriate gray-scale range (0-255): 

     sensorValues[i] = map(incomingValues[i], 0, 1023, 0, width); 
     //println(incomingValues[i]+ " " + sensorValues[i]); 
     } 
    } 
    } 
} 

我想知道如何將這些點的交點轉換爲座標?例如:在圖像中,我向您展示了,我將尺寸參數設置爲(600,600)。是否有可能將該交點更改爲座標值?目前,我的代碼正在打印座標,但它們是對角線,例如在x和y值相等。我希望x和y的座標具有不同的數量,這樣我就可以獲得正方形中不同邊的座標。有人可以幫忙嗎?

+0

所以,你基本上想要做[trilateration](https://en.wikipedia.org/wiki/Trilateration)與四個網站? –

+1

你好,我看着三邊測量,我認爲這就是我要如何解決問題。你能幫忙嗎? – marshmellooooooos

+0

要回答你的問題,我們需要更多的細節。你在Arduino中得到的是什麼意思('sensorValue1' - 'sensorValue4')?這是壓力嗎?如果是的話在哪些地方?什麼是規模?不只是[0-1],而是0.5的意思(是線性的,對數等)?也許你有一些你使用的硬件(觸摸屏)的參考資料/手冊。如果不知道這些值**完全**意味着不可能將它們恰當地聚合到任何你想要的。 – SergGr

回答

2

通過閱讀您的代碼,我假設您知道所有n個傳感器的位置以及從每個n傳感器到目標的距離。所以你基本上試圖做的是trilateration(如Nico Schertler所提到的)。換句話說,基於n個點之間的距離來確定相對位置。

只是一個快速的定義筆記在混亂的情況下:

工作三邊至少需要3分和距離。

  • 1傳感器給你的目標是從傳感器
  • 2傳感器給你2個可能的位置遠的距離的目標可以是
  • 3個傳感器告訴您該2個地點的目標是在

可能想到的第一個解決方案是計算3個傳感器之間的交點 ,將它們視爲圓。鑑於距離可能存在一些誤差,這意味着圓圈可能不總是相交。這排除了這個解決方案。

以下代碼已在Processing中完成。

我冒昧做了一個class Sensor

class Sensor { 
    public PVector p; // position 
    public float d; // distance from sensor to target (radius of the circle) 

    public Sensor(float x, float y) { 
     this.p = new PVector(x, y); 
     this.d = 0; 
    } 
} 

現在計算並接近傳感器/圓之間的交叉點,請執行下列操作:

PVector trilateration(Sensor s1, Sensor s2, Sensor s3) { 
    PVector s = PVector.sub(s2.p, s1.p).div(PVector.sub(s2.p, s1.p).mag()); 
    float a = s.dot(PVector.sub(s3.p, s1.p)); 

    PVector t = PVector.sub(s3.p, s1.p).sub(PVector.mult(s, a)).div(PVector.sub(s3.p, s1.p).sub(PVector.mult(s, a)).mag()); 
    float b = t.dot(PVector.sub(s3.p, s1.p)); 
    float c = PVector.sub(s2.p, s1.p).mag(); 

    float x = (sq(s1.d) - sq(s2.d) + sq(c))/(c * 2); 
    float y = ((sq(s1.d) - sq(s3.d) + sq(a) + sq(b))/(b * 2)) - ((a/b) * x); 

    s.mult(x); 
    t.mult(y); 

    return PVector.add(s1.p, s).add(t); 
} 

s1s2s3是你的任何3個傳感器,執行以下操作來計算給定傳感器之間的交點:

PVector target = trilateration(s1, s2, s3); 

雖然有可能計算t他在任何量的傳感器之間交叉。您想要包含的傳感器越多,它就越複雜。特別是因爲你自己做。如果你能夠使用外部Java庫,那麼它會容易得多。

如果您能夠使用外部Java庫,那麼我強烈建議使用com.lemmingapex.trilateration。然後,你可以這樣做,計算4個傳感器之間的交叉點:

考慮s1s2s3s4如先前提到的實例class Sensor

double[][] positions = new double[][] { { s1.x, s1.y }, { s2.x, s2.y }, { s3.x, s3.y }, { s4.x, s4.y } }; 
double[] distances = new double[] { s1.d, s2.d, s3.d, s4.d }; 

NonLinearLeastSquaresSolver solver = new NonLinearLeastSquaresSolver(
      new TrilaterationFunction(positions, distances), 
      new LevenbergMarquardtOptimizer()); 
Optimum optimum = solver.solve(); 

double[] target = optimum.getPoint().toArray(); 
double x = target[0]; 
double y = target[1]; 

下面的實施例,是trilateration()方法我寫和不高於所述庫的示例的實施例。

實施例1 - 無傳感器錯誤

3個大圓圈是任何3個傳感器和單個紅色圓圈是近似點。

Example 1

實施例2 - 用傳感器錯誤

3個大圓圈是任何3個傳感器和單個紅色圓圈是近似點。

Example 2

+1

感謝您的評論,但問題是我有4個傳感器。另外,當我獲得值時,x和y值完全相同,這是我卡住的部分。我只能得到對角線值。所以基本上我的觸摸板幾乎不可能起牀,下來,左右。 – marshmellooooooos

+0

@marshmellooooooos看看我的編輯。 – Vallentin

+1

我將整合您的代碼並查看它是否有效。同時你可以看看我創建的這個視頻嗎?它向你展示了我的觸控板目前的工作原理。 [我的觸摸板視頻](https://www.youtube.com/watch?v=q4ptAQQpeBo)和 [視頻的第二部分](https://www.youtube.com/watch?v=Oq1ik9o- Zbs) – marshmellooooooos

0

你需要計算要點是什麼,它最接近的一組圓, 讓由(X1,Y1),(X2,Y2)表示其中心(X3,Y3) ,(x4,y4)及其半徑r1,r2,r3,r4。

你想找到(X,Y),最大限度地減少

F(X,Y)= Sum_i [方(D2((X,Y),(XI,YI)) - RI)]

這可以通過使用Newton's algorithm來實現。牛頓算法的工作原理是從「初步猜測」(假設在屏幕中心)開始,通過求解一系列線性系統(在這種情況下,有兩個變量,易於求解)迭代地改進。 MP = -G

其中M是F的二階導數的(2×2)矩陣相對於x和y(稱爲Hessian的),和G與F的一階導數的向量 尊重x和y(梯度)。這給出了指示如何移動座標的「更新」向量P:

然後(x,y)通過x = x + Px,y = y + Py等更新等等(重新計算M和G,求解P,更新x和y,重新計算M和G,求解P,更新x和y)。在你的情況下,它可能會收斂在少數幾次迭代中。

由於您只有兩個變量,因此2x2線性求解很簡單,而且F及其派生的表達式很簡單,因此您可以在不需要外部庫的情況下實現它。

注1:在對方的回答中提到的Levenberg-Marquardt算法是牛頓算法的一個變種(專門用於平方和,喜歡這裏,並且忽略了一些條款,並通過添加少量的規則化的矩陣M到其對角線係數)。 More on this here

注2:簡單gradient descent也可能會工作(有點容易實現,因爲它僅使用一階導數),但考慮到你只有一兩個變量來實現,2x2的線性解決的是微不足道的,所以牛頓可能是值得的(如果你的系統是交互式的話,要求迭代數量少得多)。

+1

我該如何執行此操作?是否有內置函數? – marshmellooooooos

+1

到目前爲止,我有這麼多的計算,但有語法問題。我使用的是levenberg-marquardt算法,但是此時有3點。 http://pastebin.com/CMCd9XTQ – marshmellooooooos

+0

不需要內建函數,它只是幾行代碼(一旦正式計算完成),我將嘗試做計算並擴展我的答案一個簡單的C函數.. – BrunoLevy