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