Draft of Documentation

This commit is contained in:
chk
2026-04-28 19:15:04 +02:00
parent 356c424373
commit c212aa1cff
12 changed files with 8773 additions and 5 deletions

Binary file not shown.

BIN
info/pic/robot_image_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 KiB

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 552 KiB

Binary file not shown.

11
info/position.aux Normal file
View File

@@ -0,0 +1,11 @@
\relax
\providecommand \babel@aux [2]{\global \let \babel@toc \@gobbletwo }
\@nameuse{bbl@beforestart}
\catcode `"\active
\babel@aux{ngerman}{}
\@writefile{toc}{\contentsline {section}{\numberline {1}Intro}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {2}Angles}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Bizeps {\bf \tt y}}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Ellbow -- Rotation}{2}{}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Forearm}{2}{}\protected@file@percent }
\gdef \@abspage@last{2}

271
info/position.log Normal file
View File

@@ -0,0 +1,271 @@
This is pdfTeX, Version 3.141592653-2.6-1.40.27 (MiKTeX 25.4) (preloaded format=pdflatex 2025.6.3) 28 APR 2026 18:37
entering extended mode
restricted \write18 enabled.
%&-line parsing enabled.
**./position.tex
(position.tex
LaTeX2e <2024-11-01> patch level 2
L3 programming layer <2025-04-29>
(C:\Program Files\MiKTeX\tex/latex/base\article.cls
Document Class: article 2024/06/29 v1.4n Standard LaTeX document class
(C:\Program Files\MiKTeX\tex/latex/base\size11.clo
File: size11.clo 2024/06/29 v1.4n Standard LaTeX file (size option)
)
\c@part=\count272
\c@section=\count273
\c@subsection=\count274
\c@subsubsection=\count275
\c@paragraph=\count276
\c@subparagraph=\count277
\c@figure=\count278
\c@table=\count279
\abovecaptionskip=\skip49
\belowcaptionskip=\skip50
\bibindent=\dimen146
)
(C:\Program Files\MiKTeX\tex/latex/base\inputenc.sty
Package: inputenc 2024/02/08 v1.3d Input encoding file
\inpenc@prehook=\toks17
\inpenc@posthook=\toks18
)
(C:\Program Files\MiKTeX\tex/latex/base\fontenc.sty
Package: fontenc 2021/04/29 v2.0v Standard LaTeX package
)
(C:\Program Files\MiKTeX\tex/latex/graphics\graphicx.sty
Package: graphicx 2021/09/16 v1.2d Enhanced LaTeX Graphics (DPC,SPQR)
(C:\Program Files\MiKTeX\tex/latex/graphics\keyval.sty
Package: keyval 2022/05/29 v1.15 key=value parser (DPC)
\KV@toks@=\toks19
)
(C:\Program Files\MiKTeX\tex/latex/graphics\graphics.sty
Package: graphics 2024/08/06 v1.4g Standard LaTeX Graphics (DPC,SPQR)
(C:\Program Files\MiKTeX\tex/latex/graphics\trig.sty
Package: trig 2023/12/02 v1.11 sin cos tan (DPC)
)
(C:\Program Files\MiKTeX\tex/latex/graphics-cfg\graphics.cfg
File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration
)
Package graphics Info: Driver file: pdftex.def on input line 106.
(C:\Program Files\MiKTeX\tex/latex/graphics-def\pdftex.def
File: pdftex.def 2024/04/13 v1.2c Graphics/color driver for pdftex
))
\Gin@req@height=\dimen147
\Gin@req@width=\dimen148
)
(C:\Program Files\MiKTeX\tex/generic/babel\babel.sty
Package: babel 2025/05/14 v25.9 The multilingual framework for pdfLaTeX, LuaLaT
eX and XeLaTeX
\babel@savecnt=\count280
\U@D=\dimen149
\l@unhyphenated=\language79
(C:\Program Files\MiKTeX\tex/generic/babel\txtbabel.def)
\bbl@readstream=\read2
\bbl@dirlevel=\count281
*************************************
* Local config file bblopts.cfg used
*
(C:\Program Files\MiKTeX\tex/latex/arabi\bblopts.cfg
File: bblopts.cfg 2005/09/08 v0.1 add Arabic and Farsi to "declared" options of
babel
)
(C:\Program Files\MiKTeX\tex/latex/babel-german\ngerman.ldf
Language: ngerman 2024/12/10 v2.15 German support for babel (post-1996 orthogra
phy)
(C:\Program Files\MiKTeX\tex/generic/babel/locale/de\babel-ngerman.tex
Package babel Info: Importing font and identification data for ngerman
(babel) from babel-de.ini. Reported on input line 11.
)
(C:\Program Files\MiKTeX\tex/latex/babel-german\ngermanb.ldf
Language: ngermanb 2024/12/10 v2.15 German support for babel (post-1996 orthogr
aphy)
Package babel Info: Making " an active character on input line 122.
)))
(C:\Program Files\MiKTeX\tex/latex/lm\lmodern.sty
Package: lmodern 2015/05/01 v1.6.1 Latin Modern Fonts
LaTeX Font Info: Overwriting symbol font `operators' in version `normal'
(Font) OT1/cmr/m/n --> OT1/lmr/m/n on input line 22.
LaTeX Font Info: Overwriting symbol font `letters' in version `normal'
(Font) OML/cmm/m/it --> OML/lmm/m/it on input line 23.
LaTeX Font Info: Overwriting symbol font `symbols' in version `normal'
(Font) OMS/cmsy/m/n --> OMS/lmsy/m/n on input line 24.
LaTeX Font Info: Overwriting symbol font `largesymbols' in version `normal'
(Font) OMX/cmex/m/n --> OMX/lmex/m/n on input line 25.
LaTeX Font Info: Overwriting symbol font `operators' in version `bold'
(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 26.
LaTeX Font Info: Overwriting symbol font `letters' in version `bold'
(Font) OML/cmm/b/it --> OML/lmm/b/it on input line 27.
LaTeX Font Info: Overwriting symbol font `symbols' in version `bold'
(Font) OMS/cmsy/b/n --> OMS/lmsy/b/n on input line 28.
LaTeX Font Info: Overwriting symbol font `largesymbols' in version `bold'
(Font) OMX/cmex/m/n --> OMX/lmex/m/n on input line 29.
LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `normal'
(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 31.
LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `normal'
(Font) OT1/cmss/m/n --> OT1/lmss/m/n on input line 32.
LaTeX Font Info: Overwriting math alphabet `\mathit' in version `normal'
(Font) OT1/cmr/m/it --> OT1/lmr/m/it on input line 33.
LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `normal'
(Font) OT1/cmtt/m/n --> OT1/lmtt/m/n on input line 34.
LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `bold'
(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 35.
LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold'
(Font) OT1/cmss/bx/n --> OT1/lmss/bx/n on input line 36.
LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold'
(Font) OT1/cmr/bx/it --> OT1/lmr/bx/it on input line 37.
LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold'
(Font) OT1/cmtt/m/n --> OT1/lmtt/m/n on input line 38.
)
LaTeX Font Info: Trying to load font information for T1+lmr on input line 20
.
(C:\Program Files\MiKTeX\tex/latex/lm\t1lmr.fd
File: t1lmr.fd 2015/05/01 v1.6.1 Font defs for Latin Modern
)
(C:\Program Files\MiKTeX\tex/latex/l3backend\l3backend-pdftex.def
File: l3backend-pdftex.def 2025-04-14 L3 backend support: PDF output (pdfTeX)
\l__color_backend_stack_int=\count282
)
(position.aux
Package babel Info: 'ngerman' activates 'ngerman' shorthands.
(babel) Reported on input line 5.
)
\openout1 = `position.aux'.
LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 20.
LaTeX Font Info: ... okay on input line 20.
LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 20.
LaTeX Font Info: ... okay on input line 20.
LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 20.
LaTeX Font Info: ... okay on input line 20.
LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 20.
LaTeX Font Info: ... okay on input line 20.
LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 20.
LaTeX Font Info: ... okay on input line 20.
LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 20.
LaTeX Font Info: ... okay on input line 20.
LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 20.
LaTeX Font Info: ... okay on input line 20.
(C:\Program Files\MiKTeX\tex/context/base/mkii\supp-pdf.mkii
[Loading MPS to PDF converter (version 2006.09.02).]
\scratchcounter=\count283
\scratchdimen=\dimen150
\scratchbox=\box53
\nofMPsegments=\count284
\nofMParguments=\count285
\everyMPshowfont=\toks20
\MPscratchCnt=\count286
\MPscratchDim=\dimen151
\MPnumerator=\count287
\makeMPintoPDFobject=\count288
\everyMPtoPDFconversion=\toks21
) (C:\Program Files\MiKTeX\tex/latex/epstopdf-pkg\epstopdf-base.sty
Package: epstopdf-base 2020-01-24 v2.11 Base part for package epstopdf
Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4
85.
(C:\Program Files\MiKTeX\tex/latex/00miktex\epstopdf-sys.cfg
File: epstopdf-sys.cfg 2021/03/18 v2.0 Configuration of epstopdf for MiKTeX
))
LaTeX Font Info: Trying to load font information for OT1+lmr on input line 2
2.
(C:\Program Files\MiKTeX\tex/latex/lm\ot1lmr.fd
File: ot1lmr.fd 2015/05/01 v1.6.1 Font defs for Latin Modern
)
LaTeX Font Info: Trying to load font information for OML+lmm on input line 2
2.
(C:\Program Files\MiKTeX\tex/latex/lm\omllmm.fd
File: omllmm.fd 2015/05/01 v1.6.1 Font defs for Latin Modern
)
LaTeX Font Info: Trying to load font information for OMS+lmsy on input line
22.
(C:\Program Files\MiKTeX\tex/latex/lm\omslmsy.fd
File: omslmsy.fd 2015/05/01 v1.6.1 Font defs for Latin Modern
)
LaTeX Font Info: Trying to load font information for OMX+lmex on input line
22.
(C:\Program Files\MiKTeX\tex/latex/lm\omxlmex.fd
File: omxlmex.fd 2015/05/01 v1.6.1 Font defs for Latin Modern
)
LaTeX Font Info: External font `lmex10' loaded for size
(Font) <12> on input line 22.
LaTeX Font Info: External font `lmex10' loaded for size
(Font) <8> on input line 22.
LaTeX Font Info: External font `lmex10' loaded for size
(Font) <6> on input line 22.
LaTeX Font Info: Trying to load font information for T1+lmtt on input line 3
4.
(C:\Program Files\MiKTeX\tex/latex/lm\t1lmtt.fd
File: t1lmtt.fd 2015/05/01 v1.6.1 Font defs for Latin Modern
)
<pic/robot_image_a.png, id=1, 885.3075pt x 402.75468pt>
File: pic/robot_image_a.png Graphic file (type png)
<use pic/robot_image_a.png>
Package pdftex.def Info: pic/robot_image_a.png used on input line 43.
(pdftex.def) Requested size: 360.0pt x 163.77846pt.
LaTeX Font Info: External font `lmex10' loaded for size
(Font) <10.95> on input line 48.
LaTeX Font Info: Trying to load font information for TS1+lmr on input line 5
4.
(C:\Program Files\MiKTeX\tex/latex/lm\ts1lmr.fd
File: ts1lmr.fd 2015/05/01 v1.6.1 Font defs for Latin Modern
)
Underfull \hbox (badness 2293) in paragraph at lines 55--57
\T1/lmr/m/n/10.95 (each po-si-ti-on on its
[]
<pic/robot_sideView_measurements.pdf, id=3, 595.22375pt x 429.605pt>
File: pic/robot_sideView_measurements.pdf Graphic file (type pdf)
<use pic/robot_sideView_measurements.pdf>
Package pdftex.def Info: pic/robot_sideView_measurements.pdf used on input lin
e 62.
(pdftex.def) Requested size: 216.0022pt x 155.8966pt.
[1
{C:/Users/kech/AppData/Local/MiKTeX/fonts/map/pdftex/pdftex.map}{C:/Program Fil
es/MiKTeX/fonts/enc/dvips/lm/lm-ec.enc}{C:/Program Files/MiKTeX/fonts/enc/dvips
/lm/lm-mathsy.enc} <./pic/robot_image_a.png>]
[2{C:/Program Files/MiKTeX/fonts/enc/dvips/lm/lm-ts1.enc}{C:/Program Files/MiKT
eX/fonts/enc/dvips/lm/lm-rm.enc}{C:/Program Files/MiKTeX/fonts/enc/dvips/lm/lm-
mathit.enc} <./pic/robot_sideView_measurements.pdf>] (position.aux)
***********
LaTeX2e <2024-11-01> patch level 2
L3 programming layer <2025-04-29>
***********
)
Here is how much of TeX's memory you used:
2937 strings out of 469923
49608 string characters out of 5479241
434765 words of memory out of 5000000
29733 multiletter control sequences out of 15000+600000
661525 words of font info for 64 fonts, out of 8000000 for 9000
1141 hyphenation exceptions out of 8191
57i,6n,65p,227b,236s stack positions out of 10000i,1000n,20000p,200000b,200000s
<C:/Program Files/MiKTeX/fonts/type1/public/lm/lmbx12.pfb><C:/Program Files/M
iKTeX/fonts/type1/public/lm/lmmi10.pfb><C:/Program Files/MiKTeX/fonts/type1/pub
lic/lm/lmmi8.pfb><C:/Program Files/MiKTeX/fonts/type1/public/lm/lmr10.pfb><C:/P
rogram Files/MiKTeX/fonts/type1/public/lm/lmr12.pfb><C:/Program Files/MiKTeX/fo
nts/type1/public/lm/lmr17.pfb><C:/Program Files/MiKTeX/fonts/type1/public/lm/lm
r8.pfb><C:/Program Files/MiKTeX/fonts/type1/public/lm/lmsy10.pfb><C:/Program Fi
les/MiKTeX/fonts/type1/public/lm/lmtt10.pfb><C:/Program Files/MiKTeX/fonts/type
1/public/lm/lmtt12.pfb>
Output written on position.pdf (2 pages, 1242265 bytes).
PDF statistics:
1451 PDF objects out of 1728 (max. 8388607)
0 named destinations out of 1000 (max. 500000)
11 words of extra memory for PDF output out of 10000 (max. 10000000)

BIN
info/position.pdf Normal file

Binary file not shown.

BIN
info/position.synctex.gz Normal file

Binary file not shown.

90
info/position.tex Normal file
View File

@@ -0,0 +1,90 @@
\documentclass[a4paper,11pt]{article}
% Zeichencodierung für deutsche Umlaute
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
% Grafiken einbinden
\usepackage{graphicx}
% Deutsche Sprache (Datum, Trennungen, etc.)
\usepackage[ngerman]{babel}
% Optional: bessere Schrift
\usepackage{lmodern}
\title{How to get a robot position from video image}
\author{Christoph Kendel}
\date{\today}
\begin{document}
\maketitle
\section{Intro}
My Robot-Arm does not have homing switches. I want to use WebCams and Aruco--Markers to get the position of each joint. This way
I can get the position as well as double--check the position while working under load.
I work with Arucos. With my low resolution WebCam I can get reliable positions (when using two cams). But the angle resolution is not usable.
So I have to calculate the angle of each element from the relative positions of the markers.
\section{Angles}
\subsection{Bizeps {\bf \tt y}}
To find the angle of the bizeps (upper arm) there are different options, depending on the angle-of-view and which
ArUcos are visable.
\vspace{2mm}
\noindent
\includegraphics[width=\linewidth]{pic/robot_image_a.png}
\vspace{2mm}
\noindent
The calculation is based on two approaches: Position of the Markers 243 etc on the one hand, and relative position 198 $\leftrightarrow$ 229 on the other hand.
\noindent
\begin{minipage}{0.39\linewidth}
Several ways to calculate {\tt y}:
\begin{itemize}
\item 229 $\leftrightarrow$ 198 $\tan(y) = \frac{\Delta z}{\Delta y} $
\item From $y_{\rm Axis}$ and the positions of 243, 229, 198 (each position on its own) we can calculate $\tan(y+\delta)$
with a known $\delta$ from the geometry.
Thus we get {\tt y}
\end{itemize}
\end{minipage}\hfill
\begin{minipage}{0.6\linewidth}
\includegraphics[width=\linewidth]{pic/robot_sideView_measurements.pdf}
\end{minipage}
\vspace{2mm}
\noindent
Each availiable (if marker is visible) approach to calculate {\tt y} is done, and the mean is calculated. We can check if they deviate too much, and give
warnings.
\subsection{Ellbow -- Rotation}
At the ellbow there is a motor that turns the forearm arround. Depending on which Arucus are visible, the position {\tt a} of the motor can be calculated:
\begin{itemize}
\item {\tt x} of 223 or ...
\end{itemize}
%
%
the
{\tt y} and {\tt z} position of 223 etc can't be used, as it depends on the angle of the forearm and the angle of the bizeps. Thus is it less reliable. (Although it would be a nice
thing to use as a double--check).
\subsection{Forearm}
\end{document}

View File

@@ -374,7 +374,8 @@ async function calculate() {
const row242 = getRow(242, 3); const row242 = getRow(242, 3);
const row200 = getRow(200, 3); const row200 = getRow(200, 3);
const row204 = getRow(204, 3); const row204 = getRow(204, 3);
const row222 = getRow(222, 3); const row222 = getRow(222, 3); // Ellbow
const row223 = getRow(223, 3); // Lower Arm
const angleYCandidates = []; const angleYCandidates = [];
@@ -451,6 +452,7 @@ async function calculate() {
}); });
} }
if (angleYCandidates.length > 0) { if (angleYCandidates.length > 0) {
buildFeatureFromCandidates( buildFeatureFromCandidates(
result, result,
@@ -521,14 +523,15 @@ async function calculate() {
let x226 = 0; let x226 = 0;
let xCount = 0; let xCount = 0;
if(row222){
x226 += row222.x_mm * 5;
xCount += 5;
}
if (row226) { if (row226) {
x226 += row226.x_mm * 5; x226 += row226.x_mm * 5;
xCount += 5; xCount += 5;
} }
if(row222){
/// 222 should have the same as x226
x226 += row222.x_mm * 5;
xCount += 5;
}
if (row229) { if (row229) {
x226 += row229.x_mm + 90; x226 += row229.x_mm + 90;
xCount += 1; xCount += 1;
@@ -618,6 +621,27 @@ async function calculate() {
} }
} }
} }
// Ellbow-Rotation wenn X Position OK und 223 oder so bekannt ist.
if(row223 && xCount > 2){
// unterarm-roll => a aus der position von 223
dx = row223.x_mm - x226;
// aus der X Position kann der Unterarm-Winkel (a) berechnet werden
const angleRad = Math.asin(dx / 35);
const angleDeg = 90 - angleRad * 180 / Math.PI;
addLog(result, `(xEllbowRotation = ${angleDeg.toFixed(2)}° = ${angleRad.toFixed(4)} rad ) aus x von 223 und Ellbogen x226`);
addCalculation(result, {
type: "elbowRotationAFromX223",
input: {
x223: row223.x_mm,
x226
},
output: {
angleRad, angleDeg
}
});
}
} }
result.summary = { result.summary = {

View File

@@ -0,0 +1,265 @@
/**
* @jest-environment jsdom
*/
const fs = require("fs");
const path = require("path");
describe("calculate() row223 Ellbow-Rotation Tests", () => {
let calculate;
beforeEach(() => {
// DOM erzeugen
document.body.innerHTML = `
<textarea id="analysis-log"></textarea>
`;
// Fetch mocken - wird pro Test konfiguriert
global.fetch = jest.fn();
// Modul erst JETZT laden (DOM existiert)
({ calculate } = require("../public/calculateActions.js"));
});
/**
* Hilfsfunktion: Erstellt ein CSV mit definierten row223.x_mm und x226 Wert
* @param {number} row223_x_mm - x_mm Wert für row223 (id=223)
* @param {number} x226_base - Basis-x_mm Wert für x226-Punkt (wird durch mehrere Punkte erreicht)
*/
function createTestCSV(row223_x_mm, x226_base) {
const csvContent = `id,x_mm,y_mm,z_mm,roll_deg,pitch_deg,seen_by
222,${x226_base},120,65,0,0,3
226,${x226_base},115,61,0,0,3
229,${x226_base - 90},110,55,0,0,3
223,${row223_x_mm},125,62,0,0,3
`;
return csvContent;
}
/**
* Berechnet den erwarteten Winkel basierend auf Formel aus calculateActions.js
* angleRad = Math.asin(dx / 35)
* angleDeg = 90 - angleRad * 180 / Math.PI
*/
function calculateExpectedAngle(row223_x_mm, x226) {
const dx = row223_x_mm - x226;
if (Math.abs(dx) > 35) {
return null; // Math.asin() erlaubt nur Werte zwischen -1 und 1
}
const angleRad = Math.asin(dx / 35);
const angleDeg = 90 - angleRad * 180 / Math.PI;
return { angleRad, angleDeg, dx };
}
// Test 1: row223 mit x_mm = x226 (dx = 0, erwarteter Winkel = 90°)
test("row223.x_mm = x226 sollte Winkel von 90° ergeben", async () => {
const x226_base = 100;
const row223_x_mm = x226_base; // dx = 0
const csvContent = createTestCSV(row223_x_mm, x226_base);
global.fetch.mockResolvedValueOnce({
ok: true,
headers: { get: () => "text/csv" },
text: async () => csvContent
});
const result = await calculate();
// xCount sollte > 2 sein (wir haben 4 Zeilen)
expect(result.status).toBe("ok");
// Überprüfe, ob die elbowRotationAFromX223 Berechnung vorhanden ist
const elbowRotationCalc = result.calculations.find(
c => c.type === "elbowRotationAFromX223"
);
expect(elbowRotationCalc).toBeDefined();
expect(elbowRotationCalc.output.angleDeg).toBeCloseTo(90, 1);
expect(elbowRotationCalc.output.angleRad).toBeCloseTo(0, 4);
});
// Test 2: row223 mit x_mm = x226 + 17.5 (dx = 17.5, erwarteter Winkel = 45°)
test("row223.x_mm = x226 + 17.5 sollte Winkel von 45° ergeben", async () => {
const x226_base = 100;
const row223_x_mm = x226_base + 17.5; // dx = 17.5
const csvContent = createTestCSV(row223_x_mm, x226_base);
global.fetch.mockResolvedValueOnce({
ok: true,
headers: { get: () => "text/csv" },
text: async () => csvContent
});
const result = await calculate();
const expected = calculateExpectedAngle(row223_x_mm, x226_base);
expect(result.status).toBe("ok");
const elbowRotationCalc = result.calculations.find(
c => c.type === "elbowRotationAFromX223"
);
expect(elbowRotationCalc).toBeDefined();
expect(elbowRotationCalc.output.angleDeg).toBeCloseTo(expected.angleDeg, 1);
expect(elbowRotationCalc.output.angleRad).toBeCloseTo(expected.angleRad, 3);
});
// Test 3: row223 mit x_mm = x226 + 35 (dx = 35, erwarteter Winkel = 0°)
test("row223.x_mm = x226 + 35 sollte Winkel von 0° ergeben", async () => {
const x226_base = 100;
const row223_x_mm = x226_base + 35; // dx = 35, asin(1) = π/2
const csvContent = createTestCSV(row223_x_mm, x226_base);
global.fetch.mockResolvedValueOnce({
ok: true,
headers: { get: () => "text/csv" },
text: async () => csvContent
});
const result = await calculate();
const expected = calculateExpectedAngle(row223_x_mm, x226_base);
expect(result.status).toBe("ok");
const elbowRotationCalc = result.calculations.find(
c => c.type === "elbowRotationAFromX223"
);
expect(elbowRotationCalc).toBeDefined();
expect(elbowRotationCalc.output.angleDeg).toBeCloseTo(expected.angleDeg, 1);
expect(elbowRotationCalc.output.angleRad).toBeCloseTo(expected.angleRad, 3);
});
// Test 4: row223 mit negativem dx (x_mm = x226 - 17.5, erwarteter Winkel = 135°)
test("row223.x_mm = x226 - 17.5 sollte Winkel von 135° ergeben", async () => {
const x226_base = 100;
const row223_x_mm = x226_base - 17.5; // dx = -17.5
const csvContent = createTestCSV(row223_x_mm, x226_base);
global.fetch.mockResolvedValueOnce({
ok: true,
headers: { get: () => "text/csv" },
text: async () => csvContent
});
const result = await calculate();
const expected = calculateExpectedAngle(row223_x_mm, x226_base);
expect(result.status).toBe("ok");
const elbowRotationCalc = result.calculations.find(
c => c.type === "elbowRotationAFromX223"
);
expect(elbowRotationCalc).toBeDefined();
expect(elbowRotationCalc.output.angleDeg).toBeCloseTo(expected.angleDeg, 1);
expect(elbowRotationCalc.output.angleRad).toBeCloseTo(expected.angleRad, 3);
});
// Test 5: row223 mit x_mm = x226 - 35 (dx = -35, erwarteter Winkel = 180°)
test("row223.x_mm = x226 - 35 sollte Winkel von 180° ergeben", async () => {
const x226_base = 100;
const row223_x_mm = x226_base - 35; // dx = -35, asin(-1) = -π/2
const csvContent = createTestCSV(row223_x_mm, x226_base);
global.fetch.mockResolvedValueOnce({
ok: true,
headers: { get: () => "text/csv" },
text: async () => csvContent
});
const result = await calculate();
const expected = calculateExpectedAngle(row223_x_mm, x226_base);
expect(result.status).toBe("ok");
const elbowRotationCalc = result.calculations.find(
c => c.type === "elbowRotationAFromX223"
);
expect(elbowRotationCalc).toBeDefined();
expect(elbowRotationCalc.output.angleDeg).toBeCloseTo(expected.angleDeg, 1);
expect(elbowRotationCalc.output.angleRad).toBeCloseTo(expected.angleRad, 3);
});
// Test 6: xCount > 2 Bedingung wird erfüllt
test("xCount muss > 2 sein, damit elbowRotationAFromX223 berechnet wird", async () => {
const x226_base = 100;
const row223_x_mm = x226_base + 10;
const csvContent = createTestCSV(row223_x_mm, x226_base);
global.fetch.mockResolvedValueOnce({
ok: true,
headers: { get: () => "text/csv" },
text: async () => csvContent
});
const result = await calculate();
// Überprüfe, dass die Berechnung stattgefunden hat
const elbowXEstimate = result.calculations.find(
c => c.type === "elbowXEstimate"
);
const elbowRotationCalc = result.calculations.find(
c => c.type === "elbowRotationAFromX223"
);
expect(elbowXEstimate).toBeDefined(); // xCount wurde berechnet
expect(elbowRotationCalc).toBeDefined(); // xCount > 2 und row223 existiert
});
// Test 7: Parametrisierter Test mit verschiedenen Winkeln
test.each([
{ dx: 0, expectedDeg: 90, desc: "dx=0" },
{ dx: 5, expectedDeg: 90 - Math.asin(5 / 35) * 180 / Math.PI, desc: "dx=5" },
{ dx: 10, expectedDeg: 90 - Math.asin(10 / 35) * 180 / Math.PI, desc: "dx=10" },
{ dx: -5, expectedDeg: 90 - Math.asin(-5 / 35) * 180 / Math.PI, desc: "dx=-5" },
{ dx: -10, expectedDeg: 90 - Math.asin(-10 / 35) * 180 / Math.PI, desc: "dx=-10" },
])(
"Verschiedene dx Werte sollten korrekte Winkel ergeben ($desc)",
async ({ dx, expectedDeg }) => {
const x226_base = 100;
const row223_x_mm = x226_base + dx;
const csvContent = createTestCSV(row223_x_mm, x226_base);
global.fetch.mockResolvedValueOnce({
ok: true,
headers: { get: () => "text/csv" },
text: async () => csvContent
});
const result = await calculate();
const elbowRotationCalc = result.calculations.find(
c => c.type === "elbowRotationAFromX223"
);
expect(elbowRotationCalc).toBeDefined();
expect(elbowRotationCalc.output.angleDeg).toBeCloseTo(expectedDeg, 1);
}
);
// Test 8: row223 Input wird korrekt in Output dokumentiert
test("row223.x_mm wird korrekt in Berechnung dokumentiert", async () => {
const x226_base = 100;
const row223_x_mm = 115;
const csvContent = createTestCSV(row223_x_mm, x226_base);
global.fetch.mockResolvedValueOnce({
ok: true,
headers: { get: () => "text/csv" },
text: async () => csvContent
});
const result = await calculate();
const elbowRotationCalc = result.calculations.find(
c => c.type === "elbowRotationAFromX223"
);
expect(elbowRotationCalc).toBeDefined();
expect(elbowRotationCalc.input.x223).toBe(row223_x_mm);
expect(elbowRotationCalc.input.x226).toBe(x226_base);
});
});