diff --git a/3d_model/24-47 with frame.svg b/3d_model/24-47 with frame.svg
new file mode 100755
index 0000000..21605c9
--- /dev/null
+++ b/3d_model/24-47 with frame.svg
@@ -0,0 +1,85 @@
+
+
+
+
diff --git a/3d_model/24-47.stl b/3d_model/24-47.stl
new file mode 100755
index 0000000..2b93014
Binary files /dev/null and b/3d_model/24-47.stl differ
diff --git a/3d_model/Backplate.stl b/3d_model/Backplate.stl
new file mode 100755
index 0000000..ec7722d
Binary files /dev/null and b/3d_model/Backplate.stl differ
diff --git a/3d_model/Baseplate.step b/3d_model/Baseplate.step
new file mode 100755
index 0000000..3198e90
--- /dev/null
+++ b/3d_model/Baseplate.step
@@ -0,0 +1,831 @@
+ISO-10303-21;
+HEADER;
+/* Generated by software containing ST-Developer
+ * from STEP Tools, Inc. (www.steptools.com)
+ */
+
+FILE_DESCRIPTION(
+/* description */ (''),
+/* implementation_level */ '2;1');
+
+FILE_NAME(
+/* name */ 'Baseplate.step',
+/* time_stamp */ '2026-03-10T23:07:41+01:00',
+/* author */ (''),
+/* organization */ (''),
+/* preprocessor_version */ 'ST-DEVELOPER v20.1',
+/* originating_system */ 'Autodesk Translation Framework v14.10.0.0',
+/* authorisation */ '');
+
+FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
+ENDSEC;
+
+DATA;
+#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#13),#750);
+#11=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#757,#12);
+#12=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#14),#749);
+#13=STYLED_ITEM('',(#766),#14);
+#14=MANIFOLD_SOLID_BREP('Body1',#438);
+#15=FACE_BOUND('',#89,.T.);
+#16=FACE_BOUND('',#90,.T.);
+#17=FACE_BOUND('',#91,.T.);
+#18=FACE_BOUND('',#92,.T.);
+#19=FACE_BOUND('',#93,.T.);
+#20=FACE_BOUND('',#95,.T.);
+#21=FACE_BOUND('',#96,.T.);
+#22=FACE_BOUND('',#97,.T.);
+#23=FACE_BOUND('',#98,.T.);
+#24=FACE_BOUND('',#99,.T.);
+#25=PLANE('',#475);
+#26=PLANE('',#479);
+#27=PLANE('',#480);
+#28=PLANE('',#484);
+#29=PLANE('',#485);
+#30=PLANE('',#489);
+#31=PLANE('',#490);
+#32=PLANE('',#494);
+#33=PLANE('',#495);
+#34=PLANE('',#496);
+#35=CYLINDRICAL_SURFACE('',#455,2.);
+#36=CYLINDRICAL_SURFACE('',#460,2.);
+#37=CYLINDRICAL_SURFACE('',#465,2.);
+#38=CYLINDRICAL_SURFACE('',#470,2.);
+#39=CYLINDRICAL_SURFACE('',#472,40.);
+#40=CYLINDRICAL_SURFACE('',#476,7.);
+#41=CYLINDRICAL_SURFACE('',#481,7.);
+#42=CYLINDRICAL_SURFACE('',#486,7.);
+#43=CYLINDRICAL_SURFACE('',#491,7.);
+#44=FACE_OUTER_BOUND('',#67,.T.);
+#45=FACE_OUTER_BOUND('',#68,.T.);
+#46=FACE_OUTER_BOUND('',#69,.T.);
+#47=FACE_OUTER_BOUND('',#70,.T.);
+#48=FACE_OUTER_BOUND('',#71,.T.);
+#49=FACE_OUTER_BOUND('',#72,.T.);
+#50=FACE_OUTER_BOUND('',#73,.T.);
+#51=FACE_OUTER_BOUND('',#74,.T.);
+#52=FACE_OUTER_BOUND('',#75,.T.);
+#53=FACE_OUTER_BOUND('',#76,.T.);
+#54=FACE_OUTER_BOUND('',#77,.T.);
+#55=FACE_OUTER_BOUND('',#78,.T.);
+#56=FACE_OUTER_BOUND('',#79,.T.);
+#57=FACE_OUTER_BOUND('',#80,.T.);
+#58=FACE_OUTER_BOUND('',#81,.T.);
+#59=FACE_OUTER_BOUND('',#82,.T.);
+#60=FACE_OUTER_BOUND('',#83,.T.);
+#61=FACE_OUTER_BOUND('',#84,.T.);
+#62=FACE_OUTER_BOUND('',#85,.T.);
+#63=FACE_OUTER_BOUND('',#86,.T.);
+#64=FACE_OUTER_BOUND('',#87,.T.);
+#65=FACE_OUTER_BOUND('',#88,.T.);
+#66=FACE_OUTER_BOUND('',#94,.T.);
+#67=EDGE_LOOP('',(#293,#294,#295,#296));
+#68=EDGE_LOOP('',(#297,#298,#299,#300));
+#69=EDGE_LOOP('',(#301,#302,#303,#304));
+#70=EDGE_LOOP('',(#305,#306,#307,#308));
+#71=EDGE_LOOP('',(#309,#310,#311,#312));
+#72=EDGE_LOOP('',(#313,#314,#315,#316));
+#73=EDGE_LOOP('',(#317,#318,#319,#320));
+#74=EDGE_LOOP('',(#321,#322,#323,#324));
+#75=EDGE_LOOP('',(#325,#326,#327,#328));
+#76=EDGE_LOOP('',(#329,#330,#331,#332));
+#77=EDGE_LOOP('',(#333,#334,#335,#336));
+#78=EDGE_LOOP('',(#337,#338,#339,#340));
+#79=EDGE_LOOP('',(#341,#342,#343,#344));
+#80=EDGE_LOOP('',(#345,#346,#347,#348));
+#81=EDGE_LOOP('',(#349,#350,#351,#352));
+#82=EDGE_LOOP('',(#353,#354,#355,#356));
+#83=EDGE_LOOP('',(#357,#358,#359,#360));
+#84=EDGE_LOOP('',(#361,#362,#363,#364));
+#85=EDGE_LOOP('',(#365,#366,#367,#368));
+#86=EDGE_LOOP('',(#369,#370,#371,#372));
+#87=EDGE_LOOP('',(#373,#374,#375,#376));
+#88=EDGE_LOOP('',(#377,#378,#379,#380,#381,#382,#383,#384,#385,#386,#387,
+#388));
+#89=EDGE_LOOP('',(#389));
+#90=EDGE_LOOP('',(#390));
+#91=EDGE_LOOP('',(#391));
+#92=EDGE_LOOP('',(#392));
+#93=EDGE_LOOP('',(#393));
+#94=EDGE_LOOP('',(#394,#395,#396,#397,#398,#399,#400,#401,#402,#403,#404,
+#405));
+#95=EDGE_LOOP('',(#406));
+#96=EDGE_LOOP('',(#407));
+#97=EDGE_LOOP('',(#408));
+#98=EDGE_LOOP('',(#409));
+#99=EDGE_LOOP('',(#410));
+#100=LINE('',#631,#137);
+#101=LINE('',#635,#138);
+#102=LINE('',#641,#139);
+#103=LINE('',#645,#140);
+#104=LINE('',#651,#141);
+#105=LINE('',#655,#142);
+#106=LINE('',#661,#143);
+#107=LINE('',#665,#144);
+#108=LINE('',#671,#145);
+#109=LINE('',#676,#146);
+#110=LINE('',#678,#147);
+#111=LINE('',#680,#148);
+#112=LINE('',#681,#149);
+#113=LINE('',#687,#150);
+#114=LINE('',#690,#151);
+#115=LINE('',#692,#152);
+#116=LINE('',#693,#153);
+#117=LINE('',#696,#154);
+#118=LINE('',#698,#155);
+#119=LINE('',#699,#156);
+#120=LINE('',#705,#157);
+#121=LINE('',#708,#158);
+#122=LINE('',#710,#159);
+#123=LINE('',#711,#160);
+#124=LINE('',#714,#161);
+#125=LINE('',#716,#162);
+#126=LINE('',#717,#163);
+#127=LINE('',#723,#164);
+#128=LINE('',#726,#165);
+#129=LINE('',#728,#166);
+#130=LINE('',#729,#167);
+#131=LINE('',#732,#168);
+#132=LINE('',#734,#169);
+#133=LINE('',#735,#170);
+#134=LINE('',#741,#171);
+#135=LINE('',#743,#172);
+#136=LINE('',#744,#173);
+#137=VECTOR('',#503,2.825);
+#138=VECTOR('',#508,2.);
+#139=VECTOR('',#515,2.825);
+#140=VECTOR('',#520,2.);
+#141=VECTOR('',#527,2.825);
+#142=VECTOR('',#532,2.);
+#143=VECTOR('',#539,2.825);
+#144=VECTOR('',#544,2.);
+#145=VECTOR('',#551,40.);
+#146=VECTOR('',#556,10.);
+#147=VECTOR('',#557,10.);
+#148=VECTOR('',#558,10.);
+#149=VECTOR('',#559,10.);
+#150=VECTOR('',#566,10.);
+#151=VECTOR('',#569,10.);
+#152=VECTOR('',#570,10.);
+#153=VECTOR('',#571,10.);
+#154=VECTOR('',#574,10.);
+#155=VECTOR('',#575,10.);
+#156=VECTOR('',#576,10.);
+#157=VECTOR('',#583,10.);
+#158=VECTOR('',#586,10.);
+#159=VECTOR('',#587,10.);
+#160=VECTOR('',#588,10.);
+#161=VECTOR('',#591,10.);
+#162=VECTOR('',#592,10.);
+#163=VECTOR('',#593,10.);
+#164=VECTOR('',#600,10.);
+#165=VECTOR('',#603,10.);
+#166=VECTOR('',#604,10.);
+#167=VECTOR('',#605,10.);
+#168=VECTOR('',#608,10.);
+#169=VECTOR('',#609,10.);
+#170=VECTOR('',#610,10.);
+#171=VECTOR('',#617,10.);
+#172=VECTOR('',#620,10.);
+#173=VECTOR('',#621,10.);
+#174=CIRCLE('',#453,3.65);
+#175=CIRCLE('',#454,2.);
+#176=CIRCLE('',#456,2.00000000000001);
+#177=CIRCLE('',#458,3.65);
+#178=CIRCLE('',#459,2.);
+#179=CIRCLE('',#461,2.00000000000001);
+#180=CIRCLE('',#463,3.65);
+#181=CIRCLE('',#464,2.);
+#182=CIRCLE('',#466,2.00000000000001);
+#183=CIRCLE('',#468,3.65);
+#184=CIRCLE('',#469,2.);
+#185=CIRCLE('',#471,2.00000000000001);
+#186=CIRCLE('',#473,40.);
+#187=CIRCLE('',#474,40.);
+#188=CIRCLE('',#477,7.);
+#189=CIRCLE('',#478,7.);
+#190=CIRCLE('',#482,7.);
+#191=CIRCLE('',#483,7.);
+#192=CIRCLE('',#487,7.);
+#193=CIRCLE('',#488,7.);
+#194=CIRCLE('',#492,7.);
+#195=CIRCLE('',#493,7.);
+#196=VERTEX_POINT('',#628);
+#197=VERTEX_POINT('',#630);
+#198=VERTEX_POINT('',#634);
+#199=VERTEX_POINT('',#638);
+#200=VERTEX_POINT('',#640);
+#201=VERTEX_POINT('',#644);
+#202=VERTEX_POINT('',#648);
+#203=VERTEX_POINT('',#650);
+#204=VERTEX_POINT('',#654);
+#205=VERTEX_POINT('',#658);
+#206=VERTEX_POINT('',#660);
+#207=VERTEX_POINT('',#664);
+#208=VERTEX_POINT('',#668);
+#209=VERTEX_POINT('',#670);
+#210=VERTEX_POINT('',#674);
+#211=VERTEX_POINT('',#675);
+#212=VERTEX_POINT('',#677);
+#213=VERTEX_POINT('',#679);
+#214=VERTEX_POINT('',#683);
+#215=VERTEX_POINT('',#685);
+#216=VERTEX_POINT('',#689);
+#217=VERTEX_POINT('',#691);
+#218=VERTEX_POINT('',#695);
+#219=VERTEX_POINT('',#697);
+#220=VERTEX_POINT('',#701);
+#221=VERTEX_POINT('',#703);
+#222=VERTEX_POINT('',#707);
+#223=VERTEX_POINT('',#709);
+#224=VERTEX_POINT('',#713);
+#225=VERTEX_POINT('',#715);
+#226=VERTEX_POINT('',#719);
+#227=VERTEX_POINT('',#721);
+#228=VERTEX_POINT('',#725);
+#229=VERTEX_POINT('',#727);
+#230=VERTEX_POINT('',#731);
+#231=VERTEX_POINT('',#733);
+#232=VERTEX_POINT('',#737);
+#233=VERTEX_POINT('',#739);
+#234=EDGE_CURVE('',#196,#196,#174,.T.);
+#235=EDGE_CURVE('',#196,#197,#100,.T.);
+#236=EDGE_CURVE('',#197,#197,#175,.T.);
+#237=EDGE_CURVE('',#197,#198,#101,.T.);
+#238=EDGE_CURVE('',#198,#198,#176,.T.);
+#239=EDGE_CURVE('',#199,#199,#177,.T.);
+#240=EDGE_CURVE('',#199,#200,#102,.T.);
+#241=EDGE_CURVE('',#200,#200,#178,.T.);
+#242=EDGE_CURVE('',#200,#201,#103,.T.);
+#243=EDGE_CURVE('',#201,#201,#179,.T.);
+#244=EDGE_CURVE('',#202,#202,#180,.T.);
+#245=EDGE_CURVE('',#202,#203,#104,.T.);
+#246=EDGE_CURVE('',#203,#203,#181,.T.);
+#247=EDGE_CURVE('',#203,#204,#105,.T.);
+#248=EDGE_CURVE('',#204,#204,#182,.T.);
+#249=EDGE_CURVE('',#205,#205,#183,.T.);
+#250=EDGE_CURVE('',#205,#206,#106,.T.);
+#251=EDGE_CURVE('',#206,#206,#184,.T.);
+#252=EDGE_CURVE('',#206,#207,#107,.T.);
+#253=EDGE_CURVE('',#207,#207,#185,.T.);
+#254=EDGE_CURVE('',#208,#208,#186,.T.);
+#255=EDGE_CURVE('',#208,#209,#108,.T.);
+#256=EDGE_CURVE('',#209,#209,#187,.T.);
+#257=EDGE_CURVE('',#210,#211,#109,.T.);
+#258=EDGE_CURVE('',#210,#212,#110,.T.);
+#259=EDGE_CURVE('',#213,#212,#111,.T.);
+#260=EDGE_CURVE('',#211,#213,#112,.T.);
+#261=EDGE_CURVE('',#211,#214,#188,.T.);
+#262=EDGE_CURVE('',#215,#213,#189,.T.);
+#263=EDGE_CURVE('',#214,#215,#113,.T.);
+#264=EDGE_CURVE('',#214,#216,#114,.T.);
+#265=EDGE_CURVE('',#217,#215,#115,.T.);
+#266=EDGE_CURVE('',#216,#217,#116,.T.);
+#267=EDGE_CURVE('',#216,#218,#117,.T.);
+#268=EDGE_CURVE('',#219,#217,#118,.T.);
+#269=EDGE_CURVE('',#218,#219,#119,.T.);
+#270=EDGE_CURVE('',#218,#220,#190,.T.);
+#271=EDGE_CURVE('',#221,#219,#191,.T.);
+#272=EDGE_CURVE('',#220,#221,#120,.T.);
+#273=EDGE_CURVE('',#220,#222,#121,.T.);
+#274=EDGE_CURVE('',#223,#221,#122,.T.);
+#275=EDGE_CURVE('',#222,#223,#123,.T.);
+#276=EDGE_CURVE('',#222,#224,#124,.T.);
+#277=EDGE_CURVE('',#225,#223,#125,.T.);
+#278=EDGE_CURVE('',#224,#225,#126,.T.);
+#279=EDGE_CURVE('',#224,#226,#192,.T.);
+#280=EDGE_CURVE('',#227,#225,#193,.T.);
+#281=EDGE_CURVE('',#226,#227,#127,.T.);
+#282=EDGE_CURVE('',#226,#228,#128,.T.);
+#283=EDGE_CURVE('',#229,#227,#129,.T.);
+#284=EDGE_CURVE('',#228,#229,#130,.T.);
+#285=EDGE_CURVE('',#228,#230,#131,.T.);
+#286=EDGE_CURVE('',#231,#229,#132,.T.);
+#287=EDGE_CURVE('',#230,#231,#133,.T.);
+#288=EDGE_CURVE('',#230,#232,#194,.T.);
+#289=EDGE_CURVE('',#233,#231,#195,.T.);
+#290=EDGE_CURVE('',#232,#233,#134,.T.);
+#291=EDGE_CURVE('',#232,#210,#135,.T.);
+#292=EDGE_CURVE('',#212,#233,#136,.T.);
+#293=ORIENTED_EDGE('',*,*,#234,.F.);
+#294=ORIENTED_EDGE('',*,*,#235,.T.);
+#295=ORIENTED_EDGE('',*,*,#236,.T.);
+#296=ORIENTED_EDGE('',*,*,#235,.F.);
+#297=ORIENTED_EDGE('',*,*,#236,.F.);
+#298=ORIENTED_EDGE('',*,*,#237,.T.);
+#299=ORIENTED_EDGE('',*,*,#238,.F.);
+#300=ORIENTED_EDGE('',*,*,#237,.F.);
+#301=ORIENTED_EDGE('',*,*,#239,.F.);
+#302=ORIENTED_EDGE('',*,*,#240,.T.);
+#303=ORIENTED_EDGE('',*,*,#241,.T.);
+#304=ORIENTED_EDGE('',*,*,#240,.F.);
+#305=ORIENTED_EDGE('',*,*,#241,.F.);
+#306=ORIENTED_EDGE('',*,*,#242,.T.);
+#307=ORIENTED_EDGE('',*,*,#243,.F.);
+#308=ORIENTED_EDGE('',*,*,#242,.F.);
+#309=ORIENTED_EDGE('',*,*,#244,.F.);
+#310=ORIENTED_EDGE('',*,*,#245,.T.);
+#311=ORIENTED_EDGE('',*,*,#246,.T.);
+#312=ORIENTED_EDGE('',*,*,#245,.F.);
+#313=ORIENTED_EDGE('',*,*,#246,.F.);
+#314=ORIENTED_EDGE('',*,*,#247,.T.);
+#315=ORIENTED_EDGE('',*,*,#248,.F.);
+#316=ORIENTED_EDGE('',*,*,#247,.F.);
+#317=ORIENTED_EDGE('',*,*,#249,.F.);
+#318=ORIENTED_EDGE('',*,*,#250,.T.);
+#319=ORIENTED_EDGE('',*,*,#251,.T.);
+#320=ORIENTED_EDGE('',*,*,#250,.F.);
+#321=ORIENTED_EDGE('',*,*,#251,.F.);
+#322=ORIENTED_EDGE('',*,*,#252,.T.);
+#323=ORIENTED_EDGE('',*,*,#253,.F.);
+#324=ORIENTED_EDGE('',*,*,#252,.F.);
+#325=ORIENTED_EDGE('',*,*,#254,.F.);
+#326=ORIENTED_EDGE('',*,*,#255,.T.);
+#327=ORIENTED_EDGE('',*,*,#256,.F.);
+#328=ORIENTED_EDGE('',*,*,#255,.F.);
+#329=ORIENTED_EDGE('',*,*,#257,.F.);
+#330=ORIENTED_EDGE('',*,*,#258,.T.);
+#331=ORIENTED_EDGE('',*,*,#259,.F.);
+#332=ORIENTED_EDGE('',*,*,#260,.F.);
+#333=ORIENTED_EDGE('',*,*,#261,.F.);
+#334=ORIENTED_EDGE('',*,*,#260,.T.);
+#335=ORIENTED_EDGE('',*,*,#262,.F.);
+#336=ORIENTED_EDGE('',*,*,#263,.F.);
+#337=ORIENTED_EDGE('',*,*,#264,.F.);
+#338=ORIENTED_EDGE('',*,*,#263,.T.);
+#339=ORIENTED_EDGE('',*,*,#265,.F.);
+#340=ORIENTED_EDGE('',*,*,#266,.F.);
+#341=ORIENTED_EDGE('',*,*,#267,.F.);
+#342=ORIENTED_EDGE('',*,*,#266,.T.);
+#343=ORIENTED_EDGE('',*,*,#268,.F.);
+#344=ORIENTED_EDGE('',*,*,#269,.F.);
+#345=ORIENTED_EDGE('',*,*,#270,.F.);
+#346=ORIENTED_EDGE('',*,*,#269,.T.);
+#347=ORIENTED_EDGE('',*,*,#271,.F.);
+#348=ORIENTED_EDGE('',*,*,#272,.F.);
+#349=ORIENTED_EDGE('',*,*,#273,.F.);
+#350=ORIENTED_EDGE('',*,*,#272,.T.);
+#351=ORIENTED_EDGE('',*,*,#274,.F.);
+#352=ORIENTED_EDGE('',*,*,#275,.F.);
+#353=ORIENTED_EDGE('',*,*,#276,.F.);
+#354=ORIENTED_EDGE('',*,*,#275,.T.);
+#355=ORIENTED_EDGE('',*,*,#277,.F.);
+#356=ORIENTED_EDGE('',*,*,#278,.F.);
+#357=ORIENTED_EDGE('',*,*,#279,.F.);
+#358=ORIENTED_EDGE('',*,*,#278,.T.);
+#359=ORIENTED_EDGE('',*,*,#280,.F.);
+#360=ORIENTED_EDGE('',*,*,#281,.F.);
+#361=ORIENTED_EDGE('',*,*,#282,.F.);
+#362=ORIENTED_EDGE('',*,*,#281,.T.);
+#363=ORIENTED_EDGE('',*,*,#283,.F.);
+#364=ORIENTED_EDGE('',*,*,#284,.F.);
+#365=ORIENTED_EDGE('',*,*,#285,.F.);
+#366=ORIENTED_EDGE('',*,*,#284,.T.);
+#367=ORIENTED_EDGE('',*,*,#286,.F.);
+#368=ORIENTED_EDGE('',*,*,#287,.F.);
+#369=ORIENTED_EDGE('',*,*,#288,.F.);
+#370=ORIENTED_EDGE('',*,*,#287,.T.);
+#371=ORIENTED_EDGE('',*,*,#289,.F.);
+#372=ORIENTED_EDGE('',*,*,#290,.F.);
+#373=ORIENTED_EDGE('',*,*,#291,.F.);
+#374=ORIENTED_EDGE('',*,*,#290,.T.);
+#375=ORIENTED_EDGE('',*,*,#292,.F.);
+#376=ORIENTED_EDGE('',*,*,#258,.F.);
+#377=ORIENTED_EDGE('',*,*,#291,.T.);
+#378=ORIENTED_EDGE('',*,*,#257,.T.);
+#379=ORIENTED_EDGE('',*,*,#261,.T.);
+#380=ORIENTED_EDGE('',*,*,#264,.T.);
+#381=ORIENTED_EDGE('',*,*,#267,.T.);
+#382=ORIENTED_EDGE('',*,*,#270,.T.);
+#383=ORIENTED_EDGE('',*,*,#273,.T.);
+#384=ORIENTED_EDGE('',*,*,#276,.T.);
+#385=ORIENTED_EDGE('',*,*,#279,.T.);
+#386=ORIENTED_EDGE('',*,*,#282,.T.);
+#387=ORIENTED_EDGE('',*,*,#285,.T.);
+#388=ORIENTED_EDGE('',*,*,#288,.T.);
+#389=ORIENTED_EDGE('',*,*,#238,.T.);
+#390=ORIENTED_EDGE('',*,*,#243,.T.);
+#391=ORIENTED_EDGE('',*,*,#248,.T.);
+#392=ORIENTED_EDGE('',*,*,#253,.T.);
+#393=ORIENTED_EDGE('',*,*,#256,.T.);
+#394=ORIENTED_EDGE('',*,*,#292,.T.);
+#395=ORIENTED_EDGE('',*,*,#289,.T.);
+#396=ORIENTED_EDGE('',*,*,#286,.T.);
+#397=ORIENTED_EDGE('',*,*,#283,.T.);
+#398=ORIENTED_EDGE('',*,*,#280,.T.);
+#399=ORIENTED_EDGE('',*,*,#277,.T.);
+#400=ORIENTED_EDGE('',*,*,#274,.T.);
+#401=ORIENTED_EDGE('',*,*,#271,.T.);
+#402=ORIENTED_EDGE('',*,*,#268,.T.);
+#403=ORIENTED_EDGE('',*,*,#265,.T.);
+#404=ORIENTED_EDGE('',*,*,#262,.T.);
+#405=ORIENTED_EDGE('',*,*,#259,.T.);
+#406=ORIENTED_EDGE('',*,*,#234,.T.);
+#407=ORIENTED_EDGE('',*,*,#239,.T.);
+#408=ORIENTED_EDGE('',*,*,#244,.T.);
+#409=ORIENTED_EDGE('',*,*,#249,.T.);
+#410=ORIENTED_EDGE('',*,*,#254,.T.);
+#411=CONICAL_SURFACE('',#452,2.825,0.785398163397448);
+#412=CONICAL_SURFACE('',#457,2.825,0.785398163397448);
+#413=CONICAL_SURFACE('',#462,2.825,0.785398163397448);
+#414=CONICAL_SURFACE('',#467,2.825,0.785398163397448);
+#415=ADVANCED_FACE('',(#44),#411,.F.);
+#416=ADVANCED_FACE('',(#45),#35,.F.);
+#417=ADVANCED_FACE('',(#46),#412,.F.);
+#418=ADVANCED_FACE('',(#47),#36,.F.);
+#419=ADVANCED_FACE('',(#48),#413,.F.);
+#420=ADVANCED_FACE('',(#49),#37,.F.);
+#421=ADVANCED_FACE('',(#50),#414,.F.);
+#422=ADVANCED_FACE('',(#51),#38,.F.);
+#423=ADVANCED_FACE('',(#52),#39,.F.);
+#424=ADVANCED_FACE('',(#53),#25,.T.);
+#425=ADVANCED_FACE('',(#54),#40,.T.);
+#426=ADVANCED_FACE('',(#55),#26,.T.);
+#427=ADVANCED_FACE('',(#56),#27,.T.);
+#428=ADVANCED_FACE('',(#57),#41,.T.);
+#429=ADVANCED_FACE('',(#58),#28,.T.);
+#430=ADVANCED_FACE('',(#59),#29,.T.);
+#431=ADVANCED_FACE('',(#60),#42,.T.);
+#432=ADVANCED_FACE('',(#61),#30,.T.);
+#433=ADVANCED_FACE('',(#62),#31,.T.);
+#434=ADVANCED_FACE('',(#63),#43,.T.);
+#435=ADVANCED_FACE('',(#64),#32,.T.);
+#436=ADVANCED_FACE('',(#65,#15,#16,#17,#18,#19),#33,.T.);
+#437=ADVANCED_FACE('',(#66,#20,#21,#22,#23,#24),#34,.F.);
+#438=CLOSED_SHELL('',(#415,#416,#417,#418,#419,#420,#421,#422,#423,#424,
+#425,#426,#427,#428,#429,#430,#431,#432,#433,#434,#435,#436,#437));
+#439=DERIVED_UNIT_ELEMENT(#441,1.);
+#440=DERIVED_UNIT_ELEMENT(#752,-3.);
+#441=(
+MASS_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.KILO.,.GRAM.)
+);
+#442=DERIVED_UNIT((#439,#440));
+#443=MEASURE_REPRESENTATION_ITEM('density measure',
+POSITIVE_RATIO_MEASURE(7850.),#442);
+#444=PROPERTY_DEFINITION_REPRESENTATION(#449,#446);
+#445=PROPERTY_DEFINITION_REPRESENTATION(#450,#447);
+#446=REPRESENTATION('material name',(#448),#749);
+#447=REPRESENTATION('density',(#443),#749);
+#448=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel');
+#449=PROPERTY_DEFINITION('material property','material name',#759);
+#450=PROPERTY_DEFINITION('material property','density of part',#759);
+#451=AXIS2_PLACEMENT_3D('',#626,#497,#498);
+#452=AXIS2_PLACEMENT_3D('',#627,#499,#500);
+#453=AXIS2_PLACEMENT_3D('',#629,#501,#502);
+#454=AXIS2_PLACEMENT_3D('',#632,#504,#505);
+#455=AXIS2_PLACEMENT_3D('',#633,#506,#507);
+#456=AXIS2_PLACEMENT_3D('',#636,#509,#510);
+#457=AXIS2_PLACEMENT_3D('',#637,#511,#512);
+#458=AXIS2_PLACEMENT_3D('',#639,#513,#514);
+#459=AXIS2_PLACEMENT_3D('',#642,#516,#517);
+#460=AXIS2_PLACEMENT_3D('',#643,#518,#519);
+#461=AXIS2_PLACEMENT_3D('',#646,#521,#522);
+#462=AXIS2_PLACEMENT_3D('',#647,#523,#524);
+#463=AXIS2_PLACEMENT_3D('',#649,#525,#526);
+#464=AXIS2_PLACEMENT_3D('',#652,#528,#529);
+#465=AXIS2_PLACEMENT_3D('',#653,#530,#531);
+#466=AXIS2_PLACEMENT_3D('',#656,#533,#534);
+#467=AXIS2_PLACEMENT_3D('',#657,#535,#536);
+#468=AXIS2_PLACEMENT_3D('',#659,#537,#538);
+#469=AXIS2_PLACEMENT_3D('',#662,#540,#541);
+#470=AXIS2_PLACEMENT_3D('',#663,#542,#543);
+#471=AXIS2_PLACEMENT_3D('',#666,#545,#546);
+#472=AXIS2_PLACEMENT_3D('',#667,#547,#548);
+#473=AXIS2_PLACEMENT_3D('',#669,#549,#550);
+#474=AXIS2_PLACEMENT_3D('',#672,#552,#553);
+#475=AXIS2_PLACEMENT_3D('',#673,#554,#555);
+#476=AXIS2_PLACEMENT_3D('',#682,#560,#561);
+#477=AXIS2_PLACEMENT_3D('',#684,#562,#563);
+#478=AXIS2_PLACEMENT_3D('',#686,#564,#565);
+#479=AXIS2_PLACEMENT_3D('',#688,#567,#568);
+#480=AXIS2_PLACEMENT_3D('',#694,#572,#573);
+#481=AXIS2_PLACEMENT_3D('',#700,#577,#578);
+#482=AXIS2_PLACEMENT_3D('',#702,#579,#580);
+#483=AXIS2_PLACEMENT_3D('',#704,#581,#582);
+#484=AXIS2_PLACEMENT_3D('',#706,#584,#585);
+#485=AXIS2_PLACEMENT_3D('',#712,#589,#590);
+#486=AXIS2_PLACEMENT_3D('',#718,#594,#595);
+#487=AXIS2_PLACEMENT_3D('',#720,#596,#597);
+#488=AXIS2_PLACEMENT_3D('',#722,#598,#599);
+#489=AXIS2_PLACEMENT_3D('',#724,#601,#602);
+#490=AXIS2_PLACEMENT_3D('',#730,#606,#607);
+#491=AXIS2_PLACEMENT_3D('',#736,#611,#612);
+#492=AXIS2_PLACEMENT_3D('',#738,#613,#614);
+#493=AXIS2_PLACEMENT_3D('',#740,#615,#616);
+#494=AXIS2_PLACEMENT_3D('',#742,#618,#619);
+#495=AXIS2_PLACEMENT_3D('',#745,#622,#623);
+#496=AXIS2_PLACEMENT_3D('',#746,#624,#625);
+#497=DIRECTION('axis',(0.,0.,1.));
+#498=DIRECTION('refdir',(1.,0.,0.));
+#499=DIRECTION('center_axis',(0.,-1.,0.));
+#500=DIRECTION('ref_axis',(0.,0.,-1.));
+#501=DIRECTION('center_axis',(0.,1.,0.));
+#502=DIRECTION('ref_axis',(0.,0.,-1.));
+#503=DIRECTION('',(-8.65956056235493E-17,0.707106781186548,-0.707106781186547));
+#504=DIRECTION('center_axis',(0.,1.,0.));
+#505=DIRECTION('ref_axis',(0.,0.,-1.));
+#506=DIRECTION('center_axis',(0.,1.,0.));
+#507=DIRECTION('ref_axis',(0.,0.,-1.));
+#508=DIRECTION('',(0.,1.,0.));
+#509=DIRECTION('center_axis',(0.,-1.,0.));
+#510=DIRECTION('ref_axis',(0.,0.,-1.));
+#511=DIRECTION('center_axis',(0.,-1.,0.));
+#512=DIRECTION('ref_axis',(0.,0.,-1.));
+#513=DIRECTION('center_axis',(0.,1.,0.));
+#514=DIRECTION('ref_axis',(0.,0.,-1.));
+#515=DIRECTION('',(-8.65956056235493E-17,0.707106781186548,-0.707106781186547));
+#516=DIRECTION('center_axis',(0.,1.,0.));
+#517=DIRECTION('ref_axis',(0.,0.,-1.));
+#518=DIRECTION('center_axis',(0.,1.,0.));
+#519=DIRECTION('ref_axis',(0.,0.,-1.));
+#520=DIRECTION('',(0.,1.,0.));
+#521=DIRECTION('center_axis',(0.,-1.,0.));
+#522=DIRECTION('ref_axis',(0.,0.,-1.));
+#523=DIRECTION('center_axis',(0.,-1.,0.));
+#524=DIRECTION('ref_axis',(0.,0.,-1.));
+#525=DIRECTION('center_axis',(0.,1.,0.));
+#526=DIRECTION('ref_axis',(0.,0.,-1.));
+#527=DIRECTION('',(-8.65956056235493E-17,0.707106781186548,-0.707106781186547));
+#528=DIRECTION('center_axis',(0.,1.,0.));
+#529=DIRECTION('ref_axis',(0.,0.,-1.));
+#530=DIRECTION('center_axis',(0.,1.,0.));
+#531=DIRECTION('ref_axis',(0.,0.,-1.));
+#532=DIRECTION('',(0.,1.,0.));
+#533=DIRECTION('center_axis',(0.,-1.,0.));
+#534=DIRECTION('ref_axis',(0.,0.,-1.));
+#535=DIRECTION('center_axis',(0.,-1.,0.));
+#536=DIRECTION('ref_axis',(0.,0.,-1.));
+#537=DIRECTION('center_axis',(0.,1.,0.));
+#538=DIRECTION('ref_axis',(0.,0.,-1.));
+#539=DIRECTION('',(-8.65956056235493E-17,0.707106781186548,-0.707106781186547));
+#540=DIRECTION('center_axis',(0.,1.,0.));
+#541=DIRECTION('ref_axis',(0.,0.,-1.));
+#542=DIRECTION('center_axis',(0.,1.,0.));
+#543=DIRECTION('ref_axis',(0.,0.,-1.));
+#544=DIRECTION('',(0.,1.,0.));
+#545=DIRECTION('center_axis',(0.,-1.,0.));
+#546=DIRECTION('ref_axis',(0.,0.,-1.));
+#547=DIRECTION('center_axis',(0.,-1.,0.));
+#548=DIRECTION('ref_axis',(-1.,0.,0.));
+#549=DIRECTION('center_axis',(0.,1.,0.));
+#550=DIRECTION('ref_axis',(-1.,0.,0.));
+#551=DIRECTION('',(0.,1.,0.));
+#552=DIRECTION('center_axis',(0.,-1.,0.));
+#553=DIRECTION('ref_axis',(-1.,0.,0.));
+#554=DIRECTION('center_axis',(-0.060548874541627,0.,-0.998165233712206));
+#555=DIRECTION('ref_axis',(0.998165233712206,0.,-0.060548874541627));
+#556=DIRECTION('',(-0.998165233712206,0.,0.060548874541627));
+#557=DIRECTION('',(0.,-1.,0.));
+#558=DIRECTION('',(0.998165233712206,0.,-0.060548874541627));
+#559=DIRECTION('',(0.,-1.,0.));
+#560=DIRECTION('center_axis',(0.,-1.,0.));
+#561=DIRECTION('ref_axis',(-0.060548874541627,0.,-0.998165233712206));
+#562=DIRECTION('center_axis',(0.,1.,0.));
+#563=DIRECTION('ref_axis',(-0.060548874541627,0.,-0.998165233712206));
+#564=DIRECTION('center_axis',(0.,-1.,0.));
+#565=DIRECTION('ref_axis',(-0.060548874541627,0.,-0.998165233712206));
+#566=DIRECTION('',(0.,-1.,0.));
+#567=DIRECTION('center_axis',(-0.998165233712205,0.,-0.0605488745416456));
+#568=DIRECTION('ref_axis',(0.0605488745416456,0.,-0.998165233712205));
+#569=DIRECTION('',(-0.0605488745416456,0.,0.998165233712205));
+#570=DIRECTION('',(0.0605488745416456,0.,-0.998165233712205));
+#571=DIRECTION('',(0.,-1.,0.));
+#572=DIRECTION('center_axis',(-0.998165233712206,0.,0.0605488745416271));
+#573=DIRECTION('ref_axis',(-0.0605488745416271,0.,-0.998165233712206));
+#574=DIRECTION('',(0.0605488745416271,0.,0.998165233712206));
+#575=DIRECTION('',(-0.0605488745416271,0.,-0.998165233712206));
+#576=DIRECTION('',(0.,-1.,0.));
+#577=DIRECTION('center_axis',(0.,-1.,0.));
+#578=DIRECTION('ref_axis',(-0.998165233712206,0.,0.0605488745416264));
+#579=DIRECTION('center_axis',(0.,1.,0.));
+#580=DIRECTION('ref_axis',(-0.998165233712206,0.,0.0605488745416264));
+#581=DIRECTION('center_axis',(0.,-1.,0.));
+#582=DIRECTION('ref_axis',(-0.998165233712206,0.,0.0605488745416264));
+#583=DIRECTION('',(0.,-1.,0.));
+#584=DIRECTION('center_axis',(-0.0605488745416452,0.,0.998165233712205));
+#585=DIRECTION('ref_axis',(-0.998165233712205,0.,-0.0605488745416452));
+#586=DIRECTION('',(0.998165233712205,0.,0.0605488745416452));
+#587=DIRECTION('',(-0.998165233712205,0.,-0.0605488745416452));
+#588=DIRECTION('',(0.,-1.,0.));
+#589=DIRECTION('center_axis',(0.0605488745416267,0.,0.998165233712206));
+#590=DIRECTION('ref_axis',(-0.998165233712206,0.,0.0605488745416267));
+#591=DIRECTION('',(0.998165233712206,0.,-0.0605488745416267));
+#592=DIRECTION('',(-0.998165233712206,0.,0.0605488745416267));
+#593=DIRECTION('',(0.,-1.,0.));
+#594=DIRECTION('center_axis',(0.,-1.,0.));
+#595=DIRECTION('ref_axis',(0.0605488745416257,0.,0.998165233712206));
+#596=DIRECTION('center_axis',(0.,1.,0.));
+#597=DIRECTION('ref_axis',(0.0605488745416257,0.,0.998165233712206));
+#598=DIRECTION('center_axis',(0.,-1.,0.));
+#599=DIRECTION('ref_axis',(0.0605488745416257,0.,0.998165233712206));
+#600=DIRECTION('',(0.,-1.,0.));
+#601=DIRECTION('center_axis',(0.998165233712205,0.,0.0605488745416453));
+#602=DIRECTION('ref_axis',(-0.0605488745416453,0.,0.998165233712205));
+#603=DIRECTION('',(0.0605488745416453,0.,-0.998165233712205));
+#604=DIRECTION('',(-0.0605488745416453,0.,0.998165233712205));
+#605=DIRECTION('',(0.,-1.,0.));
+#606=DIRECTION('center_axis',(0.998165233712206,0.,-0.0605488745416266));
+#607=DIRECTION('ref_axis',(0.0605488745416266,0.,0.998165233712206));
+#608=DIRECTION('',(-0.0605488745416266,0.,-0.998165233712206));
+#609=DIRECTION('',(0.0605488745416266,0.,0.998165233712206));
+#610=DIRECTION('',(0.,-1.,0.));
+#611=DIRECTION('center_axis',(0.,-1.,0.));
+#612=DIRECTION('ref_axis',(0.998165233712206,0.,-0.0605488745416257));
+#613=DIRECTION('center_axis',(0.,1.,0.));
+#614=DIRECTION('ref_axis',(0.998165233712206,0.,-0.0605488745416257));
+#615=DIRECTION('center_axis',(0.,-1.,0.));
+#616=DIRECTION('ref_axis',(0.998165233712206,0.,-0.0605488745416257));
+#617=DIRECTION('',(0.,-1.,0.));
+#618=DIRECTION('center_axis',(0.0605488745416453,0.,-0.998165233712205));
+#619=DIRECTION('ref_axis',(0.998165233712205,0.,0.0605488745416453));
+#620=DIRECTION('',(-0.998165233712205,0.,-0.0605488745416453));
+#621=DIRECTION('',(0.998165233712205,0.,0.0605488745416453));
+#622=DIRECTION('center_axis',(0.,1.,0.));
+#623=DIRECTION('ref_axis',(-1.,0.,0.));
+#624=DIRECTION('center_axis',(0.,1.,0.));
+#625=DIRECTION('ref_axis',(-1.,0.,0.));
+#626=CARTESIAN_POINT('',(0.,0.,0.));
+#627=CARTESIAN_POINT('Origin',(-32.9861853579264,29.825,32.9861853579257));
+#628=CARTESIAN_POINT('',(-32.9861853579264,29.,36.6361853579257));
+#629=CARTESIAN_POINT('Origin',(-32.9861853579264,29.,32.9861853579257));
+#630=CARTESIAN_POINT('',(-32.9861853579264,30.65,34.9861853579257));
+#631=CARTESIAN_POINT('',(-32.9861853579264,29.825,35.8111853579258));
+#632=CARTESIAN_POINT('Origin',(-32.9861853579264,30.65,32.9861853579257));
+#633=CARTESIAN_POINT('Origin',(-32.9861853579264,30.5,32.9861853579257));
+#634=CARTESIAN_POINT('',(-32.9861853579264,32.,34.9861853579257));
+#635=CARTESIAN_POINT('',(-32.9861853579264,30.5,34.9861853579257));
+#636=CARTESIAN_POINT('Origin',(-32.9861853579264,32.,32.9861853579257));
+#637=CARTESIAN_POINT('Origin',(32.9861853579264,29.825,-32.9861853579257));
+#638=CARTESIAN_POINT('',(32.9861853579264,29.,-29.3361853579257));
+#639=CARTESIAN_POINT('Origin',(32.9861853579264,29.,-32.9861853579257));
+#640=CARTESIAN_POINT('',(32.9861853579264,30.65,-30.9861853579257));
+#641=CARTESIAN_POINT('',(32.9861853579264,29.825,-30.1611853579257));
+#642=CARTESIAN_POINT('Origin',(32.9861853579264,30.65,-32.9861853579257));
+#643=CARTESIAN_POINT('Origin',(32.9861853579264,30.5,-32.9861853579257));
+#644=CARTESIAN_POINT('',(32.9861853579264,32.,-30.9861853579257));
+#645=CARTESIAN_POINT('',(32.9861853579264,30.5,-30.9861853579257));
+#646=CARTESIAN_POINT('Origin',(32.9861853579264,32.,-32.9861853579257));
+#647=CARTESIAN_POINT('Origin',(-32.9861853579257,29.825,-32.9861853579264));
+#648=CARTESIAN_POINT('',(-32.9861853579257,29.,-29.3361853579264));
+#649=CARTESIAN_POINT('Origin',(-32.9861853579257,29.,-32.9861853579264));
+#650=CARTESIAN_POINT('',(-32.9861853579257,30.65,-30.9861853579264));
+#651=CARTESIAN_POINT('',(-32.9861853579257,29.825,-30.1611853579264));
+#652=CARTESIAN_POINT('Origin',(-32.9861853579257,30.65,-32.9861853579264));
+#653=CARTESIAN_POINT('Origin',(-32.9861853579257,30.5,-32.9861853579264));
+#654=CARTESIAN_POINT('',(-32.9861853579257,32.,-30.9861853579264));
+#655=CARTESIAN_POINT('',(-32.9861853579257,30.5,-30.9861853579264));
+#656=CARTESIAN_POINT('Origin',(-32.9861853579257,32.,-32.9861853579264));
+#657=CARTESIAN_POINT('Origin',(32.9861853579257,29.825,32.9861853579264));
+#658=CARTESIAN_POINT('',(32.9861853579257,29.,36.6361853579264));
+#659=CARTESIAN_POINT('Origin',(32.9861853579257,29.,32.9861853579264));
+#660=CARTESIAN_POINT('',(32.9861853579257,30.65,34.9861853579264));
+#661=CARTESIAN_POINT('',(32.9861853579257,29.825,35.8111853579264));
+#662=CARTESIAN_POINT('Origin',(32.9861853579257,30.65,32.9861853579264));
+#663=CARTESIAN_POINT('Origin',(32.9861853579257,30.5,32.9861853579264));
+#664=CARTESIAN_POINT('',(32.9861853579257,32.,34.9861853579264));
+#665=CARTESIAN_POINT('',(32.9861853579257,30.5,34.9861853579264));
+#666=CARTESIAN_POINT('Origin',(32.9861853579257,32.,32.9861853579264));
+#667=CARTESIAN_POINT('Origin',(0.,32.,0.));
+#668=CARTESIAN_POINT('',(40.,29.,-4.89858719658941E-15));
+#669=CARTESIAN_POINT('Origin',(0.,29.,0.));
+#670=CARTESIAN_POINT('',(40.,32.,-4.89858719658941E-15));
+#671=CARTESIAN_POINT('',(40.,32.,4.89858719658941E-15));
+#672=CARTESIAN_POINT('Origin',(0.,32.,0.));
+#673=CARTESIAN_POINT('Origin',(-33.4100274797171,32.,-39.9733419939118));
+#674=CARTESIAN_POINT('',(1.33226762955019E-14,32.,-42.));
+#675=CARTESIAN_POINT('',(-33.4100274797171,32.,-39.9733419939118));
+#676=CARTESIAN_POINT('',(5.11971709256398E-15,32.,-42.));
+#677=CARTESIAN_POINT('',(1.33226762955019E-14,29.,-42.));
+#678=CARTESIAN_POINT('',(1.33226762955019E-14,32.,-42.));
+#679=CARTESIAN_POINT('',(-33.4100274797171,29.,-39.9733419939118));
+#680=CARTESIAN_POINT('',(5.11971709256398E-15,29.,-42.));
+#681=CARTESIAN_POINT('',(-33.4100274797171,32.,-39.9733419939118));
+#682=CARTESIAN_POINT('Origin',(-32.9861853579257,32.,-32.9861853579264));
+#683=CARTESIAN_POINT('',(-39.9733419939114,32.,-33.4100274797148));
+#684=CARTESIAN_POINT('Origin',(-32.9861853579257,32.,-32.9861853579264));
+#685=CARTESIAN_POINT('',(-39.9733419939114,29.,-33.4100274797148));
+#686=CARTESIAN_POINT('Origin',(-32.9861853579257,29.,-32.9861853579264));
+#687=CARTESIAN_POINT('',(-39.9733419939114,32.,-33.4100274797148));
+#688=CARTESIAN_POINT('Origin',(-42.,32.,-8.88178419700125E-15));
+#689=CARTESIAN_POINT('',(-42.,32.,-7.69147537077341E-15));
+#690=CARTESIAN_POINT('',(-39.9733419939114,32.,-33.4100274797148));
+#691=CARTESIAN_POINT('',(-42.,29.,-7.69147537077341E-15));
+#692=CARTESIAN_POINT('',(-39.9733419939114,29.,-33.4100274797148));
+#693=CARTESIAN_POINT('',(-42.,32.,-7.69147537077341E-15));
+#694=CARTESIAN_POINT('Origin',(-39.9733419939118,32.,33.4100274797171));
+#695=CARTESIAN_POINT('',(-39.9733419939118,32.,33.4100274797171));
+#696=CARTESIAN_POINT('',(-42.,32.,-7.69147537077341E-15));
+#697=CARTESIAN_POINT('',(-39.9733419939118,29.,33.4100274797171));
+#698=CARTESIAN_POINT('',(-42.,29.,-7.69147537077341E-15));
+#699=CARTESIAN_POINT('',(-39.9733419939118,32.,33.4100274797171));
+#700=CARTESIAN_POINT('Origin',(-32.9861853579264,32.,32.9861853579257));
+#701=CARTESIAN_POINT('',(-33.4100274797148,32.,39.9733419939114));
+#702=CARTESIAN_POINT('Origin',(-32.9861853579264,32.,32.9861853579257));
+#703=CARTESIAN_POINT('',(-33.4100274797148,29.,39.9733419939114));
+#704=CARTESIAN_POINT('Origin',(-32.9861853579264,29.,32.9861853579257));
+#705=CARTESIAN_POINT('',(-33.4100274797148,32.,39.9733419939114));
+#706=CARTESIAN_POINT('Origin',(-8.88178419700125E-15,32.,42.));
+#707=CARTESIAN_POINT('',(-1.02632336489829E-14,32.,42.));
+#708=CARTESIAN_POINT('',(-33.4100274797148,32.,39.9733419939114));
+#709=CARTESIAN_POINT('',(-8.88178419700125E-15,29.,42.));
+#710=CARTESIAN_POINT('',(-33.4100274797148,29.,39.9733419939114));
+#711=CARTESIAN_POINT('',(-1.02632336489829E-14,32.,42.));
+#712=CARTESIAN_POINT('Origin',(33.4100274797171,32.,39.9733419939118));
+#713=CARTESIAN_POINT('',(33.4100274797171,32.,39.9733419939118));
+#714=CARTESIAN_POINT('',(-1.02632336489829E-14,32.,42.));
+#715=CARTESIAN_POINT('',(33.4100274797171,29.,39.9733419939118));
+#716=CARTESIAN_POINT('',(-1.02632336489829E-14,29.,42.));
+#717=CARTESIAN_POINT('',(33.4100274797171,32.,39.9733419939118));
+#718=CARTESIAN_POINT('Origin',(32.9861853579257,32.,32.9861853579264));
+#719=CARTESIAN_POINT('',(39.9733419939114,32.,33.4100274797148));
+#720=CARTESIAN_POINT('Origin',(32.9861853579257,32.,32.9861853579264));
+#721=CARTESIAN_POINT('',(39.9733419939114,29.,33.4100274797148));
+#722=CARTESIAN_POINT('Origin',(32.9861853579257,29.,32.9861853579264));
+#723=CARTESIAN_POINT('',(39.9733419939114,32.,33.4100274797148));
+#724=CARTESIAN_POINT('Origin',(42.,32.,1.33226762955019E-14));
+#725=CARTESIAN_POINT('',(42.,32.,1.28349919271923E-14));
+#726=CARTESIAN_POINT('',(39.9733419939114,32.,33.4100274797148));
+#727=CARTESIAN_POINT('',(42.,29.,1.28349919271923E-14));
+#728=CARTESIAN_POINT('',(39.9733419939114,29.,33.4100274797148));
+#729=CARTESIAN_POINT('',(42.,32.,1.28349919271923E-14));
+#730=CARTESIAN_POINT('Origin',(39.9733419939119,32.,-33.4100274797171));
+#731=CARTESIAN_POINT('',(39.9733419939119,32.,-33.4100274797171));
+#732=CARTESIAN_POINT('',(42.,32.,1.28349919271923E-14));
+#733=CARTESIAN_POINT('',(39.9733419939119,29.,-33.4100274797171));
+#734=CARTESIAN_POINT('',(42.,29.,1.28349919271923E-14));
+#735=CARTESIAN_POINT('',(39.9733419939119,32.,-33.4100274797171));
+#736=CARTESIAN_POINT('Origin',(32.9861853579264,32.,-32.9861853579257));
+#737=CARTESIAN_POINT('',(33.4100274797148,32.,-39.9733419939114));
+#738=CARTESIAN_POINT('Origin',(32.9861853579264,32.,-32.9861853579257));
+#739=CARTESIAN_POINT('',(33.4100274797148,29.,-39.9733419939114));
+#740=CARTESIAN_POINT('Origin',(32.9861853579264,29.,-32.9861853579257));
+#741=CARTESIAN_POINT('',(33.4100274797148,32.,-39.9733419939114));
+#742=CARTESIAN_POINT('Origin',(1.33226762955019E-14,32.,-42.));
+#743=CARTESIAN_POINT('',(33.4100274797148,32.,-39.9733419939114));
+#744=CARTESIAN_POINT('',(33.4100274797148,29.,-39.9733419939114));
+#745=CARTESIAN_POINT('Origin',(-8.88178419700125E-15,32.,0.));
+#746=CARTESIAN_POINT('Origin',(-8.88178419700125E-15,29.,0.));
+#747=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#751,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#748=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#751,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#749=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#747))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#751,#753,#754))
+REPRESENTATION_CONTEXT('','3D')
+);
+#750=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#748))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#751,#753,#754))
+REPRESENTATION_CONTEXT('','3D')
+);
+#751=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.MILLI.,.METRE.)
+);
+#752=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT($,.METRE.)
+);
+#753=(
+NAMED_UNIT(*)
+PLANE_ANGLE_UNIT()
+SI_UNIT($,.RADIAN.)
+);
+#754=(
+NAMED_UNIT(*)
+SI_UNIT($,.STERADIAN.)
+SOLID_ANGLE_UNIT()
+);
+#755=SHAPE_DEFINITION_REPRESENTATION(#756,#757);
+#756=PRODUCT_DEFINITION_SHAPE('',$,#759);
+#757=SHAPE_REPRESENTATION('',(#451),#749);
+#758=PRODUCT_DEFINITION_CONTEXT('part definition',#763,'design');
+#759=PRODUCT_DEFINITION('FusionComponent','FusionComponent',#760,#758);
+#760=PRODUCT_DEFINITION_FORMATION('',$,#765);
+#761=PRODUCT_RELATED_PRODUCT_CATEGORY('FusionComponent',
+'FusionComponent',(#765));
+#762=APPLICATION_PROTOCOL_DEFINITION('international standard',
+'automotive_design',2009,#763);
+#763=APPLICATION_CONTEXT(
+'Core Data for Automotive Mechanical Design Process');
+#764=PRODUCT_CONTEXT('part definition',#763,'mechanical');
+#765=PRODUCT('FusionComponent','FusionComponent',$,(#764));
+#766=PRESENTATION_STYLE_ASSIGNMENT((#767));
+#767=SURFACE_STYLE_USAGE(.BOTH.,#768);
+#768=SURFACE_SIDE_STYLE('',(#769));
+#769=SURFACE_STYLE_FILL_AREA(#770);
+#770=FILL_AREA_STYLE('Steel - Satin',(#771));
+#771=FILL_AREA_STYLE_COLOUR('Steel - Satin',#772);
+#772=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157);
+ENDSEC;
+END-ISO-10303-21;
diff --git a/3d_model/Body.step b/3d_model/Body.step
new file mode 100755
index 0000000..2cc9c12
--- /dev/null
+++ b/3d_model/Body.step
@@ -0,0 +1,603 @@
+ISO-10303-21;
+HEADER;
+/* Generated by software containing ST-Developer
+ * from STEP Tools, Inc. (www.steptools.com)
+ */
+
+FILE_DESCRIPTION(
+/* description */ (''),
+/* implementation_level */ '2;1');
+
+FILE_NAME(
+/* name */ 'Body.step',
+/* time_stamp */ '2026-03-11T00:29:01+01:00',
+/* author */ (''),
+/* organization */ (''),
+/* preprocessor_version */ 'ST-DEVELOPER v20.1',
+/* originating_system */ 'Autodesk Translation Framework v14.10.0.0',
+/* authorisation */ '');
+
+FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
+ENDSEC;
+
+DATA;
+#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#13),#499);
+#11=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#506,#12);
+#12=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#14),#498);
+#13=STYLED_ITEM('',(#515),#14);
+#14=MANIFOLD_SOLID_BREP('Body1',#241);
+#15=TOROIDAL_SURFACE('',#272,35.3326623480349,2.);
+#16=CONICAL_SURFACE('',#270,33.5,0.0872664625997165);
+#17=CONICAL_SURFACE('',#278,33.5,0.0872664625997165);
+#18=FACE_BOUND('',#54,.T.);
+#19=FACE_BOUND('',#55,.T.);
+#20=FACE_BOUND('',#56,.T.);
+#21=FACE_BOUND('',#62,.T.);
+#22=FACE_BOUND('',#66,.T.);
+#23=FACE_BOUND('',#67,.T.);
+#24=FACE_BOUND('',#68,.T.);
+#25=FACE_BOUND('',#69,.T.);
+#26=FACE_BOUND('',#70,.T.);
+#27=PLANE('',#264);
+#28=PLANE('',#279);
+#29=PLANE('',#285);
+#30=B_SPLINE_CURVE_WITH_KNOTS('',3,(#372,#373,#374,#375,#376,#377,#378,
+#379,#380,#381,#382,#383,#384,#385),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,2,2,
+4),(-0.693298333854728,-0.635328719285133,-0.574530281470346,-0.506213186869481,
+-0.42732919909018,-0.371015103127765,-0.339977937506383),.UNSPECIFIED.);
+#31=B_SPLINE_CURVE_WITH_KNOTS('',3,(#387,#388,#389,#390,#391,#392),
+ .UNSPECIFIED.,.F.,.F.,(4,2,4),(0.956340588276516,1.6017756278411,1.89333580578515),
+ .UNSPECIFIED.);
+#32=B_SPLINE_CURVE_WITH_KNOTS('',3,(#396,#397,#398,#399,#400,#401),
+ .UNSPECIFIED.,.F.,.F.,(4,2,4),(0.958389973408102,1.24995015135215,1.89538519091674),
+ .UNSPECIFIED.);
+#33=B_SPLINE_CURVE_WITH_KNOTS('',3,(#402,#403,#404,#405,#406,#407,#408,
+#409,#410,#411,#412,#413,#414,#415),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,2,2,
+4),(-0.339977937506383,-0.321176312725213,-0.267458220904289,-0.199984764370105,
+-0.129839183333261,-0.0654984574056854,-1.95997715139867E-5),
+ .UNSPECIFIED.);
+#34=B_SPLINE_CURVE_WITH_KNOTS('',3,(#432,#433,#434,#435,#436,#437),
+ .UNSPECIFIED.,.F.,.F.,(4,2,4),(0.958252228537191,1.24987969023671,1.89524548367037),
+ .UNSPECIFIED.);
+#35=B_SPLINE_CURVE_WITH_KNOTS('',3,(#443,#444,#445,#446,#447,#448,#449,
+#450,#451,#452,#453,#454,#455,#456),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,2,2,
+4),(-0.339958259929658,-0.321168074954928,-0.267454999656038,-0.199988694990343,
+-0.129839892673891,-0.0654987495597932,0.),.UNSPECIFIED.);
+#36=B_SPLINE_CURVE_WITH_KNOTS('',3,(#459,#460,#461,#462,#463,#464,#465,
+#466,#467,#468,#469,#470,#471,#472),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,2,2,
+4),(-0.693278014535726,-0.635303041750731,-0.574521365747069,-0.506206153646801,
+-0.427317450881288,-0.371003876338433,-0.339958259929658),.UNSPECIFIED.);
+#37=B_SPLINE_CURVE_WITH_KNOTS('',3,(#474,#475,#476,#477,#478,#479),
+ .UNSPECIFIED.,.F.,.F.,(4,2,4),(0.956205080432559,1.60157087386622,1.89319833556573),
+ .UNSPECIFIED.);
+#38=FACE_OUTER_BOUND('',#50,.T.);
+#39=FACE_OUTER_BOUND('',#51,.T.);
+#40=FACE_OUTER_BOUND('',#52,.T.);
+#41=FACE_OUTER_BOUND('',#53,.T.);
+#42=FACE_OUTER_BOUND('',#57,.T.);
+#43=FACE_OUTER_BOUND('',#58,.T.);
+#44=FACE_OUTER_BOUND('',#59,.T.);
+#45=FACE_OUTER_BOUND('',#60,.T.);
+#46=FACE_OUTER_BOUND('',#61,.T.);
+#47=FACE_OUTER_BOUND('',#63,.T.);
+#48=FACE_OUTER_BOUND('',#64,.T.);
+#49=FACE_OUTER_BOUND('',#65,.T.);
+#50=EDGE_LOOP('',(#157,#158,#159,#160));
+#51=EDGE_LOOP('',(#161,#162,#163,#164));
+#52=EDGE_LOOP('',(#165,#166,#167,#168,#169,#170,#171,#172));
+#53=EDGE_LOOP('',(#173,#174,#175,#176,#177));
+#54=EDGE_LOOP('',(#178));
+#55=EDGE_LOOP('',(#179));
+#56=EDGE_LOOP('',(#180));
+#57=EDGE_LOOP('',(#181,#182,#183,#184));
+#58=EDGE_LOOP('',(#185,#186,#187,#188,#189,#190,#191,#192,#193));
+#59=EDGE_LOOP('',(#194,#195,#196,#197,#198,#199,#200,#201,#202));
+#60=EDGE_LOOP('',(#203,#204,#205,#206));
+#61=EDGE_LOOP('',(#207));
+#62=EDGE_LOOP('',(#208));
+#63=EDGE_LOOP('',(#209,#210,#211,#212));
+#64=EDGE_LOOP('',(#213,#214,#215,#216));
+#65=EDGE_LOOP('',(#217));
+#66=EDGE_LOOP('',(#218));
+#67=EDGE_LOOP('',(#219));
+#68=EDGE_LOOP('',(#220));
+#69=EDGE_LOOP('',(#221));
+#70=EDGE_LOOP('',(#222));
+#71=LINE('',#361,#77);
+#72=LINE('',#367,#78);
+#73=LINE('',#417,#79);
+#74=LINE('',#481,#80);
+#75=LINE('',#490,#81);
+#76=LINE('',#494,#82);
+#77=VECTOR('',#292,1.);
+#78=VECTOR('',#299,1.);
+#79=VECTOR('',#306,2.5);
+#80=VECTOR('',#335,2.5);
+#81=VECTOR('',#348,28.4501360376889);
+#82=VECTOR('',#353,37.95);
+#83=CIRCLE('',#256,1.);
+#84=CIRCLE('',#257,1.);
+#85=CIRCLE('',#259,1.);
+#86=CIRCLE('',#260,1.);
+#87=CIRCLE('',#262,2.5);
+#88=CIRCLE('',#263,2.5);
+#89=CIRCLE('',#265,32.4501360376889);
+#90=CIRCLE('',#266,2.5);
+#91=CIRCLE('',#267,2.5);
+#92=CIRCLE('',#268,32.4501360376889);
+#93=CIRCLE('',#269,28.4501360376889);
+#94=CIRCLE('',#271,33.3402729518514);
+#95=CIRCLE('',#273,35.3326623480349);
+#96=CIRCLE('',#274,2.);
+#97=CIRCLE('',#275,33.3402729518514);
+#98=CIRCLE('',#277,2.5);
+#99=CIRCLE('',#280,37.95);
+#100=CIRCLE('',#282,28.4501360376889);
+#101=CIRCLE('',#284,37.95);
+#102=VERTEX_POINT('',#358);
+#103=VERTEX_POINT('',#360);
+#104=VERTEX_POINT('',#364);
+#105=VERTEX_POINT('',#366);
+#106=VERTEX_POINT('',#370);
+#107=VERTEX_POINT('',#371);
+#108=VERTEX_POINT('',#386);
+#109=VERTEX_POINT('',#393);
+#110=VERTEX_POINT('',#395);
+#111=VERTEX_POINT('',#416);
+#112=VERTEX_POINT('',#420);
+#113=VERTEX_POINT('',#422);
+#114=VERTEX_POINT('',#424);
+#115=VERTEX_POINT('',#427);
+#116=VERTEX_POINT('',#430);
+#117=VERTEX_POINT('',#439);
+#118=VERTEX_POINT('',#441);
+#119=VERTEX_POINT('',#457);
+#120=VERTEX_POINT('',#480);
+#121=VERTEX_POINT('',#485);
+#122=VERTEX_POINT('',#488);
+#123=VERTEX_POINT('',#492);
+#124=EDGE_CURVE('',#102,#102,#83,.T.);
+#125=EDGE_CURVE('',#102,#103,#71,.T.);
+#126=EDGE_CURVE('',#103,#103,#84,.T.);
+#127=EDGE_CURVE('',#104,#104,#85,.T.);
+#128=EDGE_CURVE('',#104,#105,#72,.T.);
+#129=EDGE_CURVE('',#105,#105,#86,.T.);
+#130=EDGE_CURVE('',#106,#107,#30,.T.);
+#131=EDGE_CURVE('',#108,#106,#31,.T.);
+#132=EDGE_CURVE('',#109,#108,#87,.T.);
+#133=EDGE_CURVE('',#110,#109,#32,.T.);
+#134=EDGE_CURVE('',#107,#110,#33,.T.);
+#135=EDGE_CURVE('',#107,#111,#73,.T.);
+#136=EDGE_CURVE('',#111,#111,#88,.T.);
+#137=EDGE_CURVE('',#112,#108,#89,.T.);
+#138=EDGE_CURVE('',#112,#113,#90,.T.);
+#139=EDGE_CURVE('',#113,#114,#91,.T.);
+#140=EDGE_CURVE('',#109,#114,#92,.T.);
+#141=EDGE_CURVE('',#115,#115,#93,.T.);
+#142=EDGE_CURVE('',#116,#106,#94,.T.);
+#143=EDGE_CURVE('',#116,#112,#34,.T.);
+#144=EDGE_CURVE('',#117,#117,#95,.T.);
+#145=EDGE_CURVE('',#117,#118,#96,.T.);
+#146=EDGE_CURVE('',#118,#116,#35,.T.);
+#147=EDGE_CURVE('',#110,#119,#97,.T.);
+#148=EDGE_CURVE('',#119,#118,#36,.T.);
+#149=EDGE_CURVE('',#114,#119,#37,.T.);
+#150=EDGE_CURVE('',#113,#120,#74,.T.);
+#151=EDGE_CURVE('',#120,#120,#98,.T.);
+#152=EDGE_CURVE('',#121,#121,#99,.T.);
+#153=EDGE_CURVE('',#122,#122,#100,.T.);
+#154=EDGE_CURVE('',#122,#115,#75,.T.);
+#155=EDGE_CURVE('',#123,#123,#101,.T.);
+#156=EDGE_CURVE('',#123,#121,#76,.T.);
+#157=ORIENTED_EDGE('',*,*,#124,.F.);
+#158=ORIENTED_EDGE('',*,*,#125,.T.);
+#159=ORIENTED_EDGE('',*,*,#126,.F.);
+#160=ORIENTED_EDGE('',*,*,#125,.F.);
+#161=ORIENTED_EDGE('',*,*,#127,.F.);
+#162=ORIENTED_EDGE('',*,*,#128,.T.);
+#163=ORIENTED_EDGE('',*,*,#129,.F.);
+#164=ORIENTED_EDGE('',*,*,#128,.F.);
+#165=ORIENTED_EDGE('',*,*,#130,.F.);
+#166=ORIENTED_EDGE('',*,*,#131,.F.);
+#167=ORIENTED_EDGE('',*,*,#132,.F.);
+#168=ORIENTED_EDGE('',*,*,#133,.F.);
+#169=ORIENTED_EDGE('',*,*,#134,.F.);
+#170=ORIENTED_EDGE('',*,*,#135,.T.);
+#171=ORIENTED_EDGE('',*,*,#136,.F.);
+#172=ORIENTED_EDGE('',*,*,#135,.F.);
+#173=ORIENTED_EDGE('',*,*,#132,.T.);
+#174=ORIENTED_EDGE('',*,*,#137,.F.);
+#175=ORIENTED_EDGE('',*,*,#138,.T.);
+#176=ORIENTED_EDGE('',*,*,#139,.T.);
+#177=ORIENTED_EDGE('',*,*,#140,.F.);
+#178=ORIENTED_EDGE('',*,*,#124,.T.);
+#179=ORIENTED_EDGE('',*,*,#127,.T.);
+#180=ORIENTED_EDGE('',*,*,#141,.F.);
+#181=ORIENTED_EDGE('',*,*,#131,.T.);
+#182=ORIENTED_EDGE('',*,*,#142,.F.);
+#183=ORIENTED_EDGE('',*,*,#143,.T.);
+#184=ORIENTED_EDGE('',*,*,#137,.T.);
+#185=ORIENTED_EDGE('',*,*,#144,.T.);
+#186=ORIENTED_EDGE('',*,*,#145,.T.);
+#187=ORIENTED_EDGE('',*,*,#146,.T.);
+#188=ORIENTED_EDGE('',*,*,#142,.T.);
+#189=ORIENTED_EDGE('',*,*,#130,.T.);
+#190=ORIENTED_EDGE('',*,*,#134,.T.);
+#191=ORIENTED_EDGE('',*,*,#147,.T.);
+#192=ORIENTED_EDGE('',*,*,#148,.T.);
+#193=ORIENTED_EDGE('',*,*,#145,.F.);
+#194=ORIENTED_EDGE('',*,*,#148,.F.);
+#195=ORIENTED_EDGE('',*,*,#149,.F.);
+#196=ORIENTED_EDGE('',*,*,#139,.F.);
+#197=ORIENTED_EDGE('',*,*,#150,.T.);
+#198=ORIENTED_EDGE('',*,*,#151,.F.);
+#199=ORIENTED_EDGE('',*,*,#150,.F.);
+#200=ORIENTED_EDGE('',*,*,#138,.F.);
+#201=ORIENTED_EDGE('',*,*,#143,.F.);
+#202=ORIENTED_EDGE('',*,*,#146,.F.);
+#203=ORIENTED_EDGE('',*,*,#133,.T.);
+#204=ORIENTED_EDGE('',*,*,#140,.T.);
+#205=ORIENTED_EDGE('',*,*,#149,.T.);
+#206=ORIENTED_EDGE('',*,*,#147,.F.);
+#207=ORIENTED_EDGE('',*,*,#152,.F.);
+#208=ORIENTED_EDGE('',*,*,#144,.F.);
+#209=ORIENTED_EDGE('',*,*,#153,.F.);
+#210=ORIENTED_EDGE('',*,*,#154,.T.);
+#211=ORIENTED_EDGE('',*,*,#141,.T.);
+#212=ORIENTED_EDGE('',*,*,#154,.F.);
+#213=ORIENTED_EDGE('',*,*,#155,.F.);
+#214=ORIENTED_EDGE('',*,*,#156,.T.);
+#215=ORIENTED_EDGE('',*,*,#152,.T.);
+#216=ORIENTED_EDGE('',*,*,#156,.F.);
+#217=ORIENTED_EDGE('',*,*,#155,.T.);
+#218=ORIENTED_EDGE('',*,*,#126,.T.);
+#219=ORIENTED_EDGE('',*,*,#129,.T.);
+#220=ORIENTED_EDGE('',*,*,#136,.T.);
+#221=ORIENTED_EDGE('',*,*,#151,.T.);
+#222=ORIENTED_EDGE('',*,*,#153,.T.);
+#223=CYLINDRICAL_SURFACE('',#255,1.);
+#224=CYLINDRICAL_SURFACE('',#258,1.);
+#225=CYLINDRICAL_SURFACE('',#261,2.5);
+#226=CYLINDRICAL_SURFACE('',#276,2.5);
+#227=CYLINDRICAL_SURFACE('',#281,28.4501360376889);
+#228=CYLINDRICAL_SURFACE('',#283,37.95);
+#229=ADVANCED_FACE('',(#38),#223,.F.);
+#230=ADVANCED_FACE('',(#39),#224,.F.);
+#231=ADVANCED_FACE('',(#40),#225,.F.);
+#232=ADVANCED_FACE('',(#41,#18,#19,#20),#27,.F.);
+#233=ADVANCED_FACE('',(#42),#16,.F.);
+#234=ADVANCED_FACE('',(#43),#15,.T.);
+#235=ADVANCED_FACE('',(#44),#226,.F.);
+#236=ADVANCED_FACE('',(#45),#17,.F.);
+#237=ADVANCED_FACE('',(#46,#21),#28,.F.);
+#238=ADVANCED_FACE('',(#47),#227,.F.);
+#239=ADVANCED_FACE('',(#48),#228,.T.);
+#240=ADVANCED_FACE('',(#49,#22,#23,#24,#25,#26),#29,.T.);
+#241=CLOSED_SHELL('',(#229,#230,#231,#232,#233,#234,#235,#236,#237,#238,
+#239,#240));
+#242=DERIVED_UNIT_ELEMENT(#244,1.);
+#243=DERIVED_UNIT_ELEMENT(#501,-3.);
+#244=(
+MASS_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.KILO.,.GRAM.)
+);
+#245=DERIVED_UNIT((#242,#243));
+#246=MEASURE_REPRESENTATION_ITEM('density measure',
+POSITIVE_RATIO_MEASURE(7850.),#245);
+#247=PROPERTY_DEFINITION_REPRESENTATION(#252,#249);
+#248=PROPERTY_DEFINITION_REPRESENTATION(#253,#250);
+#249=REPRESENTATION('material name',(#251),#498);
+#250=REPRESENTATION('density',(#246),#498);
+#251=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel');
+#252=PROPERTY_DEFINITION('material property','material name',#508);
+#253=PROPERTY_DEFINITION('material property','density of part',#508);
+#254=AXIS2_PLACEMENT_3D('',#356,#286,#287);
+#255=AXIS2_PLACEMENT_3D('',#357,#288,#289);
+#256=AXIS2_PLACEMENT_3D('',#359,#290,#291);
+#257=AXIS2_PLACEMENT_3D('',#362,#293,#294);
+#258=AXIS2_PLACEMENT_3D('',#363,#295,#296);
+#259=AXIS2_PLACEMENT_3D('',#365,#297,#298);
+#260=AXIS2_PLACEMENT_3D('',#368,#300,#301);
+#261=AXIS2_PLACEMENT_3D('',#369,#302,#303);
+#262=AXIS2_PLACEMENT_3D('',#394,#304,#305);
+#263=AXIS2_PLACEMENT_3D('',#418,#307,#308);
+#264=AXIS2_PLACEMENT_3D('',#419,#309,#310);
+#265=AXIS2_PLACEMENT_3D('',#421,#311,#312);
+#266=AXIS2_PLACEMENT_3D('',#423,#313,#314);
+#267=AXIS2_PLACEMENT_3D('',#425,#315,#316);
+#268=AXIS2_PLACEMENT_3D('',#426,#317,#318);
+#269=AXIS2_PLACEMENT_3D('',#428,#319,#320);
+#270=AXIS2_PLACEMENT_3D('',#429,#321,#322);
+#271=AXIS2_PLACEMENT_3D('',#431,#323,#324);
+#272=AXIS2_PLACEMENT_3D('',#438,#325,#326);
+#273=AXIS2_PLACEMENT_3D('',#440,#327,#328);
+#274=AXIS2_PLACEMENT_3D('',#442,#329,#330);
+#275=AXIS2_PLACEMENT_3D('',#458,#331,#332);
+#276=AXIS2_PLACEMENT_3D('',#473,#333,#334);
+#277=AXIS2_PLACEMENT_3D('',#482,#336,#337);
+#278=AXIS2_PLACEMENT_3D('',#483,#338,#339);
+#279=AXIS2_PLACEMENT_3D('',#484,#340,#341);
+#280=AXIS2_PLACEMENT_3D('',#486,#342,#343);
+#281=AXIS2_PLACEMENT_3D('',#487,#344,#345);
+#282=AXIS2_PLACEMENT_3D('',#489,#346,#347);
+#283=AXIS2_PLACEMENT_3D('',#491,#349,#350);
+#284=AXIS2_PLACEMENT_3D('',#493,#351,#352);
+#285=AXIS2_PLACEMENT_3D('',#495,#354,#355);
+#286=DIRECTION('axis',(0.,0.,1.));
+#287=DIRECTION('refdir',(1.,0.,0.));
+#288=DIRECTION('center_axis',(0.,1.,0.));
+#289=DIRECTION('ref_axis',(-1.22464679914735E-16,0.,1.));
+#290=DIRECTION('center_axis',(0.,1.,0.));
+#291=DIRECTION('ref_axis',(-1.22464679914735E-16,0.,1.));
+#292=DIRECTION('',(0.,1.,0.));
+#293=DIRECTION('center_axis',(0.,-1.,0.));
+#294=DIRECTION('ref_axis',(-1.22464679914735E-16,0.,1.));
+#295=DIRECTION('center_axis',(0.,1.,0.));
+#296=DIRECTION('ref_axis',(0.,0.,-1.));
+#297=DIRECTION('center_axis',(0.,1.,0.));
+#298=DIRECTION('ref_axis',(0.,0.,-1.));
+#299=DIRECTION('',(0.,1.,0.));
+#300=DIRECTION('center_axis',(0.,-1.,0.));
+#301=DIRECTION('ref_axis',(0.,0.,-1.));
+#302=DIRECTION('center_axis',(0.,1.,0.));
+#303=DIRECTION('ref_axis',(0.,0.,-1.));
+#304=DIRECTION('center_axis',(0.,1.,0.));
+#305=DIRECTION('ref_axis',(0.,0.,-1.));
+#306=DIRECTION('',(0.,1.,0.));
+#307=DIRECTION('center_axis',(0.,-1.,0.));
+#308=DIRECTION('ref_axis',(0.,0.,-1.));
+#309=DIRECTION('center_axis',(0.,1.,0.));
+#310=DIRECTION('ref_axis',(1.,0.,0.));
+#311=DIRECTION('center_axis',(0.,1.,0.));
+#312=DIRECTION('ref_axis',(-1.,0.,0.));
+#313=DIRECTION('center_axis',(0.,1.,0.));
+#314=DIRECTION('ref_axis',(0.,0.,-1.));
+#315=DIRECTION('center_axis',(0.,1.,0.));
+#316=DIRECTION('ref_axis',(0.,0.,-1.));
+#317=DIRECTION('center_axis',(0.,1.,0.));
+#318=DIRECTION('ref_axis',(-1.,0.,0.));
+#319=DIRECTION('center_axis',(0.,-1.,0.));
+#320=DIRECTION('ref_axis',(-1.,0.,0.));
+#321=DIRECTION('center_axis',(0.,-1.,0.));
+#322=DIRECTION('ref_axis',(-1.,0.,1.22464679914735E-16));
+#323=DIRECTION('center_axis',(0.,1.,0.));
+#324=DIRECTION('ref_axis',(1.,0.,-6.12323399573677E-17));
+#325=DIRECTION('center_axis',(0.,1.,0.));
+#326=DIRECTION('ref_axis',(0.,0.,1.));
+#327=DIRECTION('center_axis',(0.,-1.,0.));
+#328=DIRECTION('ref_axis',(1.,0.,0.));
+#329=DIRECTION('center_axis',(-1.,0.,1.22464679914735E-16));
+#330=DIRECTION('ref_axis',(-1.22464679914735E-16,0.,-1.));
+#331=DIRECTION('center_axis',(0.,1.,0.));
+#332=DIRECTION('ref_axis',(1.,0.,-6.12323399573677E-17));
+#333=DIRECTION('center_axis',(0.,1.,0.));
+#334=DIRECTION('ref_axis',(0.,0.,-1.));
+#335=DIRECTION('',(0.,1.,0.));
+#336=DIRECTION('center_axis',(0.,-1.,0.));
+#337=DIRECTION('ref_axis',(0.,0.,-1.));
+#338=DIRECTION('center_axis',(0.,-1.,0.));
+#339=DIRECTION('ref_axis',(1.,0.,0.));
+#340=DIRECTION('center_axis',(0.,1.,0.));
+#341=DIRECTION('ref_axis',(1.,0.,0.));
+#342=DIRECTION('center_axis',(0.,1.,0.));
+#343=DIRECTION('ref_axis',(1.,0.,0.));
+#344=DIRECTION('center_axis',(0.,1.,0.));
+#345=DIRECTION('ref_axis',(-1.,0.,0.));
+#346=DIRECTION('center_axis',(0.,-1.,0.));
+#347=DIRECTION('ref_axis',(-1.,0.,0.));
+#348=DIRECTION('',(0.,-1.,0.));
+#349=DIRECTION('center_axis',(0.,1.,0.));
+#350=DIRECTION('ref_axis',(1.,0.,0.));
+#351=DIRECTION('center_axis',(0.,1.,0.));
+#352=DIRECTION('ref_axis',(1.,0.,0.));
+#353=DIRECTION('',(0.,-1.,0.));
+#354=DIRECTION('center_axis',(0.,1.,0.));
+#355=DIRECTION('ref_axis',(1.,0.,0.));
+#356=CARTESIAN_POINT('',(0.,0.,0.));
+#357=CARTESIAN_POINT('Origin',(30.4501360376889,25.,3.72906616321572E-15));
+#358=CARTESIAN_POINT('',(30.4501360376889,16.,-0.999999999999996));
+#359=CARTESIAN_POINT('Origin',(30.4501360376889,16.,3.72906616321572E-15));
+#360=CARTESIAN_POINT('',(30.4501360376889,32.,-0.999999999999996));
+#361=CARTESIAN_POINT('',(30.4501360376889,25.,-0.999999999999996));
+#362=CARTESIAN_POINT('Origin',(30.4501360376889,32.,3.72906616321572E-15));
+#363=CARTESIAN_POINT('Origin',(-30.4501360376889,25.,0.));
+#364=CARTESIAN_POINT('',(-30.4501360376889,16.,1.));
+#365=CARTESIAN_POINT('Origin',(-30.4501360376889,16.,0.));
+#366=CARTESIAN_POINT('',(-30.4501360376889,32.,1.));
+#367=CARTESIAN_POINT('',(-30.4501360376889,25.,1.));
+#368=CARTESIAN_POINT('Origin',(-30.4501360376889,32.,0.));
+#369=CARTESIAN_POINT('Origin',(-3.91886975727153E-15,19.4,32.));
+#370=CARTESIAN_POINT('',(-2.15298889897732,5.82568851450469,33.2706843828742));
+#371=CARTESIAN_POINT('',(-3.57143516554875E-15,4.18157391842146,34.5));
+#372=CARTESIAN_POINT('Ctrl Pts',(-2.15298889897731,5.82568851450469,33.2706843828742));
+#373=CARTESIAN_POINT('Ctrl Pts',(-2.14326778235162,5.64499219919488,33.2871553936641));
+#374=CARTESIAN_POINT('Ctrl Pts',(-2.11870771590737,5.46881874479251,33.3292800790023));
+#375=CARTESIAN_POINT('Ctrl Pts',(-2.03095519410776,5.13173993440848,33.4600409497882));
+#376=CARTESIAN_POINT('Ctrl Pts',(-1.96689812723988,4.9764332795477,33.5489975179543));
+#377=CARTESIAN_POINT('Ctrl Pts',(-1.77842366453784,4.68979624232094,33.7635303987792));
+#378=CARTESIAN_POINT('Ctrl Pts',(-1.65223044931045,4.57104330311413,33.8861582171839));
+#379=CARTESIAN_POINT('Ctrl Pts',(-1.31827034473523,4.37082419348789,34.1359085635487));
+#380=CARTESIAN_POINT('Ctrl Pts',(-1.10442945152145,4.29994068321555,34.2579512870062));
+#381=CARTESIAN_POINT('Ctrl Pts',(-0.684402397678135,4.2200684977259,34.4117013867247));
+#382=CARTESIAN_POINT('Ctrl Pts',(-0.500348988581707,4.20033969083523,34.45672454836));
+#383=CARTESIAN_POINT('Ctrl Pts',(-0.208979437761146,4.18432476907373,34.4934345264361));
+#384=CARTESIAN_POINT('Ctrl Pts',(-0.104494904396692,4.18157391842146,34.5));
+#385=CARTESIAN_POINT('Ctrl Pts',(-3.29597460435593E-15,4.18157391842146,
+34.5));
+#386=CARTESIAN_POINT('',(-2.47457392108192,16.,32.3556457635081));
+#387=CARTESIAN_POINT('Ctrl Pts',(-2.47457392108193,16.,32.3556457635081));
+#388=CARTESIAN_POINT('Ctrl Pts',(-2.44527807933195,13.7024210312228,32.5594854642135));
+#389=CARTESIAN_POINT('Ctrl Pts',(-2.38961012163989,11.349882500011,32.7701265620035));
+#390=CARTESIAN_POINT('Ctrl Pts',(-2.25787256186806,7.93985723043458,33.0783718561048));
+#391=CARTESIAN_POINT('Ctrl Pts',(-2.20969181029125,6.87968339351787,33.1746095902318));
+#392=CARTESIAN_POINT('Ctrl Pts',(-2.15298889897731,5.82568851450469,33.2706843828742));
+#393=CARTESIAN_POINT('',(2.47457392108191,16.,32.3556457635081));
+#394=CARTESIAN_POINT('Origin',(-3.91886975727153E-15,16.,32.));
+#395=CARTESIAN_POINT('',(2.15298889897731,5.82568851450469,33.2706843828742));
+#396=CARTESIAN_POINT('Ctrl Pts',(2.1529888989773,5.82568851450469,33.2706843828742));
+#397=CARTESIAN_POINT('Ctrl Pts',(2.20969181029124,6.87968339351787,33.1746095902318));
+#398=CARTESIAN_POINT('Ctrl Pts',(2.25787256186805,7.93985723043458,33.0783718561048));
+#399=CARTESIAN_POINT('Ctrl Pts',(2.38961012163989,11.349882500011,32.7701265620035));
+#400=CARTESIAN_POINT('Ctrl Pts',(2.44527807933194,13.7024210312228,32.5594854642135));
+#401=CARTESIAN_POINT('Ctrl Pts',(2.47457392108192,16.,32.3556457635081));
+#402=CARTESIAN_POINT('Ctrl Pts',(-3.42595173898619E-15,4.18157391842146,
+34.5));
+#403=CARTESIAN_POINT('Ctrl Pts',(0.0633006895016584,4.18157391842146,34.5));
+#404=CARTESIAN_POINT('Ctrl Pts',(0.126605186099969,4.18259075195278,34.4975939484107));
+#405=CARTESIAN_POINT('Ctrl Pts',(0.369980058246124,4.19053515427657,34.4790729625172));
+#406=CARTESIAN_POINT('Ctrl Pts',(0.548136343656891,4.20466781486954,34.4457207148488));
+#407=CARTESIAN_POINT('Ctrl Pts',(0.934660048283582,4.26148508140215,34.3295712452292));
+#408=CARTESIAN_POINT('Ctrl Pts',(1.13630151348502,4.30997089020013,34.236950815797));
+#409=CARTESIAN_POINT('Ctrl Pts',(1.50460639573073,4.46669993705164,34.008714761652));
+#410=CARTESIAN_POINT('Ctrl Pts',(1.6619981194712,4.5744183121113,33.8763261150617));
+#411=CARTESIAN_POINT('Ctrl Pts',(1.9047349959034,4.85783756343064,33.6277628912268));
+#412=CARTESIAN_POINT('Ctrl Pts',(1.98882589882179,5.02014402136272,33.5183110062422));
+#413=CARTESIAN_POINT('Ctrl Pts',(2.1084895731499,5.39874116368562,33.3473493487577));
+#414=CARTESIAN_POINT('Ctrl Pts',(2.14131208447456,5.60863964692642,33.2904690377725));
+#415=CARTESIAN_POINT('Ctrl Pts',(2.1529888989773,5.82568851450469,33.2706843828742));
+#416=CARTESIAN_POINT('',(-4.22503145705837E-15,32.,34.5));
+#417=CARTESIAN_POINT('',(-3.61270805748469E-15,19.4,34.5));
+#418=CARTESIAN_POINT('Origin',(-3.91886975727153E-15,32.,32.));
+#419=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#420=CARTESIAN_POINT('',(-2.47457392108192,16.,-32.3556457635081));
+#421=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#422=CARTESIAN_POINT('',(3.06161699786838E-16,16.,-29.5));
+#423=CARTESIAN_POINT('Origin',(0.,16.,-32.));
+#424=CARTESIAN_POINT('',(2.47457392108192,16.,-32.3556457635081));
+#425=CARTESIAN_POINT('Origin',(0.,16.,-32.));
+#426=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#427=CARTESIAN_POINT('',(28.4501360376889,16.,3.48413680338625E-15));
+#428=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#429=CARTESIAN_POINT('Origin',(0.,4.,0.));
+#430=CARTESIAN_POINT('',(-2.15298889897731,5.82568851450469,-33.2706843828742));
+#431=CARTESIAN_POINT('Origin',(0.,5.82568851450468,2.04150292765919E-15));
+#432=CARTESIAN_POINT('Ctrl Pts',(-2.15298889897731,5.82568851450469,-33.2706843828742));
+#433=CARTESIAN_POINT('Ctrl Pts',(-2.20970486571512,6.87992606800465,-33.1745874697249));
+#434=CARTESIAN_POINT('Ctrl Pts',(-2.25789484203115,7.94034685384815,-33.0783274099115));
+#435=CARTESIAN_POINT('Ctrl Pts',(-2.38962156035581,11.3503715159968,-32.7700827733885));
+#436=CARTESIAN_POINT('Ctrl Pts',(-2.44528112983175,13.7026602721448,-32.5594642389157));
+#437=CARTESIAN_POINT('Ctrl Pts',(-2.47457392108192,16.,-32.3556457635081));
+#438=CARTESIAN_POINT('Origin',(0.,6.,0.));
+#439=CARTESIAN_POINT('',(-4.32700318498751E-15,4.,-35.3326623480349));
+#440=CARTESIAN_POINT('Origin',(0.,4.,0.));
+#441=CARTESIAN_POINT('',(-4.20285751708124E-15,4.18157391842146,-34.5));
+#442=CARTESIAN_POINT('Origin',(-4.32700318498751E-15,6.,-35.3326623480349));
+#443=CARTESIAN_POINT('Ctrl Pts',(-4.18694362388361E-15,4.18157391842146,
+-34.5));
+#444=CARTESIAN_POINT('Ctrl Pts',(-0.063262161766766,4.18157391842146,-34.5));
+#445=CARTESIAN_POINT('Ctrl Pts',(-0.126528132742232,4.18258951971525,-34.4975968787245));
+#446=CARTESIAN_POINT('Ctrl Pts',(-0.369848759790652,4.19052720534936,-34.4790913296945));
+#447=CARTESIAN_POINT('Ctrl Pts',(-0.547990585411446,4.2046539473299,-34.4457522346077));
+#448=CARTESIAN_POINT('Ctrl Pts',(-0.934485440504991,4.26144992909178,-34.3296391263527));
+#449=CARTESIAN_POINT('Ctrl Pts',(-1.13611627379708,4.3099184171338,-34.2370434787398));
+#450=CARTESIAN_POINT('Ctrl Pts',(-1.5044438872684,4.46660340894347,-34.0088384522548));
+#451=CARTESIAN_POINT('Ctrl Pts',(-1.66186312185693,4.57430457458071,-33.8764481321499));
+#452=CARTESIAN_POINT('Ctrl Pts',(-1.9046449171097,4.85769217161277,-33.6278699966614));
+#453=CARTESIAN_POINT('Ctrl Pts',(-1.98875430422476,5.01998196384772,-33.5184063892516));
+#454=CARTESIAN_POINT('Ctrl Pts',(-2.10846974982161,5.39861288959637,-33.3473846909005));
+#455=CARTESIAN_POINT('Ctrl Pts',(-2.14130845329707,5.6085721505247,-33.2904751902719));
+#456=CARTESIAN_POINT('Ctrl Pts',(-2.15298889897731,5.82568851450469,-33.2706843828742));
+#457=CARTESIAN_POINT('',(2.15298889897731,5.82568851450469,-33.2706843828742));
+#458=CARTESIAN_POINT('Origin',(0.,5.82568851450468,2.04150292765919E-15));
+#459=CARTESIAN_POINT('Ctrl Pts',(2.15298889897731,5.82568851450469,-33.2706843828742));
+#460=CARTESIAN_POINT('Ctrl Pts',(2.14326684320266,5.64497474227475,-33.2871569849147));
+#461=CARTESIAN_POINT('Ctrl Pts',(2.1187030956113,5.4687855147573,-33.3292881469587));
+#462=CARTESIAN_POINT('Ctrl Pts',(2.03095209486777,5.13174426578632,-33.4600443271662));
+#463=CARTESIAN_POINT('Ctrl Pts',(1.96691379452368,4.97647835780048,-33.5489736661958));
+#464=CARTESIAN_POINT('Ctrl Pts',(1.77848483103683,4.68986539340781,-33.7634675361664));
+#465=CARTESIAN_POINT('Ctrl Pts',(1.65230542564604,4.57110475576392,-33.8860914172305));
+#466=CARTESIAN_POINT('Ctrl Pts',(1.31835960896768,4.37085866406937,-34.1358541910381));
+#467=CARTESIAN_POINT('Ctrl Pts',(1.10451389511487,4.29996288007677,-34.2579116568628));
+#468=CARTESIAN_POINT('Ctrl Pts',(0.68448040998158,4.22007895178794,-34.4116790526783));
+#469=CARTESIAN_POINT('Ctrl Pts',(0.500430678551161,4.20034716548025,-34.4567077570785));
+#470=CARTESIAN_POINT('Ctrl Pts',(0.209036275833293,4.18432624876454,-34.493430946008));
+#471=CARTESIAN_POINT('Ctrl Pts',(0.104523335456357,4.18157391842146,-34.5));
+#472=CARTESIAN_POINT('Ctrl Pts',(-4.16333634234434E-15,4.18157391842146,
+-34.5));
+#473=CARTESIAN_POINT('Origin',(0.,19.4,-32.));
+#474=CARTESIAN_POINT('Ctrl Pts',(2.47457392108192,16.,-32.3556457635081));
+#475=CARTESIAN_POINT('Ctrl Pts',(2.44528112983175,13.7026602721448,-32.5594642389157));
+#476=CARTESIAN_POINT('Ctrl Pts',(2.38962156035581,11.3503715159968,-32.7700827733885));
+#477=CARTESIAN_POINT('Ctrl Pts',(2.25789484203115,7.94034685384815,-33.0783274099115));
+#478=CARTESIAN_POINT('Ctrl Pts',(2.20970486571511,6.87992606800464,-33.1745874697249));
+#479=CARTESIAN_POINT('Ctrl Pts',(2.15298889897731,5.82568851450468,-33.2706843828742));
+#480=CARTESIAN_POINT('',(-3.06161699786838E-16,32.,-29.5));
+#481=CARTESIAN_POINT('',(3.06161699786838E-16,19.4,-29.5));
+#482=CARTESIAN_POINT('Origin',(0.,32.,-32.));
+#483=CARTESIAN_POINT('Origin',(0.,4.,0.));
+#484=CARTESIAN_POINT('Origin',(0.,4.,0.));
+#485=CARTESIAN_POINT('',(-37.95,4.,4.64753460276421E-15));
+#486=CARTESIAN_POINT('Origin',(0.,4.,0.));
+#487=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#488=CARTESIAN_POINT('',(28.4501360376889,32.,3.48413680338625E-15));
+#489=CARTESIAN_POINT('Origin',(0.,32.,0.));
+#490=CARTESIAN_POINT('',(28.4501360376889,16.,-3.48413680338625E-15));
+#491=CARTESIAN_POINT('Origin',(0.,4.,0.));
+#492=CARTESIAN_POINT('',(-37.95,32.,4.64753460276421E-15));
+#493=CARTESIAN_POINT('Origin',(0.,32.,0.));
+#494=CARTESIAN_POINT('',(-37.95,4.,4.64753460276421E-15));
+#495=CARTESIAN_POINT('Origin',(0.,32.,0.));
+#496=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#500,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#497=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#500,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#498=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#496))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#500,#502,#503))
+REPRESENTATION_CONTEXT('','3D')
+);
+#499=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#497))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#500,#502,#503))
+REPRESENTATION_CONTEXT('','3D')
+);
+#500=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.MILLI.,.METRE.)
+);
+#501=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT($,.METRE.)
+);
+#502=(
+NAMED_UNIT(*)
+PLANE_ANGLE_UNIT()
+SI_UNIT($,.RADIAN.)
+);
+#503=(
+NAMED_UNIT(*)
+SI_UNIT($,.STERADIAN.)
+SOLID_ANGLE_UNIT()
+);
+#504=SHAPE_DEFINITION_REPRESENTATION(#505,#506);
+#505=PRODUCT_DEFINITION_SHAPE('',$,#508);
+#506=SHAPE_REPRESENTATION('',(#254),#498);
+#507=PRODUCT_DEFINITION_CONTEXT('part definition',#512,'design');
+#508=PRODUCT_DEFINITION('FusionComponent','FusionComponent',#509,#507);
+#509=PRODUCT_DEFINITION_FORMATION('',$,#514);
+#510=PRODUCT_RELATED_PRODUCT_CATEGORY('FusionComponent',
+'FusionComponent',(#514));
+#511=APPLICATION_PROTOCOL_DEFINITION('international standard',
+'automotive_design',2009,#512);
+#512=APPLICATION_CONTEXT(
+'Core Data for Automotive Mechanical Design Process');
+#513=PRODUCT_CONTEXT('part definition',#512,'mechanical');
+#514=PRODUCT('FusionComponent','FusionComponent',$,(#513));
+#515=PRESENTATION_STYLE_ASSIGNMENT((#516));
+#516=SURFACE_STYLE_USAGE(.BOTH.,#517);
+#517=SURFACE_SIDE_STYLE('',(#518));
+#518=SURFACE_STYLE_FILL_AREA(#519);
+#519=FILL_AREA_STYLE('Steel - Satin',(#520));
+#520=FILL_AREA_STYLE_COLOUR('Steel - Satin',#521);
+#521=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157);
+ENDSEC;
+END-ISO-10303-21;
diff --git a/3d_model/Case.stl b/3d_model/Case.stl
new file mode 100755
index 0000000..2b67094
Binary files /dev/null and b/3d_model/Case.stl differ
diff --git a/3d_model/CaseLid.stl b/3d_model/CaseLid.stl
new file mode 100755
index 0000000..2a297f6
Binary files /dev/null and b/3d_model/CaseLid.stl differ
diff --git a/3d_model/Dial_clockwise.stl b/3d_model/Dial_clockwise.stl
new file mode 100755
index 0000000..ecf86b6
Binary files /dev/null and b/3d_model/Dial_clockwise.stl differ
diff --git a/3d_model/Dial_counterclockwise.stl b/3d_model/Dial_counterclockwise.stl
new file mode 100755
index 0000000..546994f
Binary files /dev/null and b/3d_model/Dial_counterclockwise.stl differ
diff --git a/3d_model/OuterShell.step b/3d_model/OuterShell.step
new file mode 100755
index 0000000..625639d
--- /dev/null
+++ b/3d_model/OuterShell.step
@@ -0,0 +1,115 @@
+ISO-10303-21;
+HEADER;
+/* Generated by software containing ST-Developer
+ * from STEP Tools, Inc. (www.steptools.com)
+ */
+
+FILE_DESCRIPTION(
+/* description */ (''),
+/* implementation_level */ '2;1');
+
+FILE_NAME(
+/* name */ 'OuterShell.step',
+/* time_stamp */ '2026-03-10T23:06:53+01:00',
+/* author */ (''),
+/* organization */ (''),
+/* preprocessor_version */ 'ST-DEVELOPER v20.1',
+/* originating_system */ 'Autodesk Translation Framework v14.10.0.0',
+/* authorisation */ '');
+
+FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
+ENDSEC;
+
+DATA;
+#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(),#30);
+#11=DERIVED_UNIT_ELEMENT(#13,1.);
+#12=DERIVED_UNIT_ELEMENT(#32,-3.);
+#13=(
+MASS_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.KILO.,.GRAM.)
+);
+#14=DERIVED_UNIT((#11,#12));
+#15=MEASURE_REPRESENTATION_ITEM('density measure',
+POSITIVE_RATIO_MEASURE(7850.),#14);
+#16=PROPERTY_DEFINITION_REPRESENTATION(#21,#18);
+#17=PROPERTY_DEFINITION_REPRESENTATION(#22,#19);
+#18=REPRESENTATION('material name',(#20),#29);
+#19=REPRESENTATION('density',(#15),#29);
+#20=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel');
+#21=PROPERTY_DEFINITION('material property','material name',#39);
+#22=PROPERTY_DEFINITION('material property','density of part',#39);
+#23=AXIS2_PLACEMENT_3D('',#26,#24,#25);
+#24=DIRECTION('axis',(0.,0.,1.));
+#25=DIRECTION('refdir',(1.,0.,0.));
+#26=CARTESIAN_POINT('',(0.,0.,0.));
+#27=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#31,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#28=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#31,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#29=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#27))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#31,#33,#34))
+REPRESENTATION_CONTEXT('','3D')
+);
+#30=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#28))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#31,#33,#34))
+REPRESENTATION_CONTEXT('','3D')
+);
+#31=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.MILLI.,.METRE.)
+);
+#32=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT($,.METRE.)
+);
+#33=(
+NAMED_UNIT(*)
+PLANE_ANGLE_UNIT()
+SI_UNIT($,.RADIAN.)
+);
+#34=(
+NAMED_UNIT(*)
+SI_UNIT($,.STERADIAN.)
+SOLID_ANGLE_UNIT()
+);
+#35=SHAPE_DEFINITION_REPRESENTATION(#36,#37);
+#36=PRODUCT_DEFINITION_SHAPE('',$,#39);
+#37=SHAPE_REPRESENTATION('',(#23),#29);
+#38=PRODUCT_DEFINITION_CONTEXT('part definition',#43,'design');
+#39=PRODUCT_DEFINITION('FusionComponent','FusionComponent',#40,#38);
+#40=PRODUCT_DEFINITION_FORMATION('',$,#45);
+#41=PRODUCT_RELATED_PRODUCT_CATEGORY('FusionComponent',
+'FusionComponent',(#45));
+#42=APPLICATION_PROTOCOL_DEFINITION('international standard',
+'automotive_design',2009,#43);
+#43=APPLICATION_CONTEXT(
+'Core Data for Automotive Mechanical Design Process');
+#44=PRODUCT_CONTEXT('part definition',#43,'mechanical');
+#45=PRODUCT('FusionComponent','FusionComponent',$,(#44));
+#46=PRESENTATION_STYLE_ASSIGNMENT((#48));
+#47=PRESENTATION_STYLE_ASSIGNMENT((#49));
+#48=SURFACE_STYLE_USAGE(.BOTH.,#50);
+#49=SURFACE_STYLE_USAGE(.BOTH.,#51);
+#50=SURFACE_SIDE_STYLE('',(#52));
+#51=SURFACE_SIDE_STYLE('',(#53));
+#52=SURFACE_STYLE_FILL_AREA(#54);
+#53=SURFACE_STYLE_FILL_AREA(#55);
+#54=FILL_AREA_STYLE('Steel - Satin',(#56));
+#55=FILL_AREA_STYLE('ABS (White)',(#57));
+#56=FILL_AREA_STYLE_COLOUR('Steel - Satin',#58);
+#57=FILL_AREA_STYLE_COLOUR('ABS (White)',#59);
+#58=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157);
+#59=COLOUR_RGB('ABS (White)',0.937254901960784,0.2,0.250980392156863);
+ENDSEC;
+END-ISO-10303-21;
diff --git a/3d_model/OuterShell.stl b/3d_model/OuterShell.stl
new file mode 100755
index 0000000..fca58a0
Binary files /dev/null and b/3d_model/OuterShell.stl differ
diff --git a/3d_model/Pointer.step b/3d_model/Pointer.step
new file mode 100755
index 0000000..f64f9dc
--- /dev/null
+++ b/3d_model/Pointer.step
@@ -0,0 +1,269 @@
+ISO-10303-21;
+HEADER;
+/* Generated by software containing ST-Developer
+ * from STEP Tools, Inc. (www.steptools.com)
+ */
+
+FILE_DESCRIPTION(
+/* description */ (''),
+/* implementation_level */ '2;1');
+
+FILE_NAME(
+/* name */ 'Pointer.step',
+/* time_stamp */ '2026-03-10T23:07:19+01:00',
+/* author */ (''),
+/* organization */ (''),
+/* preprocessor_version */ 'ST-DEVELOPER v20.1',
+/* originating_system */ 'Autodesk Translation Framework v14.10.0.0',
+/* authorisation */ '');
+
+FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
+ENDSEC;
+
+DATA;
+#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#13),#191);
+#11=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#198,#12);
+#12=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#14),#190);
+#13=STYLED_ITEM('',(#207),#14);
+#14=MANIFOLD_SOLID_BREP('Body1',#107);
+#15=FACE_BOUND('',#32,.T.);
+#16=FACE_BOUND('',#34,.T.);
+#17=PLANE('',#124);
+#18=PLANE('',#125);
+#19=PLANE('',#129);
+#20=PLANE('',#130);
+#21=FACE_OUTER_BOUND('',#27,.T.);
+#22=FACE_OUTER_BOUND('',#28,.T.);
+#23=FACE_OUTER_BOUND('',#29,.T.);
+#24=FACE_OUTER_BOUND('',#30,.T.);
+#25=FACE_OUTER_BOUND('',#31,.T.);
+#26=FACE_OUTER_BOUND('',#33,.T.);
+#27=EDGE_LOOP('',(#75,#76,#77,#78));
+#28=EDGE_LOOP('',(#79,#80,#81,#82));
+#29=EDGE_LOOP('',(#83,#84,#85,#86));
+#30=EDGE_LOOP('',(#87,#88,#89,#90));
+#31=EDGE_LOOP('',(#91,#92,#93));
+#32=EDGE_LOOP('',(#94));
+#33=EDGE_LOOP('',(#95,#96,#97));
+#34=EDGE_LOOP('',(#98));
+#35=LINE('',#166,#43);
+#36=LINE('',#171,#44);
+#37=LINE('',#173,#45);
+#38=LINE('',#175,#46);
+#39=LINE('',#176,#47);
+#40=LINE('',#179,#48);
+#41=LINE('',#181,#49);
+#42=LINE('',#182,#50);
+#43=VECTOR('',#137,1.);
+#44=VECTOR('',#142,10.);
+#45=VECTOR('',#143,10.);
+#46=VECTOR('',#144,10.);
+#47=VECTOR('',#145,10.);
+#48=VECTOR('',#148,10.);
+#49=VECTOR('',#149,10.);
+#50=VECTOR('',#150,10.);
+#51=CIRCLE('',#122,1.);
+#52=CIRCLE('',#123,0.999999999999999);
+#53=CIRCLE('',#127,9.);
+#54=CIRCLE('',#128,9.);
+#55=VERTEX_POINT('',#163);
+#56=VERTEX_POINT('',#165);
+#57=VERTEX_POINT('',#169);
+#58=VERTEX_POINT('',#170);
+#59=VERTEX_POINT('',#172);
+#60=VERTEX_POINT('',#174);
+#61=VERTEX_POINT('',#178);
+#62=VERTEX_POINT('',#180);
+#63=EDGE_CURVE('',#55,#55,#51,.T.);
+#64=EDGE_CURVE('',#55,#56,#35,.T.);
+#65=EDGE_CURVE('',#56,#56,#52,.T.);
+#66=EDGE_CURVE('',#57,#58,#36,.T.);
+#67=EDGE_CURVE('',#58,#59,#37,.T.);
+#68=EDGE_CURVE('',#60,#59,#38,.T.);
+#69=EDGE_CURVE('',#57,#60,#39,.T.);
+#70=EDGE_CURVE('',#57,#61,#40,.T.);
+#71=EDGE_CURVE('',#62,#60,#41,.T.);
+#72=EDGE_CURVE('',#61,#62,#42,.T.);
+#73=EDGE_CURVE('',#58,#61,#53,.T.);
+#74=EDGE_CURVE('',#59,#62,#54,.T.);
+#75=ORIENTED_EDGE('',*,*,#63,.F.);
+#76=ORIENTED_EDGE('',*,*,#64,.T.);
+#77=ORIENTED_EDGE('',*,*,#65,.F.);
+#78=ORIENTED_EDGE('',*,*,#64,.F.);
+#79=ORIENTED_EDGE('',*,*,#66,.T.);
+#80=ORIENTED_EDGE('',*,*,#67,.T.);
+#81=ORIENTED_EDGE('',*,*,#68,.F.);
+#82=ORIENTED_EDGE('',*,*,#69,.F.);
+#83=ORIENTED_EDGE('',*,*,#70,.F.);
+#84=ORIENTED_EDGE('',*,*,#69,.T.);
+#85=ORIENTED_EDGE('',*,*,#71,.F.);
+#86=ORIENTED_EDGE('',*,*,#72,.F.);
+#87=ORIENTED_EDGE('',*,*,#73,.T.);
+#88=ORIENTED_EDGE('',*,*,#72,.T.);
+#89=ORIENTED_EDGE('',*,*,#74,.F.);
+#90=ORIENTED_EDGE('',*,*,#67,.F.);
+#91=ORIENTED_EDGE('',*,*,#74,.T.);
+#92=ORIENTED_EDGE('',*,*,#71,.T.);
+#93=ORIENTED_EDGE('',*,*,#68,.T.);
+#94=ORIENTED_EDGE('',*,*,#63,.T.);
+#95=ORIENTED_EDGE('',*,*,#73,.F.);
+#96=ORIENTED_EDGE('',*,*,#66,.F.);
+#97=ORIENTED_EDGE('',*,*,#70,.T.);
+#98=ORIENTED_EDGE('',*,*,#65,.T.);
+#99=CYLINDRICAL_SURFACE('',#121,1.);
+#100=CYLINDRICAL_SURFACE('',#126,9.);
+#101=ADVANCED_FACE('',(#21),#99,.F.);
+#102=ADVANCED_FACE('',(#22),#17,.T.);
+#103=ADVANCED_FACE('',(#23),#18,.T.);
+#104=ADVANCED_FACE('',(#24),#100,.T.);
+#105=ADVANCED_FACE('',(#25,#15),#19,.T.);
+#106=ADVANCED_FACE('',(#26,#16),#20,.F.);
+#107=CLOSED_SHELL('',(#101,#102,#103,#104,#105,#106));
+#108=DERIVED_UNIT_ELEMENT(#110,1.);
+#109=DERIVED_UNIT_ELEMENT(#193,-3.);
+#110=(
+MASS_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.KILO.,.GRAM.)
+);
+#111=DERIVED_UNIT((#108,#109));
+#112=MEASURE_REPRESENTATION_ITEM('density measure',
+POSITIVE_RATIO_MEASURE(7850.),#111);
+#113=PROPERTY_DEFINITION_REPRESENTATION(#118,#115);
+#114=PROPERTY_DEFINITION_REPRESENTATION(#119,#116);
+#115=REPRESENTATION('material name',(#117),#190);
+#116=REPRESENTATION('density',(#112),#190);
+#117=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel');
+#118=PROPERTY_DEFINITION('material property','material name',#200);
+#119=PROPERTY_DEFINITION('material property','density of part',#200);
+#120=AXIS2_PLACEMENT_3D('',#161,#131,#132);
+#121=AXIS2_PLACEMENT_3D('',#162,#133,#134);
+#122=AXIS2_PLACEMENT_3D('',#164,#135,#136);
+#123=AXIS2_PLACEMENT_3D('',#167,#138,#139);
+#124=AXIS2_PLACEMENT_3D('',#168,#140,#141);
+#125=AXIS2_PLACEMENT_3D('',#177,#146,#147);
+#126=AXIS2_PLACEMENT_3D('',#183,#151,#152);
+#127=AXIS2_PLACEMENT_3D('',#184,#153,#154);
+#128=AXIS2_PLACEMENT_3D('',#185,#155,#156);
+#129=AXIS2_PLACEMENT_3D('',#186,#157,#158);
+#130=AXIS2_PLACEMENT_3D('',#187,#159,#160);
+#131=DIRECTION('axis',(0.,0.,1.));
+#132=DIRECTION('refdir',(1.,0.,0.));
+#133=DIRECTION('center_axis',(0.,1.,0.));
+#134=DIRECTION('ref_axis',(0.,0.,-1.));
+#135=DIRECTION('center_axis',(0.,1.,0.));
+#136=DIRECTION('ref_axis',(0.,0.,-1.));
+#137=DIRECTION('',(0.,1.,0.));
+#138=DIRECTION('center_axis',(0.,-1.,0.));
+#139=DIRECTION('ref_axis',(0.,0.,-1.));
+#140=DIRECTION('center_axis',(0.99026806874157,0.,-0.139173100960065));
+#141=DIRECTION('ref_axis',(0.139173100960065,0.,0.99026806874157));
+#142=DIRECTION('',(0.139173100960065,0.,0.99026806874157));
+#143=DIRECTION('',(0.,-1.,0.));
+#144=DIRECTION('',(0.139173100960065,0.,0.99026806874157));
+#145=DIRECTION('',(0.,-1.,0.));
+#146=DIRECTION('center_axis',(-0.99026806874157,0.,-0.139173100960065));
+#147=DIRECTION('ref_axis',(0.139173100960065,0.,-0.99026806874157));
+#148=DIRECTION('',(-0.139173100960065,0.,0.99026806874157));
+#149=DIRECTION('',(0.139173100960065,0.,-0.99026806874157));
+#150=DIRECTION('',(0.,-1.,0.));
+#151=DIRECTION('center_axis',(0.,-1.,0.));
+#152=DIRECTION('ref_axis',(6.12323399573677E-17,0.,1.));
+#153=DIRECTION('center_axis',(0.,-1.,0.));
+#154=DIRECTION('ref_axis',(1.,0.,0.));
+#155=DIRECTION('center_axis',(0.,-1.,0.));
+#156=DIRECTION('ref_axis',(1.,0.,0.));
+#157=DIRECTION('center_axis',(0.,-1.,0.));
+#158=DIRECTION('ref_axis',(1.,0.,0.));
+#159=DIRECTION('center_axis',(0.,-1.,0.));
+#160=DIRECTION('ref_axis',(1.,0.,0.));
+#161=CARTESIAN_POINT('',(0.,0.,0.));
+#162=CARTESIAN_POINT('Origin',(1.14482050558736E-16,13.5,2.38291741477447E-16));
+#163=CARTESIAN_POINT('',(2.36946730473471E-16,14.,1.));
+#164=CARTESIAN_POINT('Origin',(1.14482050558736E-16,14.,2.38291741477447E-16));
+#165=CARTESIAN_POINT('',(2.36946730473471E-16,15.,1.));
+#166=CARTESIAN_POINT('',(2.36946730473471E-16,13.5,1.));
+#167=CARTESIAN_POINT('Origin',(1.14482050558736E-16,15.,2.38291741477447E-16));
+#168=CARTESIAN_POINT('Origin',(0.,15.,-28.));
+#169=CARTESIAN_POINT('',(0.,15.,-28.));
+#170=CARTESIAN_POINT('',(2.72986465743992,15.,-8.57600367024528));
+#171=CARTESIAN_POINT('',(0.,15.,-28.));
+#172=CARTESIAN_POINT('',(2.72986465743992,14.,-8.57600367024528));
+#173=CARTESIAN_POINT('',(2.72986465743992,15.,-8.57600367024528));
+#174=CARTESIAN_POINT('',(0.,14.,-28.));
+#175=CARTESIAN_POINT('',(0.,14.,-28.));
+#176=CARTESIAN_POINT('',(0.,15.,-28.));
+#177=CARTESIAN_POINT('Origin',(-2.72986465743992,15.,-8.57600367024528));
+#178=CARTESIAN_POINT('',(-2.72986465743992,15.,-8.57600367024528));
+#179=CARTESIAN_POINT('',(0.,15.,-28.));
+#180=CARTESIAN_POINT('',(-2.72986465743992,14.,-8.57600367024528));
+#181=CARTESIAN_POINT('',(0.,14.,-28.));
+#182=CARTESIAN_POINT('',(-2.72986465743992,15.,-8.57600367024528));
+#183=CARTESIAN_POINT('Origin',(0.,15.,0.));
+#184=CARTESIAN_POINT('Origin',(0.,15.,0.));
+#185=CARTESIAN_POINT('Origin',(0.,14.,0.));
+#186=CARTESIAN_POINT('Origin',(0.,14.,-9.5));
+#187=CARTESIAN_POINT('Origin',(0.,15.,-9.5));
+#188=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#192,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#189=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#192,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#190=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#188))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#192,#194,#195))
+REPRESENTATION_CONTEXT('','3D')
+);
+#191=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#189))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#192,#194,#195))
+REPRESENTATION_CONTEXT('','3D')
+);
+#192=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.MILLI.,.METRE.)
+);
+#193=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT($,.METRE.)
+);
+#194=(
+NAMED_UNIT(*)
+PLANE_ANGLE_UNIT()
+SI_UNIT($,.RADIAN.)
+);
+#195=(
+NAMED_UNIT(*)
+SI_UNIT($,.STERADIAN.)
+SOLID_ANGLE_UNIT()
+);
+#196=SHAPE_DEFINITION_REPRESENTATION(#197,#198);
+#197=PRODUCT_DEFINITION_SHAPE('',$,#200);
+#198=SHAPE_REPRESENTATION('',(#120),#190);
+#199=PRODUCT_DEFINITION_CONTEXT('part definition',#204,'design');
+#200=PRODUCT_DEFINITION('FusionComponent','FusionComponent',#201,#199);
+#201=PRODUCT_DEFINITION_FORMATION('',$,#206);
+#202=PRODUCT_RELATED_PRODUCT_CATEGORY('FusionComponent',
+'FusionComponent',(#206));
+#203=APPLICATION_PROTOCOL_DEFINITION('international standard',
+'automotive_design',2009,#204);
+#204=APPLICATION_CONTEXT(
+'Core Data for Automotive Mechanical Design Process');
+#205=PRODUCT_CONTEXT('part definition',#204,'mechanical');
+#206=PRODUCT('FusionComponent','FusionComponent',$,(#205));
+#207=PRESENTATION_STYLE_ASSIGNMENT((#208));
+#208=SURFACE_STYLE_USAGE(.BOTH.,#209);
+#209=SURFACE_SIDE_STYLE('',(#210));
+#210=SURFACE_STYLE_FILL_AREA(#211);
+#211=FILL_AREA_STYLE('Steel - Satin',(#212));
+#212=FILL_AREA_STYLE_COLOUR('Steel - Satin',#213);
+#213=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157);
+ENDSEC;
+END-ISO-10303-21;
diff --git a/3d_model/Port test.stl b/3d_model/Port test.stl
new file mode 100755
index 0000000..a78bcee
Binary files /dev/null and b/3d_model/Port test.stl differ
diff --git a/3d_model/Quadrant.step b/3d_model/Quadrant.step
new file mode 100755
index 0000000..3b07eaf
--- /dev/null
+++ b/3d_model/Quadrant.step
@@ -0,0 +1,425 @@
+ISO-10303-21;
+HEADER;
+/* Generated by software containing ST-Developer
+ * from STEP Tools, Inc. (www.steptools.com)
+ */
+
+FILE_DESCRIPTION(
+/* description */ (''),
+/* implementation_level */ '2;1');
+
+FILE_NAME(
+/* name */ 'Quadrant.step',
+/* time_stamp */ '2026-03-11T21:10:27+01:00',
+/* author */ (''),
+/* organization */ (''),
+/* preprocessor_version */ 'ST-DEVELOPER v20.1',
+/* originating_system */ 'Autodesk Translation Framework v14.10.0.0',
+/* authorisation */ '');
+
+FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
+ENDSEC;
+
+DATA;
+#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#13),#340);
+#11=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#347,#12);
+#12=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#14),#339);
+#13=STYLED_ITEM('',(#357),#14);
+#14=MANIFOLD_SOLID_BREP('Body1',#182);
+#15=FACE_BOUND('',#35,.T.);
+#16=FACE_BOUND('',#39,.T.);
+#17=FACE_BOUND('',#40,.T.);
+#18=FACE_BOUND('',#41,.T.);
+#19=PLANE('',#203);
+#20=PLANE('',#216);
+#21=CONICAL_SURFACE('',#199,1.5,0.785398163397448);
+#22=CONICAL_SURFACE('',#212,1.5,0.785398163397448);
+#23=FACE_OUTER_BOUND('',#32,.T.);
+#24=FACE_OUTER_BOUND('',#33,.T.);
+#25=FACE_OUTER_BOUND('',#34,.T.);
+#26=FACE_OUTER_BOUND('',#36,.T.);
+#27=FACE_OUTER_BOUND('',#37,.T.);
+#28=FACE_OUTER_BOUND('',#38,.T.);
+#29=FACE_OUTER_BOUND('',#42,.T.);
+#30=FACE_OUTER_BOUND('',#43,.T.);
+#31=FACE_OUTER_BOUND('',#44,.T.);
+#32=EDGE_LOOP('',(#118,#119,#120,#121));
+#33=EDGE_LOOP('',(#122,#123,#124,#125,#126));
+#34=EDGE_LOOP('',(#127,#128,#129,#130,#131,#132,#133,#134,#135,#136));
+#35=EDGE_LOOP('',(#137));
+#36=EDGE_LOOP('',(#138,#139,#140,#141,#142));
+#37=EDGE_LOOP('',(#143,#144,#145,#146));
+#38=EDGE_LOOP('',(#147,#148,#149,#150));
+#39=EDGE_LOOP('',(#151));
+#40=EDGE_LOOP('',(#152));
+#41=EDGE_LOOP('',(#153));
+#42=EDGE_LOOP('',(#154,#155,#156,#157,#158));
+#43=EDGE_LOOP('',(#159,#160,#161,#162));
+#44=EDGE_LOOP('',(#163,#164,#165,#166,#167));
+#45=LINE('',#291,#52);
+#46=LINE('',#299,#53);
+#47=LINE('',#318,#54);
+#48=LINE('',#322,#55);
+#49=LINE('',#325,#56);
+#50=LINE('',#333,#57);
+#51=LINE('',#335,#58);
+#52=VECTOR('',#229,3.25);
+#53=VECTOR('',#238,1.5);
+#54=VECTOR('',#261,1.5);
+#55=VECTOR('',#266,10.);
+#56=VECTOR('',#269,10.);
+#57=VECTOR('',#280,10.);
+#58=VECTOR('',#283,10.);
+#59=CIRCLE('',#197,3.25);
+#60=CIRCLE('',#198,3.25);
+#61=CIRCLE('',#200,2.);
+#62=CIRCLE('',#201,2.);
+#63=CIRCLE('',#202,1.);
+#64=CIRCLE('',#204,2.5);
+#65=CIRCLE('',#205,32.4501360376889);
+#66=CIRCLE('',#206,2.);
+#67=CIRCLE('',#207,2.);
+#68=CIRCLE('',#208,32.4501360376889);
+#69=CIRCLE('',#209,2.5);
+#70=CIRCLE('',#210,32.4501360376889);
+#71=CIRCLE('',#211,32.4501360376889);
+#72=CIRCLE('',#213,1.);
+#73=CIRCLE('',#215,2.5);
+#74=CIRCLE('',#217,32.4501360376889);
+#75=CIRCLE('',#218,2.5);
+#76=CIRCLE('',#219,32.4501360376889);
+#77=VERTEX_POINT('',#288);
+#78=VERTEX_POINT('',#290);
+#79=VERTEX_POINT('',#294);
+#80=VERTEX_POINT('',#295);
+#81=VERTEX_POINT('',#298);
+#82=VERTEX_POINT('',#302);
+#83=VERTEX_POINT('',#303);
+#84=VERTEX_POINT('',#305);
+#85=VERTEX_POINT('',#307);
+#86=VERTEX_POINT('',#310);
+#87=VERTEX_POINT('',#312);
+#88=VERTEX_POINT('',#317);
+#89=VERTEX_POINT('',#321);
+#90=VERTEX_POINT('',#323);
+#91=VERTEX_POINT('',#327);
+#92=VERTEX_POINT('',#329);
+#93=EDGE_CURVE('',#77,#77,#59,.T.);
+#94=EDGE_CURVE('',#77,#78,#45,.T.);
+#95=EDGE_CURVE('',#78,#78,#60,.T.);
+#96=EDGE_CURVE('',#79,#80,#61,.T.);
+#97=EDGE_CURVE('',#80,#79,#62,.T.);
+#98=EDGE_CURVE('',#80,#81,#46,.T.);
+#99=EDGE_CURVE('',#81,#81,#63,.T.);
+#100=EDGE_CURVE('',#82,#83,#64,.T.);
+#101=EDGE_CURVE('',#83,#84,#65,.T.);
+#102=EDGE_CURVE('',#84,#85,#66,.T.);
+#103=EDGE_CURVE('',#85,#84,#67,.T.);
+#104=EDGE_CURVE('',#84,#86,#68,.T.);
+#105=EDGE_CURVE('',#86,#87,#69,.T.);
+#106=EDGE_CURVE('',#87,#79,#70,.T.);
+#107=EDGE_CURVE('',#79,#82,#71,.T.);
+#108=EDGE_CURVE('',#85,#88,#47,.T.);
+#109=EDGE_CURVE('',#88,#88,#72,.T.);
+#110=EDGE_CURVE('',#89,#82,#48,.T.);
+#111=EDGE_CURVE('',#90,#89,#73,.T.);
+#112=EDGE_CURVE('',#83,#90,#49,.T.);
+#113=EDGE_CURVE('',#91,#89,#74,.T.);
+#114=EDGE_CURVE('',#91,#92,#75,.T.);
+#115=EDGE_CURVE('',#90,#92,#76,.T.);
+#116=EDGE_CURVE('',#87,#91,#50,.T.);
+#117=EDGE_CURVE('',#92,#86,#51,.T.);
+#118=ORIENTED_EDGE('',*,*,#93,.F.);
+#119=ORIENTED_EDGE('',*,*,#94,.T.);
+#120=ORIENTED_EDGE('',*,*,#95,.F.);
+#121=ORIENTED_EDGE('',*,*,#94,.F.);
+#122=ORIENTED_EDGE('',*,*,#96,.F.);
+#123=ORIENTED_EDGE('',*,*,#97,.F.);
+#124=ORIENTED_EDGE('',*,*,#98,.T.);
+#125=ORIENTED_EDGE('',*,*,#99,.F.);
+#126=ORIENTED_EDGE('',*,*,#98,.F.);
+#127=ORIENTED_EDGE('',*,*,#100,.T.);
+#128=ORIENTED_EDGE('',*,*,#101,.T.);
+#129=ORIENTED_EDGE('',*,*,#102,.T.);
+#130=ORIENTED_EDGE('',*,*,#103,.T.);
+#131=ORIENTED_EDGE('',*,*,#104,.T.);
+#132=ORIENTED_EDGE('',*,*,#105,.T.);
+#133=ORIENTED_EDGE('',*,*,#106,.T.);
+#134=ORIENTED_EDGE('',*,*,#96,.T.);
+#135=ORIENTED_EDGE('',*,*,#97,.T.);
+#136=ORIENTED_EDGE('',*,*,#107,.T.);
+#137=ORIENTED_EDGE('',*,*,#95,.T.);
+#138=ORIENTED_EDGE('',*,*,#102,.F.);
+#139=ORIENTED_EDGE('',*,*,#103,.F.);
+#140=ORIENTED_EDGE('',*,*,#108,.T.);
+#141=ORIENTED_EDGE('',*,*,#109,.F.);
+#142=ORIENTED_EDGE('',*,*,#108,.F.);
+#143=ORIENTED_EDGE('',*,*,#100,.F.);
+#144=ORIENTED_EDGE('',*,*,#110,.F.);
+#145=ORIENTED_EDGE('',*,*,#111,.F.);
+#146=ORIENTED_EDGE('',*,*,#112,.F.);
+#147=ORIENTED_EDGE('',*,*,#111,.T.);
+#148=ORIENTED_EDGE('',*,*,#113,.F.);
+#149=ORIENTED_EDGE('',*,*,#114,.T.);
+#150=ORIENTED_EDGE('',*,*,#115,.F.);
+#151=ORIENTED_EDGE('',*,*,#93,.T.);
+#152=ORIENTED_EDGE('',*,*,#99,.T.);
+#153=ORIENTED_EDGE('',*,*,#109,.T.);
+#154=ORIENTED_EDGE('',*,*,#110,.T.);
+#155=ORIENTED_EDGE('',*,*,#107,.F.);
+#156=ORIENTED_EDGE('',*,*,#106,.F.);
+#157=ORIENTED_EDGE('',*,*,#116,.T.);
+#158=ORIENTED_EDGE('',*,*,#113,.T.);
+#159=ORIENTED_EDGE('',*,*,#116,.F.);
+#160=ORIENTED_EDGE('',*,*,#105,.F.);
+#161=ORIENTED_EDGE('',*,*,#117,.F.);
+#162=ORIENTED_EDGE('',*,*,#114,.F.);
+#163=ORIENTED_EDGE('',*,*,#112,.T.);
+#164=ORIENTED_EDGE('',*,*,#115,.T.);
+#165=ORIENTED_EDGE('',*,*,#117,.T.);
+#166=ORIENTED_EDGE('',*,*,#104,.F.);
+#167=ORIENTED_EDGE('',*,*,#101,.F.);
+#168=CYLINDRICAL_SURFACE('',#196,3.25);
+#169=CYLINDRICAL_SURFACE('',#214,2.5);
+#170=CYLINDRICAL_SURFACE('',#220,32.4501360376889);
+#171=CYLINDRICAL_SURFACE('',#221,2.5);
+#172=CYLINDRICAL_SURFACE('',#222,32.4501360376889);
+#173=ADVANCED_FACE('',(#23),#168,.F.);
+#174=ADVANCED_FACE('',(#24),#21,.F.);
+#175=ADVANCED_FACE('',(#25,#15),#19,.F.);
+#176=ADVANCED_FACE('',(#26),#22,.F.);
+#177=ADVANCED_FACE('',(#27),#169,.F.);
+#178=ADVANCED_FACE('',(#28,#16,#17,#18),#20,.T.);
+#179=ADVANCED_FACE('',(#29),#170,.T.);
+#180=ADVANCED_FACE('',(#30),#171,.F.);
+#181=ADVANCED_FACE('',(#31),#172,.T.);
+#182=CLOSED_SHELL('',(#173,#174,#175,#176,#177,#178,#179,#180,#181));
+#183=DERIVED_UNIT_ELEMENT(#185,1.);
+#184=DERIVED_UNIT_ELEMENT(#342,-3.);
+#185=(
+MASS_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.KILO.,.GRAM.)
+);
+#186=DERIVED_UNIT((#183,#184));
+#187=MEASURE_REPRESENTATION_ITEM('density measure',
+POSITIVE_RATIO_MEASURE(7850.),#186);
+#188=PROPERTY_DEFINITION_REPRESENTATION(#193,#190);
+#189=PROPERTY_DEFINITION_REPRESENTATION(#194,#191);
+#190=REPRESENTATION('material name',(#192),#339);
+#191=REPRESENTATION('density',(#187),#339);
+#192=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel');
+#193=PROPERTY_DEFINITION('material property','material name',#349);
+#194=PROPERTY_DEFINITION('material property','density of part',#349);
+#195=AXIS2_PLACEMENT_3D('',#286,#223,#224);
+#196=AXIS2_PLACEMENT_3D('',#287,#225,#226);
+#197=AXIS2_PLACEMENT_3D('',#289,#227,#228);
+#198=AXIS2_PLACEMENT_3D('',#292,#230,#231);
+#199=AXIS2_PLACEMENT_3D('',#293,#232,#233);
+#200=AXIS2_PLACEMENT_3D('',#296,#234,#235);
+#201=AXIS2_PLACEMENT_3D('',#297,#236,#237);
+#202=AXIS2_PLACEMENT_3D('',#300,#239,#240);
+#203=AXIS2_PLACEMENT_3D('',#301,#241,#242);
+#204=AXIS2_PLACEMENT_3D('',#304,#243,#244);
+#205=AXIS2_PLACEMENT_3D('',#306,#245,#246);
+#206=AXIS2_PLACEMENT_3D('',#308,#247,#248);
+#207=AXIS2_PLACEMENT_3D('',#309,#249,#250);
+#208=AXIS2_PLACEMENT_3D('',#311,#251,#252);
+#209=AXIS2_PLACEMENT_3D('',#313,#253,#254);
+#210=AXIS2_PLACEMENT_3D('',#314,#255,#256);
+#211=AXIS2_PLACEMENT_3D('',#315,#257,#258);
+#212=AXIS2_PLACEMENT_3D('',#316,#259,#260);
+#213=AXIS2_PLACEMENT_3D('',#319,#262,#263);
+#214=AXIS2_PLACEMENT_3D('',#320,#264,#265);
+#215=AXIS2_PLACEMENT_3D('',#324,#267,#268);
+#216=AXIS2_PLACEMENT_3D('',#326,#270,#271);
+#217=AXIS2_PLACEMENT_3D('',#328,#272,#273);
+#218=AXIS2_PLACEMENT_3D('',#330,#274,#275);
+#219=AXIS2_PLACEMENT_3D('',#331,#276,#277);
+#220=AXIS2_PLACEMENT_3D('',#332,#278,#279);
+#221=AXIS2_PLACEMENT_3D('',#334,#281,#282);
+#222=AXIS2_PLACEMENT_3D('',#336,#284,#285);
+#223=DIRECTION('axis',(0.,0.,1.));
+#224=DIRECTION('refdir',(1.,0.,0.));
+#225=DIRECTION('center_axis',(0.,-1.,0.));
+#226=DIRECTION('ref_axis',(0.,0.,1.));
+#227=DIRECTION('center_axis',(0.,-1.,0.));
+#228=DIRECTION('ref_axis',(0.,0.,1.));
+#229=DIRECTION('',(0.,-1.,0.));
+#230=DIRECTION('center_axis',(0.,1.,0.));
+#231=DIRECTION('ref_axis',(0.,0.,1.));
+#232=DIRECTION('center_axis',(0.,-1.,0.));
+#233=DIRECTION('ref_axis',(-1.22464679914735E-16,0.,1.));
+#234=DIRECTION('center_axis',(0.,1.,0.));
+#235=DIRECTION('ref_axis',(-1.22464679914735E-16,0.,1.));
+#236=DIRECTION('center_axis',(0.,1.,0.));
+#237=DIRECTION('ref_axis',(-1.22464679914735E-16,0.,1.));
+#238=DIRECTION('',(0.,0.707106781186548,0.707106781186547));
+#239=DIRECTION('center_axis',(0.,-1.,0.));
+#240=DIRECTION('ref_axis',(-1.22464679914735E-16,0.,1.));
+#241=DIRECTION('center_axis',(0.,1.,0.));
+#242=DIRECTION('ref_axis',(1.,0.,0.));
+#243=DIRECTION('center_axis',(0.,1.,0.));
+#244=DIRECTION('ref_axis',(0.,0.,-1.));
+#245=DIRECTION('center_axis',(0.,-1.,0.));
+#246=DIRECTION('ref_axis',(-1.,0.,0.));
+#247=DIRECTION('center_axis',(0.,1.,0.));
+#248=DIRECTION('ref_axis',(0.,0.,-1.));
+#249=DIRECTION('center_axis',(0.,1.,0.));
+#250=DIRECTION('ref_axis',(0.,0.,-1.));
+#251=DIRECTION('center_axis',(0.,-1.,0.));
+#252=DIRECTION('ref_axis',(-1.,0.,0.));
+#253=DIRECTION('center_axis',(0.,1.,0.));
+#254=DIRECTION('ref_axis',(0.,0.,-1.));
+#255=DIRECTION('center_axis',(0.,-1.,0.));
+#256=DIRECTION('ref_axis',(-1.,0.,0.));
+#257=DIRECTION('center_axis',(0.,-1.,0.));
+#258=DIRECTION('ref_axis',(-1.,0.,0.));
+#259=DIRECTION('center_axis',(0.,-1.,0.));
+#260=DIRECTION('ref_axis',(0.,0.,-1.));
+#261=DIRECTION('',(-8.65956056235493E-17,0.707106781186548,-0.707106781186547));
+#262=DIRECTION('center_axis',(0.,-1.,0.));
+#263=DIRECTION('ref_axis',(0.,0.,-1.));
+#264=DIRECTION('center_axis',(0.,1.,0.));
+#265=DIRECTION('ref_axis',(0.,0.,-1.));
+#266=DIRECTION('',(0.,-1.,0.));
+#267=DIRECTION('center_axis',(0.,-1.,0.));
+#268=DIRECTION('ref_axis',(0.,0.,-1.));
+#269=DIRECTION('',(0.,1.,0.));
+#270=DIRECTION('center_axis',(0.,1.,0.));
+#271=DIRECTION('ref_axis',(1.,0.,0.));
+#272=DIRECTION('center_axis',(0.,-1.,0.));
+#273=DIRECTION('ref_axis',(-1.,0.,0.));
+#274=DIRECTION('center_axis',(0.,-1.,0.));
+#275=DIRECTION('ref_axis',(0.,0.,-1.));
+#276=DIRECTION('center_axis',(0.,-1.,0.));
+#277=DIRECTION('ref_axis',(-1.,0.,0.));
+#278=DIRECTION('center_axis',(0.,-1.,0.));
+#279=DIRECTION('ref_axis',(1.,0.,1.22464679914735E-16));
+#280=DIRECTION('',(0.,1.,0.));
+#281=DIRECTION('center_axis',(0.,1.,0.));
+#282=DIRECTION('ref_axis',(1.22464679914735E-16,0.,1.));
+#283=DIRECTION('',(0.,-1.,0.));
+#284=DIRECTION('center_axis',(0.,-1.,0.));
+#285=DIRECTION('ref_axis',(-1.,0.,0.));
+#286=CARTESIAN_POINT('',(0.,0.,0.));
+#287=CARTESIAN_POINT('Origin',(0.,15.45,0.));
+#288=CARTESIAN_POINT('',(3.9801020972289E-16,16.,-3.25));
+#289=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#290=CARTESIAN_POINT('',(-3.9801020972289E-16,15.,-3.25));
+#291=CARTESIAN_POINT('',(3.9801020972289E-16,15.45,-3.25));
+#292=CARTESIAN_POINT('Origin',(0.,15.,0.));
+#293=CARTESIAN_POINT('Origin',(30.4501360376889,15.5,3.72906616321572E-15));
+#294=CARTESIAN_POINT('',(32.4501360376889,15.,3.97399552304519E-15));
+#295=CARTESIAN_POINT('',(30.4501360376889,15.,-2.));
+#296=CARTESIAN_POINT('Origin',(30.4501360376889,15.,3.72906616321572E-15));
+#297=CARTESIAN_POINT('Origin',(30.4501360376889,15.,3.72906616321572E-15));
+#298=CARTESIAN_POINT('',(30.4501360376889,16.,-0.999999999999996));
+#299=CARTESIAN_POINT('',(30.4501360376889,15.5,-1.5));
+#300=CARTESIAN_POINT('Origin',(30.4501360376889,16.,3.72906616321572E-15));
+#301=CARTESIAN_POINT('Origin',(0.,15.,0.));
+#302=CARTESIAN_POINT('',(2.47457392108191,15.,32.3556457635081));
+#303=CARTESIAN_POINT('',(-2.47457392108192,15.,32.3556457635081));
+#304=CARTESIAN_POINT('Origin',(-3.91886975727153E-15,15.,32.));
+#305=CARTESIAN_POINT('',(-32.4501360376889,15.,0.));
+#306=CARTESIAN_POINT('Origin',(0.,15.,0.));
+#307=CARTESIAN_POINT('',(-30.4501360376889,15.,2.));
+#308=CARTESIAN_POINT('Origin',(-30.4501360376889,15.,0.));
+#309=CARTESIAN_POINT('Origin',(-30.4501360376889,15.,0.));
+#310=CARTESIAN_POINT('',(-2.47457392108192,15.,-32.3556457635081));
+#311=CARTESIAN_POINT('Origin',(0.,15.,0.));
+#312=CARTESIAN_POINT('',(2.47457392108192,15.,-32.3556457635081));
+#313=CARTESIAN_POINT('Origin',(0.,15.,-32.));
+#314=CARTESIAN_POINT('Origin',(0.,15.,0.));
+#315=CARTESIAN_POINT('Origin',(0.,15.,0.));
+#316=CARTESIAN_POINT('Origin',(-30.4501360376889,15.5,0.));
+#317=CARTESIAN_POINT('',(-30.4501360376889,16.,1.));
+#318=CARTESIAN_POINT('',(-30.4501360376889,15.5,1.5));
+#319=CARTESIAN_POINT('Origin',(-30.4501360376889,16.,0.));
+#320=CARTESIAN_POINT('Origin',(-3.91886975727153E-15,19.4,32.));
+#321=CARTESIAN_POINT('',(2.47457392108191,16.,32.3556457635081));
+#322=CARTESIAN_POINT('',(2.47457392108192,19.4,32.3556457635081));
+#323=CARTESIAN_POINT('',(-2.47457392108192,16.,32.3556457635081));
+#324=CARTESIAN_POINT('Origin',(-3.91886975727153E-15,16.,32.));
+#325=CARTESIAN_POINT('',(-2.47457392108193,19.4,32.3556457635081));
+#326=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#327=CARTESIAN_POINT('',(2.47457392108192,16.,-32.3556457635081));
+#328=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#329=CARTESIAN_POINT('',(-2.47457392108192,16.,-32.3556457635081));
+#330=CARTESIAN_POINT('Origin',(0.,16.,-32.));
+#331=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#332=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#333=CARTESIAN_POINT('',(2.47457392108192,19.4,-32.3556457635081));
+#334=CARTESIAN_POINT('Origin',(0.,19.4,-32.));
+#335=CARTESIAN_POINT('',(-2.47457392108192,19.4,-32.3556457635081));
+#336=CARTESIAN_POINT('Origin',(0.,16.,0.));
+#337=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#341,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#338=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#341,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#339=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#337))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#341,#343,#344))
+REPRESENTATION_CONTEXT('','3D')
+);
+#340=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#338))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#341,#343,#344))
+REPRESENTATION_CONTEXT('','3D')
+);
+#341=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.MILLI.,.METRE.)
+);
+#342=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT($,.METRE.)
+);
+#343=(
+NAMED_UNIT(*)
+PLANE_ANGLE_UNIT()
+SI_UNIT($,.RADIAN.)
+);
+#344=(
+NAMED_UNIT(*)
+SI_UNIT($,.STERADIAN.)
+SOLID_ANGLE_UNIT()
+);
+#345=SHAPE_DEFINITION_REPRESENTATION(#346,#347);
+#346=PRODUCT_DEFINITION_SHAPE('',$,#349);
+#347=SHAPE_REPRESENTATION('',(#195),#339);
+#348=PRODUCT_DEFINITION_CONTEXT('part definition',#353,'design');
+#349=PRODUCT_DEFINITION('FusionComponent','FusionComponent',#350,#348);
+#350=PRODUCT_DEFINITION_FORMATION('',$,#355);
+#351=PRODUCT_RELATED_PRODUCT_CATEGORY('FusionComponent',
+'FusionComponent',(#355));
+#352=APPLICATION_PROTOCOL_DEFINITION('international standard',
+'automotive_design',2009,#353);
+#353=APPLICATION_CONTEXT(
+'Core Data for Automotive Mechanical Design Process');
+#354=PRODUCT_CONTEXT('part definition',#353,'mechanical');
+#355=PRODUCT('FusionComponent','FusionComponent',$,(#354));
+#356=PRESENTATION_STYLE_ASSIGNMENT((#358));
+#357=PRESENTATION_STYLE_ASSIGNMENT((#359));
+#358=SURFACE_STYLE_USAGE(.BOTH.,#360);
+#359=SURFACE_STYLE_USAGE(.BOTH.,#361);
+#360=SURFACE_SIDE_STYLE('',(#362));
+#361=SURFACE_SIDE_STYLE('',(#363));
+#362=SURFACE_STYLE_FILL_AREA(#364);
+#363=SURFACE_STYLE_FILL_AREA(#365);
+#364=FILL_AREA_STYLE('Steel - Satin',(#366));
+#365=FILL_AREA_STYLE('ABS (White)',(#367));
+#366=FILL_AREA_STYLE_COLOUR('Steel - Satin',#368);
+#367=FILL_AREA_STYLE_COLOUR('ABS (White)',#369);
+#368=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157);
+#369=COLOUR_RGB('ABS (White)',0.964705882352941,0.964705882352941,0.952941176470588);
+ENDSEC;
+END-ISO-10303-21;
diff --git a/3d_model/Screw.step b/3d_model/Screw.step
new file mode 100755
index 0000000..07a893c
--- /dev/null
+++ b/3d_model/Screw.step
@@ -0,0 +1,576 @@
+ISO-10303-21;
+HEADER;
+/* Generated by software containing ST-Developer
+ * from STEP Tools, Inc. (www.steptools.com)
+ */
+
+FILE_DESCRIPTION(
+/* description */ (''),
+/* implementation_level */ '2;1');
+
+FILE_NAME(
+/* name */ 'Screw.step',
+/* time_stamp */ '2026-03-10T23:07:32+01:00',
+/* author */ (''),
+/* organization */ (''),
+/* preprocessor_version */ 'ST-DEVELOPER v20.1',
+/* originating_system */ 'Autodesk Translation Framework v14.10.0.0',
+/* authorisation */ '');
+
+FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
+ENDSEC;
+
+DATA;
+#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#13),#489);
+#11=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#496,#12);
+#12=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#14),#488);
+#13=STYLED_ITEM('',(#505),#14);
+#14=MANIFOLD_SOLID_BREP('Body1',#265);
+#15=CYLINDRICAL_SURFACE('',#292,1.);
+#16=CYLINDRICAL_SURFACE('',#295,7.);
+#17=CYLINDRICAL_SURFACE('',#300,7.);
+#18=CONICAL_SURFACE('',#289,1.575,0.785398163397448);
+#19=FACE_BOUND('',#90,.T.);
+#20=FACE_BOUND('',#102,.T.);
+#21=LINE('',#405,#43);
+#22=LINE('',#407,#44);
+#23=LINE('',#409,#45);
+#24=LINE('',#410,#46);
+#25=LINE('',#413,#47);
+#26=LINE('',#415,#48);
+#27=LINE('',#417,#49);
+#28=LINE('',#421,#50);
+#29=LINE('',#422,#51);
+#30=LINE('',#451,#52);
+#31=LINE('',#453,#53);
+#32=LINE('',#454,#54);
+#33=LINE('',#457,#55);
+#34=LINE('',#463,#56);
+#35=LINE('',#466,#57);
+#36=LINE('',#469,#58);
+#37=LINE('',#473,#59);
+#38=LINE('',#474,#60);
+#39=LINE('',#477,#61);
+#40=LINE('',#478,#62);
+#41=LINE('',#481,#63);
+#42=LINE('',#482,#64);
+#43=VECTOR('',#313,10.);
+#44=VECTOR('',#314,10.);
+#45=VECTOR('',#315,10.);
+#46=VECTOR('',#316,10.);
+#47=VECTOR('',#319,10.);
+#48=VECTOR('',#320,10.);
+#49=VECTOR('',#321,10.);
+#50=VECTOR('',#324,10.);
+#51=VECTOR('',#325,10.);
+#52=VECTOR('',#334,10.);
+#53=VECTOR('',#335,10.);
+#54=VECTOR('',#336,10.);
+#55=VECTOR('',#339,1.575);
+#56=VECTOR('',#346,1.);
+#57=VECTOR('',#351,10.);
+#58=VECTOR('',#354,10.);
+#59=VECTOR('',#359,10.);
+#60=VECTOR('',#360,10.);
+#61=VECTOR('',#363,10.);
+#62=VECTOR('',#364,10.);
+#63=VECTOR('',#367,10.);
+#64=VECTOR('',#368,10.);
+#65=PLANE('',#282);
+#66=PLANE('',#283);
+#67=PLANE('',#288);
+#68=PLANE('',#294);
+#69=PLANE('',#297);
+#70=PLANE('',#298);
+#71=PLANE('',#299);
+#72=PLANE('',#302);
+#73=FACE_OUTER_BOUND('',#87,.T.);
+#74=FACE_OUTER_BOUND('',#88,.T.);
+#75=FACE_OUTER_BOUND('',#89,.T.);
+#76=FACE_OUTER_BOUND('',#91,.T.);
+#77=FACE_OUTER_BOUND('',#92,.T.);
+#78=FACE_OUTER_BOUND('',#93,.T.);
+#79=FACE_OUTER_BOUND('',#94,.T.);
+#80=FACE_OUTER_BOUND('',#95,.T.);
+#81=FACE_OUTER_BOUND('',#96,.T.);
+#82=FACE_OUTER_BOUND('',#97,.T.);
+#83=FACE_OUTER_BOUND('',#98,.T.);
+#84=FACE_OUTER_BOUND('',#99,.T.);
+#85=FACE_OUTER_BOUND('',#100,.T.);
+#86=FACE_OUTER_BOUND('',#101,.T.);
+#87=EDGE_LOOP('',(#177,#178,#179,#180));
+#88=EDGE_LOOP('',(#181,#182,#183,#184,#185));
+#89=EDGE_LOOP('',(#186,#187,#188,#189,#190,#191,#192,#193));
+#90=EDGE_LOOP('',(#194));
+#91=EDGE_LOOP('',(#195,#196,#197,#198));
+#92=EDGE_LOOP('',(#199,#200,#201,#202,#203));
+#93=EDGE_LOOP('',(#204,#205,#206,#207,#208));
+#94=EDGE_LOOP('',(#209,#210,#211,#212,#213));
+#95=EDGE_LOOP('',(#214,#215,#216,#217));
+#96=EDGE_LOOP('',(#218,#219,#220,#221));
+#97=EDGE_LOOP('',(#222,#223,#224,#225,#226));
+#98=EDGE_LOOP('',(#227,#228,#229,#230));
+#99=EDGE_LOOP('',(#231,#232,#233,#234,#235));
+#100=EDGE_LOOP('',(#236,#237,#238,#239));
+#101=EDGE_LOOP('',(#240,#241,#242,#243,#244,#245,#246,#247));
+#102=EDGE_LOOP('',(#248));
+#103=CIRCLE('',#280,6.);
+#104=CIRCLE('',#281,7.);
+#105=CIRCLE('',#284,6.);
+#106=CIRCLE('',#285,2.15);
+#107=CIRCLE('',#287,7.);
+#108=CIRCLE('',#290,1.);
+#109=CIRCLE('',#291,1.);
+#110=CIRCLE('',#293,1.);
+#111=CIRCLE('',#296,7.);
+#112=CIRCLE('',#301,7.);
+#113=B_SPLINE_CURVE_WITH_KNOTS('',3,(#379,#380,#381,#382,#383,#384,#385,
+#386,#387,#388),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,4),(0.,0.0364663225746359,
+0.0737406434023288,0.112191492628996,0.152012057604797),.UNSPECIFIED.);
+#114=B_SPLINE_CURVE_WITH_KNOTS('',3,(#392,#393,#394,#395,#396,#397,#398,
+#399,#400,#401),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,4),(-0.152012057604797,-0.112191492628996,
+-0.0737406434023288,-0.036466322574636,0.),.UNSPECIFIED.);
+#115=B_SPLINE_CURVE_WITH_KNOTS('',3,(#427,#428,#429,#430,#431,#432,#433,
+#434,#435,#436),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,4),(0.,0.0364663225746359,
+0.0737406434023288,0.112191492628996,0.152012057604797),.UNSPECIFIED.);
+#116=B_SPLINE_CURVE_WITH_KNOTS('',3,(#438,#439,#440,#441,#442,#443,#444,
+#445,#446,#447),.UNSPECIFIED.,.F.,.F.,(4,2,2,2,4),(-0.152012057604797,-0.112191492628996,
+-0.0737406434023288,-0.036466322574636,0.),.UNSPECIFIED.);
+#117=VERTEX_POINT('',#377);
+#118=VERTEX_POINT('',#378);
+#119=VERTEX_POINT('',#389);
+#120=VERTEX_POINT('',#391);
+#121=VERTEX_POINT('',#404);
+#122=VERTEX_POINT('',#406);
+#123=VERTEX_POINT('',#408);
+#124=VERTEX_POINT('',#412);
+#125=VERTEX_POINT('',#414);
+#126=VERTEX_POINT('',#416);
+#127=VERTEX_POINT('',#418);
+#128=VERTEX_POINT('',#420);
+#129=VERTEX_POINT('',#423);
+#130=VERTEX_POINT('',#426);
+#131=VERTEX_POINT('',#437);
+#132=VERTEX_POINT('',#450);
+#133=VERTEX_POINT('',#452);
+#134=VERTEX_POINT('',#456);
+#135=VERTEX_POINT('',#458);
+#136=VERTEX_POINT('',#462);
+#137=VERTEX_POINT('',#468);
+#138=VERTEX_POINT('',#472);
+#139=VERTEX_POINT('',#476);
+#140=VERTEX_POINT('',#480);
+#141=EDGE_CURVE('',#117,#118,#113,.T.);
+#142=EDGE_CURVE('',#118,#119,#103,.T.);
+#143=EDGE_CURVE('',#119,#120,#114,.T.);
+#144=EDGE_CURVE('',#120,#117,#104,.T.);
+#145=EDGE_CURVE('',#121,#119,#21,.T.);
+#146=EDGE_CURVE('',#122,#121,#22,.T.);
+#147=EDGE_CURVE('',#123,#122,#23,.T.);
+#148=EDGE_CURVE('',#123,#120,#24,.T.);
+#149=EDGE_CURVE('',#118,#124,#25,.T.);
+#150=EDGE_CURVE('',#124,#125,#26,.T.);
+#151=EDGE_CURVE('',#125,#126,#27,.T.);
+#152=EDGE_CURVE('',#127,#126,#105,.T.);
+#153=EDGE_CURVE('',#127,#128,#28,.T.);
+#154=EDGE_CURVE('',#128,#121,#29,.T.);
+#155=EDGE_CURVE('',#129,#129,#106,.T.);
+#156=EDGE_CURVE('',#130,#127,#115,.T.);
+#157=EDGE_CURVE('',#126,#131,#116,.T.);
+#158=EDGE_CURVE('',#131,#130,#107,.T.);
+#159=EDGE_CURVE('',#132,#130,#30,.T.);
+#160=EDGE_CURVE('',#133,#132,#31,.T.);
+#161=EDGE_CURVE('',#133,#128,#32,.T.);
+#162=EDGE_CURVE('',#129,#134,#33,.T.);
+#163=EDGE_CURVE('',#135,#134,#108,.T.);
+#164=EDGE_CURVE('',#134,#135,#109,.T.);
+#165=EDGE_CURVE('',#135,#136,#34,.T.);
+#166=EDGE_CURVE('',#136,#136,#110,.T.);
+#167=EDGE_CURVE('',#122,#133,#35,.T.);
+#168=EDGE_CURVE('',#137,#131,#36,.T.);
+#169=EDGE_CURVE('',#137,#132,#111,.T.);
+#170=EDGE_CURVE('',#138,#125,#37,.T.);
+#171=EDGE_CURVE('',#137,#138,#38,.T.);
+#172=EDGE_CURVE('',#138,#139,#39,.T.);
+#173=EDGE_CURVE('',#139,#124,#40,.T.);
+#174=EDGE_CURVE('',#140,#117,#41,.T.);
+#175=EDGE_CURVE('',#139,#140,#42,.T.);
+#176=EDGE_CURVE('',#123,#140,#112,.T.);
+#177=ORIENTED_EDGE('',*,*,#141,.T.);
+#178=ORIENTED_EDGE('',*,*,#142,.T.);
+#179=ORIENTED_EDGE('',*,*,#143,.T.);
+#180=ORIENTED_EDGE('',*,*,#144,.T.);
+#181=ORIENTED_EDGE('',*,*,#143,.F.);
+#182=ORIENTED_EDGE('',*,*,#145,.F.);
+#183=ORIENTED_EDGE('',*,*,#146,.F.);
+#184=ORIENTED_EDGE('',*,*,#147,.F.);
+#185=ORIENTED_EDGE('',*,*,#148,.T.);
+#186=ORIENTED_EDGE('',*,*,#142,.F.);
+#187=ORIENTED_EDGE('',*,*,#149,.T.);
+#188=ORIENTED_EDGE('',*,*,#150,.T.);
+#189=ORIENTED_EDGE('',*,*,#151,.T.);
+#190=ORIENTED_EDGE('',*,*,#152,.F.);
+#191=ORIENTED_EDGE('',*,*,#153,.T.);
+#192=ORIENTED_EDGE('',*,*,#154,.T.);
+#193=ORIENTED_EDGE('',*,*,#145,.T.);
+#194=ORIENTED_EDGE('',*,*,#155,.T.);
+#195=ORIENTED_EDGE('',*,*,#156,.T.);
+#196=ORIENTED_EDGE('',*,*,#152,.T.);
+#197=ORIENTED_EDGE('',*,*,#157,.T.);
+#198=ORIENTED_EDGE('',*,*,#158,.T.);
+#199=ORIENTED_EDGE('',*,*,#156,.F.);
+#200=ORIENTED_EDGE('',*,*,#159,.F.);
+#201=ORIENTED_EDGE('',*,*,#160,.F.);
+#202=ORIENTED_EDGE('',*,*,#161,.T.);
+#203=ORIENTED_EDGE('',*,*,#153,.F.);
+#204=ORIENTED_EDGE('',*,*,#155,.F.);
+#205=ORIENTED_EDGE('',*,*,#162,.T.);
+#206=ORIENTED_EDGE('',*,*,#163,.F.);
+#207=ORIENTED_EDGE('',*,*,#164,.F.);
+#208=ORIENTED_EDGE('',*,*,#162,.F.);
+#209=ORIENTED_EDGE('',*,*,#163,.T.);
+#210=ORIENTED_EDGE('',*,*,#164,.T.);
+#211=ORIENTED_EDGE('',*,*,#165,.T.);
+#212=ORIENTED_EDGE('',*,*,#166,.T.);
+#213=ORIENTED_EDGE('',*,*,#165,.F.);
+#214=ORIENTED_EDGE('',*,*,#167,.F.);
+#215=ORIENTED_EDGE('',*,*,#146,.T.);
+#216=ORIENTED_EDGE('',*,*,#154,.F.);
+#217=ORIENTED_EDGE('',*,*,#161,.F.);
+#218=ORIENTED_EDGE('',*,*,#158,.F.);
+#219=ORIENTED_EDGE('',*,*,#168,.F.);
+#220=ORIENTED_EDGE('',*,*,#169,.T.);
+#221=ORIENTED_EDGE('',*,*,#159,.T.);
+#222=ORIENTED_EDGE('',*,*,#157,.F.);
+#223=ORIENTED_EDGE('',*,*,#151,.F.);
+#224=ORIENTED_EDGE('',*,*,#170,.F.);
+#225=ORIENTED_EDGE('',*,*,#171,.F.);
+#226=ORIENTED_EDGE('',*,*,#168,.T.);
+#227=ORIENTED_EDGE('',*,*,#172,.F.);
+#228=ORIENTED_EDGE('',*,*,#170,.T.);
+#229=ORIENTED_EDGE('',*,*,#150,.F.);
+#230=ORIENTED_EDGE('',*,*,#173,.F.);
+#231=ORIENTED_EDGE('',*,*,#141,.F.);
+#232=ORIENTED_EDGE('',*,*,#174,.F.);
+#233=ORIENTED_EDGE('',*,*,#175,.F.);
+#234=ORIENTED_EDGE('',*,*,#173,.T.);
+#235=ORIENTED_EDGE('',*,*,#149,.F.);
+#236=ORIENTED_EDGE('',*,*,#144,.F.);
+#237=ORIENTED_EDGE('',*,*,#148,.F.);
+#238=ORIENTED_EDGE('',*,*,#176,.T.);
+#239=ORIENTED_EDGE('',*,*,#174,.T.);
+#240=ORIENTED_EDGE('',*,*,#176,.F.);
+#241=ORIENTED_EDGE('',*,*,#147,.T.);
+#242=ORIENTED_EDGE('',*,*,#167,.T.);
+#243=ORIENTED_EDGE('',*,*,#160,.T.);
+#244=ORIENTED_EDGE('',*,*,#169,.F.);
+#245=ORIENTED_EDGE('',*,*,#171,.T.);
+#246=ORIENTED_EDGE('',*,*,#172,.T.);
+#247=ORIENTED_EDGE('',*,*,#175,.T.);
+#248=ORIENTED_EDGE('',*,*,#166,.F.);
+#249=TOROIDAL_SURFACE('',#279,6.,1.);
+#250=TOROIDAL_SURFACE('',#286,6.,1.);
+#251=ADVANCED_FACE('',(#73),#249,.T.);
+#252=ADVANCED_FACE('',(#74),#65,.T.);
+#253=ADVANCED_FACE('',(#75,#19),#66,.T.);
+#254=ADVANCED_FACE('',(#76),#250,.T.);
+#255=ADVANCED_FACE('',(#77),#67,.T.);
+#256=ADVANCED_FACE('',(#78),#18,.F.);
+#257=ADVANCED_FACE('',(#79),#15,.F.);
+#258=ADVANCED_FACE('',(#80),#68,.T.);
+#259=ADVANCED_FACE('',(#81),#16,.T.);
+#260=ADVANCED_FACE('',(#82),#69,.T.);
+#261=ADVANCED_FACE('',(#83),#70,.T.);
+#262=ADVANCED_FACE('',(#84),#71,.T.);
+#263=ADVANCED_FACE('',(#85),#17,.T.);
+#264=ADVANCED_FACE('',(#86,#20),#72,.F.);
+#265=CLOSED_SHELL('',(#251,#252,#253,#254,#255,#256,#257,#258,#259,#260,
+#261,#262,#263,#264));
+#266=DERIVED_UNIT_ELEMENT(#268,1.);
+#267=DERIVED_UNIT_ELEMENT(#491,-3.);
+#268=(
+MASS_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.KILO.,.GRAM.)
+);
+#269=DERIVED_UNIT((#266,#267));
+#270=MEASURE_REPRESENTATION_ITEM('density measure',
+POSITIVE_RATIO_MEASURE(7850.),#269);
+#271=PROPERTY_DEFINITION_REPRESENTATION(#276,#273);
+#272=PROPERTY_DEFINITION_REPRESENTATION(#277,#274);
+#273=REPRESENTATION('material name',(#275),#488);
+#274=REPRESENTATION('density',(#270),#488);
+#275=DESCRIPTIVE_REPRESENTATION_ITEM('Steel','Steel');
+#276=PROPERTY_DEFINITION('material property','material name',#498);
+#277=PROPERTY_DEFINITION('material property','density of part',#498);
+#278=AXIS2_PLACEMENT_3D('',#375,#303,#304);
+#279=AXIS2_PLACEMENT_3D('',#376,#305,#306);
+#280=AXIS2_PLACEMENT_3D('',#390,#307,#308);
+#281=AXIS2_PLACEMENT_3D('',#402,#309,#310);
+#282=AXIS2_PLACEMENT_3D('',#403,#311,#312);
+#283=AXIS2_PLACEMENT_3D('',#411,#317,#318);
+#284=AXIS2_PLACEMENT_3D('',#419,#322,#323);
+#285=AXIS2_PLACEMENT_3D('',#424,#326,#327);
+#286=AXIS2_PLACEMENT_3D('',#425,#328,#329);
+#287=AXIS2_PLACEMENT_3D('',#448,#330,#331);
+#288=AXIS2_PLACEMENT_3D('',#449,#332,#333);
+#289=AXIS2_PLACEMENT_3D('',#455,#337,#338);
+#290=AXIS2_PLACEMENT_3D('',#459,#340,#341);
+#291=AXIS2_PLACEMENT_3D('',#460,#342,#343);
+#292=AXIS2_PLACEMENT_3D('',#461,#344,#345);
+#293=AXIS2_PLACEMENT_3D('',#464,#347,#348);
+#294=AXIS2_PLACEMENT_3D('',#465,#349,#350);
+#295=AXIS2_PLACEMENT_3D('',#467,#352,#353);
+#296=AXIS2_PLACEMENT_3D('',#470,#355,#356);
+#297=AXIS2_PLACEMENT_3D('',#471,#357,#358);
+#298=AXIS2_PLACEMENT_3D('',#475,#361,#362);
+#299=AXIS2_PLACEMENT_3D('',#479,#365,#366);
+#300=AXIS2_PLACEMENT_3D('',#483,#369,#370);
+#301=AXIS2_PLACEMENT_3D('',#484,#371,#372);
+#302=AXIS2_PLACEMENT_3D('',#485,#373,#374);
+#303=DIRECTION('axis',(0.,0.,1.));
+#304=DIRECTION('refdir',(1.,0.,0.));
+#305=DIRECTION('center_axis',(0.,-1.,0.));
+#306=DIRECTION('ref_axis',(0.,0.,-1.));
+#307=DIRECTION('center_axis',(0.,1.,0.));
+#308=DIRECTION('ref_axis',(-1.,0.,1.22464679914735E-16));
+#309=DIRECTION('center_axis',(0.,-1.,0.));
+#310=DIRECTION('ref_axis',(-1.,0.,1.22464679914735E-16));
+#311=DIRECTION('center_axis',(1.,0.,-2.77555756156289E-16));
+#312=DIRECTION('ref_axis',(2.77555756156289E-16,0.,1.));
+#313=DIRECTION('',(2.77555756156289E-16,0.,1.));
+#314=DIRECTION('',(0.,-1.,0.));
+#315=DIRECTION('',(-2.77555756156289E-16,0.,-1.));
+#316=DIRECTION('',(0.,-1.,0.));
+#317=DIRECTION('center_axis',(0.,-1.,0.));
+#318=DIRECTION('ref_axis',(1.,0.,0.));
+#319=DIRECTION('',(1.38777878078145E-16,0.,1.));
+#320=DIRECTION('',(1.,0.,-1.38777878078145E-16));
+#321=DIRECTION('',(-1.38777878078145E-16,0.,-1.));
+#322=DIRECTION('center_axis',(0.,1.,0.));
+#323=DIRECTION('ref_axis',(1.,0.,-2.22044604925031E-16));
+#324=DIRECTION('',(-2.77555756156289E-16,0.,-1.));
+#325=DIRECTION('',(-1.,0.,1.38777878078145E-16));
+#326=DIRECTION('center_axis',(0.,1.,0.));
+#327=DIRECTION('ref_axis',(0.,0.,-1.));
+#328=DIRECTION('center_axis',(0.,-1.,0.));
+#329=DIRECTION('ref_axis',(0.,0.,-1.));
+#330=DIRECTION('center_axis',(0.,-1.,0.));
+#331=DIRECTION('ref_axis',(1.,0.,-2.22044604925031E-16));
+#332=DIRECTION('center_axis',(-1.,0.,2.77555756156289E-16));
+#333=DIRECTION('ref_axis',(-2.77555756156289E-16,0.,-1.));
+#334=DIRECTION('',(0.,-1.,0.));
+#335=DIRECTION('',(2.77555756156289E-16,0.,1.));
+#336=DIRECTION('',(0.,-1.,0.));
+#337=DIRECTION('center_axis',(0.,-1.,0.));
+#338=DIRECTION('ref_axis',(0.,0.,-1.));
+#339=DIRECTION('',(-8.65956056235493E-17,0.707106781186547,-0.707106781186547));
+#340=DIRECTION('center_axis',(0.,-1.,0.));
+#341=DIRECTION('ref_axis',(1.,0.,0.));
+#342=DIRECTION('center_axis',(0.,-1.,0.));
+#343=DIRECTION('ref_axis',(1.,0.,0.));
+#344=DIRECTION('center_axis',(0.,-1.,0.));
+#345=DIRECTION('ref_axis',(1.,0.,0.));
+#346=DIRECTION('',(0.,1.,0.));
+#347=DIRECTION('center_axis',(0.,1.,0.));
+#348=DIRECTION('ref_axis',(1.,0.,0.));
+#349=DIRECTION('center_axis',(1.38777878078145E-16,0.,1.));
+#350=DIRECTION('ref_axis',(-1.,0.,1.38777878078145E-16));
+#351=DIRECTION('',(1.,0.,-1.38777878078145E-16));
+#352=DIRECTION('center_axis',(0.,-1.,0.));
+#353=DIRECTION('ref_axis',(1.,0.,0.));
+#354=DIRECTION('',(0.,-1.,0.));
+#355=DIRECTION('center_axis',(0.,-1.,0.));
+#356=DIRECTION('ref_axis',(1.,0.,0.));
+#357=DIRECTION('center_axis',(-1.,0.,1.38777878078145E-16));
+#358=DIRECTION('ref_axis',(-1.38777878078145E-16,0.,-1.));
+#359=DIRECTION('',(0.,-1.,0.));
+#360=DIRECTION('',(1.38777878078145E-16,0.,1.));
+#361=DIRECTION('center_axis',(-1.38777878078145E-16,0.,-1.));
+#362=DIRECTION('ref_axis',(1.,0.,-1.38777878078145E-16));
+#363=DIRECTION('',(-1.,0.,1.38777878078145E-16));
+#364=DIRECTION('',(0.,-1.,0.));
+#365=DIRECTION('center_axis',(1.,0.,-1.38777878078145E-16));
+#366=DIRECTION('ref_axis',(1.38777878078145E-16,0.,1.));
+#367=DIRECTION('',(0.,-1.,0.));
+#368=DIRECTION('',(-1.38777878078145E-16,0.,-1.));
+#369=DIRECTION('center_axis',(0.,-1.,0.));
+#370=DIRECTION('ref_axis',(-1.,0.,1.22464679914735E-16));
+#371=DIRECTION('center_axis',(0.,-1.,0.));
+#372=DIRECTION('ref_axis',(1.,0.,0.));
+#373=DIRECTION('center_axis',(0.,-1.,0.));
+#374=DIRECTION('ref_axis',(1.,0.,0.));
+#375=CARTESIAN_POINT('',(0.,0.,0.));
+#376=CARTESIAN_POINT('Origin',(0.,13.,0.));
+#377=CARTESIAN_POINT('',(-2.,13.,-6.70820393249937));
+#378=CARTESIAN_POINT('',(-2.,12.,-5.65685424949238));
+#379=CARTESIAN_POINT('Ctrl Pts',(-2.,13.,-6.70820393249937));
+#380=CARTESIAN_POINT('Ctrl Pts',(-2.,12.8784455914179,-6.70820393249937));
+#381=CARTESIAN_POINT('Ctrl Pts',(-2.,12.7355491074581,-6.67892462605587));
+#382=CARTESIAN_POINT('Ctrl Pts',(-2.,12.5092718509832,-6.58291786833164));
+#383=CARTESIAN_POINT('Ctrl Pts',(-2.,12.38654966704,-6.4982463532934));
+#384=CARTESIAN_POINT('Ctrl Pts',(-2.,12.2104710336355,-6.31738515061704));
+#385=CARTESIAN_POINT('Ctrl Pts',(-2.,12.1271535852394,-6.18810372235763));
+#386=CARTESIAN_POINT('Ctrl Pts',(-2.,12.0297218204284,-5.94607413532843));
+#387=CARTESIAN_POINT('Ctrl Pts',(-2.,12.,-5.78958946607839));
+#388=CARTESIAN_POINT('Ctrl Pts',(-2.,12.,-5.65685424949238));
+#389=CARTESIAN_POINT('',(-2.,12.,5.65685424949238));
+#390=CARTESIAN_POINT('Origin',(0.,12.,0.));
+#391=CARTESIAN_POINT('',(-2.,13.,6.70820393249937));
+#392=CARTESIAN_POINT('Ctrl Pts',(-2.,12.,5.65685424949239));
+#393=CARTESIAN_POINT('Ctrl Pts',(-2.,12.,5.78958946607839));
+#394=CARTESIAN_POINT('Ctrl Pts',(-2.,12.0297218204284,5.94607413532843));
+#395=CARTESIAN_POINT('Ctrl Pts',(-2.,12.1271535852394,6.18810372235763));
+#396=CARTESIAN_POINT('Ctrl Pts',(-2.,12.2104710336355,6.31738515061704));
+#397=CARTESIAN_POINT('Ctrl Pts',(-2.,12.38654966704,6.4982463532934));
+#398=CARTESIAN_POINT('Ctrl Pts',(-2.,12.5092718509832,6.58291786833164));
+#399=CARTESIAN_POINT('Ctrl Pts',(-2.,12.7355491074581,6.67892462605587));
+#400=CARTESIAN_POINT('Ctrl Pts',(-2.,12.8784455914179,6.70820393249937));
+#401=CARTESIAN_POINT('Ctrl Pts',(-2.,13.,6.70820393249937));
+#402=CARTESIAN_POINT('Origin',(0.,13.,0.));
+#403=CARTESIAN_POINT('Origin',(-2.,14.,4.70820393249937));
+#404=CARTESIAN_POINT('',(-2.,12.,4.70820393249937));
+#405=CARTESIAN_POINT('',(-2.,12.,6.70820393249937));
+#406=CARTESIAN_POINT('',(-2.,14.,4.70820393249937));
+#407=CARTESIAN_POINT('',(-2.,14.,4.70820393249937));
+#408=CARTESIAN_POINT('',(-2.,14.,6.70820393249937));
+#409=CARTESIAN_POINT('',(-2.,14.,6.70820393249937));
+#410=CARTESIAN_POINT('',(-2.,14.,6.70820393249937));
+#411=CARTESIAN_POINT('Origin',(0.,12.,0.));
+#412=CARTESIAN_POINT('',(-2.,12.,-4.70820393249937));
+#413=CARTESIAN_POINT('',(-2.,12.,-4.70820393249937));
+#414=CARTESIAN_POINT('',(2.,12.,-4.70820393249937));
+#415=CARTESIAN_POINT('',(2.,12.,-4.70820393249937));
+#416=CARTESIAN_POINT('',(2.,12.,-5.65685424949238));
+#417=CARTESIAN_POINT('',(2.,12.,-6.70820393249937));
+#418=CARTESIAN_POINT('',(2.,12.,5.65685424949238));
+#419=CARTESIAN_POINT('Origin',(0.,12.,0.));
+#420=CARTESIAN_POINT('',(2.,12.,4.70820393249937));
+#421=CARTESIAN_POINT('',(2.,12.,4.70820393249937));
+#422=CARTESIAN_POINT('',(-2.,12.,4.70820393249937));
+#423=CARTESIAN_POINT('',(3.77781112375417E-16,12.,2.15));
+#424=CARTESIAN_POINT('Origin',(1.14482050558736E-16,12.,2.38291741477447E-16));
+#425=CARTESIAN_POINT('Origin',(0.,13.,0.));
+#426=CARTESIAN_POINT('',(2.,13.,6.70820393249937));
+#427=CARTESIAN_POINT('Ctrl Pts',(2.,13.,6.70820393249937));
+#428=CARTESIAN_POINT('Ctrl Pts',(2.,12.8784455914179,6.70820393249937));
+#429=CARTESIAN_POINT('Ctrl Pts',(2.,12.7355491074581,6.67892462605587));
+#430=CARTESIAN_POINT('Ctrl Pts',(2.,12.5092718509832,6.58291786833164));
+#431=CARTESIAN_POINT('Ctrl Pts',(2.,12.38654966704,6.4982463532934));
+#432=CARTESIAN_POINT('Ctrl Pts',(2.,12.2104710336355,6.31738515061704));
+#433=CARTESIAN_POINT('Ctrl Pts',(2.,12.1271535852394,6.18810372235763));
+#434=CARTESIAN_POINT('Ctrl Pts',(2.,12.0297218204284,5.94607413532843));
+#435=CARTESIAN_POINT('Ctrl Pts',(2.,12.,5.78958946607839));
+#436=CARTESIAN_POINT('Ctrl Pts',(2.,12.,5.65685424949238));
+#437=CARTESIAN_POINT('',(2.,13.,-6.70820393249937));
+#438=CARTESIAN_POINT('Ctrl Pts',(2.,12.,-5.65685424949238));
+#439=CARTESIAN_POINT('Ctrl Pts',(2.,12.,-5.78958946607839));
+#440=CARTESIAN_POINT('Ctrl Pts',(2.,12.0297218204284,-5.94607413532843));
+#441=CARTESIAN_POINT('Ctrl Pts',(2.,12.1271535852394,-6.18810372235763));
+#442=CARTESIAN_POINT('Ctrl Pts',(2.,12.2104710336355,-6.31738515061704));
+#443=CARTESIAN_POINT('Ctrl Pts',(2.,12.38654966704,-6.4982463532934));
+#444=CARTESIAN_POINT('Ctrl Pts',(2.,12.5092718509832,-6.58291786833164));
+#445=CARTESIAN_POINT('Ctrl Pts',(2.,12.7355491074581,-6.67892462605587));
+#446=CARTESIAN_POINT('Ctrl Pts',(2.,12.8784455914179,-6.70820393249937));
+#447=CARTESIAN_POINT('Ctrl Pts',(2.,13.,-6.70820393249937));
+#448=CARTESIAN_POINT('Origin',(0.,13.,0.));
+#449=CARTESIAN_POINT('Origin',(2.,14.,6.70820393249937));
+#450=CARTESIAN_POINT('',(2.,14.,6.70820393249937));
+#451=CARTESIAN_POINT('',(2.,14.,6.70820393249937));
+#452=CARTESIAN_POINT('',(2.,14.,4.70820393249937));
+#453=CARTESIAN_POINT('',(2.,14.,4.70820393249937));
+#454=CARTESIAN_POINT('',(2.,14.,4.70820393249937));
+#455=CARTESIAN_POINT('Origin',(1.14482050558736E-16,12.575,2.38291741477447E-16));
+#456=CARTESIAN_POINT('',(2.36946730473471E-16,13.15,1.));
+#457=CARTESIAN_POINT('',(3.07363921424444E-16,12.575,1.575));
+#458=CARTESIAN_POINT('',(-1.,13.15,-1.22464679914735E-16));
+#459=CARTESIAN_POINT('Origin',(0.,13.15,0.));
+#460=CARTESIAN_POINT('Origin',(0.,13.15,0.));
+#461=CARTESIAN_POINT('Origin',(0.,14.,0.));
+#462=CARTESIAN_POINT('',(-1.,14.,-1.22464679914735E-16));
+#463=CARTESIAN_POINT('',(-1.,14.,-1.22464679914735E-16));
+#464=CARTESIAN_POINT('Origin',(0.,14.,0.));
+#465=CARTESIAN_POINT('Origin',(2.,14.,4.70820393249937));
+#466=CARTESIAN_POINT('',(-2.,14.,4.70820393249937));
+#467=CARTESIAN_POINT('Origin',(0.,14.,0.));
+#468=CARTESIAN_POINT('',(2.,14.,-6.70820393249937));
+#469=CARTESIAN_POINT('',(2.,14.,-6.70820393249937));
+#470=CARTESIAN_POINT('Origin',(0.,14.,0.));
+#471=CARTESIAN_POINT('Origin',(2.,14.,-4.70820393249937));
+#472=CARTESIAN_POINT('',(2.,14.,-4.70820393249937));
+#473=CARTESIAN_POINT('',(2.,14.,-4.70820393249937));
+#474=CARTESIAN_POINT('',(2.,14.,-6.70820393249937));
+#475=CARTESIAN_POINT('Origin',(-2.,14.,-4.70820393249937));
+#476=CARTESIAN_POINT('',(-2.,14.,-4.70820393249937));
+#477=CARTESIAN_POINT('',(2.,14.,-4.70820393249937));
+#478=CARTESIAN_POINT('',(-2.,14.,-4.70820393249937));
+#479=CARTESIAN_POINT('Origin',(-2.,14.,-6.70820393249937));
+#480=CARTESIAN_POINT('',(-2.,14.,-6.70820393249937));
+#481=CARTESIAN_POINT('',(-2.,14.,-6.70820393249937));
+#482=CARTESIAN_POINT('',(-2.,14.,-4.70820393249937));
+#483=CARTESIAN_POINT('Origin',(0.,14.,0.));
+#484=CARTESIAN_POINT('Origin',(0.,14.,0.));
+#485=CARTESIAN_POINT('Origin',(0.,14.,0.));
+#486=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#490,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#487=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#490,
+'DISTANCE_ACCURACY_VALUE',
+'Maximum model space distance between geometric entities at asserted c
+onnectivities');
+#488=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#486))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#490,#492,#493))
+REPRESENTATION_CONTEXT('','3D')
+);
+#489=(
+GEOMETRIC_REPRESENTATION_CONTEXT(3)
+GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#487))
+GLOBAL_UNIT_ASSIGNED_CONTEXT((#490,#492,#493))
+REPRESENTATION_CONTEXT('','3D')
+);
+#490=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT(.MILLI.,.METRE.)
+);
+#491=(
+LENGTH_UNIT()
+NAMED_UNIT(*)
+SI_UNIT($,.METRE.)
+);
+#492=(
+NAMED_UNIT(*)
+PLANE_ANGLE_UNIT()
+SI_UNIT($,.RADIAN.)
+);
+#493=(
+NAMED_UNIT(*)
+SI_UNIT($,.STERADIAN.)
+SOLID_ANGLE_UNIT()
+);
+#494=SHAPE_DEFINITION_REPRESENTATION(#495,#496);
+#495=PRODUCT_DEFINITION_SHAPE('',$,#498);
+#496=SHAPE_REPRESENTATION('',(#278),#488);
+#497=PRODUCT_DEFINITION_CONTEXT('part definition',#502,'design');
+#498=PRODUCT_DEFINITION('FusionComponent','FusionComponent',#499,#497);
+#499=PRODUCT_DEFINITION_FORMATION('',$,#504);
+#500=PRODUCT_RELATED_PRODUCT_CATEGORY('FusionComponent',
+'FusionComponent',(#504));
+#501=APPLICATION_PROTOCOL_DEFINITION('international standard',
+'automotive_design',2009,#502);
+#502=APPLICATION_CONTEXT(
+'Core Data for Automotive Mechanical Design Process');
+#503=PRODUCT_CONTEXT('part definition',#502,'mechanical');
+#504=PRODUCT('FusionComponent','FusionComponent',$,(#503));
+#505=PRESENTATION_STYLE_ASSIGNMENT((#506));
+#506=SURFACE_STYLE_USAGE(.BOTH.,#507);
+#507=SURFACE_SIDE_STYLE('',(#508));
+#508=SURFACE_STYLE_FILL_AREA(#509);
+#509=FILL_AREA_STYLE('Steel - Satin',(#510));
+#510=FILL_AREA_STYLE_COLOUR('Steel - Satin',#511);
+#511=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157);
+ENDSEC;
+END-ISO-10303-21;
diff --git a/3d_model/Screw.stl b/3d_model/Screw.stl
new file mode 100755
index 0000000..55a2327
Binary files /dev/null and b/3d_model/Screw.stl differ
diff --git a/3d_model/base_for_stepper.stl b/3d_model/base_for_stepper.stl
new file mode 100755
index 0000000..061b900
Binary files /dev/null and b/3d_model/base_for_stepper.stl differ
diff --git a/3d_model/dial.svg b/3d_model/dial.svg
new file mode 100755
index 0000000..102801d
--- /dev/null
+++ b/3d_model/dial.svg
@@ -0,0 +1,803 @@
+
+
diff --git a/3d_model/dial_reversed.svg b/3d_model/dial_reversed.svg
new file mode 100755
index 0000000..9aa3875
--- /dev/null
+++ b/3d_model/dial_reversed.svg
@@ -0,0 +1,761 @@
+
+
diff --git a/3d_model/frame.stl b/3d_model/frame.stl
new file mode 100755
index 0000000..5f71a6f
Binary files /dev/null and b/3d_model/frame.stl differ
diff --git a/3d_model/glass.svg b/3d_model/glass.svg
new file mode 100755
index 0000000..5aafccb
--- /dev/null
+++ b/3d_model/glass.svg
@@ -0,0 +1,48 @@
+
+
+
+
diff --git a/3d_model/insidebody.stl b/3d_model/insidebody.stl
new file mode 100755
index 0000000..9bbfe41
Binary files /dev/null and b/3d_model/insidebody.stl differ
diff --git a/3d_model/pointer.stl b/3d_model/pointer.stl
new file mode 100755
index 0000000..b0adeb9
Binary files /dev/null and b/3d_model/pointer.stl differ
diff --git a/3d_model/rod-label.svg b/3d_model/rod-label.svg
new file mode 100755
index 0000000..44d3ee9
--- /dev/null
+++ b/3d_model/rod-label.svg
@@ -0,0 +1,108 @@
+
+
diff --git a/config.multi.example.json b/config.multi.example.json
new file mode 100644
index 0000000..8cd14ff
--- /dev/null
+++ b/config.multi.example.json
@@ -0,0 +1,57 @@
+{
+ "wifi_ssid": "YourWiFiSSID",
+ "wifi_password": "YourWiFiPassword",
+ "mqtt_broker": "mqtt.example.com",
+ "mqtt_port": 1883,
+ "mqtt_user": "mqtt_user",
+ "mqtt_password": "mqtt_password",
+ "mqtt_client_id": "selsyn_multi",
+ "mqtt_prefix": "home/panels/chernobyl1",
+
+ "gauges": [
+ {
+ "name": "Gauge 1",
+ "pins": [12, 13],
+ "mode": "stepdir",
+ "min": 0,
+ "max": 7300,
+ "step_us": 200,
+ "entity_name": "Power 1",
+ "unit": "W",
+ "leds": {
+ "red_pin": 33,
+ "green_pin": 32
+ }
+ },
+ {
+ "name": "Gauge 2",
+ "pins": [14, 15],
+ "mode": "stepdir",
+ "min": 0,
+ "max": 100,
+ "step_us": 200,
+ "entity_name": "Temperature",
+ "unit": "C",
+ "leds": {
+ "red_pin": 21,
+ "green_pin": 20
+ }
+ }
+ ],
+
+ "backlight": {
+ "pin": 23,
+ "num_leds_per_gauge": 3
+ },
+
+ "device": {
+ "name": "Selsyn Multi Gauge",
+ "model": "Chernobyl Selsyn-inspired gauge",
+ "manufacturer": "AdeBaumann",
+ "area": "Control Panels"
+ },
+
+ "microsteps_per_second": 600,
+ "heartbeat_ms": 10000,
+ "rezero_interval_ms": 3600000
+}
\ No newline at end of file
diff --git a/gauge_vid6008.py b/gauge_vid6008.py
index 47bd14f..9172682 100644
--- a/gauge_vid6008.py
+++ b/gauge_vid6008.py
@@ -61,6 +61,7 @@ class Gauge:
self._pin_step = Pin(pins[1], Pin.OUT)
self._total_steps = _TOTAL_STEPS
self._phase = 0
+ self._last_dir = None # track last direction to avoid redundant writes
elif mode == "4phase":
if len(pins) != 4:
@@ -135,8 +136,10 @@ class Gauge:
def step(self, direction):
if self._mode == "stepdir":
- self._pin_dir.value(1 if direction > 0 else 0)
- utime.sleep_us(10)
+ if direction != self._last_dir:
+ self._pin_dir.value(1 if direction > 0 else 0)
+ self._last_dir = direction
+ utime.sleep_us(10)
self._pulse_step(self._step_us)
self._current_step += direction
else:
diff --git a/gaugemqttcontinuous.py b/gaugemqttcontinuous.py
index ce90d3f..b3957ac 100644
--- a/gaugemqttcontinuous.py
+++ b/gaugemqttcontinuous.py
@@ -42,8 +42,12 @@ def log(level, msg):
print(f"[{_ts()}] {level:5s} {msg}")
+_DEBUG = False
+
+
def info(msg):
- log("INFO", msg)
+ if _DEBUG:
+ log("INFO", msg)
def warn(msg):
@@ -75,6 +79,9 @@ def _load_config():
_cfg = _load_config()
+DEBUG = _cfg.get("debug", False)
+_DEBUG = DEBUG
+
WIFI_SSID = _cfg["wifi_ssid"]
WIFI_PASSWORD = _cfg["wifi_password"]
MQTT_BROKER = _cfg["mqtt_broker"]
@@ -83,50 +90,148 @@ MQTT_USER = _cfg["mqtt_user"]
MQTT_PASSWORD = _cfg["mqtt_password"]
MQTT_CLIENT_ID = _cfg["mqtt_client_id"]
MQTT_PREFIX = _cfg["mqtt_prefix"]
-GAUGE_PINS = tuple(_cfg.get("gauge_pins", [12, 13]))
-GAUGE_MODE = _cfg.get("gauge_mode", "stepdir")
-GAUGE_MIN = float(_cfg.get("gauge_min", 0))
-GAUGE_MAX = float(_cfg.get("gauge_max", 7300))
-GAUGE_STEP_US = int(_cfg.get("gauge_step_us", 200))
-
-MICROSTEPS_PER_SECOND = 600 # microsteps per second (adjustable)
+MICROSTEPS_PER_SECOND = int(_cfg.get("microsteps_per_second", 600))
HEARTBEAT_MS = int(_cfg.get("heartbeat_ms", 10000))
REZERO_INTERVAL_MS = int(_cfg.get("rezero_interval_ms", 3600000))
-LED_RED_PIN = int(_cfg.get("led_red_pin", 33))
-LED_GREEN_PIN = int(_cfg.get("led_green_pin", 32))
-LED_BL_PIN = int(_cfg.get("led_bl_pin", 23))
-DEVICE_NAME = _cfg.get("device_name", "Selsyn 1")
-DEVICE_MODEL = _cfg.get("device_model", "Chernobyl Selsyn-inspired gauge")
-DEVICE_MFR = _cfg.get("device_manufacturer", "AdeBaumann")
-DEVICE_AREA = _cfg.get("device_area", "Control Panels")
-GAUGE_ENTITY = _cfg.get("gauge_entity_name", "Selsyn 1 Power")
-GAUGE_UNIT = _cfg.get("gauge_unit", "W")
-RED_ENTITY = _cfg.get("red_led_entity_name", "Selsyn 1 Red LED")
-GREEN_ENTITY = _cfg.get("green_led_entity_name", "Selsyn 1 Green LED")
-BL_ENTITY = _cfg.get("backlight_entity_name", "Selsyn 1 Backlight")
+
+backlight_cfg = _cfg.get("backlight", {})
+BACKLIGHT_PIN = int(backlight_cfg.get("pin", _cfg.get("led_bl_pin", 23)))
+BACKLIGHT_LEDS_PER_GAUGE = int(backlight_cfg.get("num_leds_per_gauge", 3))
+
+device_cfg = _cfg.get("device", {})
+DEVICE_NAME = device_cfg.get("name", _cfg.get("device_name", "Selsyn Multi"))
+DEVICE_MODEL = device_cfg.get(
+ "model", _cfg.get("device_model", "Chernobyl Selsyn-inspired gauge")
+)
+DEVICE_MFR = device_cfg.get(
+ "manufacturer", _cfg.get("device_manufacturer", "AdeBaumann")
+)
+DEVICE_AREA = device_cfg.get("area", _cfg.get("device_area", "Control Panels"))
+
+gauges = []
+if "gauges" in _cfg:
+ for i, g in enumerate(_cfg["gauges"]):
+ led_cfg = g.get("leds", {})
+ gauges.append(
+ {
+ "id": i,
+ "name": g.get("name", f"Gauge {i + 1}"),
+ "pins": tuple(g.get("pins", [12, 13])),
+ "mode": g.get("mode", "stepdir"),
+ "min": float(g.get("min", 0)),
+ "max": float(g.get("max", 100)),
+ "step_us": int(g.get("step_us", 200)),
+ "entity_name": g.get("entity_name", f"Gauge {i + 1}"),
+ "unit": g.get("unit", ""),
+ "red_pin": int(led_cfg.get("red_pin", 33)),
+ "green_pin": int(led_cfg.get("green_pin", 32)),
+ }
+ )
+else:
+ gauges.append(
+ {
+ "id": 0,
+ "name": "Gauge 1",
+ "pins": tuple(_cfg.get("gauge_pins", [12, 13])),
+ "mode": _cfg.get("gauge_mode", "stepdir"),
+ "min": float(_cfg.get("gauge_min", 0)),
+ "max": float(_cfg.get("gauge_max", 7300)),
+ "step_us": int(_cfg.get("gauge_step_us", 200)),
+ "entity_name": _cfg.get("gauge_entity_name", "Selsyn 1 Power"),
+ "unit": _cfg.get("gauge_unit", "W"),
+ "red_pin": int(_cfg.get("led_red_pin", 33)),
+ "green_pin": int(_cfg.get("led_green_pin", 32)),
+ }
+ )
BL_UNIT = _cfg.get("backlight_unit", "%")
# ---------------------------------------------------------------------------
-# Topics
+# Gauge initialization
# ---------------------------------------------------------------------------
+gauge_objects = []
+for g in gauges:
+ gauge_objects.append(
+ Gauge(
+ pins=g["pins"],
+ mode=g["mode"],
+ min_val=g["min"],
+ max_val=g["max"],
+ step_us=g["step_us"],
+ )
+ )
+ info(
+ f"Gauge {g['id']}: {g['name']} pins={g['pins']} mode={g['mode']} range=[{g['min']}, {g['max']}]"
+ )
+
+gauge_targets = [g["min"] for g in gauges] # target value per gauge
+gauge_last_rezero = [utime.ticks_ms() for _ in gauges]
+
+# ---------------------------------------------------------------------------
+# Topics (per-gauge)
+# ---------------------------------------------------------------------------
+
+
+def make_gauge_topics(prefix, gauge_id):
+ return {
+ "set": f"{prefix}/gauge{gauge_id}/set",
+ "state": f"{prefix}/gauge{gauge_id}/state",
+ "status": f"{prefix}/gauge{gauge_id}/status",
+ "zero": f"{prefix}/gauge{gauge_id}/zero",
+ "disc": f"homeassistant/number/{MQTT_CLIENT_ID}_g{gauge_id}/config",
+ "led_red": f"{prefix}/gauge{gauge_id}/led/red/set",
+ "led_green": f"{prefix}/gauge{gauge_id}/led/green/set",
+ "led_bl": f"{prefix}/gauge{gauge_id}/led/backlight/set",
+ "led_red_state": f"{prefix}/gauge{gauge_id}/led/red/state",
+ "led_green_state": f"{prefix}/gauge{gauge_id}/led/green/state",
+ "led_bl_state": f"{prefix}/gauge{gauge_id}/led/backlight/state",
+ "led_red_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_red/config",
+ "led_green_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_green/config",
+ "led_bl_disc": f"homeassistant/light/{MQTT_CLIENT_ID}_g{gauge_id}_bl/config",
+ }
+
+
+gauge_topics = [make_gauge_topics(MQTT_PREFIX, g["id"]) for g in gauges]
+
+T_SET = f"{MQTT_PREFIX}/set"
+T_STATE = f"{MQTT_PREFIX}/state"
+T_STATUS = f"{MQTT_PREFIX}/status"
+T_ZERO = f"{MQTT_PREFIX}/zero"
+
+
+gauge_topics = [make_gauge_topics(MQTT_PREFIX, g["id"]) for g in gauges]
+
T_SET = f"{MQTT_PREFIX}/set"
T_STATE = f"{MQTT_PREFIX}/state"
T_STATUS = f"{MQTT_PREFIX}/status"
T_ZERO = f"{MQTT_PREFIX}/zero"
-T_LED_RED = f"{MQTT_PREFIX}/led/red/set"
-T_LED_GREEN = f"{MQTT_PREFIX}/led/green/set"
-T_LED_BL = f"{MQTT_PREFIX}/led/backlight/set"
-T_LED_BL_STATE = f"{MQTT_PREFIX}/led/backlight/state"
-T_LED_RED_STATE = f"{MQTT_PREFIX}/led/red/state"
-T_LED_GREEN_STATE = f"{MQTT_PREFIX}/led/green/state"
T_DISC_GAUGE = f"homeassistant/number/{MQTT_CLIENT_ID}/config"
T_DISC_RED = f"homeassistant/switch/{MQTT_CLIENT_ID}_red/config"
T_DISC_GREEN = f"homeassistant/switch/{MQTT_CLIENT_ID}_green/config"
T_DISC_BL = f"homeassistant/light/{MQTT_CLIENT_ID}_bl/config"
+
+def make_gauge_topics(prefix, gauge_id):
+ return {
+ "set": f"{prefix}/gauge{gauge_id}/set",
+ "state": f"{prefix}/gauge{gauge_id}/state",
+ "status": f"{prefix}/gauge{gauge_id}/status",
+ "zero": f"{prefix}/gauge{gauge_id}/zero",
+ "disc": f"homeassistant/number/{MQTT_CLIENT_ID}_g{gauge_id}/config",
+ "led_red": f"{prefix}/gauge{gauge_id}/led/red/set",
+ "led_green": f"{prefix}/gauge{gauge_id}/led/green/set",
+ "led_bl": f"{prefix}/gauge{gauge_id}/led/backlight/set",
+ "led_red_state": f"{prefix}/gauge{gauge_id}/led/red/state",
+ "led_green_state": f"{prefix}/gauge{gauge_id}/led/green/state",
+ "led_bl_state": f"{prefix}/gauge{gauge_id}/led/backlight/state",
+ "led_red_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_red/config",
+ "led_green_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_green/config",
+ "led_bl_disc": f"homeassistant/light/{MQTT_CLIENT_ID}_g{gauge_id}_bl/config",
+ }
+
+
_DEVICE = {
"identifiers": [MQTT_CLIENT_ID],
"name": DEVICE_NAME,
@@ -201,58 +306,58 @@ def check_wifi():
# ---------------------------------------------------------------------------
-# Gauge
+# LEDs (per gauge)
# ---------------------------------------------------------------------------
-info("Initialising gauge ...")
-gauge = Gauge(
- pins=GAUGE_PINS,
- mode=GAUGE_MODE,
- min_val=GAUGE_MIN,
- max_val=GAUGE_MAX,
- step_us=GAUGE_STEP_US,
-)
-info(
- f"Gauge ready pins={GAUGE_PINS} mode={GAUGE_MODE} range=[{GAUGE_MIN}, {GAUGE_MAX}] step_us={GAUGE_STEP_US}"
-)
+num_gauges = len(gauges)
+leds_red = []
+leds_green = []
+leds_bl = []
+for g in gauges:
+ leds_red.append(Pin(g["red_pin"], Pin.OUT, value=0))
+ leds_green.append(Pin(g["green_pin"], Pin.OUT, value=0))
-# ---------------------------------------------------------------------------
-# LEDs
-# ---------------------------------------------------------------------------
-
-led_red = Pin(LED_RED_PIN, Pin.OUT, value=0)
-led_green = Pin(LED_GREEN_PIN, Pin.OUT, value=0)
-led_bl = NeoPixel(Pin(LED_BL_PIN), 3)
+total_backlight_leds = num_gauges * BACKLIGHT_LEDS_PER_GAUGE
+leds_bl = NeoPixel(Pin(BACKLIGHT_PIN), total_backlight_leds)
_backlight_color = (0, 0, 0)
-_backlight_brightness = 100 # last *active* brightness — never set to 0
+_backlight_brightness = 100
_backlight_on = False
_bl_dirty_since = None
_BL_SAVE_DELAY_MS = 5000
+backlight_color = [(0, 0, 0) for _ in range(num_gauges)]
+backlight_brightness = [100 for _ in range(num_gauges)]
+backlight_on = [False for _ in range(num_gauges)]
+
def _flush_backlight(client):
- payload = {
- "state": "ON" if _backlight_on else "OFF",
- "color": {
- "r": _backlight_color[0],
- "g": _backlight_color[1],
- "b": _backlight_color[2],
- },
- "brightness": int(_backlight_brightness * 2.55),
- }
- client.publish(T_LED_BL, ujson.dumps(payload), retain=True)
- info(
- f"Backlight state retained: {payload['state']} {_backlight_color} @ {_backlight_brightness}%"
- )
+ for i in range(num_gauges):
+ gt = gauge_topics[i]
+ payload = {
+ "state": "ON" if backlight_on[i] else "OFF",
+ "color": {
+ "r": backlight_color[i][0],
+ "g": backlight_color[i][1],
+ "b": backlight_color[i][2],
+ },
+ "brightness": int(backlight_brightness[i] * 2.55),
+ }
+ client.publish(
+ f"{gt['set'].replace('/set', '/backlight/state')}",
+ ujson.dumps(payload),
+ retain=True,
+ )
+ info(
+ f"Gauge {i} backlight: {payload['state']} {backlight_color[i]} @ {backlight_brightness[i]}%"
+ )
-def _backlight_changed(new_color, new_on, new_brightness):
- """Return True if any backlight property differs from current state."""
+def _backlight_changed(gauge_idx, new_color, new_on, new_brightness):
return (
- new_color != _backlight_color
- or new_on != _backlight_on
- or (new_on and new_brightness != _backlight_brightness)
+ new_color != backlight_color[gauge_idx]
+ or new_on != backlight_on[gauge_idx]
+ or (new_on and new_brightness != backlight_brightness[gauge_idx])
)
@@ -261,48 +366,48 @@ def _mark_bl_dirty():
_bl_dirty_since = utime.ticks_ms()
-def set_backlight_color(r, g, b, brightness=None):
- global _backlight_color, _backlight_brightness, _backlight_on
+def set_backlight_color(gauge_idx, r, g, b, brightness=None):
+ global backlight_color, backlight_brightness, backlight_on
if brightness is None:
- brightness = _backlight_brightness
+ brightness = backlight_brightness[gauge_idx]
new_on = brightness > 0
- if not _backlight_changed((r, g, b), new_on, brightness):
+ if not _backlight_changed(gauge_idx, (r, g, b), new_on, brightness):
return
- _backlight_color = (r, g, b)
+ backlight_color[gauge_idx] = (r, g, b)
if brightness > 0:
- _backlight_brightness = brightness
- _backlight_on = new_on
+ backlight_brightness[gauge_idx] = brightness
+ backlight_on[gauge_idx] = new_on
+
scale = brightness / 100
- for i in range(3):
- led_bl[i] = (int(g * scale), int(r * scale), int(b * scale))
- led_bl.write()
+ base_idx = gauge_idx * BACKLIGHT_LEDS_PER_GAUGE
+ for j in range(BACKLIGHT_LEDS_PER_GAUGE):
+ leds_bl[base_idx + j] = (int(g * scale), int(r * scale), int(b * scale))
+ leds_bl.write()
_mark_bl_dirty()
-def set_backlight_brightness(brightness):
- global _backlight_brightness, _backlight_on
+def set_backlight_brightness(gauge_idx, brightness):
+ global backlight_brightness, backlight_on
clamped = max(0, min(100, brightness))
new_on = clamped > 0
- if not _backlight_changed(_backlight_color, new_on, clamped):
+ if not _backlight_changed(gauge_idx, backlight_color[gauge_idx], new_on, clamped):
return
if clamped > 0:
- _backlight_brightness = clamped
- _backlight_on = new_on
- r, g, b = _backlight_color
+ backlight_brightness[gauge_idx] = clamped
+ backlight_on[gauge_idx] = new_on
+ r, g, b = backlight_color[gauge_idx]
scale = clamped / 100
- for i in range(3):
- led_bl[i] = (int(g * scale), int(r * scale), int(b * scale))
- led_bl.write()
+ base_idx = gauge_idx * BACKLIGHT_LEDS_PER_GAUGE
+ for j in range(BACKLIGHT_LEDS_PER_GAUGE):
+ leds_bl[base_idx + j] = (int(g * scale), int(r * scale), int(b * scale))
+ leds_bl.write()
_mark_bl_dirty()
-info(f"LEDs ready red={LED_RED_PIN} green={LED_GREEN_PIN} backlight={LED_BL_PIN}")
-
# ---------------------------------------------------------------------------
# State
# ---------------------------------------------------------------------------
-_target_value = GAUGE_MIN
_last_rezero_ms = None # set to ticks_ms() in main()
client_ref = None
_mqtt_connected = False
@@ -333,74 +438,80 @@ def on_message(topic, payload):
payload = payload.decode().strip()
info(f"MQTT rx {topic} {payload}")
- if topic == T_ZERO:
- global _last_rezero_ms
- info("Zero command received")
- gauge.zero()
- _last_rezero_ms = utime.ticks_ms()
- info("Zero complete")
- return
-
- if topic == T_LED_RED:
- state = payload.upper() == "ON"
- led_red.value(1 if state else 0)
- _publish(T_LED_RED_STATE, "ON" if state else "OFF", retain=True)
- info(f"Red LED → {'ON' if state else 'OFF'}")
- return
-
- if topic == T_LED_GREEN:
- state = payload.upper() == "ON"
- led_green.value(1 if state else 0)
- _publish(T_LED_GREEN_STATE, "ON" if state else "OFF", retain=True)
- info(f"Green LED → {'ON' if state else 'OFF'}")
- return
-
- if topic == T_LED_BL:
- info(f"Backlight raw payload: '{payload}'")
- try:
- data = ujson.loads(payload)
- info(
- f"Backlight parsed: state={data.get('state')} color={data.get('color')} brightness={data.get('brightness')}"
- )
- if data.get("state", "ON").upper() == "OFF":
- set_backlight_brightness(0)
- _publish(T_LED_BL_STATE, ujson.dumps({"state": "OFF"}), retain=True)
- info("Backlight → OFF")
- return
- color = data.get("color", {})
- r = max(0, min(255, int(color.get("r", _backlight_color[0]))))
- g = max(0, min(255, int(color.get("g", _backlight_color[1]))))
- b = max(0, min(255, int(color.get("b", _backlight_color[2]))))
- # HA sends brightness as 0-255; convert to 0-100
- raw_br = data.get("brightness", None)
- if raw_br is not None:
- brightness = max(0, min(100, round(int(raw_br) / 2.55)))
- elif _backlight_brightness > 0:
- brightness = _backlight_brightness
- else:
- brightness = 100
- except Exception as e:
- warn(f"Invalid backlight payload: '{payload}' ({e})")
+ for i, gt in enumerate(gauge_topics):
+ if topic == gt["zero"]:
+ info(f"Zero command received for gauge {i}")
+ gauge_objects[i].zero()
+ gauge_last_rezero[i] = utime.ticks_ms()
+ info(f"Zero complete gauge {i}")
return
- set_backlight_color(r, g, b, brightness)
- color_hex = f"#{r:02x}{g:02x}{b:02x}"
- state = {
- "state": "ON",
- "color_mode": "rgb",
- "brightness": int(brightness * 2.55),
- "color": {"r": r, "g": g, "b": b},
- }
- _publish(T_LED_BL_STATE, ujson.dumps(state), retain=True)
- info(f"Backlight → {color_hex} @ {brightness}%")
+
+ if topic == gt["set"]:
+ g = gauges[i]
+ try:
+ gauge_targets[i] = max(g["min"], min(g["max"], float(payload)))
+ info(f"Gauge {i} target → {gauge_targets[i]:.1f}")
+ except ValueError:
+ warn(f"Invalid set value for gauge {i}: '{payload}'")
+ return
+
+ if topic == T_ZERO:
+ for i, g in enumerate(gauge_objects):
+ info(f"Zeroing all gauges")
+ g.zero()
+ gauge_last_rezero[i] = utime.ticks_ms()
+ info("All gauges zeroed")
return
- if topic == T_SET:
- global _target_value
- try:
- _target_value = max(GAUGE_MIN, min(GAUGE_MAX, float(payload)))
- info(f"New target → {_target_value:.1f}")
- except ValueError:
- warn(f"Invalid set value: '{payload}'")
+ for i, gt in enumerate(gauge_topics):
+ if topic == gt["led_red"]:
+ state = payload.upper() == "ON"
+ leds_red[i].value(1 if state else 0)
+ _publish(gt["led_red_state"], "ON" if state else "OFF", retain=True)
+ info(f"Gauge {i} red LED → {'ON' if state else 'OFF'}")
+ return
+
+ if topic == gt["led_green"]:
+ state = payload.upper() == "ON"
+ leds_green[i].value(1 if state else 0)
+ _publish(gt["led_green_state"], "ON" if state else "OFF", retain=True)
+ info(f"Gauge {i} green LED → {'ON' if state else 'OFF'}")
+ return
+
+ if topic == gt["led_bl"]:
+ try:
+ data = ujson.loads(payload)
+ if data.get("state", "ON").upper() == "OFF":
+ set_backlight_brightness(i, 0)
+ _publish(
+ gt["led_bl_state"], ujson.dumps({"state": "OFF"}), retain=True
+ )
+ info(f"Gauge {i} backlight → OFF")
+ return
+ color = data.get("color", {})
+ r = max(0, min(255, int(color.get("r", backlight_color[i][0]))))
+ g = max(0, min(255, int(color.get("g", backlight_color[i][1]))))
+ b = max(0, min(255, int(color.get("b", backlight_color[i][2]))))
+ raw_br = data.get("brightness", None)
+ if raw_br is not None:
+ brightness = max(0, min(100, round(int(raw_br) / 2.55)))
+ elif backlight_brightness[i] > 0:
+ brightness = backlight_brightness[i]
+ else:
+ brightness = 100
+ except Exception as e:
+ warn(f"Invalid backlight payload for gauge {i}: '{payload}' ({e})")
+ return
+ set_backlight_color(i, r, g, b, brightness)
+ state = {
+ "state": "ON",
+ "color_mode": "rgb",
+ "brightness": int(brightness * 2.55),
+ "color": {"r": r, "g": g, "b": b},
+ }
+ _publish(gt["led_bl_state"], ujson.dumps(state), retain=True)
+ info(f"Gauge {i} backlight → #{r:02x}{g:02x}{b:02x} @ {brightness}%")
+ return
# ---------------------------------------------------------------------------
@@ -425,9 +536,12 @@ def connect_mqtt():
client_ref = client
client.subscribe(T_SET)
client.subscribe(T_ZERO)
- client.subscribe(T_LED_RED)
- client.subscribe(T_LED_GREEN)
- client.subscribe(T_LED_BL)
+ for gt in gauge_topics:
+ client.subscribe(gt["set"])
+ client.subscribe(gt["zero"])
+ client.subscribe(gt["led_red"])
+ client.subscribe(gt["led_green"])
+ client.subscribe(gt["led_bl"])
_mqtt_connected = True
info(f"MQTT connected client_id={MQTT_CLIENT_ID}")
return client
@@ -472,9 +586,12 @@ def check_mqtt():
client_ref.connect()
client_ref.subscribe(T_SET)
client_ref.subscribe(T_ZERO)
- client_ref.subscribe(T_LED_RED)
- client_ref.subscribe(T_LED_GREEN)
- client_ref.subscribe(T_LED_BL)
+ for gt in gauge_topics:
+ client_ref.subscribe(gt["set"])
+ client_ref.subscribe(gt["zero"])
+ client_ref.subscribe(gt["led_red"])
+ client_ref.subscribe(gt["led_green"])
+ client_ref.subscribe(gt["led_bl"])
_mqtt_connected = True
info("MQTT reconnected!")
publish_discovery(client_ref)
@@ -489,94 +606,104 @@ def check_mqtt():
def publish_discovery(client):
- """Publish all HA MQTT discovery payloads using short-form keys to stay under 512 bytes."""
- # Full device block only on first payload; subsequent use identifiers-only ref
- _dev_ref = {"identifiers": [MQTT_CLIENT_ID]}
+ """Publish all HA MQTT discovery payloads for gauges and LEDs."""
+ _dev_ref = {
+ "identifiers": [MQTT_CLIENT_ID],
+ "name": DEVICE_NAME,
+ "model": DEVICE_MODEL,
+ "manufacturer": DEVICE_MFR,
+ "suggested_area": DEVICE_AREA,
+ }
- client.publish(
- T_DISC_GAUGE,
- ujson.dumps(
- {
- "name": GAUGE_ENTITY,
- "unique_id": MQTT_CLIENT_ID,
- "cmd_t": T_SET,
- "stat_t": T_STATE,
- "avty_t": T_STATUS,
- "min": GAUGE_MIN,
- "max": GAUGE_MAX,
- "step": 1,
- "unit_of_meas": GAUGE_UNIT,
- "icon": "mdi:gauge",
- "dev": _DEVICE,
- }
- ),
- retain=True,
- )
- info("Discovery: gauge")
+ for i, g in enumerate(gauges):
+ gt = gauge_topics[i]
- client.publish(
- T_DISC_RED,
- ujson.dumps(
- {
- "name": RED_ENTITY,
- "uniq_id": f"{MQTT_CLIENT_ID}_led_red",
- "cmd_t": T_LED_RED,
- "stat_t": T_LED_RED_STATE,
- "pl_on": "ON",
- "pl_off": "OFF",
- "icon": "mdi:led-on",
- "dev": _dev_ref,
- "ret": True,
- }
- ),
- retain=True,
- )
- info("Discovery: red LED")
+ client.publish(
+ gt["disc"],
+ ujson.dumps(
+ {
+ "name": g["entity_name"],
+ "unique_id": f"{MQTT_CLIENT_ID}_g{i}",
+ "cmd_t": gt["set"],
+ "stat_t": gt["state"],
+ "avty_t": gt["status"],
+ "min": g["min"],
+ "max": g["max"],
+ "step": 1,
+ "unit_of_meas": g["unit"],
+ "icon": "mdi:gauge",
+ "dev": _dev_ref,
+ }
+ ),
+ retain=True,
+ )
+ info(f"Discovery: gauge {i} ({g['name']})")
- client.publish(
- T_DISC_GREEN,
- ujson.dumps(
- {
- "name": GREEN_ENTITY,
- "uniq_id": f"{MQTT_CLIENT_ID}_led_green",
- "cmd_t": T_LED_GREEN,
- "stat_t": T_LED_GREEN_STATE,
- "pl_on": "ON",
- "pl_off": "OFF",
- "icon": "mdi:led-on",
- "dev": _dev_ref,
- "ret": True,
- }
- ),
- retain=True,
- )
- info("Discovery: green LED")
+ client.publish(
+ gt["led_red_disc"],
+ ujson.dumps(
+ {
+ "name": f"{g['name']} Red LED",
+ "uniq_id": f"{MQTT_CLIENT_ID}_g{i}_red",
+ "cmd_t": gt["led_red"],
+ "stat_t": gt["led_red_state"],
+ "pl_on": "ON",
+ "pl_off": "OFF",
+ "icon": "mdi:led-on",
+ "dev": _dev_ref,
+ "ret": True,
+ }
+ ),
+ retain=True,
+ )
+ info(f"Discovery: gauge {i} red LED")
- client.publish(
- T_DISC_BL,
- ujson.dumps(
- {
- "name": BL_ENTITY,
- "uniq_id": f"{MQTT_CLIENT_ID}_led_bl",
- "cmd_t": T_LED_BL,
- "stat_t": T_LED_BL_STATE,
- "schema": "json",
- "supported_color_modes": ["rgb"],
- "icon": "mdi:led-strip",
- "dev": _dev_ref,
- "ret": True,
- }
- ),
- retain=True,
- )
- info("Discovery: backlight")
+ client.publish(
+ gt["led_green_disc"],
+ ujson.dumps(
+ {
+ "name": f"{g['name']} Green LED",
+ "uniq_id": f"{MQTT_CLIENT_ID}_g{i}_green",
+ "cmd_t": gt["led_green"],
+ "stat_t": gt["led_green_state"],
+ "pl_on": "ON",
+ "pl_off": "OFF",
+ "icon": "mdi:led-on",
+ "dev": _dev_ref,
+ "ret": True,
+ }
+ ),
+ retain=True,
+ )
+ info(f"Discovery: gauge {i} green LED")
+
+ client.publish(
+ gt["led_bl_disc"],
+ ujson.dumps(
+ {
+ "name": f"{g['name']} Backlight",
+ "uniq_id": f"{MQTT_CLIENT_ID}_g{i}_bl",
+ "cmd_t": gt["led_bl"],
+ "stat_t": gt["led_bl_state"],
+ "schema": "json",
+ "supported_color_modes": ["rgb"],
+ "icon": "mdi:led-strip",
+ "dev": _dev_ref,
+ "ret": True,
+ }
+ ),
+ retain=True,
+ )
+ info(f"Discovery: gauge {i} backlight")
def publish_state(client):
- val = gauge.get()
- client.publish(T_STATE, str(round(val, 1)), retain=True)
- client.publish(T_STATUS, "online", retain=True)
- info(f"State published value={val:.1f} step={gauge._current_step}")
+ for i, g in enumerate(gauge_objects):
+ gt = gauge_topics[i]
+ val = g.get()
+ client.publish(gt["state"], str(round(val, 1)), retain=True)
+ client.publish(gt["status"], "online", retain=True)
+ info(f"Gauge {i} state: {val:.1f} step={g._current_step}")
# ---------------------------------------------------------------------------
@@ -591,11 +718,12 @@ def main():
connect_wifi(WIFI_SSID, WIFI_PASSWORD)
- info("Zeroing gauge on startup ...")
- gauge.zero()
+ info("Zeroing gauges on startup ...")
+ for i, g in enumerate(gauge_objects):
+ g.zero()
+ info(f"Zeroed gauge {i}")
info("Zero complete")
- # umqtt.robust handles reconnection automatically — just connect once
connect_mqtt()
publish_discovery(client_ref)
publish_state(client_ref)
@@ -611,15 +739,8 @@ def main():
except ImportError:
pass
- global _last_rezero_ms, _bl_dirty_since
+ global _bl_dirty_since
last_heartbeat = utime.ticks_ms()
- _last_rezero_ms = utime.ticks_ms()
-
- target_step = gauge._val_to_step(_target_value)
-
- # Period at which to publish state updates during movement
- MOVE_STATE_INTERVAL_MS = 500
- last_move_state = utime.ticks_ms()
while True:
try:
@@ -633,45 +754,35 @@ def main():
now = utime.ticks_ms()
- # Continuously move towards target at constant speed
- current_target = gauge._val_to_step(_target_value)
- moved = False
- if current_target != gauge._current_step:
- direction = 1 if current_target > gauge._current_step else -1
- gauge.step(direction)
- moved = True
+ moved_any = False
+ for i, g in enumerate(gauge_objects):
+ current_target = g._val_to_step(gauge_targets[i])
+ if current_target != g._current_step:
+ direction = 1 if current_target > g._current_step else -1
+ steps_to_move = current_target - g._current_step
+ steps_to_move = max(-5, min(5, steps_to_move))
+ for _ in range(abs(steps_to_move)):
+ g.step(direction)
+ moved_any = True
- # Publish state during movement at intervals
- if (
- moved
- and utime.ticks_diff(now, last_move_state) >= MOVE_STATE_INTERVAL_MS
- ):
- publish_state(client_ref)
- last_move_state = now
-
- # Sleep to achieve constant speed
- if moved or (
- current_target == gauge._current_step
- and gauge._current_step != gauge._val_to_step(_target_value)
- ):
+ if moved_any:
delay_us = 1_000_000 // MICROSTEPS_PER_SECOND
utime.sleep_us(delay_us)
- # Periodic auto-rezero (disabled when interval is 0)
if (
REZERO_INTERVAL_MS > 0
- and utime.ticks_diff(now, _last_rezero_ms) >= REZERO_INTERVAL_MS
+ and utime.ticks_diff(now, gauge_last_rezero[0]) >= REZERO_INTERVAL_MS
):
- info("Auto-rezero triggered")
- saved = _target_value
- gauge.zero()
- if saved > GAUGE_MIN:
- gauge.set(saved)
+ for i, g in enumerate(gauge_objects):
+ info(f"Auto-rezero gauge {i}")
+ saved = gauge_targets[i]
+ g.zero()
+ if saved > gauges[i]["min"]:
+ g.set(saved)
+ gauge_last_rezero[i] = now
publish_state(client_ref)
- _last_rezero_ms = now
- info(f"Auto-rezero complete, restored to {saved:.1f}")
+ info("Auto-rezero complete")
- # Retain backlight state via MQTT after settling
if (
_bl_dirty_since is not None
and utime.ticks_diff(now, _bl_dirty_since) >= _BL_SAVE_DELAY_MS
@@ -679,12 +790,8 @@ def main():
_flush_backlight(client_ref)
_bl_dirty_since = None
- # Heartbeat
if utime.ticks_diff(now, last_heartbeat) >= HEARTBEAT_MS:
publish_state(client_ref)
- info(
- f"step={gauge._current_step} phase={gauge._phase} target_step={gauge._val_to_step(_target_value)} expected_phase={gauge._current_step % 4}"
- )
last_heartbeat = now
except Exception as e: