diff --git a/src/modules/needy_finetuner/doc/face.svg b/src/modules/needy_finetuner/doc/face.svg
new file mode 100644
index 0000000..6e8e08f
--- /dev/null
+++ b/src/modules/needy_finetuner/doc/face.svg
@@ -0,0 +1,209 @@
+
+
+
+
diff --git a/src/modules/needy_finetuner/doc/index.md b/src/modules/needy_finetuner/doc/index.md
new file mode 100644
index 0000000..098bf91
--- /dev/null
+++ b/src/modules/needy_finetuner/doc/index.md
@@ -0,0 +1,20 @@
+# Finetuner
+
+Schrijf de handleiding voor je module hier. Kijk gerust naar de handleiding
+voor de "Doolhof"-module (`src/modules/puzzle_maze/doc/index.md`)
+
+
+Hieronder wat voorbeelden van markup die je kan gebruiken. Daarnaast kan je ook LaTeX
+gebruiken (zie bijvoorbeeld de "Doolhof"-module)
+
+Use drawings! Create the docs/images/your_module directory, put your image there and include them like this:
+
+![](./your_module/filename.png)
+
+Use tables! Write them like this:
+
+| Symbol | Action to take |
+|--------------------------------|----------------|
+| ![](./your_module/symbol1.png) | Do nothing |
+| ![](./your_module/symbol2.png) | Press the red button |
+| ![](./your_module/symbol3.png) | Press the yellow button |
diff --git a/src/modules/needy_finetuner/needy_finetuner.ino b/src/modules/needy_finetuner/needy_finetuner.ino
new file mode 100644
index 0000000..e71dc17
--- /dev/null
+++ b/src/modules/needy_finetuner/needy_finetuner.ino
@@ -0,0 +1,114 @@
+// (c) 2022, Midgard
+// See the LICENSE file for conditions for copying
+
+#include
+
+#define PIN_GAUGE 3
+#define PIN_SLIDER A7
+
+#define ADJUSTMENT_PERIOD_MS 15000
+#define SLEEP_PERIOD_MS 5000
+
+#define ARRAY_LENGTH(array) ((sizeof array)/(sizeof (array[0])))
+
+uint32_t deadline = 0;
+int16_t target = 0;
+int16_t previousTarget = 0;
+uint8_t moved = 0;
+
+
+void setup() {
+ Serial.begin(115200);
+
+ obus_module::setup(OBUS_TYPE_NEEDY, OBUS_NEEDY_ID_DEVELOPMENT);
+
+ pinMode(PIN_GAUGE, OUTPUT);
+ pinMode(PIN_SLIDER, INPUT);
+
+ target = getSliderValue();
+ previousTarget = target;
+}
+
+uint16_t stops[] { 0, 18, 147, 526, 900, 1008, 1024 };
+uint16_t getSliderValue() {
+ uint16_t value = analogRead(PIN_SLIDER) + 1;
+ for (int i = 1; i < ARRAY_LENGTH(stops); i++) {
+ if (value <= stops[i]) return (value - stops[i - 1]) * 170 / (stops[i] - stops[i-1]) + (i-1)*170 - 1;
+ }
+}
+
+void gauge(unsigned char value) {
+ // analogWrite accepts values from 0 to 255
+ analogWrite(PIN_GAUGE, value);
+}
+
+obus_can::message message;
+
+bool is_in_tune(int16_t target, int16_t sliderValue) {
+ return abs(target - sliderValue) <= 20;
+}
+
+/*
+int amountOfLedsToLight(timeLeft, target, sliderValue) {
+ if (is_in_tune(target, sliderValue)) {
+ return 0;
+ }
+ if (timeLeft <= ADJUSTMENT_PERIOD_MS * 2 / 4) return 3;
+ if (timeLeft <= ADJUSTMENT_PERIOD_MS * 3 / 4) return 2;
+ if (timeLeft <= ADJUSTMENT_PERIOD_MS * 4 / 4) return 1;
+}
+*/
+
+
+void loop() {
+ bool is_message_valid = obus_module::loopNeedy(&message, callback_game_start, callback_game_stop);
+
+ int16_t sliderValue = getSliderValue();
+ int16_t gaugeValue = previousTarget - sliderValue;
+
+ int32_t timeLeft = deadline - millis();
+ if (timeLeft <= ADJUSTMENT_PERIOD_MS) {
+ // Require a movement being detected for at least 2 successive loops, to combat jitter
+ if (moved >= 2) {
+ gaugeValue = target - sliderValue;
+ } else {
+ if (abs(sliderValue - previousTarget) > 2) moved++;
+ else moved = 0;
+
+ gaugeValue = (ADJUSTMENT_PERIOD_MS - timeLeft) * 127 / ADJUSTMENT_PERIOD_MS;
+ if (target > previousTarget) {
+ gaugeValue *= -1;
+ }
+ }
+ }
+
+ /*amountLeds = amountOfLedsToLight(timeLeft, target, sliderValue);*/
+
+ if (timeLeft < 0) {
+ deadline = millis() + ADJUSTMENT_PERIOD_MS + SLEEP_PERIOD_MS;
+ previousTarget = sliderValue;
+ do {
+ target = random(1023 - 2*30) + 30;
+ } while(abs(target - previousTarget) < 50);
+ moved = 0;
+
+ if (!is_in_tune(target, sliderValue)) {
+ obus_module::strike();
+ target = sliderValue;
+ }
+ }
+
+ if (gaugeValue > 127) gaugeValue = 127;
+ else if (gaugeValue < -127) gaugeValue = -127;
+ gauge(gaugeValue + 127);
+
+ delay(50);
+}
+
+void callback_game_start(uint8_t puzzle_modules) {
+
+}
+
+void callback_game_stop() {
+ ((void (*)(void))0)();
+}