88 lines
5.1 KiB
Markdown
88 lines
5.1 KiB
Markdown
|
Title: Slot Car Racing over IP (SCRoIP)
|
|||
|
Date: 2022-08-28 16:05
|
|||
|
Author: Error
|
|||
|
Slug: scroip
|
|||
|
Summary: I built a remote control for a slot car racing track to play with it over the LAN. It's unnecessary complicated and inefficient, but at least it supports IPv6. Ladies, Gentlemen and everyone else, start your engines.
|
|||
|
License: CC-BY-NC
|
|||
|
https://creativecommons.org/licenses/by-nc/4.0/
|
|||
|
|
|||
|
## The Idea
|
|||
|
|
|||
|
When I was a child, I used to play a lot with my slot car racing track.
|
|||
|
After stubling upon it again recently, I started wondering if I could build something to control it over the network.
|
|||
|
Not that I needed a remote control for it, but it seemed like a fun project.
|
|||
|
However, simply creating an API that offers precise control over the device seemed way to sriaght forward - the controling mechanism itself should add its challenges.
|
|||
|
So I came up with the idea to control it with the traffic itself.
|
|||
|
The more traffic is sent to the remote control, the faster the car is supposed to go.[°Use more bandwidth!!!]
|
|||
|
|
|||
|
## Reversing
|
|||
|
|
|||
|
In order to build the remote control, the first step was to figure out how the slot car racing system works. So I disassembled it and took a look at its wiring.
|
|||
|
|
|||
|
![Simplified circuit diagram for a slot car racing system]({static}/posts/scroip/carrera.svg "Simplified circuit diagram of a slot car racing system")
|
|||
|
|
|||
|
The underlying mechanism is fairly simple. The power supply provides about 14.8 V DC voltage, which a used to power the car's motor.
|
|||
|
The speed of the car is controlled by a variable resistor within the controller, which allows to control the voltage the car receives.
|
|||
|
Pushing the controller further down lowers the resistance, which raises the voltage available to the car and makes is go faster.
|
|||
|
A third wire is used to brake the car when the controller is in its neutral position by utilizing the current generated by the motor when the car is rolling out.
|
|||
|
A look at wikipedia confirms this analysis. [^1]
|
|||
|
|
|||
|
## Building a digital Controller
|
|||
|
|
|||
|
Now that I understood the mechanism, the next step was to create a digital version of it, so that I could control the slot car racing track with a Raspberry Pi.
|
|||
|
My first idea was to simply use a digital potentiometer.
|
|||
|
However, searching for a suitable digipot, I quickly realized that there were no options with the desired dimensions of about 30 Ω available.
|
|||
|
Therefore I built it myself using a few resistors, solid state relais and multiplexers.[°I'm sure there are simpler solutions for this, but, well, it worked for me.]
|
|||
|
|
|||
|
![SCRoIP controller circuit diagram]({static}/posts/scroip/scroip.svg "SCRoIP controller circuit diagram")
|
|||
|
|
|||
|
For the sake of simplicity,[°or maybe out of laziness, who knows? :)] I did not add the braking mechanism from the analog controller to my digital version.
|
|||
|
|
|||
|
## Implementing the Server
|
|||
|
|
|||
|
With the hardware fully assembled and soldered, it was time to have a look at the software.
|
|||
|
Python offers an easy way of implementing TCP servers.[°This project will use TCP. Even though the payload is immediately discarded, reliability is of the utmost importance and packet loss will not be accepted!!!]
|
|||
|
By default, it only supports IPv4, but IPv6 support can be added by setting `address_family` to `AF_INET6`.
|
|||
|
|
|||
|
if not legacy:
|
|||
|
self.address_family = AF_INET6
|
|||
|
super(SCRoIPServer, self).__init__((address, port), SCRoIPRequestHandler)
|
|||
|
|
|||
|
The server's logic itself is implemented in the method `handle()` of the class `SCRoIPRequestHandler`. While there is an active connection, it reads from the socket and sums up the ammount of data that was received.
|
|||
|
Once every 100 ms, it then calculates the average throughput for that time period and sets the raspi's GPIO pins accordingly.
|
|||
|
|
|||
|
while self.data != b'':
|
|||
|
try:
|
|||
|
self.data = self.request.recv(4096)
|
|||
|
self.traffic_counter += len(self.data)
|
|||
|
except TimeoutError:
|
|||
|
pass
|
|||
|
|
|||
|
time = clock_gettime_ns(CLOCK_REALTIME)
|
|||
|
diff = time - self.last
|
|||
|
if (diff > 100000000):
|
|||
|
self.last = time
|
|||
|
traffic: float = self.traffic_counter / diff * 1000000000
|
|||
|
print(f"{traffic} Bytes/s")
|
|||
|
self.server.set_throttle(traffic)
|
|||
|
self.server.apply_throttle()
|
|||
|
self.traffic_counter = 0
|
|||
|
|
|||
|
The full server code can be found [here](https://git.undefinedbehavior.de/undef/SCRoIP "Slot Car Racing over IP - SCRoIP - undefined git server").
|
|||
|
|
|||
|
## Lights out and away we go
|
|||
|
|
|||
|
Once the server was implemented as well, all that was left to do was to test it.
|
|||
|
So I deployed the server script to a Raspberry Pi, connected its GPIO pins to the controller and the controller to the slot car racing track.
|
|||
|
Using netcat, I was now able to accelerate the car with the network traffic I generated:
|
|||
|
|
|||
|
<video controls preload="metadata">
|
|||
|
<source src="{static}/posts/scroip/demo.webm" type="video/webm">
|
|||
|
<p>
|
|||
|
The video could not be loaded.
|
|||
|
You can try to download it directly <a href="/posts/scroip/demo.webm">here</a> instead.
|
|||
|
</p>
|
|||
|
</video>
|
|||
|
|
|||
|
[^1]: [https://de.wikipedia.org/wiki/Autorennbahn#Fahrzeugsteuerung](https://de.wikipedia.org/wiki/Autorennbahn#Fahrzeugsteuerung "Autorennbahn – Wikipedia")
|