Raspberry Pi Lidar Visualization notes

Xiaomi lidar sensor pinout

I’ve tried matplotlib which has a very convenient polar coordinate mode, but the output looked very wrong, so there must be a few mistakes in here:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import serial
import numpy as np

com_port = "/dev/ttyACM0"
baudrate = 115200
ser = serial.Serial(com_port, baudrate)

fig = plt.figure(figsize=(4,4))
ax = fig.add_subplot(111, projection='polar')

data = np.zeros(360)
theta = np.linspace(0,360, num=360)
l,  = ax.plot([],[])

databuffer = ""

def update(i):
	global data, databuffer
	if (ser.inWaiting()>0):
		data_str = ser.read(ser.inWaiting()).decode('ascii')
		databuffer +=  data_str
		if ('A' in databuffer and 'B' in databuffer and 'C' in databuffer):
			databuffer = databuffer.split('A')[1]
			databuffer = databuffer.split('C')[0]
				(angle, distance) = databuffer.split('B')
			except Exception as e: print(e)

	l.set_data(theta, data )
	return l, 

ani = animation.FuncAnimation(fig, update, frames=360, interval=200, blit=True)

Super simple temperature controller

The idea is to use an adjustable voltage divider to set a desired temperature while a temperature dependent voltage divider provides feedback about the actual print bed temperature.  The first op-amp IC1B works as a comparator that turns on its output to 5V as soon as the non-inverting input pin sees a higher voltage than the inverting input pin. That output controls a simple constant current sink in which the mosfet Q1 can be the heater or the shunt resistor R1 can be replaced with higher resistance power resistors to become heaters. IC2 is just a voltage regulator that provides a stable supply voltage for the op-amps.

Smooth 3D printing timelapse by optimal frame selection

To process video files OpenCV has to be compiled with ffmpeg option. On Windows it was a bit of a fight until I found out about Anaconda: https://www.anaconda.com/download/

In the Anaconda prompt you can just execute

conda install -c menpo opencv3 ffmpeg

and satisfy the other requirements normally.

#!/usr/bin/env python

import numpy as np
import cv2
from skimage.measure import compare_ssim as ssim
import time

cap = cv2.VideoCapture('video.mp4')

ret,previous = cap.read()
best_frame = previous
number = 50
file = 0

	i = 0
	best_s = 0
	i += 1
	ret, frame = cap.read()
	s = ssim(frame, previous, multichannel=True)
	if(s > best_s):
		best_s = s
		best_frame = frame
	cv2.imwrite('folder/%d.png' % file,best_frame)
	file += 1
	previous = best_frame


A few ideas to improve performance in the future:

  • Simplify images before comparing them – This needs a run-time analysis to make sure that the simplifications actually improve speed. The idea is that it would be sufficient to look at a single channel image with half the size instead of RGB Full HD to measure similarity.
  • Make decisions more dynamic – When similarity is larger than a certain threshold and the frame is far enough away from the last, we can use that one right away instead of going through all the remaining candidates.
  • Implement the whole thing in C++ – the actual comparison that is taking a lot of time is done in python scikit-image. Python is a relatively abstract language that’s made for people who want to solve algorithmic problems instead of worrying about syntax. That’s why there are no type declarations, no pointer arithmetic, etc. but on the other hand is a bit slower!
  • Use multithreading – You could start one thread for every comparison and distribute them to CPU cores or even GPU! I am seeing about 15% CPU utilization when the script is running.

RT-ZL03 Rohde & Schwarz active logic probes for RTB2004 PCB photos

Bottom side
Top side

The most important components are the the 4 ADCMP562BRQ Dual High Speed Comparators which determine whether a signal is high or low. N5311 is an EN5311QI ENPIRION DC-DC CONVERTER. The 8-Pin SOIC seems to be Z8 Encore! XP F0823 Series 8-Bit microcontroller by Zilog, not sure what it does, but it seems a bit too powerful to just store a serial number or something like that.

Pressure Sensor Matrix Mat Project

Abbreviations and terminology

  • Pressure: Force to be measured by the sensor matrix
  • MCU: Central microcontroller unit, system on chip or FPGA that evaluates sensor data and communicates with a PC
  • User: Person on the mat
  • FPS: Frames per second, number of times all sensor values are transmitted to the PC
  • Mat: The final product, in protective foil or rubber, likely not involving optional cushioning material like an actual gym mat
  • X dimension: Width of the mat, second to the longest extent
  • Y dimension: Length of the mat, longest extent
  • Z dimension: Thickness of the mat
  • DPcm: Dots per cm, resolution in both X and Y
  • Dynamic range: Range of pressure values that can be measured by a single sensor
  • Image: Data from all sensors
  • Sensor: A single pressure sensor embedded in the mat
  • ADC: Analog to digital converter

Project description

Desired is a human interface device in the shape of a gym mat, that detects and digitizes pressure. To allow computer-based evaluation of the user’s posture, a sufficiently high resolution in the time, space and pressure domains are required.

Fundamental ideas

A 3M Product called Velostat is a polymeric foil impregnated with carbon to make it electrically conductive. Applying force decreases its resistance drastically. Using small sections of this product we will form a number of pressure dependent voltage dividers, whose output voltage will be fed into an ADC via a multiplexer. To control the multiplexer and transmit the digitized data to a computer, a MCU is used.


  • Mat size: 1m x 2m to fit most adults
  • DPcm: 1
  • NDots: 2000
  • Resolution pressure: 100 g
  • Dynamic range: 0 … 10 kg
  • Resolution ADC: 8 b
  • Size of 1 image: 16000 b
  • Serial Baudrate: 115200 bps
  • FPS: 7
  • Sensor size: TBD, this is what we can adjust to get the desired dynamic range

Characterizing Velostat

Experiment description

A test-fixture was made to test differently sized sections of Velostat in. It is based on a vise whose jaws were replaced with plane, parallel surfaces. These were covered with copper tape to ensure good contact with the test object. One of the jaws is also mounted on a load cell, with which we can measure the clamping force. In this fixture we are testing 3 differently sized Velostat samples at different pressure levels while recording their resistance. Doing so we expect to see the materials dynamic range and the influence of sensor area on the same.

Figure 1: Velostat test fixture
Experiment result

As we can see in Figure 3 the dynamic range of Velostat is roughly 0g … 1000g and independent of sensor area. This result can be used as a foundation for estimations involving a flexible mat material, that will distribute pressure evenly on sensor area and surrounding non-sensor area.

400mm² 40mm² 4mm²
100g 500 Ω 600 Ω 800 Ω
200g 300 Ω 440 Ω 570 Ω
300g 200 Ω 320 Ω 430 Ω
400g 140 Ω 230 Ω 340 Ω
500g 110 Ω 170 Ω 270 Ω
600g 92 Ω 140 Ω 230 Ω
700g 72 Ω 120 Ω 200 Ω
800g 60 Ω 103 Ω 180 Ω
900g 50 Ω 91 Ω 160 Ω
1000g 45 Ω 84 Ω 150 Ω
1100g 39 Ω 76 Ω 144 Ω
1200g 32 Ω 72 Ω 139 Ω
1300g 29 Ω 70 Ω 135 Ω
1400g 27 Ω 69 Ω 131 Ω
1500g 26 Ω 68 Ω 129 Ω
Figure 3: Resistance of differently sized Velostat samples at different pressure levels

Further estimations

To accommodate most adults, the final product should be dimensioned for users between roughly 50 kg and 200 kg.
The average foot size can pessimistically be assumed to be size 9.
Using computer software we have scaled and vectorized a footprint to measure its area, which is approximately 126 cm² (Figure 4).
Based on these figures we expect a maximum pressure of 200kg per 126cm² ≅ 1.6kg/cm²
Sticking with the sensor pitch DPcm = 1 with no gaps, each sensor would see a maximum of 1.6 kg, which would be outside of its dynamic range.
To correct this, we will include 5mm gaps between the sensors, effectively halving their areas and their expected maximum pressure at the same time.

Figure 4: Measurement of footprint area

8×8 Sensor matrix demonstrator

Experiment description

To verify our aforementioned ideas, a demonstrator unit will be made. In particular we want to find out

  • if it is viable to arrange pressure-dependent voltage dividers in a scalable matrix
  • If the pressure per sensor can be regulated by adjusting the sensor-area non-sensor-area ratio
  • which conductive and protective materials will work well

A small 8 x 8 sensor matrix along with its control circuitry fits well on a single 100 mm x 160 mm circuit board and is easy to assemble.

Circuit description

Every pressure-dependent voltage divider in our matrix consists of a variable resistor (sensor) and a fixed resistor. The sensors are arranged in columns and rows of 8. The high sides of all sensors in a column are connected to one output of a shift register. The low sides of all sensors in a row are connected to a fixed ground-resistor and an analog switch input. A MCU controls the shift register and the analog switch in a common scanning strategy: Rows are connected one at a time to a MCU analog input pin by the analog switch and their voltage is measured while columns are energized one at a time by the shift register. That way we are able to measure all 64 sensor voltages with only one ADC and a few digital pins.

Figure 5: Half schematic circuit diagram
Construction details

In the introduction 3.1 we were talking about small sections of Velostat. Upon closer inspection it seems unnecessary to actually cut the material into sensor sized pieces, because the resistance in X and Y dimensions negligibly high. So instead we will use a 8 cm x 8 cm piece of velostat and the sensor size will be defined entirely by the copper layers.
As we have seen in 4.2 the sensor resistance can be as low as 30 Ω, so it is important for the fixed resistors to have a high enough resistance as to not overload the shift registers. A resistance, that is too high, on the other hand will decrease the sensor voltage swing. 200 Ω will be used, so that even if a column and a row were shorted, only 25 mA could flow.

Figures 6,7,8: Bottom copper layer, Velostat layer, populated circuit board
Experiment Results
  • The matrix arrangement and the pressure distribution work very well.
  • The readings on the outer edges were slightly offset by pressure from the upper layer of sticky tape. Wider margins should be used in the following attempts.
  • The shift register and multiplexer are fast enough to operate without any delay() calls in the MCU.
  • We have tried to use conductive adhesive tape to ensure good contact between the 3 sensor layers. But because its viscosity is a lot lower than that of the velostat and copper layers, it turns all the pressure into deformation, making the intended operation impossible.
  • All copper surfaces are known to oxidize quickly, which will change their resistance. The copper tape product we use appears to be lightly coated in an antioxidant. So far no problems could be observed.

    Figure 9: 8 x 8 sensor matrix and data visualization

Scaling up to 24×24 sensors

Experiment description

Additional problems might only become visible in a larger sensor matrix. Before committing the expensive materials for the final full-size version, we want to assemble one more prototype to test the interaction of multiple shift registers and multiplexers for example. A 24 x 24 sensor matrix will serve that purpose well and might also help us to get used to the proper handling of the delicate copper tape.
This version will not be based on a circuit board, but will be enclosed in adhesive vinyl foil and connected to an interface board via ribbon cables.
The interface board contains 3 shift registers in a daisy chain configuration, so that 24 outputs can be controlled by 3 MCU pins. It will also contain 3 analog multiplexers, so that every one of 24 analog inputs can be connected to one of 3 MCU analog inputs.

Construction details

We see only one way of aligning the copper traces in an economically viable way: Using the release liner of the previous strip as a spacer to guide the next strip. Originally we had aimed for a resolution of 1 DPcm, but relying on this technique in assembly we have to adjust that value to 1.2 DPcm, because only 6 mm wide copper tape is conveniently available.

Figure 10: 24 x 24 sensor matrix
Experiment result

My EleksMaker laser CNC machine setup

Belt holders and adjustable X-axis
Small dot laser module
Trinamic stepper drivers
1. Snip SPI pins
2. Connect DIAG0 pins to limit switch inputs D9 and D10
3. Connect both SDO pins with D12
4. Connect CS pins separately to D9 and D10
5. Connect both SCK pins to D13
6. Connect both SDI pins to D11
7. Connect VCC and GND

Grbl configuration

Update to the newest GRBL version according to their Wiki: https://github.com/gnea/grbl/wiki/Flashing-Grbl-to-an-Arduino

Open a serial terminal and check the configuration by sending $$. Here’s my config, I have added // comments to the settings that are of special interest:

$3=7 //Direction port invert, mask
$22=1 //Homing cycle, boolean
$24=1000.000 //Homing feed, mm/min
$25=2000.000 //Homing seek, mm/min
$27=10.000 //Homing pull-off, mm
$32=1 //Laser mode, boolean
$100=80.000 // X steps/mm
$101=80.000 // Y steps/mm
$110=5000.000 // X Max rate, mm/min
$111=5000.000 // Y Max rate, mm/min
$120=100.000 // X Acceleration, mm/sec^2
$121=100.000 // Y Acceleration, mm/sec^2

Secondary Arduino Sketch:

There were a few false positive stall detections, so this only a starting point for fine tuning as described in the datasheet.
Use the Arduino IDE library manager (Sketch -> Include library -> Manage libraries…)
Search for TMC2130Stepper and then install.
Or download the zip file from https://github.com/teemuatlut/TMC2130Stepper

#include <TMC2130Stepper.h>
TMC2130Stepper X = TMC2130Stepper(2, 3, 4, 9); //Only param 4 (CS pin) matters
TMC2130Stepper Y = TMC2130Stepper(5, 6, 7, 10);

void setup() {
 X.begin(); // Init
 X.rms_current(500); // Current in mA
 X.microsteps(16); // Behave like the original Pololu A4988 driver
 X.interpolate(1); // But generate intermediate steps
 X.shaft_dir(1); // Invert direction to mimic original driver
 X.diag0_stall(1); // diag0 will pull low on stall
 X.diag1_active_high(1); // diag1 will pull high on stall
 X.coolstep_min_speed(25000); // avoid false stall detection at low speeds
 X.sg_stall_value(14); // figured out by trial and error


void loop() {


Test PCB Layout