This is part 2 of a 2 part series. For part 1 see: Image Pixels
In part 1 we discussed a method of attaining the values for the LED Index to Physical Position array when building a keyboard file for QMK that utilises the RGB Matrix feature set, using an image of the PCB. Now there would be several criticisms of this approach, and to be honest the opinions and assumptions that are citied in that method are, in the greater perspective, irrelevant. For example, the oval rotation (as apposed to true circular), would really not make a visual difference as the KB is not uniform - i.e. it's rectangular shape skews ones eye anyway, and even perfect circles would illusionary look oval anyway.
With that in mind - the thinking around centre is also debatable, since there are 2 axis' for centre: vertical and horizontal. For vertical, the fact that one sits at an angle to the KB would skew optically the centre anyway - so a slight variation, that be centre of the switch vs. the over or under offset of the LED - would not matter. Horizontally though, the centre could be a significant nuisance if not done correctly.
Given this, there is some leeway we can leverage to be able to use up the entire range of positional values... i.e. use the entire { 224, 64 }
resolution as per QMK Docs.
Herein I'll detail an approach I use to determine the coordinates of the LED positions that deliver rotational effects that look aligned and centred horizontally, and at the same time leverage the entire effect resolution offered by the QMK Matrix library.
For this one you will need to know the keycap widths of the keyboard you wish to measure for. For existing KB's this is easily sourced from either from the VIA file (find that on the https://github.com/the-via/keyboards repo.), or in the QMK Configurator keyboard file, usually in the QMK keyboards
folder under the KB name as the info.json
file.
You will also need access to a spreadsheet application (Excel, Numbers, G-Docs, whatever) - this will be a mathematical exercise.
For this tutorial I'll use the Keychron Q1 KB, as it has an offset navigation cluster that requires some additional explanation.
What we will need to do is map out both the keycap and the inter-key gaps on a linear scale, using the keycap "U" widths.
For example, for the F-Row you will have (note the gaps are added):
1 | 2 | 3 | .. | Sum |
---|---|---|---|---|
1 | 0.25 | 1 | .. | 16.25 |
The horizontal sum should be the total "U" length of the KB. Do this for each row... the lengths should all match (except when the keys don't align on both sides, as in row Shift-Z on the Q1). Don't worry too much if the column count is different, as some rows have more keys that others - the sanity check is that the total lengths are bound to the the same (in this case 16.25U).
You should also do a vertical row for the heights. With the Q1 the navigation arrows are offset slightly lower, so you'd also create a second column for that clusters heights (as depicted in the image below).
Once you have these you'll also need the grid resolution to U-width ratios. The formula for the X and Y multipliers are:
X = 224 / ( {total width} - 1 )
Y = 64 / ( {total height} - 1 )
For our Q1 X = 14.689, and Y = 11.636. (I've rounded to 3 decimals.)
Your sheet should look something like this:
Next we need to work towards the positional coordinates of the keys (think of it as "U"-coordinates). To do this one creates another table and then, for the column just copy the 1st key width. For the second column, use the prior column value, and add the width of the current column. Column 3 is a duplication for column 2, with the appropriate column shift.
Formula for the cells are:
1 | 2 | .. |
---|---|---|
=C3 |
=(D3)+C16 |
.. |
Giving you a progressive length (i.e. "U"-length from the left edge to the right edge of each key, for each row.
(For the sake of brevity, I'll not explain the Y-axis, but it's the same theory, except applied top-down, instead of right-to-left.)
Your sheet should now have a second table that looks like this:
The "U"-coordinates established in step two only give you the coordinates for the right edge of each key. We'd need to bring back the position the the centre of the individual keys (we're making an assumption that the LED is in the middle, this may not be true always, e.g. a stepped Caps-Lock).
Yup - you guessed it, another table. First column is the same-key "U"=width (from tbl.1) divided by 2.
The second (and subsequent) columns are: same-key "U"=width (from tbl.1) divided by 2, then add prior key progressive length (from tbl.2).
Formulas are:
1 | 2 | .. |
---|---|---|
=C3/2 |
=(D3/2)+C16 |
.. |
You should get this:
We're almost done... last step is getting the LED Index to Physical Position. This one is simple... just take the centred "U"-coordinates and multiply it with the grid resolution ratio. Two caveats:
- you also need to bring the point back by 1/2 "U" so that the middle of a 1U key starts at 0.
- Apply rounding to the result, since the coordinates are code "byte" types.
Formulas for table 4 are:
1 | 2 | .. |
---|---|---|
=(C26-0.5) * $W$12 |
=(D26-0.5) * $W$12 |
.. |
Your final table should look like this:
Then you have all the data to build the coordinate array, with the top-left coordinate at { 0, 0 }
and the bottom-right coordinate at { 224, 64 }
- a edge-to-edge use of the RGB Matrix ... matrix.
(Remember to ignore the gaps.)
Keychron Q1 LED Index to Physical Position array of the g_led_config
variable should look like this:
}, {
// LED Index to Physical Position
{0, 0}, {18, 0}, {33, 0}, {48, 0}, {62, 0}, {81, 0}, {95, 0}, {110, 0}, {125, 0}, {143, 0}, {158, 0}, {173, 0}, {187, 0}, {206, 0}, {224, 0},
{0, 15}, {15, 15}, {29, 15}, {44, 15}, {59, 15}, {73, 15}, {88, 15}, {103, 15}, {118, 15}, {132, 15}, {147, 15}, {162, 15}, {176, 15}, {198, 15}, {224, 15},
{4, 26}, {22, 26}, {37, 26}, {51, 26}, {66, 26}, {81, 26}, {95, 26}, {110, 26}, {125, 26}, {140, 26}, {154, 26}, {169, 26}, {184, 26}, {202, 26}, {224, 26},
{6, 38}, {26, 38}, {40, 38}, {55, 38}, {70, 38}, {84, 38}, {99, 38}, {114, 38}, {129, 38}, {143, 38}, {158, 38}, {173, 38}, {196, 38}, {224, 38},
{9, 49}, {33, 49}, {48, 49}, {62, 49}, {77, 49}, {92, 49}, {106, 49}, {121, 49}, {136, 49}, {151, 49}, {165, 49}, {185, 49}, {209, 49},
{2, 57}, {20, 57}, {39, 57}, {94, 57}, {147, 57}, {162, 57}, {176, 57}, {195, 64}, {209, 64}, {224, 64}
}, {
Before (top) and after (bottom) (with center guidelines drawn in) for comparison:
--made with ♡, Vino Rodrigues
Great job, and I found a easier way which is using the pick place data exported from EDA to acheive accurate key layout.
Here we get the final accrutae position date.
PS: Maybe we can write an app/script to extract the data from the .csv and generate C code and json automaticly, I will try when I get time.