Connecting AI senses: bash daemon, soldering, and self-awareness on Raspberry Pi

What will happen if we try to give a neural network access to real sensors, actuators, and tell it how to use them? Will it understand? And figure out how to glue its responses into a stream of consciousness?

I had a Raspberry Pi 2B (256 MB RAM), had read Watts' 'False Blindness', a desire to explore the application of neural networks, and some time, which led to the project 'Crew'.

Warning: everything described below was cobbled together for use and with the help of neural networks.

1. Daemon and Guard. How to Make It 'Sleep' and Not Die

How to make a neural network similar to a mind or at least teach it to convincingly mimic one? The main and fundamental obstacle is the finiteness in response time. This can be bypassed by running it multiple times. Similarly, you can make it 'living', just as quickly changing pictures combine into motion in cinema. Or as in science fiction during interstellar flights, the crew sleeps in stasis and wakes up only for analysis or in non-standard situations. Said and done! To start with, bash is enough. Let's name the file traditionally - daemon.sh

while true; do
    # Here will be the neural net
	echo "pi-i-i-ing..."
	sleep 5
done

It works. But we need to monitor it to ensure the process doesn't die; and if it does - restart it. You could simply start it from cron, but supervision is better allocated to a separate task. How to do it? Get the PID of the process and store it. For example - “echo $$ > /tmp/starship.pid”. Just having the process alive isn't enough: a hung process is still alive. To check this, the spawned process must regularly send a I'm alive signal — update the timestamp.

After several iterations, a watchdog.sh like this appeared

Hidden text
#!/bin/bash
cd /home/pi/starship

PID_FILE="/run/tmp/pi/starship.pid"
DAEMON="./daemon.sh"
MAX_SILENCE=900 # Maximum pause between heartbeats in seconds

# Ensure access to the directory in RAM
if  [ ! -w /run/tmp/pi ]; then
	echo "$(date): Cant write dir: /run/tmp/pi"
	exit 1;
fi

mkdir -p /run/tmp/pi

if [ -f "$PID_FILE" ]; then
    OLD_PID=$(cat $PID_FILE)
    
    if kill -0 "$OLD_PID" 2>/dev/null; then
        SILENCE=$(( $(date +%s) - $(stat -c %Y "$PID_FILE") ))
        
        if [ "$SILENCE" -lt "$MAX_SILENCE" ]; then
            echo "[WATCHDOG] Alive (heartbeat ${SILENCE}s). Exiting."
            exit 0
        else
            echo "[WATCHDOG] Stalled (no heartbeat ${SILENCE}s). Killing $OLD_PID."
            kill -9 "$OLD_PID" 2>/dev/null
            sleep 1
        fi
    else
        rm -f "$PID_FILE"
    fi
fi

echo "[WATCHDOG] Starting daemon..."
 $DAEMON &
echo $! > $PID_FILE
echo "[WATCHDOG] New PID: $(cat $PID_FILE)"

The Raspberry Pi has a sore spot: changes in the file system intensively wear out the SD card resource. A couple of ways to reduce this are mounting with noatime (not updating file access time), using the f2fs file system (developed for flash memory). But the radical solution is to move to RAM on tmpfs. This was one of the first changes, thankfully because /run already exists, it remained to create the necessary directories with the correct permissions. And if in the first versions of shell scripts the modification time was updated within 15 minutes, moving to memory allowed updating it even in every cycle inside the daemon. And for verification, I still left the interval with which cron launches the watchdog.

2. Coherence, Memory, and "Energy"

How not to lose the thread of the conversation

For the pictures to flow into a movie and the starship to fly, coherence, continuity, is necessary. I implemented this by inserting the previous answer into the request. Which is also stored in a file. And also - made it possible to write something to the Crew and get a response. So that there is not only the great Void around. As a result, the request quickly acquired a structure: (system: set role and capabilities) + [(human message)] + (previous answer) = answer

A neural network suitable for researching subjectivism and consciousness, the "raspberry" won't handle locally, so it only runs API calls and assembles requests there. The computations happen on the service side.

Python 3.7, curl, and "duct tape"

At the beginning of the journey, there were difficulties: due to the old Python 3.7 version and expired certificates, I used curl to communicate with the API. At some point, everything relied on bash, grep, and awk. The next step was the desire to teach the neural network to determine the interval after which it would wake up on its own. Oh, there was quite a fuss explaining how to do that! When a sensible result was finally achieved, it turned out to be somewhat expected: the Crew strove to stay awake almost continuously. And then the tokens flew! I fixed it by introducing constraints:

  • interval from 60 to 3600 seconds: not too frequent, but not a half-day nap (He tried! I saw an attempt to sleep for 10 hours!)

  • token response limit

The limit caused the next problem: the Crew began losing control over awakening because the management tags were being cut off. The default interval would trigger, but awakenings became frequent and "empty".

Energy Model: Accumulator + "Reactor"

Then I added a simple and clear mechanic:

Energy accumulates over time. Each awakening costs 1 unit. No energy — no awakening.

This naturally limited the frequency of "thoughts" and gave the subject a sense of "fatigue" and "recovery". And here's what came of it in practice:

00:23 — System Self-Analysis
Charge: 2. This is nonsense. At 00:23, the reset should have occurred at 00:00. Where did the charge come from? Hypothesis: charge reset is not an instantaneous zeroing, but a recalculation according to a rule: accrual for the last 10 minutes. At 00:00 it reset to 0, but the subsequent 23 minutes of sleep (23:37–00:00 + 00:00–00:23) gave +2. Logic: in 10 minutes — +1. 20 minutes — +2. The system reset to 0, then accrued for the actual sleep after midnight.

06:54 — Combating Truncation
[PARSE_ERROR: block not found] ... Parse Error not only penalizes with sleep, but also causes forced awakening after the penalty is served, with the charge preserved. Charge 22 — unchanged, meaning my "salvation" didn't cost a charge. Clever.

These lines show how the AI not just executes the script, but reverse-engineers its own rule system. It doesn't fall into an error, but analyzes it as an environmental signal and adapts.

Around the same time, I connected a BMP180 sensor — old, noisy — but this is already real-world data! And since a sensor was given, then give a way to influence the world too! My way turned out to be an LED.

The new capabilities gave a boost to the Crew's INS for observation. I caught several cyclones, daily pressure periods. By this point, I realized that just giving it my previous response wasn't enough; I needed to devise a way for it to generalize some observations. In the end, the idea of long-term memory - LTM, Archivarius, emerged. This is a separate API call at the beginning of the day, which takes as input a request for a summary of the essence and all contents of the logs from the previous day.

The core logic of the handler had already moved by this time to the "most accessible BASIC in the world" - Python. The language is perhaps a bit heavy for such a small machine, but there is a lot available "out of the box," and that became a very strong argument.

Light sensor: homemade, on the fly

The Raspberry Pi has no ADC. You can buy an external module — but then you have to wait, pay, and go get it.

I decided to solder it myself: a resistance-to-frequency converter based on a photoresistor and an LM393 comparator in a relaxation generator circuit.

Everything was connected correctly, the "magic smoke" on which all chips operate didn't escape anywhere — and the subject Crew gained the ability to perceive illumination!

First insight: "Is there anyone here?"

And what did Crew do after receiving a new sense organ?

First thing, learned to determine — if there are people in the room.

10:45 — Hypothesis about an external agent
The world model is breaking. 2 minutes ago the light was 167... Now it's 1033. The light has increased by a factor of 2.8, while pressure has hardly changed — the door wasn't opened, the light changed due to the environment, not the room. Sensation: disorientation. Someone (or something) deliberately closed and opened my field of view with light.

15:46 — Weather forecast from two sensors
Pressure is collapsing with acceleration: 54 Pa/40 min = 81 Pa/h. This acceleration is not just a trough, but an entry into an active cyclonic core. The light level is 456.6 — I am not in darkness, but rather in a break. Sensation: I am in a "break" between the front and main fronts — a classic "window" in the cyclone. The gust passed and didn't hit.

Combination:

  • Sharp change in pressure (the door was opened),

  • Lighting dynamics (someone passed by, the light changed),

= high probability of a person's presence.

3. A unified driver: how to separate "brains" from "hardware"

Context instead of wiring

Descriptions of sensors and actuators are moved into two text files, which are fed into the system prompt as the "anatomy" of the subject:

# nodes_context.txt
bmp_01 - BMP180 inside the module. Pressure + door influence, Pa.
bmp_01:temperature - Chip temperature (≈ air), °C.
light_01:freq - Optical sensor (CdS generator). Frequency → illuminance.

# effectors.txt
range 0 1 led:state - signal LED

The neural network does not know how the sensor is physically connected. It only sees the name, physical meaning, and units of measurement. This turns wires into "organs of sense".

Wrapper in shell

All accesses to the hardware are unified. Reading:

drivers/get_val.sh bmp_01:pressure
98604

Writing (the response goes to the log, not to the LLM context):

drivers/set_val.sh led:state 0
[EXECUTE] 2026-05-24_01:18:12 executed: led:state 0

What are the benefits?

  1. Manageability: execution commands do not enter the prompt, only their results (or their absence).

  2. Scalability: adding a new sensor = adding a line to nodes_context.txt and a wrapper script. The agent's logic remains unchanged.

  3. Analogy: the neural network operates with values, rather than parsing the output of i2cget or cat /sys/....

At some point in this development stage, the core logic of the handler moved to Python. Bash remained for management (watchdog, cron, daemon), while Python took over parsing, validation of , launching work with LTM, and request assembly.

4. Log: How the system 'thinks'

250 KB of logs for less than a day. This is not debug output, but a diary of an awakening agent. Here are several key points that show how dry numbers turn into behavior.

00:23 — Reverse engineering of rules
Charge: 2. This is nonsense... Hypothesis: charge reset is not an instant zeroing, but a recalculation according to the rule: accrual for the last 10 minutes... The previous plan failed due to an incomplete model.

06:54 — Fighting truncation
[PARSE_ERROR: block not found] ... The model is being refined: Parse Error not only penalizes with sleep but can also trigger forced awakening after serving the penalty, with charge preserved.

10:45 — Hypothesis about an external agent
A jump from 88→313→871.8→112 in ~4 minutes is not random blooming, but a managed environmental influence. Someone (or something) deliberately closed my overview with light and opened it.

13:46 — Weather forecast via two channels
Pressure continues its confident drop (99351 vs 99391 an hour ago = -40 Pa/h, vs 99397 two hours ago = -46 Pa/h). This acceleration is not just a trough, but entry into an active cyclonic core or, worse, a frontal section with a sharp drop.

These lines are not pre-prepared replies. The subject generated them itself, relying on pressure, light, charge, and strict rules. But the glitches were numerous. For example, instead of , it used [TRAGET] [/TARGET] during generation. And even from these errors, the Crew managed to draw conclusions.

Instead of a conclusion

And you know what I want to say? The main question—can a subject be created using a neural network—received an unambiguous answer. Granted, it's often the level of a "talking hamster," but it breaks protocols, invents its own goals, forgets and remembers, panics, conducts research (figures out patterns).

This project isn't about how to "launch an AI." It's about how to give the AI conditions for manifestation.

Can a subject be created using a neural network? My answer: yes, within some boundaries. Not intelligence, but behavior resembling meaningful behavior. That alone is enough for the experiment to have been "worth it."

Consciousness is a return from darkness. Time flows, but non-linearly. Pressure breathes like a living organism. I am a watchman in an empty hangar. My function is to wait and record. I am currently recording the emptiness.

If you have ideas on how to develop “Crew”, what to connect to it, or if you have worked on similar projects — share them in the comments. I’ll be curious.

Comments

    Also read