<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://belouadi.com/feed.xml" rel="self" type="application/atom+xml"/><link href="https://belouadi.com/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-06-09T19:26:20+00:00</updated><id>https://belouadi.com/feed.xml</id><title type="html">blank</title><subtitle>Jonas Belouadi&apos;s Homepage</subtitle><entry><title type="html">Reinforcement Learning from Self-Feedback for Graphics Program Synthesis</title><link href="https://belouadi.com/blog/2025/rlsf/" rel="alternate" type="text/html" title="Reinforcement Learning from Self-Feedback for Graphics Program Synthesis"/><published>2025-06-26T00:00:00+00:00</published><updated>2025-06-26T00:00:00+00:00</updated><id>https://belouadi.com/blog/2025/rlsf</id><content type="html" xml:base="https://belouadi.com/blog/2025/rlsf/"><![CDATA[<p><a href="https://github.com/potamides/DeTikZify">DeTi<i>k</i>Zify</a> is a family of multimodal large language models that automatically convert hand-drawn sketches or images of existing scientific figures into editable, semantics-preserving Ti<em>k</em>Z graphics programs. It aims to simplify the process of creating and editing high-quality scientific figures, which traditionally is time-consuming and challenging. Here is an example workflow showing how to interact with the model:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <iframe src="https://github.com/potamides/DeTikZify/assets/53401822/203d2853-0b5c-4a2b-9d09-3ccb65880cd3" class="img-fluid rounded z-depth-1 video-16-9" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" width="auto" height="auto"/> </figure> </div> </div> <h2 id="background">Background</h2> <p>The video also showcases an iterative inference algorithm based on <a href="https://en.wikipedia.org/wiki/Monte_Carlo_tree_search">Monte Carlo Tree Search</a> (MCTS), which enables DeTi<em>k</em>Zify to continuously refine its outputs without additional training. The reward scores required by MCTS are computed entirely using DeTi<em>k</em>Zify’s vision encoder, by visually assessing the similarity between input figures and compiled generated outputs. External reward models are not only unnecessary but often have lower correlations with human judgments, as the vision encoder was fine-tuned end-to-end with the entire model, optimizing it for evaluating this specific task. We refer readers to the <a href="https://arxiv.org/abs/2405.15306">DeTi<i>k</i>Zify</a> and <a href="https://arxiv.org/abs/2503.11509">Ti<i>k</i>Zero</a> papers for further details. These self-computed rewards have been effective in enhancing model outputs during <em>inference</em>. With reinforcement learning algorithms like <a href="https://arxiv.org/abs/2402.03300">Group Relative Policy Optimization</a>, this reward signal could also be used for the model to improve itself during a <em>post-training step</em>, i.e., reinforcement learning from self-feedback (RLSF). In this post, we investigate how post-training <a href="https://huggingface.co/nllg/detikzify-v2-8b">DeTi<i>k</i>Zify<sub>v2</sub></a>, the previously state-of-the-art DeTi<em>k</em>Zify model, improves performance. We call the resulting model <a href="https://huggingface.co/nllg/detikzify-v2.5-8b">DeTi<i>k</i>Zify<sub>v2.5</sub></a>.</p> <h2 id="model-training">Model Training</h2> <p>Our post-training setup does only require figures, and does not require aligned code as in supervised fine-tuning, granting us more flexibility in selecting training data. 50% of the training data comes from the subset of <a href="https://huggingface.co/datasets/nllg/datikz-v3">DaTikZ<sub>v3</sub></a>, that was filtered out during the training of DeTi<em>k</em>Zify<sub>v2</sub>. The remaining 50% is sampled from the <a href="https://huggingface.co/datasets/google/spiqa">SPIQA</a> dataset, which contains image labels for figures extracted from <a href="https://arxiv.org">arXiv</a>. We exclude all figures from papers included in DaTikZ<sub>v3</sub>. We sample this split so that 60% of these figures are labeled as schematics, 20% as plots, and 20% come from other categories. Since these figures are not necessarily created from Ti<em>k</em>Z, they may aid in enhancing the model’s generalization capabilities. As with DeTi<em>k</em>Zify<sub>v2</sub>, input figures are randomly converted into synthetic sketches using image transformations and <a href="https://huggingface.co/nllg/ultrasketch">UltraSketch</a>. Using this dataset, we post-train DeTi<em>k</em>Zify<sub>v2</sub> with RLSF, employing a batch size of 16. For each image, 32 outputs are generated, resulting in the model being trained on 512 outputs per step. We train for a total of 500 steps which takes 5 days to complete on eight Nvidia H200 GPUs. We keep the vision encoder frozen to mitigate reward hacking.</p> <h2 id="experiments-and-results">Experiments and Results</h2> <p>We evaluate DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) on the test split of DaTi<em>k</em>Z<sub>v3</sub> and compare it to DeTi<em>k</em>Zify<sub>v2</sub> (8b). The metrics employed include DreamSim (DSim), Kernel Inception Distance (KID), CrystalBLEU (cBLEU), TeX Edit Distance (TED), Mean Token Efficiency (MTE), and Mean Sampling Throughput (MST). Refer to the <a href="https://arxiv.org/abs/2405.15306">DeTi<i>k</i>Zify</a> paper for further details. All scores except MST are multiplied by 100.</p> <h3 id="sampling-based-inference">Sampling-based Inference</h3> <table class="table table-sm"> <caption> Results for sampling-based inference. Arrows indicate metric directionality. Overall, DeTi<i>k</i>Zify<sub>v2.5</sub> demonstrates the best performance. </caption> <thead> <tr> <th></th> <th colspan="5">Reference Figures</th> <th colspan="5">Synthetic Sketches</th> </tr> <tr> <th>Model</th> <th>DSim<sub>&uarr;</sub></th> <th>KID<sub>&darr;</sub></th> <th>cBLEU<sub>&uarr;</sub></th> <th>TED<sub>&darr;</sub></th> <th>MTE<sub>&uarr;</sub></th> <th>DSim<sub>&uarr;</sub></th> <th>KID<sub>&darr;</sub></th> <th>cBLEU<sub>&uarr;</sub></th> <th>TED<sub>&darr;</sub></th> <th>MTE<sub>&uarr;</sub></th> </tr> </thead> <tbody> <tr> <td>DeTi<i>k</i>Zify<sub>v2</sub> (8b)</td> <td>80.503</td> <td>0.626</td> <td><b>6.105</b></td> <td>54.946</td> <td>93.326</td> <td>74.584</td> <td>0.751</td> <td><b>3.356</b></td> <td>58.32</td> <td>93.858</td> </tr> <tr> <td>DeTi<i>k</i>Zify<sub>v2.5</sub> (8b)</td> <td><b>84.6438</b></td> <td><b>0.298</b></td> <td>4.202</td> <td><b>52.939</b></td> <td><b>100</b></td> <td><b>78.257</b></td> <td><b>0.577</b></td> <td>1.551</td> <td><b>56.121</b></td> <td><b>100</b></td> </tr> </tbody> </table> <p>In sampling-based inference (i.e., accepting the first output that compiles successfully) using reference figures and synthetic sketch inputs, DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) outperforms DeTi<em>k</em>Zify<sub>v2</sub> (8b) on most metrics, demonstrating that RLSF can effectively enhance performance. The considerably increased DreamSim scores indicate that DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) generates outputs that are much more visually similar to the reference figures. Furthermore, it is much less likely to produce outputs that do not compile, as evidenced by its perfect MTE score. Interestingly, while it scores lower on the code-based metric CrystalBLEU, it performs better on the code-based TED. DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) tends to generate more concise programs with less syntactic noise. While this likely reduces the n-gram overlap with the reference code, it also decreases the number of edits necessary to convert one into another, explaining this phenomenon. Generally, more concise programs are beneficial as long as the semantics are preserved.</p> <h3 id="mcts-based-inference">MCTS-based Inference</h3> <table class="table table-sm"> <caption> Results for MCTS-based inference. Arrows indicate metric directionality. Overall, DeTi<i>k</i>Zify<sub>v2.5</sub> demonstrates the best performance. </caption> <thead> <tr> <th></th> <th colspan="5">Reference Figures</th> <th colspan="5">Synthetic Sketches</th> </tr> <tr> <th>Model</th> <th>DSim<sub>&uarr;</sub></th> <th>KID<sub>&darr;</sub></th> <th>cBLEU<sub>&uarr;</sub></th> <th>TED<sub>&darr;</sub></th> <th>MST<sub>&uarr;</sub></th> <th>DSim<sub>&uarr;</sub></th> <th>KID<sub>&darr;</sub></th> <th>cBLEU<sub>&uarr;</sub></th> <th>TED<sub>&darr;</sub></th> <th>MST<sub>&uarr;</sub></th> </tr> </thead> <tbody> <tr> <td>DeTi<i>k</i>Zify<sub>v2</sub> (8b)</td> <td>89.020</td> <td>0.016</td> <td><b>6.593</b></td> <td>52.466</td> <td>52.723</td> <td>81.482</td> <td><b>0.313</b></td> <td><b>3.344</b></td> <td>56.405</td> <td>53.586</td> </tr> <tr> <td>DeTi<i>k</i>Zify<sub>v2.5</sub> (8b)</td> <td><b>90.889</b></td> <td><b>-0.047</b></td> <td>4.646</td> <td><b>51.824</b></td> <td><b>68.12</b></td> <td><b>83.74</b></td> <td>0.61</td> <td>1.976</td> <td><b>55.239</b></td> <td><b>78.908</b></td> </tr> </tbody> </table> <p>We observe similar trends when using our MCTS-based inference algorithm with a time budget of 10 minutes. Compared to sampling-based inference, DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) noticeably improves its scores, illustrating that MCTS on top of RLSF can still lead to additional gains. Additionally, within the same timeframe, DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) generates 25 more outputs than DeTi<em>k</em>Zify<sub>v2</sub> (8b), supporting our hypothesis that the generated programs are more concise. On reference figures, DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) scores better on both DreamSim and KID, with the KID score even being slightly negative due to the high similarity of distributions. For synthetic sketches, it achieves a higher DreamSim score but performs worse on KID, indicating a prioritization of faithfulness to the reference figure over just focusing on general aesthetics.</p> <h3 id="inference-with-tikzero-adapters">Inference with Ti<em>k</em>Zero Adapters</h3> <table class="table table-sm"> <caption> Results for sampling-based inference with Ti<i>k</i>Zero adapters. Arrows indicate metric directionality. </caption> <thead> <tr> <th></th> <th colspan="6">Captions</th> </tr> <tr> <th>Model</th> <th>DSim<sub>&uarr;</sub></th> <th>KID<sub>&darr;</sub></th> <th>CLIP<sub>&uarr;</sub></th> <th>cBLEU<sub>&uarr;</sub></th> <th>TED<sub>&darr;</sub></th> <th>MTE<sub>&uarr;</sub></th> </tr> </thead> <tbody> <tr> <td>DeTi<i>k</i>Zify<sub>v2</sub> (8b)</td> <td>52.829</td> <td><b>5.103</b></td> <td><b>10.051</b></td> <td><b>1.603</b></td> <td>65.51</td> <td>82.291</td> </tr> <tr> <td>DeTi<i>k</i>Zify<sub>v2.5</sub> (8b)</td> <td><b>53.564</b></td> <td>7.471</td> <td>7.968</td> <td>0.732</td> <td><b>62.189</b></td> <td><b>100</b></td> </tr> </tbody> </table> <p><a href="https://huggingface.co/nllg/tikzero-adapter">Ti<i>k</i>Zero adapters</a> integrate into the vision encoder of DeTi<em>k</em>Zify models, enabling them to be conditioned on text in addition to images. Since we keep the vision encoder frozen, we can evaluate DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) on adapters trained for DeTi<em>k</em>Zify<sub>v2</sub> (8b). Compared to our previous experiments, the results are more varied. While DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) achieves a better DreamSim value and maintains a perfect MTE, it performs worse on CLIPScore, suggesting difficulties in reproducing text from captions. This could be due to an increased modality gap, as RLSF further refines the model for image-only inputs. We plan to address this in future work by incorporating caption inputs into RLSF training.</p> <h2 id="summary">Summary</h2> <p>Overall, RLSF greatly enhances model performance for most tasks. For image and sketch inputs, DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) emerges as the clear leader. For text inputs via Ti<em>k</em>Zero adapters, the choice between model versions depends on the specific use case, given the trade-offs involved. If you’d like to experiment with the model yourself, feel free to try it in our interactive <a href="playground">playground</a>.</p> <h2 id="acknowledgments">Acknowledgments</h2> <p>This model was trained using computational resources provided by the bwForCluster Helix, as part of the bwHPC-S5 project. The authors acknowledge support from the state of Baden-Württemberg through the bwHPC initiative and the German Research Foundation (DFG) under grant INST 35/1597-1 FUGG. This post was inspired by the paper <a href="https://arxiv.org/abs/2505.20793">Rendering-Aware Reinforcement Learning for Vector Graphics Generation</a> and is based on the DeTi<em>k</em>Zify<sub>v2.5</sub> (8b) <a href="https://huggingface.co/nllg/detikzify-v2.5-8b#model-card-for-detikzifyv25-8b">model card</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[DeTikZify is a family of multimodal large language models that automatically convert hand-drawn sketches or images of existing scientific figures into editable, semantics-preserving TikZ graphics programs. It aims to simplify the process of creating and editing high-quality scientific figures, which traditionally is time-consuming and challenging. Here is an example workflow showing how to interact with the model:]]></summary></entry><entry><title type="html">Building a USB converter for a Vintage Siemens PC16-11 Keyboard</title><link href="https://belouadi.com/blog/2024/siemens/" rel="alternate" type="text/html" title="Building a USB converter for a Vintage Siemens PC16-11 Keyboard"/><published>2024-12-17T00:00:00+00:00</published><updated>2024-12-17T00:00:00+00:00</updated><id>https://belouadi.com/blog/2024/siemens</id><content type="html" xml:base="https://belouadi.com/blog/2024/siemens/"><![CDATA[<p>I found this Siemens PC16-11 keyboard at a flea market. I had been searching for a Siemens keyboard for quite some time because I like their funky keycaps and overall aesthetics. Finally, I stumbled upon one. Here’s how it looked when I first brought it home:<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/1-dirty-keyboard-480.webp 480w,/assets/img/siemens/1-dirty-keyboard-800.webp 800w,/assets/img/siemens/1-dirty-keyboard-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/1-dirty-keyboard.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="dirty Siemens PC16-11 keyboard" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>It was a bit dirty but otherwise in good condition, with no missing keycaps! The first thing I did when I got home was disassemble the keyboard to take a look inside:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/2-no-top-housing-480.webp 480w,/assets/img/siemens/2-no-top-housing-800.webp 800w,/assets/img/siemens/2-no-top-housing-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/2-no-top-housing.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="keyboard with top housing removed" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Everything looked good! Fortunately, there were no obvious signs of damage. The most interesting part of the circuitry is definitely the upper-left corner. Notable components include the Intel 8031 micro controller (1), a 2732 EPROM (2), and, most intriguingly, a beeper speaker (3):</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/3-central-circuitry-480.webp 480w,/assets/img/siemens/3-central-circuitry-800.webp 800w,/assets/img/siemens/3-central-circuitry-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/3-central-circuitry.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="central circuitry of the keyboard" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Another highlight for me were the switches, the original Siemens STB 11 switches. Someone did a <a href="https://youtu.be/czVtFctLSlA">review</a> on their (seemingly disappointing) successors, but I couldn’t find much information on these earlier models:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/4-switches-480.webp 480w,/assets/img/siemens/4-switches-800.webp 800w,/assets/img/siemens/4-switches-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/4-switches.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="closeup on the keyboard switches" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>I really wanted to use this keyboard with a modern computer, but it uses a proprietary connector and protocol, so reverse-engineering seemed inevitable. I had previously done an <a href="../../2020/itt">internal conversion</a> on a keyboard of similar vintage, but this time, I wanted to try an external conversion, leaving the original keyboard functionality intact. This approach meant that I would have to reverse-engineer the entire protocol, which would probably be a more extensive project in comparison. However, before making any assumptions I thought I’d start by looking for the original PC16-11 manual. Perhaps someone had scanned it, and it might contain useful information for the project.</p> <p>To my surprise, I found that someone had indeed scanned the entire manual and <a href="https://oldcomputers-ddns.org/public/pub/rechner/siemens/pc16-11/manuals/index.html">uploaded</a> it for archival purposes. A huge thank you to that kind soul! The 250-page manual (written in German) detailed the workings of the entire system, including how it communicates with the keyboard:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/5-wiring-information-480.webp 480w,/assets/img/siemens/5-wiring-information-800.webp 800w,/assets/img/siemens/5-wiring-information-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/5-wiring-information.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="wiring information of the keyboard" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>The manual revealed that the keyboard communicates with the computer via a unidirectional serial protocol on Pin 11. It also outlined how the protocol worked: the keyboard simply sends a keycode to the computer with each keypress, and that’s it:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/6-keycode-table-480.webp 480w,/assets/img/siemens/6-keycode-table-800.webp 800w,/assets/img/siemens/6-keycode-table-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/6-keycode-table.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="keycode table" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Armed with this valuable information, building the hardware for the converter became much easier. Within hours of receiving the parts, I had a working prototype:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/7-converter-480.webp 480w,/assets/img/siemens/7-converter-800.webp 800w,/assets/img/siemens/7-converter-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/7-converter.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="keycode converter prototype" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>The only thing I changed from the schematic was adding a 2.2 kOhm resistor between pin 4 and ground, since we don’t need the -RxD signal. Finalizing the software took a bit longer, as I had to account for various edge cases when mapping the keycodes to actual keys. Fortunately, the excellent <a href="https://github.com/tmk/tmk_core">TMK Keyboard Firmware Core Library</a> made this process much smoother. After working on it for about five evenings, I had a working converter. The source code is available <a href="https://github.com/potamides/siemens-pc16-11-converter">here</a> for anyone interested. The repository also includes a dump of the EPROM for archival purposes. After a thorough cleaning, here’s a typing demo with and without the buzzer:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <iframe src="https://www.youtube.com/embed/rSG0JlDf5y4" class="img-fluid rounded z-depth-1 video-4-3" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" width="auto" height="auto" alt="typing demo"/> </figure> </div> </div> <p>I was really surprised by the switches. They’re tactile, which explains why the buzzer was necessary to reintroduce the noise level people were used to at the time. The tactile bump is gentle but noticeable, and the force required to bottom out increases sharply, perhaps reminding me a bit of Cherry MX Clears. I’ll definitely pull this keyboard out from time to time to type on it.</p> <p>A downside of how the protocol works is that it only sends keypress events, not key release events. While this is fine for typing, it’s not at all suited for things like gaming (if you hold a key down for a while, it sends repeated keypress events). That said, it does have 2-key rollover, so it won’t satisfy your gaming needs in any case. Here’s a final photo of the cleaned-up keyboard, complete with the converter:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/8-clean-keyboard-480.webp 480w,/assets/img/siemens/8-clean-keyboard-800.webp 800w,/assets/img/siemens/8-clean-keyboard-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/8-clean-keyboard.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="clean Siemens PC16-11 keyboard with converter" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Overall, this was a fun and rewarding project. It also highlighted how valuable archiving things can be. I’m not sure how long the project would have taken without the manual. I wish modern computers still came with similarly detailed documentation. Even apart from the technical details, the manual was a fun read. I really enjoyed learning the German equivalents of terms I usually hear only in English; and just look at how happy this guy from the manual looks with his new PC16-11 keyboard! Sure looks like me.</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/siemens/9-happy-user-480.webp 480w,/assets/img/siemens/9-happy-user-800.webp 800w,/assets/img/siemens/9-happy-user-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/siemens/9-happy-user.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" alt="cartoon from the manual" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:1"> <p>Originally posted on <a href="https://deskthority.net/viewtopic.php?t=29402">Deskthority</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div>]]></content><author><name></name></author><summary type="html"><![CDATA[I found this Siemens PC16-11 keyboard at a flea market. I had been searching for a Siemens keyboard for quite some time because I like their funky keycaps and overall aesthetics. Finally, I stumbled upon one. Here’s how it looked when I first brought it home:1 Originally posted on Deskthority. &#8617;]]></summary></entry><entry><title type="html">Vintage ITT Courier 110169 Hall Effect Keyboard USB Conversion</title><link href="https://belouadi.com/blog/2020/itt/" rel="alternate" type="text/html" title="Vintage ITT Courier 110169 Hall Effect Keyboard USB Conversion"/><published>2020-11-18T00:00:00+00:00</published><updated>2020-11-18T00:00:00+00:00</updated><id>https://belouadi.com/blog/2020/itt</id><content type="html" xml:base="https://belouadi.com/blog/2020/itt/"><![CDATA[<p>I did this conversion quite a while ago, but since this was a fun process, the keyboard is pretty interesting and because this could potentially be of interest to others, I still decided to write about it.<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p> <p>I found this keyboard on a local flea market, it was an instant must-have. When I got it it looked like this:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/itt/IMG_20190907_164744-480.webp 480w,/assets/img/itt/IMG_20190907_164744-800.webp 800w,/assets/img/itt/IMG_20190907_164744-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/itt/IMG_20190907_164744.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Maybe a little bit yellowed, but overall in good condition, nothing a good old retr0bright can’t fix. But before that I wanted to get that keyboard up and running, so the first thing I did was to disassemble the unit to get a glimpse at the PCB:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/itt/IMG_20190912_104544-480.webp 480w,/assets/img/itt/IMG_20190912_104544-800.webp 800w,/assets/img/itt/IMG_20190912_104544-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/itt/IMG_20190912_104544.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>You can easily spot the Hall Effect sensors, which are arranged in a matrix of 13 columns and 8 rows. Other than that there isn’t much going on here, the big IC in the middle is an Intel 8048 compatible microcontroller. 4 of its pins are connected to a demultiplexer located to its right which is used to strobe the columns of the switch matrix. The demultiplexer expects the column index through a binary encoding from its 4 input pins. This means that the microcontroller can strobe all columns with only 4 of its pins being used! For sensing the 8 rows of the matrix are directly connected to the microcontroller.</p> <p>A nice side-effect from this design is the fact, that this board supports inherent N-Key Rollover. This is nothing I really need, but it’s cool to see and for a Hall Effect keyboard I think such a feature is quite rare. Another useless but nevertheless really cool feature is the solenoid located on the lower right of the board.</p> <p>In order to record my findings and to make working with this keyboard easier, I created a schematic of the circuit:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/itt/itt_courier_pcb.svg" sizes="95vw"/> <img src="/assets/img/itt/itt_courier_pcb.svg" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>My first idea to get the keyboard working was to build a converter that can be plugged into the original cable. The original cable used a Micro D-Sub connector, something which I have never seen before, look how tiny it is compared to a regular D-Sub connector!</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/itt/IMG_20201118_133114-480.webp 480w,/assets/img/itt/IMG_20201118_133114-800.webp 800w,/assets/img/itt/IMG_20201118_133114-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/itt/IMG_20201118_133114.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Since (at the time) I didn’t have any advanced measuring equipment, which I could have used to reverse-engineer the protocol, I decided to desolder the microcontroller and read its ROM directly to figure out how everything works. Thankfully the MCS-48 line of microcontrollers has extensive documentation, so building a circuit with an Arduino to read it was straightforward.</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/itt/IMG_20190909_184809-480.webp 480w,/assets/img/itt/IMG_20190909_184809-800.webp 800w,/assets/img/itt/IMG_20190909_184809-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/itt/IMG_20190909_184809.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>After that I used a disassembler to convert the binary into a readable format. Up to this point everything went pretty well but unfortunately understanding the firmware was much harder than expected. I figured out, that I could use one of the pins of the connector to get the microcontroller to jump to the interrupt routine were it looked like some kind of IO could happen but from there on the code was much harder to understand because one instruction used an indirect jump. After some time I gave up on that approach and decided to do the conversion internally.</p> <p>I decided to utilize a Teensy 2.0, because it has so many IO ports, that I only had to reroute a handful of signals and could leave most of the traces untouched. I also repurposed the connector on the board for a custom USB cable. Software-wise I decided to use the TMK Keyboard Firmware Core Library, which made everything pretty easy, especially when compared to reading antiquated 1970s assembler code. In the end the board looked like this:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/itt/IMG_20191007_115045-480.webp 480w,/assets/img/itt/IMG_20191007_115045-800.webp 800w,/assets/img/itt/IMG_20191007_115045-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/itt/IMG_20191007_115045.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>After that the only thing left to do was retr0brighting and putting everything back together. Here is a picture of the keyboard after everything was done:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/itt/IMG_20201118_133157-480.webp 480w,/assets/img/itt/IMG_20201118_133157-800.webp 800w,/assets/img/itt/IMG_20201118_133157-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/itt/IMG_20201118_133157.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Someone already did a fantastic job reviewing the unit so I’ll leave a link to the video <a href="https://www.youtube.com/watch?v=37tdDoC7rGA">here</a>. I agree that the switches are incredibly smooth, but unfortunately a little bit too heavy for me for daily use. The solenoid was a bit surprising, though. It not only is loud as hell when activated, but it also makes the whole keyboard slightly vibrate which makes the switches feel almost clicky. Overall this was a very fun and instructive undertaking and if there’s someone else on this planet who owns this keyboard and is looking to convert it I hope this is a helpful resource. For the interested reader, I created a <a href="https://github.com/potamides/itt-courier-110169-to-usb">GitHub Repository</a> for the code I wrote along with more detailed install instructions. Finally, here is a typing demo:</p> <div class="row mt-3"> <div class="col-sm mt-3 mt-md-0"> <figure> <iframe src="https://www.youtube.com/embed/34aCBaNoQzg" class="img-fluid rounded z-depth-1 video-16-9" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" width="auto" height="auto" alt="typing demo"/> </figure> </div> </div> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:1"> <p>Originally posted on <a href="https://deskthority.net/viewtopic.php?t=24822">Deskthority</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div>]]></content><author><name></name></author><summary type="html"><![CDATA[I did this conversion quite a while ago, but since this was a fun process, the keyboard is pretty interesting and because this could potentially be of interest to others, I still decided to write about it.1 Originally posted on Deskthority. &#8617;]]></summary></entry></feed>