Password Helper
Tells you how strong a password is and checks if it showed up in a known data leak. Comes with a small vault server.
Telecom engineer, into cybersecurity.
I built a tracked robot for my thesis and got a 9.00. Last summer I tested power equipment at Siemens Energy. Now I'm doing a master's in Brașov.
Move over the signal. Left and right change the frequency, up and down the amplitude.
2.0 Hz1.0 V
--:----
in Brașov, where I live
Tested protection relays and 6 kV and 0.4 kV switchgear.
Did some PLC and HMI programming and helped restart a SCADA server.
Courses: the GoIT cybersecurity course, and Cisco CCNA 1, in progress.
Lab: VMware with Parrot OS, Metasploitable 2 and GNS3.
Things I've built, biggest first.
Tells you how strong a password is and checks if it showed up in a known data leak. Comes with a small vault server.
My friends and I used it to pick where to go on a trip. Four voting rounds, live flight prices, runs on my own server.
Virtual machines where I practice attacking and defending: Parrot OS, Metasploitable 2 and GNS3.
The card game my friends and I play, with our own house rules, so we can play it online.
Bachelor's thesis · 2026 · graded 9.00
Pick a part to explore.
← → to choose · Enter to open
Scroll
Eight parts, each built to its real size from my CAD, my photos and the thesis. Keep scrolling to go through them.
A T101 aluminium tank kit with ABS plastic tracks. Each track has its own 33GB-520 gear motor, 12 V and 320 rpm, fed straight from the 7.4 V pack.
No steering: one track runs faster than the other, so the rover turns on the spot.
left = y + xright = y − x
The T101 is one bent aluminium sheet: a slotted deck between the tracks, its sides bent down to carry the wheels. The motors hang under the deck.
My 3D printed chassis sits right on top of it: the battery box stands on the deck and the electronics plate rests on the box. Pins on the plate's front and corner tabs hold the five distance sensors.
The rover's computer. It runs two services that start on boot: rover.py takes the commands, reads the sensors and drives, and camera_stream.py streams both cameras.
The extra memory is for the self-docking model I want to run on it next.
Linux can't promise timing, so a Nano does the real-time part. The Pi sends it short text lines over USB at 115200 baud.
M 182 -64S 90
The DRV8833 H-bridge is glued to the front of the battery box, with a 1000 µF capacitor on its supply that catches the dips when the motors start. It switches battery power to the motors, and if the lines stop for half a second, the Nano stops them on its own.
Five VL53L0X laser time-of-flight sensors, three at the front and two at the back. They all have the same I²C address, so a TCA9548A switches them on one at a time.
Under 400 mm the rover slows down, and at 120 mm it stops. Turning stays free, so it can always get out.
Two Waveshare IMX219 cameras, 8 MP with a 120° lens, each streaming 1920 × 1080 at 30 fps.
The front one is the driving view. The other sits on a mast and turns on an MG90S servo that the right stick controls. The tower and the camera mount are parts I designed.
Four Samsung 21700 cells in 2S2P: 7.2 V, 10 Ah, about 72 Wh, roughly four hours of driving. Two double holders slide into the battery box from the Pi's side. There's no power switch: to turn it off, I pull the holders out.
A 2S BMS protects the cells and a USB-C module under the Nano shield charges them. Under the plate, an XL4015 makes 5.1 V for the Pi; a second one on top makes 3.3 V for the fibre converter. The motors run straight off the pack, and an INA219 measures the battery.
The backup path. A media converter turns the Pi's Ethernet into light on a single strand of single-mode fibre: 1310 nm one way, 1550 nm the other, up to 3 km.
The converter has its own 3.3 V supply, so the backup path doesn't depend on the Pi's. And light in glass can't be jammed by radio.
On power-up the camera runs the servo check from rover.py: full left, full right, centre. Then it drives off.
Twenty times a second, rover.py takes the newest command, limits it near obstacles and turns it into two track speeds.
def axis_limit(dist_mm, stop=120, slow=400): """1.0 = free, 0.0 = blocked, linear in between.""" if dist_mm is None: return 1.0 # a dead sensor never blocks driving if dist_mm <= stop: return 0.0 if dist_mm >= slow: return 1.0 return (dist_mm - stop) / float(slow - stop) # collision limit on the drive axis only; turning stays free if y > 0: y *= axis_limit(min_valid([tof[i] for i in FRONT_IDX])) elif y < 0: y *= axis_limit(min_valid([tof[i] for i in REAR_IDX])) l = max(-1.0, min(1.0, y + x)) # tank mixing r = max(-1.0, min(1.0, y - x)) nano.send(f'M {int(l * 255 * TRIM_L)} {int(r * 255 * TRIM_R)}')
The Nano only has to understand two kinds of line.
void handleLine(char *line) { if (line[0] == 'M') { // M <left> <right>, -255..255 int l = 0, r = 0; if (sscanf(line + 1, "%d %d", &l, &r) == 2) { setMotor(PIN_L_IN1, PIN_L_IN2, l); setMotor(PIN_R_IN1, PIN_R_IN2, r); } } else if (line[0] == 'S') { // S <angle> int a = 0; if (sscanf(line + 1, "%d", &a) == 1) steer.write(a); } }


This is the real model, every part where it sits. Keep scrolling to go through them.
The frame and the two grips, 3D printed in black PLA. I worked out where everything goes; the CAD modelling was done together with a friend.
A 7-inch 800 × 480 capacitive touch screen: HDMI for the picture, USB for touch.
It runs my control interface, built in Electron: both cameras, both batteries and a map of nearby obstacles.
The left stick drives, the right one turns the rover's camera. The Pi has no analog inputs, so an ADS1015 reads all four axes over I²C.
A six-step calibration measures each stick's real forward and turn directions, so a crooked stick still drives straight.
A small green MTS-102 toggle on the top edge turns the controller on and off.
Three solder lugs inside, an M6 bushing through the wall and a nut on the outside.
The controller is the Wi-Fi access point the rover joins. Its Pi reads the sticks, sends every command 20 times a second over both links, and shows the two video streams.
It sits upside down under the screen. A 30 mm fan under it blows through a window in the back cover.
A printed frame hangs off the Pi's mounting holes. It carries the 30 mm fan and the XL4015 that makes 5.1 V for the Pi, so one fan cools both.
A second XL4015 makes 3.3 V for the fibre converter. A 2S BMS protects the cells, and an INA219 measures the battery for the on-screen gauge.
Four Samsung INR21700-50S cells, two in each grip, in 2S2P: 7.2 V and 10 Ah, about 72 Wh. That's roughly four hours.
The middle cover holds the Pi in its middle and the small boards in its two side pockets. The bottom cover closes everything up, with a window for the fan.
The screen wakes up with my interface: the mast camera full screen, the front camera in the corner, both batteries and the obstacle map.
The calibration in monitor.py: each reading is projected onto the stick's own measured directions.
def calibrate_xy(ax, ay, which): c = joycal[which] dx, dy = ax - c['cx'], ay - c['cy'] fp = dx * c['fwd_unit'][0] + dy * c['fwd_unit'][1] # onto "forward" tp = dx * c['turn_unit'][0] + dy * c['turn_unit'][1] # onto "turn" y = max(-1.0, min(1.0, fp / c['fwd_scale'])) x = max(-1.0, min(1.0, tp / c['turn_scale'])) return _deadzone(x, c['deadzone']), _deadzone(y, c['deadzone'])






The left stick drives and the right one turns the camera. An ADS1015 converts their four analog axes into numbers the Pi can read.
The Pi corrects each reading with the stick's calibration and packs both sticks into a tiny message with a timestamp.
{"m":"dlr1","t":1749…,"j1":{"x":0.42,"y":0.80},"j2":{"x":-0.1,"y":0}}
Every 50 ms the same packet goes out on both links: Wi-Fi on 2.4 GHz, where the controller is the access point, and a single fibre through the two media converters.
It's UDP: a late command isn't worth resending, the next one is already on its way.
Both copies reach the rover. It keeps whichever arrives first and drops the twin with the same timestamp.
The distance sensors cap the speed near obstacles, tank mixing makes two track speeds, and the Nano drives the motors and the camera servo.
No command for 0.4 s and the motors stop.
Ten times a second the rover sends its distances, battery, servo angle and failsafe state, also on both links. Both cameras stream video to the screen.
The controller always shows the freshest data.
For the thesis demo I jammed the Wi-Fi band. The radio packets stopped, and after 1.5 s of silence the controller switched to the fibre on its own.
The data kept coming the whole time.
That's the whole trip, 20 times a second while you drive.
20 Hz commands10 Hz telemetry1.5 s failover
Three small pieces make the link redundant. The controller sends every command on both links.
pkt = json.dumps({'m': 'dlr1', 't': int(time.time() * 1000), 'j1': {'x': j1['x'], 'y': j1['y'], 'ok': j1['available']}, 'j2': {'x': j2['x'], 'y': j2['y'], 'ok': j2['available']}}).encode() for ip in ROVER_IPS: # Wi-Fi first, then fibre _cmd_sock.sendto(pkt, (ip, CMD_PORT))
The rover keeps the first copy and drops the late twin.
t = int(d.get('t', 0)) if t <= last and (last - t) < 60000: # same or older: it came by the other link continue last = t
The controller listens to both links and uses Wi-Fi while it's fresh.
chosen = None for ip in ROVER_IPS: # Wi-Fi wins while it is fresh entry = _tel_last.get(ip) if entry and (now - entry[0]) <= TEL_TIMEOUT: # 1.5 s chosen = ip break # otherwise the fibre takes over
Where I've been and what I picked up along the way.
Internship, PRAM department, Petrobrazi refinery.
B.Eng. Telecommunications, Brașov.
[Add yours, each with a verification link.]
Off the clock: competitive tennis, F1 and games.
Competitive player. The serve animation lands here.
Race-engineer brain, sofa on Sundays.
[Your current rotation]
Open a channel. I read everything.
[your email]
[linkedin.com/in/…]
[github.com/…]