Digital twin for valve sensor

Written by

in

,

Project

Summary

Working with Spacelab LLC space startup (#1 space startup of Kazakhstan) I participated in development of one of their side projects, with internal name “Valve Sensor”.

Problem

My goal was to develop an algorithm allowing detect rotation of pipeline valve. This algorithm should work on a physical gadget, attaching to a valve handle. Gadget should be “plug and play” (just stick it to handle, calibrate, and let it work), should use an off-the-shelf electronic components and should be cheap. So, I need to get information about rotation valve from standard 9-axis IMU. Also this algorithm must use different physical principles and math than algorithms of company Aloxy (that was request of my partners from SpaceLab).

Solution

As an astrodynamicist, I understood that I need to use quaternion math in this case. But same time, as an ACDS developer, I knew amount of pain I would face with this quats later if I would try to deal with this task “hurriedly”. So, as experienced game developer, I used Unity to create digital twin of real pipeline valve, and developed an algorithm using this twin as a test installation.

And that was extremely good decision! Unity is great to create digital twins of such stuff. It is game development tool, but it is powerful, simple and fast enough when you need to focus on a problem and make a prototype rapidly!

Result

Sadly, at fall 2024 SpaceLab did not find funding at moment we developed the prototype of the sensor. So I left the project and published the algorithm under MIT-alike lincese on GitHub (now this repository moved here).

First place on Digital Bridge 2025

In October, 2025 SpaceLab “Valve Sensor” project won the Industry 4.0 Pitch Battle competition held as part of the Digital Bridge 2025 international forum in Astana.

I am proud and pretty glad that algorithm developed by me helped SpaceLab LLC to achieve this great success!


Algorithm

The core idea of an algorithm was to use available and easily detectable physical effects (gravity pull and geomagnetism) to form a basis of the “world” coordinate system.

Algorithm was separated in two steps – calibration and rotation detection.

Calibration

On calibration, at first step I formulated default axes of “sensor” coordinate system:

xs=[100]\vec{x_s} = \begin{bmatrix}1 & 0 & 0 \end{bmatrix}
ys=[010]\vec{y_s} = \begin{bmatrix} 0 & 1 & 0 \end{bmatrix}
zs=[001]\vec{z_s} = \begin{bmatrix} 0 & 0 & 1 \end{bmatrix}

Then, I formulated “constant” axis (rotation around which is less probable) as:

cs=[111]\vec{c_s} = \begin{bmatrix} 1 & 1 & 1 \end{bmatrix}

From this I calculated rotation from one of “sensor” axes to constant axis:

ws=zs×cs\vec{w_s} = \vec{z_s} \cross \vec{c_s}
wqs=1+zscsw_{qs} = 1 + \vec{z_s} \cdot \vec{c_s}
Qc=[wqsws]Q_c = \|\begin{bmatrix} w_{qs} & \vec{w_s} \end{bmatrix}\|

After this, I formulated default “word” axes, gathering data from 9-axis IMU sensor; first, X axis from vector to “magnetic north” (or any other stable magnetic direction):

xw=N\vec{x_w} = \vec{N}

Then, Y axis from inverted gravity direction:

yw=G\vec{y_w} = -\vec{G}

Then, Z axis I expressed as:

zw=xw×yw\vec{z_w} = \|\vec{x_w} \cross \vec{y_w}\|

From this I gathered “world” constant axis:

cw=Qczw\vec{c_w} = Q_c \vec{z_w}

Now, rotation from “sensor” to “world” will be:

ww=zw×cw\vec{w_w} = \vec{z_w} \cross \vec{c_w}
wqw=1+zwcww_{qw} = 1 + \vec{z_w} \cdot \vec{c_w}
Qs2w=[wqwww]Q_{s2w} = \|\begin{bmatrix} w_{qw} & \vec{w_w} \end{bmatrix}\|

Now, to simplify calculation of default rotation, let’s introduce so-called “handle” vector (vector connecting valve rotation axis and sensor position):

h=(xw+yw)((xw+yw)ys)ys\vec{h} = (\vec{x_w} + \vec{y_w}) – ((\vec{x_w} + \vec{y_w}) \cdot \|\vec{y_s}\|)\|\vec{y_s}\|

From here, default quaternion of rotation will be:

w0=(Qs2wxs)×(Qs2wh)\vec{w_0} = (Q_{s2w} \vec{x_s}) \cross (Q_{s2w} \vec{h})
wq0=1+(Qs2wxs)(Qs2wh)w_{q0} = 1 + (Q_{s2w} \vec{x_s}) \cdot (Q_{s2w} \vec{h})
Q0=[wq0w0]Q_{0} = \|\begin{bmatrix} w_{q0} & \vec{w_0} \end{bmatrix}\|

Rotation detection

To calculate current sensor rotation, we should start with setting “sensor” axis:

xs=(1,0,0)\vec{x_s} = (1,0,0)
ys=(0,1,0)\vec{y_s} = (0,1,0)

Then, set current “world” axis, gathering data from 9-axis IMU sensor:

xw=N\vec{x_w} = \vec{N}
yw=G\vec{y_w} = -\vec{G}

Same as on calibration, define “handle” vector as:

h=(xw+yw)((xw+yw)ys)ys\vec{h} = (\vec{x_w} + \vec{y_w}) – ((\vec{x_w} + \vec{y_w}) \cdot \|\vec{y_s}\|)\|\vec{y_s}\|

Now, current quaternion of rotation will be:

w1=(Qs2wxs)×(Qs2wh)\vec{w_1} = (Q_{s2w} \vec{x_s}) \cross (Q_{s2w} \vec{h})
wq1=1+(Qs2wxs)(Qs2wh)w_{q1} = 1 + (Q_{s2w} \vec{x_s}) \cdot (Q_{s2w} \vec{h})
Q1=[wq1w1]Q_{1} = \|\begin{bmatrix} w_{q1} & \vec{w_1} \end{bmatrix}\|

Now, it is easy to calculate quaternion of true rotation, which will be:

dQ=Q1Q01dQ = Q_1 Q_0^{-1}

From this it’s elementary to get valve turn angle utilizing quaternion, axis and angle relations.


Source code

C# source code of an algorithm is provided at GitHub repo.


Digital twin

Digital twin web app available here.

Views: 6