touchscreen calibration again

From: Andrew Zabolotny <zap_at_homelink.ru>
Date: Tue, 4 May 2004 13:58:16 +0400

On Tue, 04 May 2004 09:11:28 +0200
Michael Opdenacker <zumbi3_at_free.fr> wrote:

> However, that's quite difficult to achieve, as the touchscreen is still
> not very accurate in this area.
I was thinking a lot about the non-linearity of the h2200 touchscreen, and
came to the conclusion that unless there are tonns of different
non-linear touchscreens (and h2200' is the only one I know of as of today),
the linearization must be performed in the driver rather than in tslib. Adding
generic support for such touchscreens to tslib is a very complex task, it
would be rather easy to create a static array containing the curves that Alain
(if I'm not wrong) has put into that PDF and linearize the touchscreen in
accordance to those curves. After that, tslib and older progs can perform
calibration as usual, since they will see a rectangular field of coordinates.

Since WinCE seems to work fine with the five-point calibration scheme, I think
the shape of the top and bottom curves is quite standard amongst all iPAQ
221x's, so it can be hard-coded into the driver. The only unknowns are the
absolute values of the pen readings.

On one hand, since Alain's formulas seems to work more or less for everybody
here, it seems like the touchscreen parameters are quite steady amongst
different examplaires. On the other hand, we must be prepared to see 221x's
with largely biased values - who knows what will happen, and even the
parameters may change with time.

First, here's an idea how the linearization could be done:

First, we must approximate the top and bottom curves. Here's some ascii art
(use fixed font to view):

 Y
^
| B,____ __,C
| | ~~~~~~~~---------~~~~ |
| | |
| | |
| | |
| | |
| | |
| | |
| | _______ |
| A`-~~ ~~~~~~-----___ |
| ~~~'D X
+-------------------------------------->

First of all, we must bound the figure into a rectangle, which is basically
our target (e.g. our goal is to map any point from within the touchscreen to
a point within the embedding rectangle). This way:

   ,___________________________,
   | ~~~~~~~~---------~~~~ |
   | |
   | |
   | |
   | |
   | |
   | |
   | _______ |
   |-~~ ~~~~~~-----___ |
   '~~~~~~~~~~~~~~~~~~~~~~~~~~~'

We need the coordinates of the rectangle: Rx, Ry, Rw, Rh:

        Rx = min(Ax, Bx);
        Ry = min(Ay, Dy);
        Rw = max(Cx, Dx) - Rx;
        Rh = max(By, Cy) - Ry;

Also we need the width and height of the rectangle, it's obvious how to
compute it.

This rectangle is, probably, mostly constant amongst different 2210's so the
driver can come with these parameters already preset. However, I think it
would be good to have some way to change these parameters, say via sysfs.
It would need just four numbers: Rx, Ry, Rw and Rh. And there could be a
simple "fine-calibration" tool written specifically for 2210, perhaps based
on ts_calibrate, that could compute these numbers and put them into
/etc/sysctl.conf so that they will be loaded at each startup automatically.

The easiest way is to interpolate the curves with several linear segments,
something like this:

       2 3
   1 *_____* 4
  A*-~~ ~~~~~~--*--___ 5
                            ~~~*D

The segments 1-2, 2-3, 3-4, 4-5 are straight lines. Their slope can be
precalculated and put into some array. The whole curve has to be translated
and scaled so that vertices A and 1, D and 5 will coincide (in reality it
would be good to have at least 8-10 points per each curve, this will be
rewarded with higher precision).

Now let's see how we will map a point T from touchscreen area to the
normalized rectangle:
    1 2 5
  B*____* 3 4 __*C
   | ~~~~~~~*-------*~~~~ |
   | |
   | |
   | |
   | |
   | |
   | T |
   | * |
   | |
   | *_____* |
  A*-~~2 3~~~~~~--*--___ |
    1 4 ~~~*D
                              5

The algorithm would work as follows: First, it finds the relative Tx
coordinate in the range 0-1 (of course, all math should use fixed-point
integer arithmetic, 16.16 precision should be quite enough for this):

x = (Tx - Rx) / Rw
y = (Ty - Ry) / Rh

Now we find the segments on the top and bottom curves with the same X
(the curve points must use fixed-point coordinates in the range 0-1
as well):

for (int top = 0; top_curve [top].x < x; top++) ;
for (int bot = 0; bot_curve [bot].x < x; bot++) ;

Now find the respective Y on the top and bottom curves:

top_y = (x - top_curve [top].x) * (top_curve [top + 1].y - top_curve [top].y)
bot_y = (x - bot_curve [bot].x) * (bot_curve [bot + 1].y - bot_curve [bot].y)

(I hope you see that there's a lot that could be precomputed here in advance).
Now let's find the Y coordinate of the point in rectangle space (range 0-1):

y = (y - bot_y) / (top_y - bot_y);

Now find the X and Y coordinates of the T point in real coordinates:

Mx = Rx + Rw * x;
My = Ry + Rh * y;

Ugh, okay, I hope nobody felt asleep due to my shitty English and math.

--
Greetings,
   Andrew
Received on Tue May 04 2004 - 11:49:42 EDT

This archive was generated by hypermail 2.2.0 : Mon Jul 25 2005 - 17:19:27 EDT