Compare commits

...

41 commits

Author SHA1 Message Date
25210fd400 fix div 0 when expected size is 0. fix expected size 0 reading 2025-04-10 19:24:25 +02:00
681e33b355 optimize rc control 2024-09-22 19:03:46 +02:00
67f0a2cf7e add schematic pdf 2024-09-21 23:24:29 +02:00
2135cba000 add cad files brake and teensy 2024-09-21 22:51:53 +02:00
2868ab0bd2 add remote control ppm input 2024-09-21 22:10:51 +02:00
5a1734f181 decrease freewheel breaking 2024-08-27 08:13:17 +02:00
f09919ca62 add deletion flag and verification 2024-07-22 14:57:18 +02:00
f3775e7d01 minor changes 2024-07-22 14:30:18 +02:00
186bfbcf99 update for wheelcircumference correction 2024-07-22 14:29:55 +02:00
e20a3eb040 recalibrate throttle and minor display fixes 2024-07-22 14:29:36 +02:00
b3ab5841a7 remove first and last values of travel 2024-07-22 10:55:36 +02:00
a575fb009d recalibrate throttle lever 2024-07-22 10:50:00 +02:00
4ef6e7448b fix tank steering in standstill 2024-07-20 01:56:48 +02:00
7734c41809 fix warning in print function 2024-07-19 22:57:12 +02:00
07d6aa5e3e add minvoltage and voltage to display 2024-07-17 00:02:48 +02:00
890daa9702 use pandas csv reader and use subplots 2024-07-16 23:51:28 +02:00
a68df6afab change led gauge min voltage to 3.3V 2024-07-16 23:49:45 +02:00
16dfabc6ba fix logging file first row zero values 2024-07-16 23:47:58 +02:00
e31ccb1813 add name main check 2024-07-16 22:36:28 +02:00
64bd6f79f5 change tanksteering and add standstill tanksteering 2024-07-16 22:34:54 +02:00
24a5a97cfb add automatic consecuitve filename adding 2024-07-15 19:24:19 +02:00
3c5cd0b1c3 fix tank steering safety check 2024-07-14 16:46:33 +02:00
156455f363 improve disable logging check and add experimental tanksteering 2024-07-14 12:30:20 +02:00
a8d43211e9 add slow acceleration in slower modes 2024-07-14 11:12:08 +02:00
2e557af21f refactor temperature sensor variable 2024-07-14 10:54:49 +02:00
8a3fdaa574 Update controller_teensy/README.md 2024-07-14 08:39:58 +00:00
8ebfef2df4 Update controller_teensy/README.md 2024-07-14 08:39:12 +00:00
b2245f83f6 add command documentation 2024-07-14 10:34:29 +02:00
e11ec8c5f5 project file update 2024-07-13 23:40:53 +02:00
b416250d47 add transmission protocol for sd card over serial 2024-07-13 23:34:14 +02:00
b68bc580cc fix debug output 2024-07-13 21:16:57 +02:00
abdff38ae4 change display ui 2024-07-13 20:58:27 +02:00
f5cfe91fcb add sensor serial command 2024-07-13 19:19:10 +02:00
71e9fd7d4f add logging disabled when connected via usb 2024-07-13 18:18:58 +02:00
7b757c3c0b change fit for spring plate 2024-07-13 17:26:08 +02:00
ff8c11eb1b add sd card read and delete commands 2024-07-13 01:30:20 +02:00
841ab4f7e9 add gitignore 2024-07-12 23:51:12 +02:00
ec9e9f09ee add start button debug display output 2024-07-12 21:44:40 +02:00
9c1fd5f7dd change led pin to match pcb 2024-07-12 19:57:43 +02:00
e023b45118 move 1wire pullup resistor to pcb 2024-07-12 19:37:27 +02:00
80c83c45b9 change comments 2024-07-10 00:32:53 +02:00
27 changed files with 76410 additions and 48368 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
logdata_visualization/logs/*
*.sync-conflict*
*.FCStd1

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,353 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('FreeCAD Model'),'2;1');
FILE_NAME('Open CASCADE Shape Model','2024-07-20T11:24:02',('Author'),(
''),'Open CASCADE STEP processor 7.7','FreeCAD','Unknown');
FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));
ENDSEC;
DATA;
#1 = APPLICATION_PROTOCOL_DEFINITION('international standard',
'automotive_design',2000,#2);
#2 = APPLICATION_CONTEXT(
'core data for automotive mechanical design processes');
#3 = SHAPE_DEFINITION_REPRESENTATION(#4,#10);
#4 = PRODUCT_DEFINITION_SHAPE('','',#5);
#5 = PRODUCT_DEFINITION('design','',#6,#9);
#6 = PRODUCT_DEFINITION_FORMATION('','',#7);
#7 = PRODUCT('Body','Body','',(#8));
#8 = PRODUCT_CONTEXT('',#2,'mechanical');
#9 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
#10 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#15),#313);
#11 = AXIS2_PLACEMENT_3D('',#12,#13,#14);
#12 = CARTESIAN_POINT('',(0.,0.,0.));
#13 = DIRECTION('',(0.,0.,1.));
#14 = DIRECTION('',(1.,0.,-0.));
#15 = MANIFOLD_SOLID_BREP('',#16);
#16 = CLOSED_SHELL('',(#17,#50,#75,#95,#115,#140,#165,#185,#210,#235,
#253,#278,#304));
#17 = ADVANCED_FACE('',(#18),#45,.T.);
#18 = FACE_BOUND('',#19,.F.);
#19 = EDGE_LOOP('',(#20,#30,#37,#38));
#20 = ORIENTED_EDGE('',*,*,#21,.T.);
#21 = EDGE_CURVE('',#22,#24,#26,.T.);
#22 = VERTEX_POINT('',#23);
#23 = CARTESIAN_POINT('',(4.,2.22044604925E-15,-10.));
#24 = VERTEX_POINT('',#25);
#25 = CARTESIAN_POINT('',(4.,0.,0.));
#26 = LINE('',#27,#28);
#27 = CARTESIAN_POINT('',(4.,2.331468351713E-15,-10.5));
#28 = VECTOR('',#29,1.);
#29 = DIRECTION('',(0.,-2.22044604925E-16,1.));
#30 = ORIENTED_EDGE('',*,*,#31,.F.);
#31 = EDGE_CURVE('',#24,#24,#32,.T.);
#32 = CIRCLE('',#33,4.);
#33 = AXIS2_PLACEMENT_3D('',#34,#35,#36);
#34 = CARTESIAN_POINT('',(0.,0.,0.));
#35 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#36 = DIRECTION('',(1.,0.,0.));
#37 = ORIENTED_EDGE('',*,*,#21,.F.);
#38 = ORIENTED_EDGE('',*,*,#39,.T.);
#39 = EDGE_CURVE('',#22,#22,#40,.T.);
#40 = CIRCLE('',#41,4.);
#41 = AXIS2_PLACEMENT_3D('',#42,#43,#44);
#42 = CARTESIAN_POINT('',(0.,2.22044604925E-15,-10.));
#43 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#44 = DIRECTION('',(1.,0.,0.));
#45 = CYLINDRICAL_SURFACE('',#46,4.);
#46 = AXIS2_PLACEMENT_3D('',#47,#48,#49);
#47 = CARTESIAN_POINT('',(0.,2.331468351713E-15,-10.5));
#48 = DIRECTION('',(0.,-2.22044604925E-16,1.));
#49 = DIRECTION('',(1.,0.,0.));
#50 = ADVANCED_FACE('',(#51),#70,.T.);
#51 = FACE_BOUND('',#52,.T.);
#52 = EDGE_LOOP('',(#53,#61,#62,#63));
#53 = ORIENTED_EDGE('',*,*,#54,.F.);
#54 = EDGE_CURVE('',#22,#55,#57,.T.);
#55 = VERTEX_POINT('',#56);
#56 = CARTESIAN_POINT('',(3.5,2.331468351713E-15,-10.5));
#57 = LINE('',#58,#59);
#58 = CARTESIAN_POINT('',(4.,2.22044604925E-15,-10.));
#59 = VECTOR('',#60,1.);
#60 = DIRECTION('',(-0.707106781187,1.570092458684E-16,-0.707106781187)
);
#61 = ORIENTED_EDGE('',*,*,#39,.T.);
#62 = ORIENTED_EDGE('',*,*,#54,.T.);
#63 = ORIENTED_EDGE('',*,*,#64,.F.);
#64 = EDGE_CURVE('',#55,#55,#65,.T.);
#65 = CIRCLE('',#66,3.5);
#66 = AXIS2_PLACEMENT_3D('',#67,#68,#69);
#67 = CARTESIAN_POINT('',(0.,2.331468351713E-15,-10.5));
#68 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#69 = DIRECTION('',(1.,0.,0.));
#70 = CONICAL_SURFACE('',#71,4.,0.785398163397);
#71 = AXIS2_PLACEMENT_3D('',#72,#73,#74);
#72 = CARTESIAN_POINT('',(0.,2.22044604925E-15,-10.));
#73 = DIRECTION('',(-0.,-2.22044604925E-16,1.));
#74 = DIRECTION('',(1.,0.,0.));
#75 = ADVANCED_FACE('',(#76,#79),#90,.T.);
#76 = FACE_BOUND('',#77,.F.);
#77 = EDGE_LOOP('',(#78));
#78 = ORIENTED_EDGE('',*,*,#31,.T.);
#79 = FACE_BOUND('',#80,.F.);
#80 = EDGE_LOOP('',(#81));
#81 = ORIENTED_EDGE('',*,*,#82,.F.);
#82 = EDGE_CURVE('',#83,#83,#85,.T.);
#83 = VERTEX_POINT('',#84);
#84 = CARTESIAN_POINT('',(5.25,0.,0.));
#85 = CIRCLE('',#86,5.25);
#86 = AXIS2_PLACEMENT_3D('',#87,#88,#89);
#87 = CARTESIAN_POINT('',(0.,0.,0.));
#88 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#89 = DIRECTION('',(1.,0.,0.));
#90 = PLANE('',#91);
#91 = AXIS2_PLACEMENT_3D('',#92,#93,#94);
#92 = CARTESIAN_POINT('',(0.,0.,0.));
#93 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#94 = DIRECTION('',(1.,0.,0.));
#95 = ADVANCED_FACE('',(#96,#99),#110,.T.);
#96 = FACE_BOUND('',#97,.T.);
#97 = EDGE_LOOP('',(#98));
#98 = ORIENTED_EDGE('',*,*,#64,.T.);
#99 = FACE_BOUND('',#100,.T.);
#100 = EDGE_LOOP('',(#101));
#101 = ORIENTED_EDGE('',*,*,#102,.F.);
#102 = EDGE_CURVE('',#103,#103,#105,.T.);
#103 = VERTEX_POINT('',#104);
#104 = CARTESIAN_POINT('',(1.7,2.331468351713E-15,-10.5));
#105 = CIRCLE('',#106,1.7);
#106 = AXIS2_PLACEMENT_3D('',#107,#108,#109);
#107 = CARTESIAN_POINT('',(0.,2.331468351713E-15,-10.5));
#108 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#109 = DIRECTION('',(1.,0.,0.));
#110 = PLANE('',#111);
#111 = AXIS2_PLACEMENT_3D('',#112,#113,#114);
#112 = CARTESIAN_POINT('',(0.,2.331468351713E-15,-10.5));
#113 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#114 = DIRECTION('',(1.,0.,0.));
#115 = ADVANCED_FACE('',(#116),#135,.F.);
#116 = FACE_BOUND('',#117,.F.);
#117 = EDGE_LOOP('',(#118,#119,#127,#134));
#118 = ORIENTED_EDGE('',*,*,#82,.T.);
#119 = ORIENTED_EDGE('',*,*,#120,.T.);
#120 = EDGE_CURVE('',#83,#121,#123,.T.);
#121 = VERTEX_POINT('',#122);
#122 = CARTESIAN_POINT('',(5.25,6.661338147751E-16,-3.));
#123 = LINE('',#124,#125);
#124 = CARTESIAN_POINT('',(5.25,0.,0.));
#125 = VECTOR('',#126,1.);
#126 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#127 = ORIENTED_EDGE('',*,*,#128,.F.);
#128 = EDGE_CURVE('',#121,#121,#129,.T.);
#129 = CIRCLE('',#130,5.25);
#130 = AXIS2_PLACEMENT_3D('',#131,#132,#133);
#131 = CARTESIAN_POINT('',(0.,6.661338147751E-16,-3.));
#132 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#133 = DIRECTION('',(1.,0.,0.));
#134 = ORIENTED_EDGE('',*,*,#120,.F.);
#135 = CYLINDRICAL_SURFACE('',#136,5.25);
#136 = AXIS2_PLACEMENT_3D('',#137,#138,#139);
#137 = CARTESIAN_POINT('',(0.,0.,0.));
#138 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#139 = DIRECTION('',(1.,0.,0.));
#140 = ADVANCED_FACE('',(#141),#160,.F.);
#141 = FACE_BOUND('',#142,.T.);
#142 = EDGE_LOOP('',(#143,#144,#152,#159));
#143 = ORIENTED_EDGE('',*,*,#102,.T.);
#144 = ORIENTED_EDGE('',*,*,#145,.T.);
#145 = EDGE_CURVE('',#103,#146,#148,.T.);
#146 = VERTEX_POINT('',#147);
#147 = CARTESIAN_POINT('',(1.2,2.22044604925E-15,-10.));
#148 = LINE('',#149,#150);
#149 = CARTESIAN_POINT('',(1.7,2.331468351713E-15,-10.5));
#150 = VECTOR('',#151,1.);
#151 = DIRECTION('',(-0.707106781187,-1.570092458684E-16,0.707106781187)
);
#152 = ORIENTED_EDGE('',*,*,#153,.F.);
#153 = EDGE_CURVE('',#146,#146,#154,.T.);
#154 = CIRCLE('',#155,1.2);
#155 = AXIS2_PLACEMENT_3D('',#156,#157,#158);
#156 = CARTESIAN_POINT('',(0.,2.22044604925E-15,-10.));
#157 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#158 = DIRECTION('',(1.,0.,0.));
#159 = ORIENTED_EDGE('',*,*,#145,.F.);
#160 = CONICAL_SURFACE('',#161,1.7,0.785398163397);
#161 = AXIS2_PLACEMENT_3D('',#162,#163,#164);
#162 = CARTESIAN_POINT('',(0.,2.331468351713E-15,-10.5));
#163 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#164 = DIRECTION('',(1.,0.,0.));
#165 = ADVANCED_FACE('',(#166,#169),#180,.T.);
#166 = FACE_BOUND('',#167,.F.);
#167 = EDGE_LOOP('',(#168));
#168 = ORIENTED_EDGE('',*,*,#128,.T.);
#169 = FACE_BOUND('',#170,.F.);
#170 = EDGE_LOOP('',(#171));
#171 = ORIENTED_EDGE('',*,*,#172,.F.);
#172 = EDGE_CURVE('',#173,#173,#175,.T.);
#173 = VERTEX_POINT('',#174);
#174 = CARTESIAN_POINT('',(5.45,6.661338147751E-16,-3.));
#175 = CIRCLE('',#176,5.45);
#176 = AXIS2_PLACEMENT_3D('',#177,#178,#179);
#177 = CARTESIAN_POINT('',(0.,6.661338147751E-16,-3.));
#178 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#179 = DIRECTION('',(1.,0.,0.));
#180 = PLANE('',#181);
#181 = AXIS2_PLACEMENT_3D('',#182,#183,#184);
#182 = CARTESIAN_POINT('',(0.,6.661338147751E-16,-3.));
#183 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#184 = DIRECTION('',(1.,0.,0.));
#185 = ADVANCED_FACE('',(#186),#205,.F.);
#186 = FACE_BOUND('',#187,.T.);
#187 = EDGE_LOOP('',(#188,#189,#197,#204));
#188 = ORIENTED_EDGE('',*,*,#153,.T.);
#189 = ORIENTED_EDGE('',*,*,#190,.T.);
#190 = EDGE_CURVE('',#146,#191,#193,.T.);
#191 = VERTEX_POINT('',#192);
#192 = CARTESIAN_POINT('',(1.2,1.443289932013E-15,-6.5));
#193 = LINE('',#194,#195);
#194 = CARTESIAN_POINT('',(1.2,2.22044604925E-15,-10.));
#195 = VECTOR('',#196,1.);
#196 = DIRECTION('',(0.,-2.22044604925E-16,1.));
#197 = ORIENTED_EDGE('',*,*,#198,.F.);
#198 = EDGE_CURVE('',#191,#191,#199,.T.);
#199 = CIRCLE('',#200,1.2);
#200 = AXIS2_PLACEMENT_3D('',#201,#202,#203);
#201 = CARTESIAN_POINT('',(0.,1.443289932013E-15,-6.5));
#202 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#203 = DIRECTION('',(1.,0.,0.));
#204 = ORIENTED_EDGE('',*,*,#190,.F.);
#205 = CYLINDRICAL_SURFACE('',#206,1.2);
#206 = AXIS2_PLACEMENT_3D('',#207,#208,#209);
#207 = CARTESIAN_POINT('',(0.,2.22044604925E-15,-10.));
#208 = DIRECTION('',(0.,-2.22044604925E-16,1.));
#209 = DIRECTION('',(1.,0.,0.));
#210 = ADVANCED_FACE('',(#211),#230,.T.);
#211 = FACE_BOUND('',#212,.F.);
#212 = EDGE_LOOP('',(#213,#214,#222,#229));
#213 = ORIENTED_EDGE('',*,*,#172,.T.);
#214 = ORIENTED_EDGE('',*,*,#215,.T.);
#215 = EDGE_CURVE('',#173,#216,#218,.T.);
#216 = VERTEX_POINT('',#217);
#217 = CARTESIAN_POINT('',(6.25,4.440892098501E-16,-2.));
#218 = LINE('',#219,#220);
#219 = CARTESIAN_POINT('',(5.45,6.661338147751E-16,-3.));
#220 = VECTOR('',#221,1.);
#221 = DIRECTION('',(0.624695047554,-1.733877062911E-16,0.780868809443)
);
#222 = ORIENTED_EDGE('',*,*,#223,.F.);
#223 = EDGE_CURVE('',#216,#216,#224,.T.);
#224 = CIRCLE('',#225,6.25);
#225 = AXIS2_PLACEMENT_3D('',#226,#227,#228);
#226 = CARTESIAN_POINT('',(0.,4.440892098501E-16,-2.));
#227 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#228 = DIRECTION('',(1.,0.,0.));
#229 = ORIENTED_EDGE('',*,*,#215,.F.);
#230 = CONICAL_SURFACE('',#231,5.45,0.674740942224);
#231 = AXIS2_PLACEMENT_3D('',#232,#233,#234);
#232 = CARTESIAN_POINT('',(0.,6.661338147751E-16,-3.));
#233 = DIRECTION('',(0.,-2.22044604925E-16,1.));
#234 = DIRECTION('',(1.,0.,0.));
#235 = ADVANCED_FACE('',(#236),#248,.F.);
#236 = FACE_BOUND('',#237,.T.);
#237 = EDGE_LOOP('',(#238,#239,#247));
#238 = ORIENTED_EDGE('',*,*,#198,.T.);
#239 = ORIENTED_EDGE('',*,*,#240,.T.);
#240 = EDGE_CURVE('',#191,#241,#243,.T.);
#241 = VERTEX_POINT('',#242);
#242 = CARTESIAN_POINT('',(0.,1.33226762955E-15,-6.));
#243 = LINE('',#244,#245);
#244 = CARTESIAN_POINT('',(1.2,1.443289932013E-15,-6.5));
#245 = VECTOR('',#246,1.);
#246 = DIRECTION('',(-0.923076923077,-8.540177112501E-17,0.384615384615)
);
#247 = ORIENTED_EDGE('',*,*,#240,.F.);
#248 = CONICAL_SURFACE('',#249,1.2,1.176005207095);
#249 = AXIS2_PLACEMENT_3D('',#250,#251,#252);
#250 = CARTESIAN_POINT('',(0.,1.443289932013E-15,-6.5));
#251 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#252 = DIRECTION('',(1.,0.,0.));
#253 = ADVANCED_FACE('',(#254),#273,.T.);
#254 = FACE_BOUND('',#255,.F.);
#255 = EDGE_LOOP('',(#256,#257,#265,#272));
#256 = ORIENTED_EDGE('',*,*,#223,.T.);
#257 = ORIENTED_EDGE('',*,*,#258,.T.);
#258 = EDGE_CURVE('',#216,#259,#261,.T.);
#259 = VERTEX_POINT('',#260);
#260 = CARTESIAN_POINT('',(6.25,-1.110223024625E-16,0.5));
#261 = LINE('',#262,#263);
#262 = CARTESIAN_POINT('',(6.25,4.440892098501E-16,-2.));
#263 = VECTOR('',#264,1.);
#264 = DIRECTION('',(0.,-2.22044604925E-16,1.));
#265 = ORIENTED_EDGE('',*,*,#266,.F.);
#266 = EDGE_CURVE('',#259,#259,#267,.T.);
#267 = CIRCLE('',#268,6.25);
#268 = AXIS2_PLACEMENT_3D('',#269,#270,#271);
#269 = CARTESIAN_POINT('',(0.,-1.110223024625E-16,0.5));
#270 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#271 = DIRECTION('',(1.,0.,0.));
#272 = ORIENTED_EDGE('',*,*,#258,.F.);
#273 = CYLINDRICAL_SURFACE('',#274,6.25);
#274 = AXIS2_PLACEMENT_3D('',#275,#276,#277);
#275 = CARTESIAN_POINT('',(0.,4.440892098501E-16,-2.));
#276 = DIRECTION('',(0.,-2.22044604925E-16,1.));
#277 = DIRECTION('',(1.,0.,0.));
#278 = ADVANCED_FACE('',(#279),#299,.T.);
#279 = FACE_BOUND('',#280,.F.);
#280 = EDGE_LOOP('',(#281,#282,#291,#298));
#281 = ORIENTED_EDGE('',*,*,#266,.T.);
#282 = ORIENTED_EDGE('',*,*,#283,.T.);
#283 = EDGE_CURVE('',#259,#284,#286,.T.);
#284 = VERTEX_POINT('',#285);
#285 = CARTESIAN_POINT('',(4.75,-4.440892098501E-16,2.));
#286 = CIRCLE('',#287,1.5);
#287 = AXIS2_PLACEMENT_3D('',#288,#289,#290);
#288 = CARTESIAN_POINT('',(4.75,-1.110223024625E-16,0.5));
#289 = DIRECTION('',(0.,-1.,-2.22044604925E-16));
#290 = DIRECTION('',(1.,0.,0.));
#291 = ORIENTED_EDGE('',*,*,#292,.F.);
#292 = EDGE_CURVE('',#284,#284,#293,.T.);
#293 = CIRCLE('',#294,4.75);
#294 = AXIS2_PLACEMENT_3D('',#295,#296,#297);
#295 = CARTESIAN_POINT('',(0.,-4.440892098501E-16,2.));
#296 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#297 = DIRECTION('',(1.,0.,0.));
#298 = ORIENTED_EDGE('',*,*,#283,.F.);
#299 = TOROIDAL_SURFACE('',#300,4.75,1.5);
#300 = AXIS2_PLACEMENT_3D('',#301,#302,#303);
#301 = CARTESIAN_POINT('',(0.,-1.110223024625E-16,0.5));
#302 = DIRECTION('',(0.,-2.22044604925E-16,1.));
#303 = DIRECTION('',(1.,0.,0.));
#304 = ADVANCED_FACE('',(#305),#308,.F.);
#305 = FACE_BOUND('',#306,.T.);
#306 = EDGE_LOOP('',(#307));
#307 = ORIENTED_EDGE('',*,*,#292,.F.);
#308 = PLANE('',#309);
#309 = AXIS2_PLACEMENT_3D('',#310,#311,#312);
#310 = CARTESIAN_POINT('',(0.,-4.440892098501E-16,2.));
#311 = DIRECTION('',(0.,2.22044604925E-16,-1.));
#312 = DIRECTION('',(1.,0.,0.));
#313 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#317)) GLOBAL_UNIT_ASSIGNED_CONTEXT
((#314,#315,#316)) REPRESENTATION_CONTEXT('Context #1',
'3D Context with UNIT and UNCERTAINTY') );
#314 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
#315 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
#316 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
#317 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#314,
'distance_accuracy_value','confusion accuracy');
#318 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#7));
#319 = MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#320)
,#313);
#320 = STYLED_ITEM('color',(#321),#15);
#321 = PRESENTATION_STYLE_ASSIGNMENT((#322,#328));
#322 = SURFACE_STYLE_USAGE(.BOTH.,#323);
#323 = SURFACE_SIDE_STYLE('',(#324));
#324 = SURFACE_STYLE_FILL_AREA(#325);
#325 = FILL_AREA_STYLE('',(#326));
#326 = FILL_AREA_STYLE_COLOUR('',#327);
#327 = COLOUR_RGB('',0.800000010877,0.800000010877,0.800000010877);
#328 = CURVE_STYLE('',#329,POSITIVE_LENGTH_MEASURE(0.1),#330);
#329 = DRAUGHTING_PRE_DEFINED_CURVE_FONT('continuous');
#330 = COLOUR_RGB('',9.803921802644E-02,9.803921802644E-02,
9.803921802644E-02);
ENDSEC;
END-ISO-10303-21;

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,618 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('FreeCAD Model'),'2;1');
FILE_NAME('Open CASCADE Shape Model','2024-07-19T18:26:40',('Author'),(
''),'Open CASCADE STEP processor 7.7','FreeCAD','Unknown');
FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));
ENDSEC;
DATA;
#1 = APPLICATION_PROTOCOL_DEFINITION('international standard',
'automotive_design',2000,#2);
#2 = APPLICATION_CONTEXT(
'core data for automotive mechanical design processes');
#3 = SHAPE_DEFINITION_REPRESENTATION(#4,#10);
#4 = PRODUCT_DEFINITION_SHAPE('','',#5);
#5 = PRODUCT_DEFINITION('design','',#6,#9);
#6 = PRODUCT_DEFINITION_FORMATION('','',#7);
#7 = PRODUCT('clipbody','clipbody','',(#8));
#8 = PRODUCT_CONTEXT('',#2,'mechanical');
#9 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
#10 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#15),#567);
#11 = AXIS2_PLACEMENT_3D('',#12,#13,#14);
#12 = CARTESIAN_POINT('',(0.,0.,0.));
#13 = DIRECTION('',(0.,0.,1.));
#14 = DIRECTION('',(1.,0.,-0.));
#15 = MANIFOLD_SOLID_BREP('',#16);
#16 = CLOSED_SHELL('',(#17,#156,#187,#211,#236,#260,#284,#308,#333,#357,
#381,#405,#430,#454,#478,#502,#526,#543));
#17 = ADVANCED_FACE('',(#18),#151,.F.);
#18 = FACE_BOUND('',#19,.F.);
#19 = EDGE_LOOP('',(#20,#30,#38,#46,#54,#62,#70,#78,#86,#94,#102,#110,
#119,#127,#136,#144));
#20 = ORIENTED_EDGE('',*,*,#21,.F.);
#21 = EDGE_CURVE('',#22,#24,#26,.T.);
#22 = VERTEX_POINT('',#23);
#23 = CARTESIAN_POINT('',(-3.397282455353E-15,-13.,2.3));
#24 = VERTEX_POINT('',#25);
#25 = CARTESIAN_POINT('',(3.774758283726E-16,4.,2.3));
#26 = LINE('',#27,#28);
#27 = CARTESIAN_POINT('',(-3.619327060278E-15,-14.,2.3));
#28 = VECTOR('',#29,1.);
#29 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#30 = ORIENTED_EDGE('',*,*,#31,.T.);
#31 = EDGE_CURVE('',#22,#32,#34,.T.);
#32 = VERTEX_POINT('',#33);
#33 = CARTESIAN_POINT('',(-3.306598177652E-15,-13.35981560033,
1.531778720403));
#34 = LINE('',#35,#36);
#35 = CARTESIAN_POINT('',(-1.434656898377E-15,-12.66426019411,
3.016818456582));
#36 = VECTOR('',#37,1.);
#37 = DIRECTION('',(2.010812452599E-16,-0.42415539625,-0.905589421224));
#38 = ORIENTED_EDGE('',*,*,#39,.F.);
#39 = EDGE_CURVE('',#40,#32,#42,.T.);
#40 = VERTEX_POINT('',#41);
#41 = CARTESIAN_POINT('',(-2.886579864025E-15,-12.5,0.5));
#42 = LINE('',#43,#44);
#43 = CARTESIAN_POINT('',(-2.886579864025E-15,-12.5,0.5));
#44 = VECTOR('',#45,1.);
#45 = DIRECTION('',(-3.127288826259E-16,-0.640184399664,0.768221279597)
);
#46 = ORIENTED_EDGE('',*,*,#47,.F.);
#47 = EDGE_CURVE('',#48,#40,#50,.T.);
#48 = VERTEX_POINT('',#49);
#49 = CARTESIAN_POINT('',(-2.775557561563E-15,-12.,0.5));
#50 = LINE('',#51,#52);
#51 = CARTESIAN_POINT('',(-2.775557561563E-15,-12.,0.5));
#52 = VECTOR('',#53,1.);
#53 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#54 = ORIENTED_EDGE('',*,*,#55,.F.);
#55 = EDGE_CURVE('',#56,#48,#58,.T.);
#56 = VERTEX_POINT('',#57);
#57 = CARTESIAN_POINT('',(-2.997602166488E-15,-12.,1.5));
#58 = LINE('',#59,#60);
#59 = CARTESIAN_POINT('',(-2.997602166488E-15,-12.,1.5));
#60 = VECTOR('',#61,1.);
#61 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#62 = ORIENTED_EDGE('',*,*,#63,.T.);
#63 = EDGE_CURVE('',#56,#64,#66,.T.);
#64 = VERTEX_POINT('',#65);
#65 = CARTESIAN_POINT('',(4.440892098501E-16,3.5,1.5));
#66 = LINE('',#67,#68);
#67 = CARTESIAN_POINT('',(-2.997602166488E-15,-12.,1.5));
#68 = VECTOR('',#69,1.);
#69 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#70 = ORIENTED_EDGE('',*,*,#71,.T.);
#71 = EDGE_CURVE('',#64,#72,#74,.T.);
#72 = VERTEX_POINT('',#73);
#73 = CARTESIAN_POINT('',(7.771561172376E-16,3.5,-7.771561172376E-16));
#74 = LINE('',#75,#76);
#75 = CARTESIAN_POINT('',(4.440892098501E-16,3.5,1.5));
#76 = VECTOR('',#77,1.);
#77 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#78 = ORIENTED_EDGE('',*,*,#79,.T.);
#79 = EDGE_CURVE('',#72,#80,#82,.T.);
#80 = VERTEX_POINT('',#81);
#81 = CARTESIAN_POINT('',(0.,0.,0.));
#82 = LINE('',#83,#84);
#83 = CARTESIAN_POINT('',(7.771561172376E-16,3.5,-7.771561172376E-16));
#84 = VECTOR('',#85,1.);
#85 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#86 = ORIENTED_EDGE('',*,*,#87,.T.);
#87 = EDGE_CURVE('',#80,#88,#90,.T.);
#88 = VERTEX_POINT('',#89);
#89 = CARTESIAN_POINT('',(3.552713678801E-16,-3.552713678801E-16,-1.6));
#90 = LINE('',#91,#92);
#91 = CARTESIAN_POINT('',(0.,0.,0.));
#92 = VECTOR('',#93,1.);
#93 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#94 = ORIENTED_EDGE('',*,*,#95,.T.);
#95 = EDGE_CURVE('',#88,#96,#98,.T.);
#96 = VERTEX_POINT('',#97);
#97 = CARTESIAN_POINT('',(-1.86517468137E-15,-10.,-1.6));
#98 = LINE('',#99,#100);
#99 = CARTESIAN_POINT('',(3.552713678801E-16,-3.552713678801E-16,-1.6));
#100 = VECTOR('',#101,1.);
#101 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#102 = ORIENTED_EDGE('',*,*,#103,.T.);
#103 = EDGE_CURVE('',#96,#104,#106,.T.);
#104 = VERTEX_POINT('',#105);
#105 = CARTESIAN_POINT('',(-1.754152378908E-15,-10.,-2.1));
#106 = LINE('',#107,#108);
#107 = CARTESIAN_POINT('',(-1.86517468137E-15,-10.,-1.6));
#108 = VECTOR('',#109,1.);
#109 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#110 = ORIENTED_EDGE('',*,*,#111,.T.);
#111 = EDGE_CURVE('',#104,#112,#114,.T.);
#112 = VERTEX_POINT('',#113);
#113 = CARTESIAN_POINT('',(-1.310063169058E-15,-9.,-3.1));
#114 = CIRCLE('',#115,1.);
#115 = AXIS2_PLACEMENT_3D('',#116,#117,#118);
#116 = CARTESIAN_POINT('',(-2.98494965712E-16,-9.,-2.1));
#117 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#118 = DIRECTION('',(-2.775557561563E-16,0.,1.));
#119 = ORIENTED_EDGE('',*,*,#120,.T.);
#120 = EDGE_CURVE('',#112,#121,#123,.T.);
#121 = VERTEX_POINT('',#122);
#122 = CARTESIAN_POINT('',(1.576516694968E-15,4.,-3.1));
#123 = LINE('',#124,#125);
#124 = CARTESIAN_POINT('',(-1.532107773983E-15,-10.,-3.1));
#125 = VECTOR('',#126,1.);
#126 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#127 = ORIENTED_EDGE('',*,*,#128,.T.);
#128 = EDGE_CURVE('',#121,#129,#131,.T.);
#129 = VERTEX_POINT('',#130);
#130 = CARTESIAN_POINT('',(1.576516694968E-15,5.,-2.1));
#131 = CIRCLE('',#132,1.);
#132 = AXIS2_PLACEMENT_3D('',#133,#134,#135);
#133 = CARTESIAN_POINT('',(-2.98494965712E-16,4.,-2.1));
#134 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#135 = DIRECTION('',(-2.775557561563E-16,0.,1.));
#136 = ORIENTED_EDGE('',*,*,#137,.T.);
#137 = EDGE_CURVE('',#129,#138,#140,.T.);
#138 = VERTEX_POINT('',#139);
#139 = CARTESIAN_POINT('',(8.215650382226E-16,5.,1.3));
#140 = LINE('',#141,#142);
#141 = CARTESIAN_POINT('',(1.798561299893E-15,5.,-3.1));
#142 = VECTOR('',#143,1.);
#143 = DIRECTION('',(-2.22044604925E-16,2.22044604925E-16,1.));
#144 = ORIENTED_EDGE('',*,*,#145,.T.);
#145 = EDGE_CURVE('',#138,#24,#146,.T.);
#146 = CIRCLE('',#147,1.);
#147 = AXIS2_PLACEMENT_3D('',#148,#149,#150);
#148 = CARTESIAN_POINT('',(-1.053446622457E-15,4.,1.3));
#149 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#150 = DIRECTION('',(-2.775557561563E-16,0.,1.));
#151 = PLANE('',#152);
#152 = AXIS2_PLACEMENT_3D('',#153,#154,#155);
#153 = CARTESIAN_POINT('',(-7.738628142252E-16,-3.444301816353,
4.086646542781E-02));
#154 = DIRECTION('',(1.,0.,2.22044604925E-16));
#155 = DIRECTION('',(-2.22044604925E-16,0.,1.));
#156 = ADVANCED_FACE('',(#157),#182,.T.);
#157 = FACE_BOUND('',#158,.T.);
#158 = EDGE_LOOP('',(#159,#160,#168,#176));
#159 = ORIENTED_EDGE('',*,*,#21,.F.);
#160 = ORIENTED_EDGE('',*,*,#161,.T.);
#161 = EDGE_CURVE('',#22,#162,#164,.T.);
#162 = VERTEX_POINT('',#163);
#163 = CARTESIAN_POINT('',(12.,-13.,2.3));
#164 = LINE('',#165,#166);
#165 = CARTESIAN_POINT('',(-3.397282455353E-15,-13.,2.3));
#166 = VECTOR('',#167,1.);
#167 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#168 = ORIENTED_EDGE('',*,*,#169,.T.);
#169 = EDGE_CURVE('',#162,#170,#172,.T.);
#170 = VERTEX_POINT('',#171);
#171 = CARTESIAN_POINT('',(12.,4.,2.3));
#172 = LINE('',#173,#174);
#173 = CARTESIAN_POINT('',(12.,-14.,2.3));
#174 = VECTOR('',#175,1.);
#175 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#176 = ORIENTED_EDGE('',*,*,#177,.F.);
#177 = EDGE_CURVE('',#24,#170,#178,.T.);
#178 = LINE('',#179,#180);
#179 = CARTESIAN_POINT('',(3.774758283726E-16,4.,2.3));
#180 = VECTOR('',#181,1.);
#181 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#182 = PLANE('',#183);
#183 = AXIS2_PLACEMENT_3D('',#184,#185,#186);
#184 = CARTESIAN_POINT('',(-3.619327060278E-15,-14.,2.3));
#185 = DIRECTION('',(-2.775557561563E-16,2.22044604925E-16,1.));
#186 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#187 = ADVANCED_FACE('',(#188),#206,.T.);
#188 = FACE_BOUND('',#189,.F.);
#189 = EDGE_LOOP('',(#190,#191,#192,#200));
#190 = ORIENTED_EDGE('',*,*,#31,.F.);
#191 = ORIENTED_EDGE('',*,*,#161,.T.);
#192 = ORIENTED_EDGE('',*,*,#193,.T.);
#193 = EDGE_CURVE('',#162,#194,#196,.T.);
#194 = VERTEX_POINT('',#195);
#195 = CARTESIAN_POINT('',(12.,-13.35981560033,1.531778720403));
#196 = LINE('',#197,#198);
#197 = CARTESIAN_POINT('',(12.,-12.66426019411,3.016818456582));
#198 = VECTOR('',#199,1.);
#199 = DIRECTION('',(2.010812452599E-16,-0.42415539625,-0.905589421224)
);
#200 = ORIENTED_EDGE('',*,*,#201,.F.);
#201 = EDGE_CURVE('',#32,#194,#202,.T.);
#202 = LINE('',#203,#204);
#203 = CARTESIAN_POINT('',(-3.263953330021E-15,-13.35981560033,
1.531778720403));
#204 = VECTOR('',#205,1.);
#205 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#206 = PLANE('',#207);
#207 = AXIS2_PLACEMENT_3D('',#208,#209,#210);
#208 = CARTESIAN_POINT('',(-3.330617892687E-15,-13.17990780016,
1.915889360201));
#209 = DIRECTION('',(-2.785526547833E-16,-0.905589421224,0.42415539625)
);
#210 = DIRECTION('',(-1.,1.855897747597E-16,-2.604812270467E-16));
#211 = ADVANCED_FACE('',(#212),#231,.T.);
#212 = FACE_BOUND('',#213,.T.);
#213 = EDGE_LOOP('',(#214,#215,#216,#225));
#214 = ORIENTED_EDGE('',*,*,#145,.T.);
#215 = ORIENTED_EDGE('',*,*,#177,.T.);
#216 = ORIENTED_EDGE('',*,*,#217,.F.);
#217 = EDGE_CURVE('',#218,#170,#220,.T.);
#218 = VERTEX_POINT('',#219);
#219 = CARTESIAN_POINT('',(12.,5.,1.3));
#220 = CIRCLE('',#221,1.);
#221 = AXIS2_PLACEMENT_3D('',#222,#223,#224);
#222 = CARTESIAN_POINT('',(12.,4.,1.3));
#223 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#224 = DIRECTION('',(-2.775557561563E-16,0.,1.));
#225 = ORIENTED_EDGE('',*,*,#226,.F.);
#226 = EDGE_CURVE('',#138,#218,#227,.T.);
#227 = LINE('',#228,#229);
#228 = CARTESIAN_POINT('',(8.770761894539E-16,5.,1.3));
#229 = VECTOR('',#230,1.);
#230 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#231 = CYLINDRICAL_SURFACE('',#232,1.);
#232 = AXIS2_PLACEMENT_3D('',#233,#234,#235);
#233 = CARTESIAN_POINT('',(6.550315845288E-16,4.,1.3));
#234 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#235 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#236 = ADVANCED_FACE('',(#237),#255,.T.);
#237 = FACE_BOUND('',#238,.T.);
#238 = EDGE_LOOP('',(#239,#240,#248,#254));
#239 = ORIENTED_EDGE('',*,*,#39,.F.);
#240 = ORIENTED_EDGE('',*,*,#241,.T.);
#241 = EDGE_CURVE('',#40,#242,#244,.T.);
#242 = VERTEX_POINT('',#243);
#243 = CARTESIAN_POINT('',(12.,-12.5,0.5));
#244 = LINE('',#245,#246);
#245 = CARTESIAN_POINT('',(-2.886579864025E-15,-12.5,0.5));
#246 = VECTOR('',#247,1.);
#247 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#248 = ORIENTED_EDGE('',*,*,#249,.T.);
#249 = EDGE_CURVE('',#242,#194,#250,.T.);
#250 = LINE('',#251,#252);
#251 = CARTESIAN_POINT('',(12.,-12.5,0.5));
#252 = VECTOR('',#253,1.);
#253 = DIRECTION('',(-3.127288826259E-16,-0.640184399664,0.768221279597)
);
#254 = ORIENTED_EDGE('',*,*,#201,.F.);
#255 = PLANE('',#256);
#256 = AXIS2_PLACEMENT_3D('',#257,#258,#259);
#257 = CARTESIAN_POINT('',(-2.886579864025E-15,-12.5,0.5));
#258 = DIRECTION('',(7.107474605133E-18,-0.768221279597,-0.640184399664)
);
#259 = DIRECTION('',(-3.127288826259E-16,-0.640184399664,0.768221279597)
);
#260 = ADVANCED_FACE('',(#261),#279,.F.);
#261 = FACE_BOUND('',#262,.F.);
#262 = EDGE_LOOP('',(#263,#264,#272,#278));
#263 = ORIENTED_EDGE('',*,*,#137,.F.);
#264 = ORIENTED_EDGE('',*,*,#265,.T.);
#265 = EDGE_CURVE('',#129,#266,#268,.T.);
#266 = VERTEX_POINT('',#267);
#267 = CARTESIAN_POINT('',(12.,5.,-2.1));
#268 = LINE('',#269,#270);
#269 = CARTESIAN_POINT('',(1.521005543736E-15,5.,-2.1));
#270 = VECTOR('',#271,1.);
#271 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#272 = ORIENTED_EDGE('',*,*,#273,.T.);
#273 = EDGE_CURVE('',#266,#218,#274,.T.);
#274 = LINE('',#275,#276);
#275 = CARTESIAN_POINT('',(12.,5.,-3.1));
#276 = VECTOR('',#277,1.);
#277 = DIRECTION('',(-2.22044604925E-16,2.22044604925E-16,1.));
#278 = ORIENTED_EDGE('',*,*,#226,.F.);
#279 = PLANE('',#280);
#280 = AXIS2_PLACEMENT_3D('',#281,#282,#283);
#281 = CARTESIAN_POINT('',(1.798561299893E-15,5.,-3.1));
#282 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#283 = DIRECTION('',(-2.22044604925E-16,2.22044604925E-16,1.));
#284 = ADVANCED_FACE('',(#285),#303,.T.);
#285 = FACE_BOUND('',#286,.T.);
#286 = EDGE_LOOP('',(#287,#295,#301,#302));
#287 = ORIENTED_EDGE('',*,*,#288,.T.);
#288 = EDGE_CURVE('',#48,#289,#291,.T.);
#289 = VERTEX_POINT('',#290);
#290 = CARTESIAN_POINT('',(12.,-12.,0.5));
#291 = LINE('',#292,#293);
#292 = CARTESIAN_POINT('',(-2.775557561563E-15,-12.,0.5));
#293 = VECTOR('',#294,1.);
#294 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#295 = ORIENTED_EDGE('',*,*,#296,.T.);
#296 = EDGE_CURVE('',#289,#242,#297,.T.);
#297 = LINE('',#298,#299);
#298 = CARTESIAN_POINT('',(12.,-12.,0.5));
#299 = VECTOR('',#300,1.);
#300 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#301 = ORIENTED_EDGE('',*,*,#241,.F.);
#302 = ORIENTED_EDGE('',*,*,#47,.F.);
#303 = PLANE('',#304);
#304 = AXIS2_PLACEMENT_3D('',#305,#306,#307);
#305 = CARTESIAN_POINT('',(-2.775557561563E-15,-12.,0.5));
#306 = DIRECTION('',(2.775557561563E-16,-2.22044604925E-16,-1.));
#307 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#308 = ADVANCED_FACE('',(#309),#328,.T.);
#309 = FACE_BOUND('',#310,.T.);
#310 = EDGE_LOOP('',(#311,#312,#313,#322));
#311 = ORIENTED_EDGE('',*,*,#128,.T.);
#312 = ORIENTED_EDGE('',*,*,#265,.T.);
#313 = ORIENTED_EDGE('',*,*,#314,.F.);
#314 = EDGE_CURVE('',#315,#266,#317,.T.);
#315 = VERTEX_POINT('',#316);
#316 = CARTESIAN_POINT('',(12.,4.,-3.1));
#317 = CIRCLE('',#318,1.);
#318 = AXIS2_PLACEMENT_3D('',#319,#320,#321);
#319 = CARTESIAN_POINT('',(12.,4.,-2.1));
#320 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#321 = DIRECTION('',(-2.775557561563E-16,0.,1.));
#322 = ORIENTED_EDGE('',*,*,#323,.F.);
#323 = EDGE_CURVE('',#121,#315,#324,.T.);
#324 = LINE('',#325,#326);
#325 = CARTESIAN_POINT('',(1.576516694968E-15,4.,-3.1));
#326 = VECTOR('',#327,1.);
#327 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#328 = CYLINDRICAL_SURFACE('',#329,1.);
#329 = AXIS2_PLACEMENT_3D('',#330,#331,#332);
#330 = CARTESIAN_POINT('',(1.298960938811E-15,4.,-2.1));
#331 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#332 = DIRECTION('',(2.775557561563E-16,-2.22044604925E-16,-1.));
#333 = ADVANCED_FACE('',(#334),#352,.T.);
#334 = FACE_BOUND('',#335,.T.);
#335 = EDGE_LOOP('',(#336,#344,#350,#351));
#336 = ORIENTED_EDGE('',*,*,#337,.T.);
#337 = EDGE_CURVE('',#56,#338,#340,.T.);
#338 = VERTEX_POINT('',#339);
#339 = CARTESIAN_POINT('',(12.,-12.,1.5));
#340 = LINE('',#341,#342);
#341 = CARTESIAN_POINT('',(-2.997602166488E-15,-12.,1.5));
#342 = VECTOR('',#343,1.);
#343 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#344 = ORIENTED_EDGE('',*,*,#345,.T.);
#345 = EDGE_CURVE('',#338,#289,#346,.T.);
#346 = LINE('',#347,#348);
#347 = CARTESIAN_POINT('',(12.,-12.,1.5));
#348 = VECTOR('',#349,1.);
#349 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#350 = ORIENTED_EDGE('',*,*,#288,.F.);
#351 = ORIENTED_EDGE('',*,*,#55,.F.);
#352 = PLANE('',#353);
#353 = AXIS2_PLACEMENT_3D('',#354,#355,#356);
#354 = CARTESIAN_POINT('',(-2.997602166488E-15,-12.,1.5));
#355 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#356 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#357 = ADVANCED_FACE('',(#358),#376,.F.);
#358 = FACE_BOUND('',#359,.F.);
#359 = EDGE_LOOP('',(#360,#361,#369,#375));
#360 = ORIENTED_EDGE('',*,*,#120,.F.);
#361 = ORIENTED_EDGE('',*,*,#362,.T.);
#362 = EDGE_CURVE('',#112,#363,#365,.T.);
#363 = VERTEX_POINT('',#364);
#364 = CARTESIAN_POINT('',(12.,-9.,-3.1));
#365 = LINE('',#366,#367);
#366 = CARTESIAN_POINT('',(-1.310063169058E-15,-9.,-3.1));
#367 = VECTOR('',#368,1.);
#368 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#369 = ORIENTED_EDGE('',*,*,#370,.T.);
#370 = EDGE_CURVE('',#363,#315,#371,.T.);
#371 = LINE('',#372,#373);
#372 = CARTESIAN_POINT('',(12.,-10.,-3.1));
#373 = VECTOR('',#374,1.);
#374 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#375 = ORIENTED_EDGE('',*,*,#323,.F.);
#376 = PLANE('',#377);
#377 = AXIS2_PLACEMENT_3D('',#378,#379,#380);
#378 = CARTESIAN_POINT('',(-1.532107773983E-15,-10.,-3.1));
#379 = DIRECTION('',(-2.775557561563E-16,2.22044604925E-16,1.));
#380 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#381 = ADVANCED_FACE('',(#382),#400,.F.);
#382 = FACE_BOUND('',#383,.F.);
#383 = EDGE_LOOP('',(#384,#385,#393,#399));
#384 = ORIENTED_EDGE('',*,*,#337,.T.);
#385 = ORIENTED_EDGE('',*,*,#386,.T.);
#386 = EDGE_CURVE('',#338,#387,#389,.T.);
#387 = VERTEX_POINT('',#388);
#388 = CARTESIAN_POINT('',(12.,3.5,1.5));
#389 = LINE('',#390,#391);
#390 = CARTESIAN_POINT('',(12.,-12.,1.5));
#391 = VECTOR('',#392,1.);
#392 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#393 = ORIENTED_EDGE('',*,*,#394,.F.);
#394 = EDGE_CURVE('',#64,#387,#395,.T.);
#395 = LINE('',#396,#397);
#396 = CARTESIAN_POINT('',(4.440892098501E-16,3.5,1.5));
#397 = VECTOR('',#398,1.);
#398 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#399 = ORIENTED_EDGE('',*,*,#63,.F.);
#400 = PLANE('',#401);
#401 = AXIS2_PLACEMENT_3D('',#402,#403,#404);
#402 = CARTESIAN_POINT('',(-2.997602166488E-15,-12.,1.5));
#403 = DIRECTION('',(-2.775557561563E-16,2.22044604925E-16,1.));
#404 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#405 = ADVANCED_FACE('',(#406),#425,.T.);
#406 = FACE_BOUND('',#407,.T.);
#407 = EDGE_LOOP('',(#408,#409,#410,#419));
#408 = ORIENTED_EDGE('',*,*,#111,.T.);
#409 = ORIENTED_EDGE('',*,*,#362,.T.);
#410 = ORIENTED_EDGE('',*,*,#411,.F.);
#411 = EDGE_CURVE('',#412,#363,#414,.T.);
#412 = VERTEX_POINT('',#413);
#413 = CARTESIAN_POINT('',(12.,-10.,-2.1));
#414 = CIRCLE('',#415,1.);
#415 = AXIS2_PLACEMENT_3D('',#416,#417,#418);
#416 = CARTESIAN_POINT('',(12.,-9.,-2.1));
#417 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#418 = DIRECTION('',(-2.775557561563E-16,0.,1.));
#419 = ORIENTED_EDGE('',*,*,#420,.F.);
#420 = EDGE_CURVE('',#104,#412,#421,.T.);
#421 = LINE('',#422,#423);
#422 = CARTESIAN_POINT('',(-1.809663530139E-15,-10.,-2.1));
#423 = VECTOR('',#424,1.);
#424 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#425 = CYLINDRICAL_SURFACE('',#426,1.);
#426 = AXIS2_PLACEMENT_3D('',#427,#428,#429);
#427 = CARTESIAN_POINT('',(-1.587618925214E-15,-9.,-2.1));
#428 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#429 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#430 = ADVANCED_FACE('',(#431),#449,.F.);
#431 = FACE_BOUND('',#432,.F.);
#432 = EDGE_LOOP('',(#433,#434,#442,#448));
#433 = ORIENTED_EDGE('',*,*,#394,.T.);
#434 = ORIENTED_EDGE('',*,*,#435,.T.);
#435 = EDGE_CURVE('',#387,#436,#438,.T.);
#436 = VERTEX_POINT('',#437);
#437 = CARTESIAN_POINT('',(12.,3.5,2.553512956638E-15));
#438 = LINE('',#439,#440);
#439 = CARTESIAN_POINT('',(12.,3.5,1.5));
#440 = VECTOR('',#441,1.);
#441 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#442 = ORIENTED_EDGE('',*,*,#443,.F.);
#443 = EDGE_CURVE('',#72,#436,#444,.T.);
#444 = LINE('',#445,#446);
#445 = CARTESIAN_POINT('',(7.771561172376E-16,3.5,-7.771561172376E-16));
#446 = VECTOR('',#447,1.);
#447 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#448 = ORIENTED_EDGE('',*,*,#71,.F.);
#449 = PLANE('',#450);
#450 = AXIS2_PLACEMENT_3D('',#451,#452,#453);
#451 = CARTESIAN_POINT('',(4.440892098501E-16,3.5,1.5));
#452 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#453 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#454 = ADVANCED_FACE('',(#455),#473,.F.);
#455 = FACE_BOUND('',#456,.F.);
#456 = EDGE_LOOP('',(#457,#458,#466,#472));
#457 = ORIENTED_EDGE('',*,*,#103,.F.);
#458 = ORIENTED_EDGE('',*,*,#459,.T.);
#459 = EDGE_CURVE('',#96,#460,#462,.T.);
#460 = VERTEX_POINT('',#461);
#461 = CARTESIAN_POINT('',(12.,-10.,-1.6));
#462 = LINE('',#463,#464);
#463 = CARTESIAN_POINT('',(-1.86517468137E-15,-10.,-1.6));
#464 = VECTOR('',#465,1.);
#465 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#466 = ORIENTED_EDGE('',*,*,#467,.T.);
#467 = EDGE_CURVE('',#460,#412,#468,.T.);
#468 = LINE('',#469,#470);
#469 = CARTESIAN_POINT('',(12.,-10.,-1.6));
#470 = VECTOR('',#471,1.);
#471 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#472 = ORIENTED_EDGE('',*,*,#420,.F.);
#473 = PLANE('',#474);
#474 = AXIS2_PLACEMENT_3D('',#475,#476,#477);
#475 = CARTESIAN_POINT('',(-1.86517468137E-15,-10.,-1.6));
#476 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#477 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#478 = ADVANCED_FACE('',(#479),#497,.F.);
#479 = FACE_BOUND('',#480,.F.);
#480 = EDGE_LOOP('',(#481,#482,#490,#496));
#481 = ORIENTED_EDGE('',*,*,#443,.T.);
#482 = ORIENTED_EDGE('',*,*,#483,.T.);
#483 = EDGE_CURVE('',#436,#484,#486,.T.);
#484 = VERTEX_POINT('',#485);
#485 = CARTESIAN_POINT('',(12.,-2.6645352591E-15,3.330669073875E-15));
#486 = LINE('',#487,#488);
#487 = CARTESIAN_POINT('',(12.,3.5,2.553512956638E-15));
#488 = VECTOR('',#489,1.);
#489 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#490 = ORIENTED_EDGE('',*,*,#491,.F.);
#491 = EDGE_CURVE('',#80,#484,#492,.T.);
#492 = LINE('',#493,#494);
#493 = CARTESIAN_POINT('',(0.,0.,0.));
#494 = VECTOR('',#495,1.);
#495 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#496 = ORIENTED_EDGE('',*,*,#79,.F.);
#497 = PLANE('',#498);
#498 = AXIS2_PLACEMENT_3D('',#499,#500,#501);
#499 = CARTESIAN_POINT('',(7.771561172376E-16,3.5,-7.771561172376E-16));
#500 = DIRECTION('',(2.775557561563E-16,-2.22044604925E-16,-1.));
#501 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#502 = ADVANCED_FACE('',(#503),#521,.F.);
#503 = FACE_BOUND('',#504,.F.);
#504 = EDGE_LOOP('',(#505,#513,#519,#520));
#505 = ORIENTED_EDGE('',*,*,#506,.T.);
#506 = EDGE_CURVE('',#88,#507,#509,.T.);
#507 = VERTEX_POINT('',#508);
#508 = CARTESIAN_POINT('',(12.,-3.01980662698E-15,-1.6));
#509 = LINE('',#510,#511);
#510 = CARTESIAN_POINT('',(3.552713678801E-16,-3.552713678801E-16,-1.6)
);
#511 = VECTOR('',#512,1.);
#512 = DIRECTION('',(1.,-2.22044604925E-16,2.775557561563E-16));
#513 = ORIENTED_EDGE('',*,*,#514,.T.);
#514 = EDGE_CURVE('',#507,#460,#515,.T.);
#515 = LINE('',#516,#517);
#516 = CARTESIAN_POINT('',(12.,-3.01980662698E-15,-1.6));
#517 = VECTOR('',#518,1.);
#518 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#519 = ORIENTED_EDGE('',*,*,#459,.F.);
#520 = ORIENTED_EDGE('',*,*,#95,.F.);
#521 = PLANE('',#522);
#522 = AXIS2_PLACEMENT_3D('',#523,#524,#525);
#523 = CARTESIAN_POINT('',(3.552713678801E-16,-3.552713678801E-16,-1.6)
);
#524 = DIRECTION('',(2.775557561563E-16,-2.22044604925E-16,-1.));
#525 = DIRECTION('',(-2.22044604925E-16,-1.,2.22044604925E-16));
#526 = ADVANCED_FACE('',(#527),#538,.F.);
#527 = FACE_BOUND('',#528,.F.);
#528 = EDGE_LOOP('',(#529,#530,#536,#537));
#529 = ORIENTED_EDGE('',*,*,#491,.T.);
#530 = ORIENTED_EDGE('',*,*,#531,.T.);
#531 = EDGE_CURVE('',#484,#507,#532,.T.);
#532 = LINE('',#533,#534);
#533 = CARTESIAN_POINT('',(12.,-2.6645352591E-15,3.330669073875E-15));
#534 = VECTOR('',#535,1.);
#535 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#536 = ORIENTED_EDGE('',*,*,#506,.F.);
#537 = ORIENTED_EDGE('',*,*,#87,.F.);
#538 = PLANE('',#539);
#539 = AXIS2_PLACEMENT_3D('',#540,#541,#542);
#540 = CARTESIAN_POINT('',(0.,0.,0.));
#541 = DIRECTION('',(2.22044604925E-16,1.,-2.22044604925E-16));
#542 = DIRECTION('',(2.22044604925E-16,-2.22044604925E-16,-1.));
#543 = ADVANCED_FACE('',(#544),#562,.T.);
#544 = FACE_BOUND('',#545,.T.);
#545 = EDGE_LOOP('',(#546,#547,#548,#549,#550,#551,#552,#553,#554,#555,
#556,#557,#558,#559,#560,#561));
#546 = ORIENTED_EDGE('',*,*,#169,.F.);
#547 = ORIENTED_EDGE('',*,*,#193,.T.);
#548 = ORIENTED_EDGE('',*,*,#249,.F.);
#549 = ORIENTED_EDGE('',*,*,#296,.F.);
#550 = ORIENTED_EDGE('',*,*,#345,.F.);
#551 = ORIENTED_EDGE('',*,*,#386,.T.);
#552 = ORIENTED_EDGE('',*,*,#435,.T.);
#553 = ORIENTED_EDGE('',*,*,#483,.T.);
#554 = ORIENTED_EDGE('',*,*,#531,.T.);
#555 = ORIENTED_EDGE('',*,*,#514,.T.);
#556 = ORIENTED_EDGE('',*,*,#467,.T.);
#557 = ORIENTED_EDGE('',*,*,#411,.T.);
#558 = ORIENTED_EDGE('',*,*,#370,.T.);
#559 = ORIENTED_EDGE('',*,*,#314,.T.);
#560 = ORIENTED_EDGE('',*,*,#273,.T.);
#561 = ORIENTED_EDGE('',*,*,#217,.T.);
#562 = PLANE('',#563);
#563 = AXIS2_PLACEMENT_3D('',#564,#565,#566);
#564 = CARTESIAN_POINT('',(12.,-3.444301816353,4.086646542781E-02));
#565 = DIRECTION('',(1.,0.,2.22044604925E-16));
#566 = DIRECTION('',(-2.22044604925E-16,0.,1.));
#567 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#571)) GLOBAL_UNIT_ASSIGNED_CONTEXT
((#568,#569,#570)) REPRESENTATION_CONTEXT('Context #1',
'3D Context with UNIT and UNCERTAINTY') );
#568 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
#569 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
#570 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
#571 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#568,
'distance_accuracy_value','confusion accuracy');
#572 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#7));
#573 = MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#574)
,#567);
#574 = STYLED_ITEM('color',(#575),#15);
#575 = PRESENTATION_STYLE_ASSIGNMENT((#576,#582));
#576 = SURFACE_STYLE_USAGE(.BOTH.,#577);
#577 = SURFACE_SIDE_STYLE('',(#578));
#578 = SURFACE_STYLE_FILL_AREA(#579);
#579 = FILL_AREA_STYLE('',(#580));
#580 = FILL_AREA_STYLE_COLOUR('',#581);
#581 = COLOUR_RGB('',0.800000010877,0.800000010877,0.800000010877);
#582 = CURVE_STYLE('',#583,POSITIVE_LENGTH_MEASURE(0.1),#584);
#583 = DRAUGHTING_PRE_DEFINED_CURVE_FONT('continuous');
#584 = COLOUR_RGB('',9.803921802644E-02,9.803921802644E-02,
9.803921802644E-02);
ENDSEC;
END-ISO-10303-21;

Binary file not shown.

View file

@ -14,6 +14,7 @@
"/home/fisch/.platformio/packages/framework-arduinoteensy/libraries/SdFat/src",
"/home/fisch/.platformio/packages/framework-arduinoteensy/libraries/Time",
"/media/fisch/HDD/Projects/bobbycar/bobbycar_repo/controller_teensy/lib/hoverboard-esc-serial-comm/src",
"/media/fisch/HDD/Projects/bobbycar/bobbycar_repo/controller_teensy/.pio/libdeps/teensy41/PulsePosition",
"/media/fisch/HDD/Projects/bobbycar/bobbycar_repo/controller_teensy/.pio/libdeps/teensy41/DallasTemperature",
"/media/fisch/HDD/Projects/bobbycar/bobbycar_repo/controller_teensy/.pio/libdeps/teensy41/OneWire",
"/home/fisch/.platformio/packages/framework-arduinoteensy/libraries/VirtualWire",
@ -129,6 +130,7 @@
"/home/fisch/.platformio/packages/framework-arduinoteensy/libraries/SdFat/src",
"/home/fisch/.platformio/packages/framework-arduinoteensy/libraries/Time",
"/media/fisch/HDD/Projects/bobbycar/bobbycar_repo/controller_teensy/lib/hoverboard-esc-serial-comm/src",
"/media/fisch/HDD/Projects/bobbycar/bobbycar_repo/controller_teensy/.pio/libdeps/teensy41/PulsePosition",
"/media/fisch/HDD/Projects/bobbycar/bobbycar_repo/controller_teensy/.pio/libdeps/teensy41/DallasTemperature",
"/media/fisch/HDD/Projects/bobbycar/bobbycar_repo/controller_teensy/.pio/libdeps/teensy41/OneWire",
"/home/fisch/.platformio/packages/framework-arduinoteensy/libraries/VirtualWire",

View file

@ -1,3 +1,48 @@
{
"cmake.configureOnOpen": false
"cmake.configureOnOpen": false,
"files.associations": {
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"limits": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
}
}

View file

@ -0,0 +1,78 @@
# Bobbycar Controller
## Serial Commands
If Vusb jumper on PCB is soldered, do not connect USB while LiPo is connected!
**echo off**
Turn off serial command echo.
Useful for automated transfer.
**echo on**
Turns on serial command echo.
Useful for manual command execution.
**test**
Returns "OK"
**ls**
List files on SD card in a machine readable way.
One file per line with full path.
**la -a**
List files tab formatted. With file sizes.
**cat FILENAME**
Print out the contents of a specified file.
If no filename given, the current active logfile is used.
**get FILENAME**
Sends the contents of a specified file in chunks.
Waits for the checksum of the send chunks before sending the next chunk.
Exits with an error message when checksum does not match.
Used for automated transfer of files.
**sizeof FILENAME**
Returns the size in bytes of the specified file.
**chunksize SIZE**
Sets the size of chunks for file transmission. See **get** command.
Default is 128.
**rm FILENAME**
Deletes file from sd card.
**log off**
Turns off logging flag.
**log on**
Turns on logging flag.
**show stats**
Prints some current stats values.
One variable per line.
Format: parametername\<Tab\>value
**show sensors**
Prints some sensor values that are useful in standstill.
One variable per line.
Format: parametername\<Tab\>value

View file

@ -29,17 +29,25 @@ bool controllers_connected=false;
//const uint16_t calib_throttle_min = 420; //better a bit too high than too low
//const uint16_t calib_throttle_max = 790;
/*
const uint16_t failsafe_throttle_min_A = 4900; //if adc value falls below this failsafe is triggered.
const uint16_t failsafe_throttle_max_A = 14500; //if adc value goes above this failsafe is triggered.
const uint16_t failsafe_throttle_min_B = 3900; //if adc value falls below this failsafe is triggered.
const uint16_t failsafe_throttle_max_B = 12500; //if adc value goes above this failsafe is triggered.
const uint16_t failsafe_throttle_maxDiff = 200;//maximum adc value difference between both sensors A and B. value range 0-1000. choose value at least 2x higher than maximum difference when moving throttle slowly
//const uint16_t throttleCurvePerMM[] = {414,460,490,511,527,539,548,555,561,567,573,578,584,590,599,611,630,657,697,754,789,795}; //adc values for every unit (mm) of linear travel
//const uint16_t throttleCurvePerMM[] = {8485,8904,9177,9368,9513,9623,9705,9768,9823,9877,9932,9978,10032,10087,10169,10278,10451,10697,11061,11579,11898,11952}; //adc values for every unit (mm) of linear travel. config used until 20230826
*/
const uint16_t failsafe_throttle_min_A = 3000; //if adc value falls below this failsafe is triggered.
const uint16_t failsafe_throttle_max_A = 13000; //if adc value goes above this failsafe is triggered.
const uint16_t failsafe_throttle_min_B = 5000; //if adc value falls below this failsafe is triggered.
const uint16_t failsafe_throttle_max_B = 14500; //if adc value goes above this failsafe is triggered.
const uint16_t failsafe_throttle_maxDiff = 200;//maximum throttle pos value difference between both sensors A and B (after linearization). value range 0-1000. choose value at least 2x higher than maximum difference when moving throttle slowly
//Throttle Calibration: First value pair should be 1-2mm pressed down (start of throttle=1). Last value pair should be a bit before fully pressed. all values in between need to be equidistant (for example every 1mm). Use define CALIBRATION_THROTTLE_CURVE for easy calibration output
const uint16_t throttleCurvePerMM_A[] = {9996,9718,9507,9357,9232,9162,9071,8958,8838,8703,8577,8396,8192,7845,7407,6800,5923}; //adc values for every unit (mm) of linear travel
const uint16_t throttleCurvePerMM_B[] = {7698,7948,8133,8277,8403,8503,8588,8695,8791,8899,9034,9196,9400,9711,10110,10657,1146}; //adc values for every unit (mm) of linear travel
const uint16_t throttleCurvePerMM_A[] = {11800,11130,10300,9990,9650,9470,9370,9240,9130,9030,8950,8850,8700,8560,8350,8040,7750,7150,6520}; //adc values for every unit (mm) of linear travel
const bool throttleCurvePerMM_A_Descending=true; //set true if corresponding array is descending
const uint16_t throttleCurvePerMM_B[] = {6200,6700,7420,7710,8030,8200,8310,8440,8560,8640,8740,8840,8990,9130,9330,9630,9900,10440,10990}; //adc values for every unit (mm) of linear travel
const bool throttleCurvePerMM_B_Descending=false; //set true if corresponding array is descending
const uint16_t calib_brake_min = 7000; //better a bit too high than too low
@ -59,28 +67,25 @@ uint16_t ads_brake_raw=failsafe_brake_min;
uint16_t ads_control_raw=0;
int16_t throttle_posA; //scaled and clamped throttle position for sensor A
int16_t throttle_posB; //scaled and clamped throttle position for sensor B
int16_t throttle_pos=0; //combined and filtered throttle position
int16_t brake_pos=0; //filtered throttle position
int16_t brake_pos=0; //filtered and constrained throttle position
bool control_buttonA=false;
bool control_buttonB=false;
unsigned long loopmillis;
unsigned long looptime_duration;
unsigned long looptime_duration_min;
unsigned long looptime_duration_max;
#define ADSREADPERIOD 3 //set slightly higher as actual read time to avoid unnecessary register query
#define ADCREADPERIOD 10
#define BUTTONREADPERIOD 20
unsigned long last_adsread=0; //needed for failcheck
uint16_t throttle_rawA=failsafe_throttle_min_A; //start at min so that failsafe is not triggered
uint16_t throttle_rawB=failsafe_throttle_min_B; //start at min so that failsafe is not triggered
#define THROTTLE_ADC_FILTER 0.4 //higher value = faster response
uint16_t brake_raw=failsafe_brake_min; //start at min so that failsafe is not triggered
int16_t brake_linear=0; //linearized bake position
#define ADC_OUTOFRANGE_TIME 100 //for failsafe_throttle_min_X. how long values need to stay bad to trigger failsafe
#define ADC_DIFFHIGH_TIME 500 //for failsafe_throttle_maxDiff. how long values need to stay bad to trigger failsafe
@ -90,20 +95,21 @@ bool error_brake_outofrange=false;
bool error_ads_max_read_interval=false;
bool error_sdfile_unavailable=false;
#define REVERSE_ENABLE_TIME 1000 //ms. how long standstill to be able to drive backward
#define REVERSE_ENABLE_TIME 300 //ms. how long standstill to be able to drive backward
#define NORMAL_MAX_ACCELERATION_RATE 10000
#define SLOW_MAX_ACCELERATION_RATE 500
#define MEDIUM_MAX_ACCELERATION_RATE 500
#define SLOW_MAX_ACCELERATION_RATE 250
int16_t max_acceleration_rate=NORMAL_MAX_ACCELERATION_RATE; //maximum cmd send increase per second
//Driving parameters
int16_t minimum_constant_cmd_reduce=1; //reduce cmd every loop by this constant amount when freewheeling/braking
int16_t brake_cmdreduce_proportional=500; //cmd gets reduced by an amount proportional to brake position (ignores freewheeling). cmd_new-=brake_cmdreduce_proportional / second @ full brake. with BREAK_CMDREDUCE_CONSTANT=1000 car would stop with full brake at least after a second (ignoring influence of brake current control/freewheeling)
float startbrakecurrent=2; //Ampere. "targeted brake current @full brake". at what point to start apply brake proportional to brake_pos. for everything above that cmd is reduced by freewheel_break_factor
float startbrakecurrent=2.0; //Ampere. "targeted brake current @full brake". at what point to start apply brake proportional to brake_pos. for everything above that cmd is reduced by freewheel_break_factor
float startbrakecurrent_offset=0.13; //offset start point for breaking, because of reading fluctuations around 0A. set this slightly above idle current reading
float freewheel_break_factor=500.0; //speed cmd units per amp per second. 1A over freewheel_current decreases cmd speed by this amount (on average)
float freewheel_break_factor=200.0; //speed cmd units per amp per second. 1A over freewheel_current decreases cmd speed by this amount (on average). Was 500 until 20240809
float reverse_speed=0.25; //reverse driving speed //0 to 1
int16_t throttle_max=1000; //maximum allowed set speed. used for scaling and limiting. [0,1000]
@ -131,6 +137,8 @@ float max_filtered_wattAll;
float min_filtered_wattAll;
float max_meanSpeed;
float min_voltage;
float minSpeedms; //speed in m/s of slowest wheel
double overallTrip; //m. trip with read distance from sd card
double trip; //m. trip distance since boot

View file

@ -15,7 +15,12 @@
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
uint8_t standingDisplayScreen=0;
#define NUM_STANDINGDISPLAYSCREEN 5
#define DISPLAYSTANDSTILLTIME 5000
#include "rc.h"
bool display_init();
void display_update(ESCSerialComm& escFront, ESCSerialComm& escRear);
@ -81,17 +86,14 @@ void display_update(ESCSerialComm& escFront, ESCSerialComm& escRear){
display.print(errorstring);
}else{
//Normal Display Routinges here
//Normal Display Routines here
if (armed) {
if (loopmillis-last_notidle>5000) {
if (loopmillis-last_notidle>DISPLAYSTANDSTILLTIME) {
display_standingDisplay(escFront,escRear);
}else{
if (!control_buttonA) {
display_drivingDisplay(escFront,escRear);
}else{
display_debugDisplay(escFront,escRear);
}
display_drivingDisplay(escFront,escRear);
//display_debugDisplay(escFront,escRear);
}
}else{
@ -108,13 +110,16 @@ void display_update(ESCSerialComm& escFront, ESCSerialComm& escRear){
void display_drivingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
//Display stuff here for when bobbycar is moving or was moving recently and is armed
//## Km/h Display
display.setFont(&FreeMonoBold18pt7b);
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0,SCREEN_HEIGHT-(SCREEN_HEIGHT-18)/2 - 3); // Start at top-left corner
//float _speeddisplay=(escFront.getMeanSpeed()+escRear.getMeanSpeed())/2.0*3.6;
float _speeddisplay=minSpeedms*3.6;
@ -132,6 +137,17 @@ void display_drivingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
display.setCursor(SCREEN_WIDTH-25,SCREEN_HEIGHT-16);
display.print("km/h");
#ifdef RC
display.setCursor(0,0);
if (rc_fullcontrol_enabled) {
display.print("RC Fullcontrol");
}else if(rc_steer_enabled){
display.print("RC Steering");
}
#endif
//A
display.setCursor(SCREEN_WIDTH-37,1);
static float averaged_filtered_currentAll;
@ -151,40 +167,36 @@ void display_drivingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
//## Trip / Current Consumed Display
display.setCursor(1,SCREEN_HEIGHT-7);
//if (((millis()/2500)%2)==0) {
if (control_buttonB) {
//## Speed statistic
display.print("max: ");
dtostrf(max_meanSpeed*3.6,1,0,buf);
display.print((String)buf);
display.print("km/h");
}else{
//## Current Consumed
/*
dtostrf(min_filtered_currentAll,1,1,buf);
display.print("min:");
display.print((String)buf);
display.print("A max:");
dtostrf(max_filtered_currentAll,1,1,buf);
display.print((String)buf);
display.print("A");
*/
//## Watt Hours Consumed
dtostrf(min_filtered_wattAll,1,0,buf);
display.print("min:");
display.print((String)buf);
display.print("W max:");
//## Current
/*
dtostrf(min_filtered_currentAll,1,1,buf);
display.print("min:");
display.print((String)buf);
display.print("A max:");
dtostrf(max_filtered_wattAll,1,0,buf);
display.print((String)buf);
display.print("W");
}
dtostrf(max_filtered_currentAll,1,1,buf);
display.print((String)buf);
display.print("A");
*/
//## Watt
dtostrf(min_filtered_wattAll,1,0,buf);
display.print((String)buf);
display.print(" / ");
dtostrf(max_filtered_wattAll,1,0,buf);
display.print((String)buf);
display.print("W ");
display.setCursor(SCREEN_WIDTH-6*6,SCREEN_HEIGHT-7);
dtostrf(max_meanSpeed*3.6,1,0,buf);
display.print((String)buf);
display.print("km/h");
}
void display_debugDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
//Debug
display.setTextSize(2); // Normal 1:1 pixel scale
@ -220,30 +232,172 @@ void display_debugDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
display.print(" thrpos=");
display.print(throttle_pos);
*/
}
void display_standingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
//Display stuff here when ESCs are powered on and bobbycar is armed but was not moving for a while
double _displaytrip=trip;
//double _displaycurrent=currentConsumed;
double _displaywatthours=watthoursConsumed;
//bool _displayOverall= ((millis()/3000)%2==0); //switch based on time
bool _displayOverall=control_buttonB; //switch with button
bool _displayParameters=control_buttonA;
bool _displayOverall= ((millis()/2500)%2==0); //switch based on time
char buf[8];
display.setFont();
display.setCursor(0,0);
if (_displayParameters) {
if (_displayOverall) { //alternate between this trip and overall trip
_displaytrip=overallTrip;
//_displaycurrent=overallCurrentConsumed;
_displaywatthours=overallWatthoursConsumed;
}
//Row 1
if (!_displayOverall) {
display.print(F("Vbat:")); display.print(escFront.getFeedback_batVoltage());
display.print(F("/")); display.print(escRear.getFeedback_batVoltage());
}else{
display.print(F("Vmin:")); display.print(min_voltage);
}
display.print(" V");
display.println();
//Row 2
//display.print(F("Temp:")); display.print(escFront.getFeedback_boardTemp());
//display.print(F("/")); display.print(escRear.getFeedback_boardTemp());
display.print(F("T:")); display.print(temp_Front,0);
display.print(F("/")); display.print(temp_Rear,0);
display.print(F("/")); display.print(temp_Air,0);
display.print(" C");
display.println();
//Row 3
display.print(F("Trip:"));
dtostrf(_displaytrip,1,0,buf);
display.print((String)buf);
display.print("m ");
//dtostrf(_displaycurrent,1,2,buf);
dtostrf(_displaywatthours,1,2,buf);
display.print((String)buf);
//display.print(" Ah");
display.print("Wh");
display.println();
//Row 4
display.print(F(""));
//dtostrf( _displaytrip/1000/_displaycurrent ,1,2,buf);
dtostrf( _displaywatthours/_displaytrip*100,1,2,buf);
display.print((String)buf);
//display.print(" km/Ah");
display.print(" kWh/100km");
if (_displayOverall){
display.print(" sum");
}
display.println();
}
void display_standingDisarmedDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
//Displayed stuff here when escs are powered off / disconnected or bobbycar is not armed
char buf[8];
display.setFont();
display.setCursor(0,0);
switch(standingDisplayScreen)
{
case 0:
//Quick overview of inputs and status
//Row1
if (getDatalogging()) {
display.print(getLogFilename());
}else{
display.print("LOG DISABLED");
}
display.print(F(" ")); display.print(loopmillis/1000);
display.print(F("s"));
display.println();
//Row2
display.print(F("Throttle "));
dtostrf((throttle_posA+throttle_posB)/2.0,4,0,buf);
display.print((String)buf);
display.print(F(" ("));
if (throttle_posA>throttle_posB) { //use values acutally taken for diff check
display.print(F("+")); //add + for better formatting
}
dtostrf((throttle_posA-throttle_posB),1,0,buf);
display.print((String)buf);
display.print(F(")"));
display.println();
//Row3
display.print("Brake ");
dtostrf(brake_linear,4,0,buf); //use only linearized values (not constrained)
display.print((String)buf);
display.setCursor(8*10,2*8);
dtostrf((escFront.getFeedback_batVoltage()+escRear.getFeedback_batVoltage())/2.0,1,1,buf);
display.print((String)buf);
display.print(F("V"));
display.println();
/*display.print(" c=");
dtostrf(ads_control_raw,1,0,buf);
display.print((String)buf); */
break;
case 1:
//Trip Stats (trip / overall)
//Row 1
display.print(F("Trip ")); display.print(trip,0); display.print(F(" / ")); display.print(overallTrip,0); display.print(F("m"));
display.println();
//Row 2
display.print(F("Curr ")); display.print(currentConsumed*1000,0); display.print(F(" / ")); display.print(overallCurrentConsumed*1000,0); display.print(F("mAh"));
display.println();
//Row 3
display.print(F("Pow ")); display.print(watthoursConsumed,0); display.print(F(" / ")); display.print(overallWatthoursConsumed,0); display.print(F("Wh"));
display.println();
break;
case 2:
//Configuration parameters
//Row 1
display.print(F("cmdred min=")); display.print(minimum_constant_cmd_reduce);
display.print(F(" p=")); display.print(brake_cmdreduce_proportional);
display.println();
//Row 2
display.print(F("brkI="));
dtostrf(startbrakecurrent,1,1,buf);
@ -254,105 +408,127 @@ void display_standingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
display.print((String)buf);
display.println();
//Row 3
display.print(F("thrmax=")); display.print(throttle_max);
display.print(F(" rev="));
dtostrf(reverse_speed,1,2,buf);
display.print((String)buf);
display.println();
break;
case 3:
//Raw inputs and Input Debug
//TODO: show deviation (and max deviation), show resulting throttle and brake pos
}else{
if (_displayOverall) { //alternate between this trip and overall trip
_displaytrip=overallTrip;
//_displaycurrent=overallCurrentConsumed;
_displaywatthours=overallWatthoursConsumed;
//Row1
display.print(F("Throttle "));
dtostrf(ads_throttle_A_raw,1,0,buf);
display.print((String)buf);
display.print(F("/"));
dtostrf(ads_throttle_B_raw,1,0,buf);
display.print((String)buf);
display.println();
//Row2
static int16_t _throttle_maxdiff = 0;
if (control_buttonA || control_buttonB) { //any button press
_throttle_maxdiff=0; //reset maxdiff for this display
}
display.print(F("Vbat:")); display.print(escFront.getFeedback_batVoltage());
display.print(F("/")); display.print(escRear.getFeedback_batVoltage());
display.print(" V");
display.println();
//display.print(F("Temp:")); display.print(escFront.getFeedback_boardTemp());
//display.print(F("/")); display.print(escRear.getFeedback_boardTemp());
display.print(F("T:")); display.print(temp_ESCFront,0);
display.print(F("/")); display.print(temp_ESCRear,0);
display.print(F("/")); display.print(temp_Air,0);
display.print(" C");
display.println();
display.print(F("Trip:"));
dtostrf(_displaytrip,1,0,buf);
_throttle_maxdiff=max(_throttle_maxdiff,abs(throttle_posA-throttle_posB));
display.print(F("Thr.maxdiff "));
dtostrf(_throttle_maxdiff,1,0,buf);
display.print((String)buf);
display.print("m ");
//dtostrf(_displaycurrent,1,2,buf);
dtostrf(_displaywatthours,1,2,buf);
display.print((String)buf);
//display.print(" Ah");
display.print("Wh");
display.println();
display.print(F(""));
//dtostrf( _displaytrip/1000/_displaycurrent ,1,2,buf);
dtostrf( _displaywatthours/_displaytrip*100,1,2,buf);
display.print((String)buf);
//display.print(" km/Ah");
display.print(" kWh/100km");
if (_displayOverall){
display.print(" sum");
}
//Row3
display.print("Brake ");
dtostrf(ads_brake_raw,1,0,buf);
display.print((String)buf);
display.println();
break;
case 4:
//Row 1
display.print(F("RC "));
dtostrf(ppm[0],4,0,buf);
display.print((String)buf);
display.print(F("/"));
dtostrf(ppm[1],4,0,buf);
display.print((String)buf);
display.println();
//Row 2
display.print(F("T"));
dtostrf(getRCThrottle(),3,0,buf);
display.print((String)buf);
display.print(F(" B"));
dtostrf(getRCBrake(),3,0,buf);
display.print((String)buf);
display.print(F(" S"));
dtostrf(getRCSteer(),3,0,buf);
display.print((String)buf);
display.println();
//Row 3
display.print(F("Mode="));
dtostrf(getRCMode(6),1,0,buf);
display.print((String)buf);
display.print(F(" %="));
dtostrf(getPPMSuccessrate(),1,5,buf);
display.print((String)buf);
display.println();
break;
}
}
void display_standingDisarmedDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
//Displayed stuff here when escs are powered off / disconnected
char buf[8];
display.setFont();
display.setCursor(0,0);
display.print(getLogFilename());
display.print(F(" ")); display.print(loopmillis/1000);
display.print(F("s"));
display.println();
display.print(F("ESC F="));
display.print(escFront.getControllerConnected());
display.print(F(" R="));
display.print(escRear.getControllerConnected());
display.println();
display.print("throttle=");
dtostrf(ads_throttle_A_raw,1,0,buf);
display.print((String)buf);
display.print("/");
dtostrf(ads_throttle_B_raw,1,0,buf);
display.print((String)buf);
display.println();
display.print("brake=");
dtostrf(ads_brake_raw,1,0,buf);
display.print((String)buf);
/*display.print(" c=");
dtostrf(ads_control_raw,1,0,buf);
display.print((String)buf); */
if (control_buttonA){
display.print(" A");
//Put User Inputs in last row
//Row 4
display.setCursor(0,24);
if (button_start_state){
display.print("S");
}else{
display.print(" ");
}
if (control_buttonB){
display.print(" B");
display.print("B");
}else{
display.print(" ");
}
if (control_buttonA){
display.print("A");
}else{
display.print(" ");
}
if (escFront.getControllerConnected()){
display.print("F");
}else{
display.print(" ");
}
if (escRear.getControllerConnected()){
display.print("R");
}else{
display.print(" ");
}
display.setCursor(SCREEN_WIDTH-6*3,24);
display.print(standingDisplayScreen);
display.print("/"); display.print(NUM_STANDINGDISPLAYSCREEN-1);
}

View file

@ -17,7 +17,7 @@
#include <Adafruit_NeoPixel.h>
#define LED_PIN 3
#define LED_PIN 20
#define LED_COUNT 16
// NeoPixel brightness, 0 (min) to 255 (max)
@ -31,6 +31,9 @@ unsigned long last_ledupdate=0;
uint8_t led_errorcount=0; //count led progress errors. used for delay at end if any errors occured
extern bool rc_fullcontrol_enabled; //from rc.h
extern bool rc_steer_enabled;
void led_dotcircle(unsigned long loopmillis);
void led_gauge(unsigned long loopmillis,float value,float value_min,float value_max,uint32_t colorGauge,uint32_t colorBG);
@ -109,18 +112,22 @@ void led_update(unsigned long loopmillis,ESCSerialComm& escFront, ESCSerialComm&
}else{
if (armed) {
if (loopmillis-last_notidle>5000) {
//Standing
float vbat=min(escRear.getFeedback_batVoltage(),escFront.getFeedback_batVoltage());
led_gauge(loopmillis,vbat,3*12,4.2*12,strip.Color(0, 255, 0, 0),strip.Color(100, 0, 0, 0));
}else{
//Driving
float currentMean=escRear.getFiltered_curL()+escRear.getFiltered_curR()+escFront.getFiltered_curL()+escFront.getFiltered_curR();
uint32_t _bgColor=strip.Color(0, 0, 20, 0);
if (reverse_enabled) {
_bgColor=strip.Color(20, 0, 20, 0);
if (rc_fullcontrol_enabled || rc_steer_enabled) {
led_gauge(loopmillis,escFront.getCmdL(),0,1000,strip.Color(100, 0, 0, 0),strip.Color(0, 50, 50, 0));
}else{ //normal driving
if (loopmillis-last_notidle>5000) {
//Standing
float vbat=min(escRear.getFeedback_batVoltage(),escFront.getFeedback_batVoltage());
led_gauge(loopmillis,vbat,3.3*12,4.2*12,strip.Color(0, 255, 0, 0),strip.Color(100, 0, 0, 0));
}else{
//Driving
float currentMean=escRear.getFiltered_curL()+escRear.getFiltered_curR()+escFront.getFiltered_curL()+escFront.getFiltered_curR();
uint32_t _bgColor=strip.Color(0, 0, 20, 0);
if (reverse_enabled) {
_bgColor=strip.Color(20, 0, 20, 0);
}
led_gauge(loopmillis,currentMean,0,32.0,strip.Color(0, 0, 0, 255),_bgColor);
}
led_gauge(loopmillis,currentMean,0,32.0,strip.Color(0, 0, 0, 255),_bgColor);
}
}else{
//Disarmed

View file

@ -7,67 +7,109 @@
#include <SD.h> //Format sd cart with FAT or FAT16. FAT32 for >1GB Cards on Teensy4.1
//#define SDCHIPSELECT 14
boolean sdcard_available=false;
boolean datalogging=true;
String datalogging_filename="UNKNOWN.txt";
uint16_t chunksize=128; //for bulk data transmission
#define LOGGINGINTERVAL 100 //logging interval when driving
#define LOGGINGSTANDSTILLTIME 30000 //after which time of standstill logging interval should change
#define LOGGINGINTERVALSTANDSTILL 500 //logging interval when standing still
#define LOGGINGINTERVALDISARMED 1000 //logging interval when disarmed
bool serialCommandEcho_Enabled=true;
bool initLogging();
void loggingLoop(unsigned long loopmillis,ESCSerialComm& escFront, ESCSerialComm& escRear);
void writeLogComment(unsigned long time, String msg);
void printFileListing(bool pretty);
void printDirectory(File dir, int numTabs,String parent,bool printSize,bool printFullDirectoryNames);
void printFile(String filename);
void printFilesize(String filename);
void transferFile(String filename);
void removeFile(String filename);
void serialCommandLoop(unsigned long loopmillis, ESCSerialComm& escFront, ESCSerialComm& escRear);
float getBatteryVoltage(ESCSerialComm& escFront, ESCSerialComm& escRear);
bool initLogging() {
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(BUILTIN_SDCARD)) {
Serial.println("Card failed, or not present");
display.println(F("SD Init Fail!")); display.display();
datalogging=false; //disable logging
delay(1000);
return false;
}else{
Serial.println("Card initialized.");
display.print(F("LOG=")); display.display();
if (datalogging){
int filenumber=0;
char buffer[6];
Serial.print("Datalogging is ");
if (datalogging) {
Serial.println("enabled");
}else{
Serial.println("disabled");
}
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(BUILTIN_SDCARD)) {
Serial.println("Card failed, or not present");
display.println(F("SD Init Fail!")); display.display();
sdcard_available=false; //disable logging
datalogging=false;
delay(1000);
return false;
}else{
sdcard_available=true;
Serial.println("Card initialized.");
display.print(F("LOG=")); display.display();
int filenumber=0;
char buffer[6];
sprintf(buffer, "%04d", filenumber);
datalogging_filename="LOG_"+String(buffer)+".TXT";
while(SD.exists(datalogging_filename.c_str()) && filenumber<10000) {
//Serial.print(datalogging_filename); Serial.println(" exists");
filenumber++;
sprintf(buffer, "%04d", filenumber);
datalogging_filename="LOG_"+String(buffer)+".TXT";
while(SD.exists(datalogging_filename.c_str()) && filenumber<10000) {
Serial.print(datalogging_filename); Serial.println(" exists");
filenumber++;
sprintf(buffer, "%04d", filenumber);
datalogging_filename="LOG_"+String(buffer)+".TXT";
}
Serial.print(datalogging_filename); Serial.println(" is free");
display.print(datalogging_filename); display.println(); display.display();
}
}
return true;
}
Serial.print(datalogging_filename); Serial.println(" is free");
display.print(datalogging_filename);
if (!datalogging) { //datalogging is disabled during boot
display.print(" OFF");
}
display.println(); display.display();
}
return true;
}
void loggingLoop(unsigned long loopmillis,ESCSerialComm& escFront, ESCSerialComm& escRear) {
static unsigned long last_datalogging_write=0;
static unsigned long last_datalogging_write=loopmillis; //initialize with current time to have first log written after one interval
static boolean logging_headerWritten=false;
if (datalogging) {
#define LOGGINGINTERVAL 100
if (loopmillis-last_datalogging_write>LOGGINGINTERVAL)
{
last_datalogging_write=loopmillis;
File dataFile = SD.open(datalogging_filename.c_str(), FILE_WRITE);
unsigned long logginginterval=LOGGINGINTERVAL;
if (armed) { //Change Logginginterval when less is happening
if (loopmillis-last_notidle>LOGGINGSTANDSTILLTIME) {
logginginterval=LOGGINGINTERVALSTANDSTILL;
}
}else{ //disamred
logginginterval=LOGGINGINTERVALDISARMED;
}
if (loopmillis-last_datalogging_write>logginginterval)
{
last_datalogging_write=loopmillis;
if (datalogging && sdcard_available) {
File dataFile = SD.open(datalogging_filename.c_str(), FILE_WRITE);
if (dataFile) { // if the file is available, write to it
if (!logging_headerWritten) {
dataFile.print("time,cmd_FrontL,cmd_FrontR,cmd_RearL,cmd_RearR,");
dataFile.print("current_FrontL,current_FrontR,current_RearL,current_RearR,");
dataFile.print("rpm_FrontL,rpm_FrontR,rpm_RearL,rpm_RearR,");
dataFile.print("temp_Front,temp_Rear,vbat_Front,vbat_Rear,");
dataFile.print("temp_ESCFront,temp_ESCRear,vbat_Front,vbat_Rear,");
dataFile.print("currentAll,throttle,brake,speed,trip_Front,trip_Rear,trip,currentConsumed_Front,currentConsumed_Rear,currentConsumed,watthoursConsumed,");
dataFile.println("temp_ESCFront,temp_ESCRear,temp_Air,looptime_duration");
dataFile.println("temp_Front,temp_Rear,temp_Air,looptime_duration_min,looptime_duration_max");
dataFile.print("#TIMESTAMP:"); dataFile.println(now());
logging_headerWritten=true;
}
@ -99,11 +141,15 @@ void loggingLoop(unsigned long loopmillis,ESCSerialComm& escFront, ESCSerialComm
dataFile.print(escRear.getCurrentConsumed(),3); dataFile.print(",");
dataFile.print(currentConsumed,3); dataFile.print(",");
dataFile.print(watthoursConsumed,3); dataFile.print(",");
dataFile.print(temp_ESCFront,2); dataFile.print(",");
dataFile.print(temp_ESCRear,2); dataFile.print(",");
dataFile.print(temp_Front,2); dataFile.print(",");
dataFile.print(temp_Rear,2); dataFile.print(",");
dataFile.print(temp_Air,2); dataFile.print(",");
dataFile.print(looptime_duration); //dataFile.print(",");
looptime_duration=0; //reset
dataFile.print(looptime_duration_min); dataFile.print(",");
dataFile.print(looptime_duration_max); //dataFile.print(",");
looptime_duration_max=0; //reset
looptime_duration_min=1000; //reset
dataFile.println("");
dataFile.close();
@ -111,12 +157,16 @@ void loggingLoop(unsigned long loopmillis,ESCSerialComm& escFront, ESCSerialComm
error_sdfile_unavailable=true;
}
}
looptime_duration_max=0; //reset
looptime_duration_min=1000; //reset
}
}
void writeLogComment(unsigned long time, String msg) {
//SerialRef.print("#"); SerialRef.print(time/1000.0,3); SerialRef.print(","); SerialRef.print(msg); SerialRef.println();
if (datalogging) {
if (datalogging && sdcard_available) {
File dataFile = SD.open(datalogging_filename.c_str(), FILE_WRITE);
if (dataFile) { // if the file is available, write to it
@ -134,6 +184,10 @@ String getLogFilename() {
return datalogging_filename;
}
bool getDatalogging() {
return datalogging;
}
bool loadTripSD()
{
//stats.txt containt lines with driven distance or consume current.
@ -149,6 +203,7 @@ bool loadTripSD()
myFile.close();
Serial.println("TripSD: time written");
}else{
Serial.println("TripSD: could not open stats.txt");
return false;
}
@ -191,7 +246,7 @@ bool loadTripSD()
}
void writeTrip(unsigned long loopmillis,ESCSerialComm& escFront, ESCSerialComm& escRear) {
if (datalogging) {
if (datalogging && sdcard_available) {
File myFile = SD.open("stats.txt", FILE_WRITE);
if (myFile) {
myFile.print("trp=");
@ -201,15 +256,19 @@ void writeTrip(unsigned long loopmillis,ESCSerialComm& escFront, ESCSerialComm&
myFile.print("owh=");
myFile.println(overallWatthoursConsumed);
myFile.print("vlt=");
float _voltage=(escFront.getFeedback_batVoltage()+escRear.getFeedback_batVoltage())/2.0;
float _voltage=getBatteryVoltage(escFront, escRear);
myFile.println(_voltage,2);
myFile.close();
}
}
}
float getBatteryVoltage(ESCSerialComm& escFront, ESCSerialComm& escRear) {
return (escFront.getFeedback_batVoltage()+escRear.getFeedback_batVoltage())/2.0;
}
void resetTrip() {
if (datalogging) {
if (datalogging && sdcard_available) {
File myFile = SD.open("stats.txt", FILE_WRITE);
if (myFile) {
myFile.print("trp=");
@ -227,4 +286,260 @@ void resetTrip() {
}
}
void serialCommandLoop(unsigned long loopmillis,ESCSerialComm& escFront, ESCSerialComm& escRear) {
#define MAX_MESSAGE_LENGTH 80
uint8_t timeoutcounter=MAX_MESSAGE_LENGTH;
while (Serial.available() > 0 && timeoutcounter>0)
{
timeoutcounter--;
static char message[MAX_MESSAGE_LENGTH];
static unsigned int message_pos = 0;
char inByte = Serial.read();
if (inByte == '\r') {
break; //ignore CR
}
if ( inByte != '\n' && (message_pos < MAX_MESSAGE_LENGTH - 1) )
{
message[message_pos] = inByte;
message_pos++;
}
else
{
message[message_pos] = '\0';
String smessage=String(message);
if(smessage.equals("echo off")) {
serialCommandEcho_Enabled=false;
}else if(smessage.equals("echo on")) {
serialCommandEcho_Enabled=true;
}
if (serialCommandEcho_Enabled) { //Echo Command
Serial.print("$"); Serial.println(message);
}
//Handle Commands
if(smessage.equals("test")) {
Serial.println("OK");
}else if(smessage.equals("ls")) {
printFileListing(false);
}else if(smessage.equals("ls -a")) {
printFileListing(true);
}else if(smessage.startsWith("cat")) {
String _filename=smessage.substring(4);
if (_filename.length()<3){ //if no filename given, use current log file
_filename=getLogFilename();
}
printFile(_filename);
}else if(smessage.startsWith("get")) {
String _filename=smessage.substring(4);
transferFile(_filename);
}else if(smessage.startsWith("sizeof")) {
String _filename=smessage.substring(7);
printFilesize(_filename);
}else if(smessage.startsWith("chunksize")) { //change chunksize for get command
String _chunksizestring=smessage.substring(10);
long _chunksize=_chunksizestring.toInt();
if (_chunksize>0 && _chunksize<LONG_MAX) { //value ok
chunksize=_chunksize;
}else{
Serial.println("Chunksize value out of range");
}
}else if(smessage.startsWith("rm")) {
removeFile(smessage.substring(3));
}else if(smessage.equals("log off")) {
writeLogComment(loopmillis, "Datalogging disabled by serial command");
datalogging=false;
Serial.print("Log disabled: "); Serial.println(datalogging_filename);
}else if(smessage.equals("log on")) {
datalogging=true;
writeLogComment(loopmillis, "Datalogging enabled by serial command");
Serial.print("Log enabled: "); Serial.println(datalogging_filename);
}else if(smessage.equals("show stats")) {
Serial.print("overallTrip\t"); Serial.println(overallTrip);
Serial.print("overallCurrentConsumed\t"); Serial.println(overallCurrentConsumed);
Serial.print("overallWatthoursConsumed\t"); Serial.println(overallWatthoursConsumed);
Serial.print("voltage\t"); Serial.println(getBatteryVoltage(escFront,escRear));
}else if(smessage.equals("show sensors")) {
Serial.print("loopmillis\t"); Serial.println(loopmillis);
Serial.print("temp_ESCFront\t"); Serial.println(escFront.getFeedback_boardTemp());
Serial.print("temp_ESCRear\t"); Serial.println(escRear.getFeedback_boardTemp());
Serial.print("vbat_Front\t"); Serial.println(escFront.getFeedback_batVoltage());
Serial.print("vbat_Rear\t"); Serial.println(escRear.getFeedback_batVoltage());
Serial.print("throttle\t"); Serial.println(throttle_pos);
Serial.print("brake\t"); Serial.println(brake_pos);
Serial.print("trip_Front\t"); Serial.println(escFront.getTrip());
Serial.print("trip_Rear\t"); Serial.println(escRear.getTrip());
Serial.print("trip\t"); Serial.println(trip);
Serial.print("currentConsumed_Front\t"); Serial.println(escFront.getCurrentConsumed(),3);
Serial.print("currentConsumed_Rear\t"); Serial.println(escRear.getCurrentConsumed(),3);
Serial.print("currentConsumed\t"); Serial.println(currentConsumed,3);
Serial.print("watthoursConsumed\t"); Serial.println(watthoursConsumed,3);
Serial.print("temp_Front\t"); Serial.println(temp_Front,3);
Serial.print("temp_Rear\t"); Serial.println(temp_Rear,3);
Serial.print("temp_Air\t"); Serial.println(temp_Air,3);
Serial.print("looptime_duration_min\t"); Serial.println(looptime_duration_min);
Serial.print("looptime_duration_max\t"); Serial.println(looptime_duration_max);
}
message_pos = 0;
}
}
}
void printFileListing(bool pretty) {
File root;
root = SD.open("/");
if (pretty) {
printDirectory(root, 0,"",true,false); //tabbed with file sizes
}else{
printDirectory(root, 0,"",false,true); //full paths without size
}
}
void printDirectory(File dir, int numTabs,String parent,bool printSize,bool printFullDirectoryNames) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
if (!printFullDirectoryNames) {
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
}
if (!entry.isDirectory() || !printFullDirectoryNames) {
Serial.print(parent+entry.name());
}
if (entry.isDirectory()) {
if (!printFullDirectoryNames) {
Serial.println("/");
}
printDirectory(entry, numTabs + 1,parent+entry.name()+"/",printSize,printFullDirectoryNames);
} else {
if (printSize) {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.print(entry.size(), DEC);
}
Serial.println();
}
entry.close();
}
}
void printFilesize(String filename) {
File dataFile = SD.open(filename.c_str(), FILE_READ);
if (dataFile) {
Serial.println(dataFile.size(), DEC);
dataFile.close();
}else{
Serial.println('0');
}
}
void printFile(String filename) {
File dataFile = SD.open(filename.c_str(), FILE_READ);
// if the file is available, write to it:
if (dataFile) {
while (dataFile.available()) {
Serial.write(dataFile.read());
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.print("error opening "); Serial.println(filename);
}
}
void transferFile(String filename) {
//similar to printFile, but with checksum and chunk based transfer
File dataFile = SD.open(filename.c_str(), FILE_READ);
bool transmiterror=false;
// if the file is available, write to it:
if (dataFile) {
while (dataFile.available() && !transmiterror) {
byte checksum=0;
for (uint16_t i=0;i<chunksize;i++) {
if (dataFile.available()) {
byte b = dataFile.read();
Serial.write(b);
checksum+=b;
}
}
int inByte=-1;
while (inByte==-1) {
if (Serial.available() > 0)
{
inByte = Serial.read();
if ((byte)inByte!=checksum){
transmiterror=true; //exit
Serial.println();
Serial.println("TRANSMISSION ERROR WRONG CHECKSUM");
}
}
}
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.print("error opening "); Serial.println(filename);
}
}
void removeFile(String filename) {
SD.remove(filename.c_str());
if (SD.exists(filename.c_str())) {
Serial.println("File still exists");
} else {
Serial.println("OK");
}
}
#endif

View file

@ -0,0 +1,121 @@
#ifndef _RC_H_
#define _RC_H_
#define RC
#include <PulsePosition.h>
PulsePositionInput ppmIn;
#define PPMREADPERIOD 20 //period for d4r-ii is 18ms
static int count=0;
#define PIN_PPM 9
#define PPM_CHANNELS 8
#define PPM_SAVE_MIN 950 //minimum allowed for valid data
#define PPM_SAVE_MAX 2050 //maximum allowed for valid data
#define PPM_MIN 1000
#define PPM_MAX 2000
#define PPM_MID 1500
#define PPM_DEADBAND 5
#define PPM_CHANNEL_THROTTLE 1
#define PPM_CHANNEL_STEER 2
#define PPM_CHANNEL_MODE 5
float ppm[PPM_CHANNELS];
unsigned long ppm_count_success=0;
unsigned long ppm_count_fail=0;
void initRC();
void readPPM(unsigned long loopmillis);
void printPPM();
int16_t getRCThrottle();
int16_t getRCSteer();
uint8_t getRCMode(uint8_t modes);
bool rc_fullcontrol_enabled=false; //full remote control. can be cancelled by button press
bool rc_steer_enabled=false; //only rc steering
void initRC() {
ppmIn.begin(PIN_PPM);
}
void readPPM(unsigned long loopmillis) {
int ppm_num = ppmIn.available();
if (ppm_num > 0) {
bool ppm_ok=true;
float new_ppm[PPM_CHANNELS];
if (ppm_num != PPM_CHANNELS) {
ppm_ok=false;
}else{
for (int i=1; i <= ppm_num; i++) {
float val=ppmIn.read(i);
new_ppm[i-1]=val;
if (val<PPM_SAVE_MIN || val>PPM_SAVE_MAX) {
ppm_ok=false;
}
}
}
if (ppm_ok) {
ppm_count_success+=1;
std::copy(std::begin(new_ppm), std::end(new_ppm), std::begin(ppm));
}else{
ppm_count_fail+=1;
}
}
}
float getPPMSuccessrate() {
float rate=ppm_count_success*1.0/(ppm_count_success+ppm_count_fail);
if (ppm_count_success+ppm_count_fail>500) {
ppm_count_success=0;
ppm_count_fail=0;
}
return rate;
}
//Return value 0 - 1000
int16_t getRCThrottle() {
return constrain(map(ppm[PPM_CHANNEL_THROTTLE-1],PPM_MID+PPM_DEADBAND,PPM_MAX,0,1000), 0,1000);
}
int16_t getRCBrake() {
return constrain(map(ppm[PPM_CHANNEL_THROTTLE-1],PPM_MID-PPM_DEADBAND,PPM_MIN,0,1000), 0,1000);
}
//Return value -1000 - 1000
int16_t getRCSteer() {
if (ppm[PPM_CHANNEL_STEER-1]>PPM_MID+PPM_DEADBAND){
return constrain(map(ppm[PPM_CHANNEL_STEER-1],PPM_MID+PPM_DEADBAND,PPM_MAX,0,1000), 0,1000);
}else if (ppm[PPM_CHANNEL_STEER-1]<PPM_MID-PPM_DEADBAND){
return constrain(map(ppm[PPM_CHANNEL_STEER-1],PPM_MID-PPM_DEADBAND,PPM_MIN,0,-1000), -1000,0);
}else{
return 0;
}
}
//Return descrete value for equidistant ranges. modes = number of ranges.
uint8_t getRCMode(uint8_t modes) {
float v=constrain(map(ppm[PPM_CHANNEL_MODE-1],PPM_MIN,PPM_MAX,0.0,1.0), 0.0,0.999);
return uint8_t(v*modes);
}
void printPPM(unsigned long loopmillis){
count = count + 1;
Serial.print("ms :");
Serial.print(count);
Serial.print(" : ");
for (int i=1; i <= PPM_CHANNELS; i++) {
Serial.print(ppm[i-1]);
Serial.print(" ");
}
Serial.println();
}
#endif

View file

@ -4,11 +4,13 @@
#include <OneWire.h>
#include <DallasTemperature.h>
//#define SEARCH_DEVICES
DeviceAddress thermometerESCFront={0x28,0xFF,0x64,0x0E,0x77,0xB0,0xAB,0x4B}; //IC with one marking 28FF640E77B0AB4B
float temp_ESCFront;
DeviceAddress thermometerESCRear={0x28,0xFF,0x64,0x0E,0x76,0x5D,0x86,0xC2}; //IC with two markings
float temp_ESCRear;
DeviceAddress thermometerFront={0x28,0xFF,0x64,0x0E,0x77,0xB0,0xAB,0x4B}; //IC with one marking 28FF640E77B0AB4B
float temp_Front;
DeviceAddress thermometerRear={0x28,0xFF,0x64,0x0E,0x76,0x5D,0x86,0xC2}; //IC with two markings
float temp_Rear;
DeviceAddress thermometerAir={0x28,0xFF,0x64,0x0E,0x74,0x7E,0xFE,0x23}; //IC with three markings 28FF640E747EFE23
float temp_Air;
@ -29,20 +31,15 @@ void printAddress(DeviceAddress deviceAddress);
void initTemperature() {
sensors.begin();
delay(1000);
//Just search for devices. Only needed when connecting a new sensor to find the address
#ifdef SEARCH_DEVICES
Serial.print("Locating 1Wire devices...");
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" devices.");
delay(1000);
delay(1000);
//Just search for devices. Only needed when connecting a new sensor to find the address
oneWire.reset_search();
for (uint8_t i=0;i<sensors.getDeviceCount();i++){
@ -58,8 +55,9 @@ void initTemperature() {
}
delay(1000);
#endif
//sensors.setResolution(thermometerReservoir, TEMPERATURE_PRECISION);
//sensors.setResolution(thermometerESCFront, TEMPERATURE_PRECISION);
}
@ -86,8 +84,8 @@ bool temperatureLoop(unsigned long loopmillis) {
if (sensors.isConversionComplete()) {
flag_requestTemperatures=false;
last_read_ds18b20=loopmillis;
temp_ESCFront= sensors.getTempC(thermometerESCFront); //This takes ~12.5ms
temp_ESCRear= sensors.getTempC(thermometerESCRear);
temp_Front= sensors.getTempC(thermometerFront); //This takes ~12.5ms
temp_Rear= sensors.getTempC(thermometerRear);
temp_Air= sensors.getTempC(thermometerAir);
}
}

@ -1 +1 @@
Subproject commit 150ce61f9f8d8c013f2fca424ec2976c3582d403
Subproject commit 0cf2df74e186bc5c6dd60cecedb3a865f5b9d467

View file

@ -26,6 +26,7 @@ lib_deps =
adafruit/Adafruit SSD1306@^2.5.7
https://github.com/adafruit/Adafruit_NeoPixel
https://github.com/milesburton/Arduino-Temperature-Control-Library/
https://github.com/PaulStoffregen/PulsePosition
[env:teensy31]

View file

@ -16,15 +16,18 @@
#include "led.h"
#include "temperature.h"
//#include "comms.h"
String getLogFilename();
bool getDatalogging();
#include "display.h"
#include "logging.h"
#include "rc.h"
#include "ADS1X15.h"
//#define CALIBRATION_THROTTLE_CURVE //uncomment to enable throttleA and B serial output on button press
@ -48,7 +51,7 @@ void readADC();
void failChecks();
//void sendCMD();
void calculateSetSpeed(unsigned long timediff);
void checkLog();
void leds();
@ -69,11 +72,25 @@ void setup()
Serial1.begin(SERIAL_LOG_BAUD); //TX1=1, RX1=0
//Serial2.begin(SERIAL_CONTROL_BAUD); //control, TX2=10, RX2=9
//Serial3.begin(SERIAL_CONTROL_BAUD); //control, TX3=8, RX3=7
pinMode(PIN_PWRBUTTON, INPUT_PULLUP); //Pressed=High
datalogging=false; //disable logging when connected via usb to not clutter up sd card
Serial.print("PWRBUTTON ");
for (uint8_t i=0;i<10;i++) { //check a few times
if (!digitalRead(PIN_PWRBUTTON)) { //button is not pressed during startup means teensy is powered externally (usb)
Serial.print(".");
delay(100); //give more time to disable logging
}else{
datalogging=true; //button presse at least once recognized. enable logging
Serial.print("X");
}
}
if (!datalogging){
Serial.println(" not pressed. Logging disabled!");
}else{
Serial.println(" Pressed. Logging enabled");
}
pinMode(PIN_LED_START, OUTPUT); //Active High
@ -90,19 +107,21 @@ void setup()
led_testLEDSBlocking();
delay(2000);
delay(100);
Serial.println("Init Functions");
led_simpeProgress(0,1);
bool initResult=false;
initResult=display_init();
if (!initResult) {
writeLogComment((unsigned long)millis(), "SSD1306 allocation failed");
}
led_simpeProgress(1,initResult);
initResult=initLogging();
led_simpeProgress(2,initResult);
led_simpeProgress(2,(initResult ? (datalogging ? 1:2):0)); //0=sd card fail, 1=sd ok and logging, 2(warn)=sd ok and logging off
@ -127,7 +146,6 @@ void setup()
// also set ADSREADPERIOD to at least the read interval
ADS.requestADC(0); //Start requesting a channel
led_simpeProgress(6,true);
writeLogComment((unsigned long)millis(), "ADS1115 Initialized");
}
delay(10);
for (uint8_t i=0;i<4;i++){ //read all channels once to have adc readings ready in first loop (to prevent premature failsafe)
@ -139,6 +157,8 @@ void setup()
setSyncProvider(getTeensy3Time); //See https://www.pjrc.com/teensy/td_libs_Time.html#teensy3
if (timeStatus()!= timeSet) {
Serial.println("Unable to sync with the RTC");
writeLogComment((unsigned long)millis(), "Unable to sync with the RTC");
led_simpeProgress(7,false);
} else {
Serial.println("RTC has set the system time");
@ -146,7 +166,7 @@ void setup()
}
if (datalogging) { //sd init was successful
if (sdcard_available) { //sd init was successful
initResult=loadTripSD();
}else{
initResult=false;
@ -156,13 +176,18 @@ void setup()
initTemperature();
led_simpeProgress(9,true);
initRC();
led_simpeProgress(10,true);
writeLogComment(millis(), "Setup Finished");
led_simpeProgress(15,true);
led_simpleProgressWait(); //wait longer if any errors were displayed with led_simpeProgress()
Serial.println("Ready");
}
@ -173,46 +198,6 @@ void loop() {
loopmillis=millis(); //read millis for this cycle
/*
// ____ Debugging pending serial byted for feedback
static int s2availmax=0;
int _a2=Serial2.available();
if (_a2>s2availmax) {
s2availmax=_a2;
//Serial.print("new s2availmax"); Serial.println(s2availmax);
String _text="Serial2 Bytes Available Max=";
_text+=s2availmax;
writeLogComment(Serial1,loopmillis, _text);
}
static int s3availmax=0;
int _a3=Serial3.available();
if (_a3>s3availmax) {
s3availmax=_a3;
//Serial.print("new s3availmax"); Serial.println(s3availmax);
String _text="Serial3 Bytes Available Max=";
_text+=s3availmax;
writeLogComment(Serial1,loopmillis, _text);
}
// ----- End of debug
bool newData2=ReceiveSerial(SerialcomFront,FeedbackFront, NewFeedbackFront, Serial2);
bool newData3=ReceiveSerial(SerialcomRear,FeedbackRear, NewFeedbackRear, Serial3);
//Max (40) or 22 available/pending bytes
if (newData2) {
updateMotorparams(motorparamsFront,FeedbackFront,loopmillis);
}
if (newData3) {
updateMotorparams(motorparamsRear,FeedbackRear,loopmillis);
}
*/
@ -240,6 +225,13 @@ void loop() {
readADSButtons();
}
static unsigned long last_ppmread=0;
if (loopmillis - last_ppmread > PPMREADPERIOD) { //read digital input states
last_ppmread=loopmillis;
readPPM(loopmillis);
}
failChecks();
@ -253,14 +245,17 @@ void loop() {
max_filtered_currentAll=max(max_filtered_currentAll,filtered_currentAll);
min_filtered_currentAll=min(min_filtered_currentAll,filtered_currentAll);
max_filtered_wattAll=max(max_filtered_wattAll,filtered_currentAll*(escFront.getFeedback_batVoltage()+escRear.getFeedback_batVoltage())/2.0);
min_filtered_wattAll=min(min_filtered_wattAll,filtered_currentAll*(escFront.getFeedback_batVoltage()+escRear.getFeedback_batVoltage())/2.0);
float _meanVoltage=(escFront.getFeedback_batVoltage()+escRear.getFeedback_batVoltage())/2.0;
max_filtered_wattAll=max(max_filtered_wattAll,filtered_currentAll*_meanVoltage);
min_filtered_wattAll=min(min_filtered_wattAll,filtered_currentAll*_meanVoltage);
min_voltage=min(min_voltage,_meanVoltage);
max_meanSpeed=max(max_meanSpeed,(escFront.getMeanSpeed()+escRear.getMeanSpeed())/2);
if (!armed) { //reset statistics if disarmed
max_filtered_currentAll=0;
min_filtered_currentAll=0;
max_filtered_wattAll=0;
min_filtered_wattAll=0;
min_voltage=99;
max_meanSpeed=0;
}
}
@ -288,32 +283,8 @@ void loop() {
last_statsupdate=loopmillis;
}
/* TODO: remove this if, because everything contained in esc.update()
if (loopmillis - last_send > SENDPERIOD) { //Calculate motor stuff and send to motor controllers
last_send=loopmillis;
//sendCMD();
//Update speed and trip
float _meanRPM=(FeedbackFront.speedL_meas-FeedbackFront.speedR_meas+FeedbackRear.speedL_meas-FeedbackRear.speedR_meas)/4.0;
meanSpeedms=_meanRPM*wheelcircumference/60.0; // Units: 1/min * m / 60s
trip+=abs(meanSpeedms)* (SENDPERIOD/1000.0);
//mah consumed
currentConsumed += (motorparamsFront.filtered_curL+motorparamsFront.filtered_curR+motorparamsRear.filtered_curL+motorparamsRear.filtered_curR)* (SENDPERIOD/1000.0)/3600.0; //amp hours
}
*/
//If needed write log to serial port
//checkLog(); //TODO remove
loggingLoop(loopmillis,escFront,escRear);
if (!armed && !statswritten) { //write stats only once when disarmed
statswritten=true;
writeTrip(loopmillis,escFront,escRear);
}
if (statswritten && armed) {
statswritten=false;
}
leds();
led_update(loopmillis,escFront,escRear); //ws2812 led ring
@ -340,11 +311,11 @@ void loop() {
last_fan_update=loopmillis;
boolean fanstatus=digitalRead(PIN_FAN);
//float temp=max(escFront.getFeedback_boardTemp(),escRear.getFeedback_boardTemp());
float temp=max(temp_ESCFront,temp_ESCRear);
if (temp_ESCFront==DEVICE_DISCONNECTED_C || temp_ESCRear==DEVICE_DISCONNECTED_C ) { //temperature error
float temp=max(temp_Front,temp_Rear);
if (temp_Front==DEVICE_DISCONNECTED_C || temp_Rear==DEVICE_DISCONNECTED_C ) { //temperature error
digitalWrite(PIN_FAN,HIGH); //force fan on
}else{ //normal temperature control
}else{ //normal temperature control_currentIncrease
if (!fanstatus) { //fan is off
if (temp>=fan_turn_on_temp){
@ -359,8 +330,24 @@ void loop() {
}
serialCommandLoop(loopmillis,escFront,escRear);
looptime_duration=max(looptime_duration,millis()-loopmillis);
//Logging
loggingLoop(loopmillis,escFront,escRear);
if (!armed && !statswritten) { //write stats only once when disarmed
statswritten=true;
writeTrip(loopmillis,escFront,escRear);
}
if (statswritten && armed) {
statswritten=false;
}
looptime_duration_min=min(looptime_duration_min,millis()-loopmillis);
looptime_duration_max=max(looptime_duration_max,millis()-loopmillis);
}
@ -408,24 +395,9 @@ void readADS() { //sequentially read ads and write to variable
void readADC() {
//Serial.print(ads_throttle_A_raw); Serial.print('\t');
//Serial.print(ads_throttle_B_raw); Serial.print('\t');
//Serial.print(ads_brake_raw); Serial.print('\t');
//Serial.print(ads_control_raw); Serial.println();
//throttle_raw = (ads_throttle_A_raw+ads_throttle_B_raw)/2.0*THROTTLE_ADC_FILTER + throttle_raw*(1-THROTTLE_ADC_FILTER); //apply filter
throttle_rawA=ads_throttle_A_raw;
throttle_rawB=ads_throttle_B_raw;
//maps throttle curve to be linear
//throttle_pos=max(0,min(1000,linearizeThrottle(throttle_raw))); //map and constrain
throttle_posA=max(0,min(1000, linearizeThrottle(ads_throttle_A_raw, throttleCurvePerMM_A, sizeof(throttleCurvePerMM_A)/sizeof(throttleCurvePerMM_A[0]), throttleCurvePerMM_A_Descending ) )); //map and constrain
throttle_posB=max(0,min(1000, linearizeThrottle(ads_throttle_B_raw, throttleCurvePerMM_B, sizeof(throttleCurvePerMM_B)/sizeof(throttleCurvePerMM_B[0]), throttleCurvePerMM_B_Descending ) )); //map and constrain
//Serial.print(throttle_posA); Serial.print('\t');
//Serial.print(throttle_posB); Serial.print('\t');
throttle_posA=max(0,min(1000, linearizeThrottle(ads_throttle_A_raw, throttleCurvePerMM_A, sizeof(throttleCurvePerMM_A)/sizeof(throttleCurvePerMM_A[0]), throttleCurvePerMM_A_Descending ) )); //linearize and constrain (linear function already constrains)
throttle_posB=max(0,min(1000, linearizeThrottle(ads_throttle_B_raw, throttleCurvePerMM_B, sizeof(throttleCurvePerMM_B)/sizeof(throttleCurvePerMM_B[0]), throttleCurvePerMM_B_Descending ) )); //linearize and constrain (linear function already constrains
int16_t throttle_posMean = (throttle_posA+throttle_posB)/2.0;
@ -433,20 +405,13 @@ void readADC() {
throttle_pos = throttle_posMean*THROTTLE_ADC_FILTER + throttle_pos*(1-THROTTLE_ADC_FILTER); //apply filter
brake_raw=ads_brake_raw;
brake_pos=max(0,min(1000,map(brake_raw,calib_brake_min,calib_brake_max,0,1000))); //map and constrain
brake_linear=map(ads_brake_raw,calib_brake_min,calib_brake_max,0,1000);
brake_pos=max(0,min(1000,brake_linear)); //map and constrain
//brake_pos = (int16_t)(pow((brake_pos/1000.0),2)*1000);
if (throttle_pos>0 || ((escFront.getMeanSpeed()+escRear.getMeanSpeed())/2.0) >0.5 || (!reverse_enabled && brake_pos>0)) { //reset idle time on these conditions (disables reverse driving)
last_notidle=loopmillis;
reverse_enabled=false;
}
if (loopmillis-last_notidle > REVERSE_ENABLE_TIME) {
reverse_enabled=true;
}
int16_t throttlebreak_pos = throttle_pos-brake_pos*2; //reduce throttle_when applying brake
throttle_pos=constrain(throttlebreak_pos,0,1000);
@ -483,6 +448,7 @@ void failChecks() {
if ((ads_throttle_A_raw >= failsafe_throttle_min_A) & (ads_throttle_A_raw <= failsafe_throttle_max_A) & (ads_throttle_B_raw >= failsafe_throttle_min_B) & (ads_throttle_B_raw <= failsafe_throttle_max_B)) { //inside safe range (to check if wire got disconnected)
throttle_ok_time=loopmillis;
}
if (loopmillis>throttle_ok_time+ADC_OUTOFRANGE_TIME) { //not ok for too long
if (!error_throttle_outofrange) {
error_throttle_outofrange=true;
@ -491,10 +457,12 @@ void failChecks() {
//Serial.print("Error Throttle ADC Out of Range="); Serial.println(throttle_raw);
}
static unsigned long throttlediff_ok_time=0;
if (abs(throttle_posA-throttle_posB) <= failsafe_throttle_maxDiff) { //inside safe range (to check if wire got disconnected)
throttlediff_ok_time=loopmillis;
}
#ifndef CALIBRATION_THROTTLE_CURVE //do not check if throttle calibration enabled
if (loopmillis>throttlediff_ok_time+ADC_DIFFHIGH_TIME) { //not ok for too long
if (!error_throttle_difftoohigh) {
error_throttle_difftoohigh=true;
@ -502,16 +470,17 @@ void failChecks() {
}
//Serial.print("Error Throttle ADC Out of Range="); Serial.println(throttle_raw);
}
#endif
static unsigned long brake_ok_time=0;
if ((brake_raw >= failsafe_brake_min) & (brake_raw <= failsafe_brake_max)) { //outside safe range. maybe wire got disconnected
if ((ads_brake_raw >= failsafe_brake_min) & (ads_brake_raw <= failsafe_brake_max)) { //outside safe range. maybe wire got disconnected
brake_ok_time=loopmillis;
}
if (loopmillis>brake_ok_time+ADC_OUTOFRANGE_TIME) { //not ok for too long
if(!error_brake_outofrange) {
error_brake_outofrange=true;
writeLogComment(loopmillis, "Error Brake ADC Out of Range. ADC="+(String)brake_raw);
writeLogComment(loopmillis, "Error Brake ADC Out of Range. ADC="+(String)ads_brake_raw);
}
//Serial.print("Error Brake ADC Out of Range="); Serial.println(brake_raw);
}
@ -540,9 +509,39 @@ void failChecks() {
void calculateSetSpeed(unsigned long timediff){
int16_t adjusted_throttle_pos=constrain(throttle_pos*(throttle_max/1000.0),0,throttle_max);
int16_t brake_pos_linear=brake_pos;
int16_t brake_pos_expo = (int16_t)(pow((brake_pos_linear/1000.0),2)*1000);
int16_t brake_pos_expo = (int16_t)(pow((brake_pos/1000.0),2)*1000);
#ifdef RC
if (throttle_pos>0 || brake_pos>0) { //touch any pedal to cancel rc fullcontrol mode
rc_fullcontrol_enabled=false;
}
if (rc_fullcontrol_enabled) {
int16_t rcthrottle_pos=getRCThrottle();
int16_t rcbrake_pos=getRCBrake();
adjusted_throttle_pos=constrain(rcthrottle_pos*(throttle_max/1000.0),0,throttle_max); //overwrite with rc values
brake_pos_linear=rcbrake_pos;
brake_pos_expo = (int16_t)(pow((brake_pos_linear/1000.0),2)*1000);
}
#endif
//Reverse Enable
if (throttle_pos>0 || ((escFront.getMeanSpeed()+escRear.getMeanSpeed())/2.0) >0.5 || (!reverse_enabled && brake_pos_linear>0)) { //reset idle time on these conditions (disables reverse driving)
last_notidle=loopmillis;
reverse_enabled=false;
}
if (loopmillis-last_notidle > REVERSE_ENABLE_TIME) {
reverse_enabled=true;
}
//Throttle Management
float brakepedal_current_multiplier=startbrakecurrent/1000.0; //how much breaking (in Ampere) for unit of brake_pos (0<=brake_pos<=1000)
int16_t cmdreduce_constant=map(brake_pos_expo,0,1000,0,(int16_t)(brake_cmdreduce_proportional*timediff/1000)); //reduce cmd value every cycle
@ -564,27 +563,157 @@ void calculateSetSpeed(unsigned long timediff){
}
//acceleration
cmd_send += constrain(adjusted_throttle_pos-cmd_send,0,(int16_t)(max_acceleration_rate*(timediff/1000.0)) ); //if throttle higher than last applied value, apply throttle directly
// ## Acceleration
cmd_send += constrain(adjusted_throttle_pos-cmd_send,0,(int16_t)(max_acceleration_rate*(timediff/1000.0)) ); //if throttle higher than last applied value, apply throttle directly with rate limit
cmd_send=constrain(cmd_send,0,throttle_max);
last_cmd_send=cmd_send;
int16_t cmd_send_toMotor=constrain(cmd_send* (1.0-(brake_pos*0.5/1000.0) ) ,0,throttle_max); //brake "ducking"
int16_t cmd_send_toMotor_FL=0;
int16_t cmd_send_toMotor_FR=0;
int16_t cmd_send_toMotor_RL=0;
int16_t cmd_send_toMotor_RR=0;
int16_t _cmd_send_toMotor=constrain(cmd_send* (1.0-(brake_pos_expo*0.5/1000.0) ) ,0,throttle_max); //brake "ducking"
if (reverse_enabled) {
cmd_send_toMotor-=brake_pos*reverse_speed;
cmd_send_toMotor_FL=_cmd_send_toMotor;
cmd_send_toMotor_FR=_cmd_send_toMotor;
cmd_send_toMotor_RL=_cmd_send_toMotor;
cmd_send_toMotor_RR=_cmd_send_toMotor;
#ifdef RC
int16_t differential_steering_max=200;
#define RC_STEER_ENABLE_WAITTIME 1000/SENDPERIOD*2; //in cycles. every SENDPERIOD
static uint16_t rc_steer_enable_wait=0; //give some time to release buttons after arming with rc mode to not cancel immediately
if (rc_steer_enabled) {
if (rc_steer_enable_wait>0) {
rc_steer_enable_wait--;
}else{ //allow control when counter reached 0
if (control_buttonA || control_buttonB) { //cancel rc modes by button press
rc_fullcontrol_enabled=false;
rc_steer_enabled=false;
}
float rcsteer=getRCSteer()/1000.0;
cmd_send_toMotor_FL+=rcsteer*differential_steering_max;
cmd_send_toMotor_FR-=rcsteer*differential_steering_max;
}
}else{
rc_steer_enable_wait=RC_STEER_ENABLE_WAITTIME;
}
#endif
#ifdef DRIVING_TANKSTEERING
// ## Experimental Tank steering
/* Notes from Drivetest 20240722
When driving slow and pressing button steering wheel is turned more violently.
When driving faster (>10km/h) steering wheel is not forced as strong, but bobbycar turns better around itself.
As cmd increase in higher ranges is more pronounces in motor torque, the same tanksteering_max_speed=200 is way too strong when driving >20km/h, but okay when driving <10km/h.
Disabled this function for now, because if button press is triggered erroneously during fast driving it could be dangerous. Steering manually against it is not possible.
*/
static float tanksteering_differential=0; //to ramp up slowly. value between -1.0 and 1.0
//Parameters:
int16_t tanksteering_max_speed=200;
float tanksteering_rate_increase=2.0; //increase units per second
float tanksteering_rate_decrease=3.0; //decrease units per second
if (control_buttonA && !control_buttonB && !reverse_enabled && throttle_pos>0) { //Right button (A) only. and throttle touched
tanksteering_differential+=tanksteering_rate_increase*(timediff/1000.0);
tanksteering_differential=constrain(tanksteering_differential,-1.0,1.0); //constrain between 0 and 1
}else if(control_buttonB && !control_buttonA && !reverse_enabled && throttle_pos>0) { //Left button (B) only. and throttle touched
tanksteering_differential-=tanksteering_rate_increase*(timediff/1000.0);
tanksteering_differential=constrain(tanksteering_differential,-1.0,1.0); //constrain between 0 and 1
}else{ //buttons released
if(tanksteering_differential>0) {
tanksteering_differential-=tanksteering_rate_decrease*(timediff/1000.0);
}else if(tanksteering_differential<0){
tanksteering_differential+=tanksteering_rate_decrease*(timediff/1000.0);
}
tanksteering_differential=constrain(tanksteering_differential,-1.0,1.0); //constrain between 0 and 1
}
cmd_send_toMotor_FL+=tanksteering_differential*tanksteering_max_speed;
cmd_send_toMotor_FR-=tanksteering_differential*tanksteering_max_speed;
cmd_send_toMotor_RL+=tanksteering_differential*tanksteering_max_speed;
cmd_send_toMotor_RR-=tanksteering_differential*tanksteering_max_speed;
#endif
// ## Braking, Reversing and Standstill movements below here ##
/*
if (reverse_enabled) { //backwards driving not prohibited
_cmd_send_toMotor-=brake_pos_linear*reverse_speed;
cmd_send_toMotor_FL=_cmd_send_toMotor;
cmd_send_toMotor_FR=_cmd_send_toMotor;
cmd_send_toMotor_RL=_cmd_send_toMotor;
cmd_send_toMotor_RR=_cmd_send_toMotor;
}
*/
float steeringdifferential_speed=0.4; //Speed for turning the steering wheel by differtially driving the front wheels
if (reverse_enabled) { //backwards driving not prohibited
static bool tanksteering_prohibit_left=false;
static bool tanksteering_prohibit_right=false;
static bool prohibit_reverse=false;
if (control_buttonA && !control_buttonB) { //Right button (A) only
tanksteering_prohibit_left=true;
prohibit_reverse=true;
}else if(control_buttonB && !control_buttonA) {//Left button (B) only
tanksteering_prohibit_right=true;
prohibit_reverse=true;
}else if(!control_buttonA && !control_buttonB){ //no button pressed
tanksteering_prohibit_left=true;
tanksteering_prohibit_right=true;
if (throttle_pos<=0 && brake_pos_linear<=0) {//levers released
tanksteering_prohibit_left=false;
tanksteering_prohibit_right=false;
prohibit_reverse=false;
}
}
if (!tanksteering_prohibit_right && tanksteering_prohibit_left && prohibit_reverse) { //Right Tanksteering
cmd_send_toMotor_FL+=brake_pos_linear*steeringdifferential_speed;
cmd_send_toMotor_FR-=brake_pos_linear*steeringdifferential_speed;
cmd_send_toMotor_RL+=brake_pos_linear*steeringdifferential_speed;
cmd_send_toMotor_RR-=brake_pos_linear*steeringdifferential_speed;
}else if(tanksteering_prohibit_right && !tanksteering_prohibit_left && prohibit_reverse) { //Left Tanksteering
cmd_send_toMotor_FL-=brake_pos_linear*steeringdifferential_speed;
cmd_send_toMotor_FR+=brake_pos_linear*steeringdifferential_speed;
cmd_send_toMotor_RL-=brake_pos_linear*steeringdifferential_speed;
cmd_send_toMotor_RR+=brake_pos_linear*steeringdifferential_speed;
}else if(tanksteering_prohibit_right && tanksteering_prohibit_left && !prohibit_reverse){ //no button on steering wheel pressed, drive backwards
int16_t cmd_send_brake=brake_pos_linear*reverse_speed;
cmd_send_toMotor_FL-=cmd_send_brake;
cmd_send_toMotor_FR-=cmd_send_brake;
cmd_send_toMotor_RL-=cmd_send_brake;
cmd_send_toMotor_RR-=cmd_send_brake;
}
}
if (!controllers_connected || !armed) { //controllers not connected or not armed
cmd_send=0;
cmd_send_toMotor=0; //safety off
cmd_send_toMotor_FL=0; //safety off
cmd_send_toMotor_FR=0; //safety off
cmd_send_toMotor_RL=0; //safety off
cmd_send_toMotor_RR=0; //safety off
}
escFront.setSpeed(cmd_send_toMotor,cmd_send_toMotor);
escRear.setSpeed(cmd_send_toMotor,cmd_send_toMotor);
escFront.setSpeed(cmd_send_toMotor_FL,cmd_send_toMotor_FR);
escRear.setSpeed(cmd_send_toMotor_RL,cmd_send_toMotor_RR);
log_update=true;
}
@ -610,6 +739,7 @@ void readButtons() {
static bool button_start_wait_release_flag=false;
bool last_button_start_state=button_start_state;
if (loopmillis > button_start_lastchange+DEBOUNCE_TIME) { //wait some time after last change
if (digitalRead(PIN_PWRBUTTON) && !button_start_state) { //start engine button pressed and was not pressed before
button_start_state=true; //pressed
@ -641,23 +771,87 @@ void readButtons() {
writeLogComment(loopmillis, "Disarmed by button");
}
if (button_start_longpress_flag) {
#ifndef CALIBRATION_THROTTLE_CURVE //disable arming when throttle calibration enabled (because errorcheck is disabled)
if (escFront.getControllerConnected() && escRear.getControllerConnected()) {
armed=true; //arm if button pressed long enough
writeLogComment(loopmillis, "Armed by button");
if (control_buttonA) { //button A is held down during start button press
rc_fullcontrol_enabled=false;
rc_steer_enabled=false;
if (control_buttonA && control_buttonB) { //button A and B is held down during start button press
uint8_t rcmode=getRCMode(6);
if (getRCThrottle()==0 && getRCBrake()==0) {
switch (rcmode) {
case 0:
throttle_max=250;
reverse_speed=0.15;
max_acceleration_rate=SLOW_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: RC 0");
break;
case 1:
throttle_max=250;
reverse_speed=0.15;
max_acceleration_rate=MEDIUM_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: RC 1");
break;
case 2:
throttle_max=300;
reverse_speed=0.2;
max_acceleration_rate=NORMAL_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: RC 2");
break;
case 3:
throttle_max=400;
reverse_speed=0.25;
max_acceleration_rate=NORMAL_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: RC 3");
break;
case 4:
throttle_max=600;
reverse_speed=0.25;
max_acceleration_rate=NORMAL_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: RC 4");
break;
case 5:
throttle_max=750;
reverse_speed=0.25;
max_acceleration_rate=NORMAL_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: RC 5");
break;
}
rc_fullcontrol_enabled=true;
rc_steer_enabled=true;
}else{
writeLogComment(loopmillis, "Not Arming. RC throttle and brake not zero");
armed=false;
}
}else if (control_buttonA) { //button A is held down during start button press
throttle_max=1000;
reverse_speed=0.25;
max_acceleration_rate=NORMAL_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: Fast");
}else if (control_buttonB) { //button B is held down during start button press
throttle_max=750;
reverse_speed=0.25;
max_acceleration_rate=SLOW_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: Medium");
}else { //no control button pressed during start
throttle_max=250;
reverse_speed=0.15;
max_acceleration_rate=SLOW_MAX_ACCELERATION_RATE;
writeLogComment(loopmillis, "Mode: Slow");
}
}else{
writeLogComment(loopmillis, "Unable to arm");
}
#endif
}
@ -682,10 +876,31 @@ void readADSButtons() {
if (control_buttonA && !last_control_buttonA) { //button A was just pressed
writeLogComment(loopmillis, "Button A Pressed");
if (!armed) { //standing disarmed display is showing
if (standingDisplayScreen<NUM_STANDINGDISPLAYSCREEN-1){
standingDisplayScreen++;
}
#ifdef CALIBRATION_THROTTLE_CURVE
if (standingDisplayScreen==(NUM_STANDINGDISPLAYSCREEN-1)) { //on last page and button A pressed
Serial.print(ads_throttle_A_raw); Serial.print(',');
Serial.println(ads_throttle_B_raw);
}
#endif
}
}
if (control_buttonB && !last_control_buttonB) { //button B was just pressed
writeLogComment(loopmillis, "Button B Pressed");
if (!armed) { //standing disarmed display is showing
if (standingDisplayScreen>0){
standingDisplayScreen--;
}
}
}
}

View file

@ -1,52 +1,114 @@
import matplotlib.pyplot as plt
import csv
#import csv
import pandas as pd
x=[]
speed_FrontL=[]
speed_FrontR=[]
speed_RearL=[]
speed_RearR=[]
fp = open('LOG00203c_replacedFrontLeftWheel.TXT')
rdr = csv.DictReader(filter(lambda row: row[0]!='#', fp))
for row in rdr:
#print(row)
x.append(float(row['cmd_FrontL']))
speed_FrontL.append(float(row['speed_FrontL']))
speed_FrontR.append(float(row['speed_FrontR']))
speed_RearL.append(float(row['speed_RearL']))
speed_RearR.append(float(row['speed_RearR']))
fp.close()
import numpy as np
#plt.plot(x,y, label='Loaded from file!')
scattersize=5
scatteralpha=0.1
plt.scatter(x,speed_FrontL, s=scattersize, alpha=scatteralpha, label="speed_FrontL")
plt.scatter(x,speed_FrontR, s=scattersize, alpha=scatteralpha, label="speed_FrontR")
plt.scatter(x,speed_RearL, s=scattersize, alpha=scatteralpha, label="speed_RearL")
plt.scatter(x,speed_RearR, s=scattersize, alpha=scatteralpha, label="speed_RearR")
plt.xlabel('cmd')
plt.ylabel('speed')
plt.title('Interesting Graph\nCheck it out')
plt.legend()
plt.show()
import argparse
def mapRange(value, inMin, inMax, outMin, outMax,constrain=False):
if constrain:
return max(outMin, min(outMax, outMin + (((value - inMin) / (inMax - inMin)) * (outMax - outMin))))
else:
return outMin + (((value - inMin) / (inMax - inMin)) * (outMax - outMin))
'''
with open(,'r') as csvfile:
plots = csv.reader(filter(lambda row: row[0]!='#', csvfile), delimiter=',')
for row in plots:
x.append(float(row[0]))
y.append(float(row[1]))
parser = argparse.ArgumentParser(description='Analyzes fixed csv logs from bobbycar')
parser.add_argument('-i', '--input', type=argparse.FileType('r'), required=True, help="input csv log file")
args = parser.parse_args()
plt.plot(x,y, label='Loaded from file!')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Interesting Graph\nCheck it out')
plt.legend()
plt.show()
'''
df = pd.read_csv(args.input.name)
x = df['timestamp']
x = [i-x[0] for i in x] #offset time by starttime
def template():
scattersize=1
scatteralpha=0.1
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
#plt.scatter(x,df['rpm_FrontL'], s=scattersize, alpha=scatteralpha, label="rpm_FrontL")
ax1.plot(x,np.array(df['temp_Front']), c='#0000ff', alpha=0.5, label="temp_Front")
ax1.plot(x,np.array(df['temp_Rear']), c='#ff0000', alpha=0.5, label="temp_Rear")
ax1.plot(x,np.array(df['temp_Air']), c='#00ff00', alpha=0.5, label="temp_Air")
#ax2.plot(x,np.array(df['throttle']), c='g', alpha=0.5, label="throttle")
#confidence
#confidence_FrontL=[abs(x-df['cmd_FrontL'][i-5 if i>4 else 0])+abs(x-df['cmd_FrontL'][i-10 if i>9 else 0])+abs(x-df['cmd_FrontL'][i-20 if i>19 else 0]) for i,x in enumerate(df['cmd_FrontL'])]
#confidence_FrontL=[mapRange(x,0,50,1.0,0.0,True) for x in confidence_FrontL]
#ax1.scatter(df['cmd_FrontL'],df['rpm_FrontL'], s=scattersize, alpha=scatteralpha, label="FrontL")
#ax1.scatter(df['cmd_FrontR'],df['rpm_FrontR'], s=scattersize, alpha=scatteralpha, label="FrontR")
#ax1.scatter(df['cmd_RearL'],df['rpm_RearL'], s=scattersize, alpha=scatteralpha, label="RearL")
#ax1.scatter(df['cmd_RearR'],df['rpm_RearR'], s=scattersize, alpha=scatteralpha, label="RearR")
ax1.set_xlabel('timestamp')
#plt.ylabel('data')
ax1.set_ylabel('first axis')
ax2.set_ylabel('second axis')
#plt.title('')
ax1.legend(loc='upper left')
ax2.legend(loc='upper right')
plt.show()
def rpmDifference():
scattersize=1
scatteralpha=0.1
fig, ax1 = plt.subplots()
#confidence_FrontL=[abs(x-df['cmd_FrontL'][i-5 if i>4 else 0])+abs(x-df['cmd_FrontL'][i-10 if i>9 else 0])+abs(x-df['cmd_FrontL'][i-20 if i>19 else 0]) for i,x in enumerate(df['cmd_FrontL'])]
frontRPMdiff=np.convolve(np.array(df['rpm_FrontL'])-np.array(df['rpm_FrontR']), np.ones(10)/10, mode='same')
rearRPMdiff=np.convolve(np.array(df['rpm_RearL'])-np.array(df['rpm_RearR']), np.ones(10)/10, mode='same')
ax1.plot(x,frontRPMdiff, c='#0000ff', alpha=0.5, label="rpm Difference Front")
ax1.plot(x,rearRPMdiff, c='#00ff00', alpha=0.5, label="rpm Difference Rear")
ax1.set_xlabel('timestamp')
ax1.set_ylabel('rpm Difference')
ax1.legend(loc='upper left')
plt.show()
def plot_rpmVsCurrent():
scattersize=2
scatteralpha=0.5
#confidence
#confidence_FrontL=[abs(x-df['cmd_FrontL'][i-5 if i>4 else 0])+abs(x-df['cmd_FrontL'][i-10 if i>9 else 0])+abs(x-df['cmd_FrontL'][i-20 if i>19 else 0]) for i,x in enumerate(df['cmd_FrontL'])]
#confidence_FrontL=[mapRange(x,0,50,1.0,0.0,True) for x in confidence_FrontL]
fig, ax1 = plt.subplots()
ax1.scatter(df['rpm_FrontL'],df['current_FrontL'], s=5, alpha=scatteralpha, label="FrontL")
ax1.scatter(df['rpm_FrontR'],df['current_FrontR'], s=5, alpha=scatteralpha, label="FrontR")
#ax1.scatter(df['cmd_FrontR'],df['rpm_FrontR'], s=scattersize, alpha=scatteralpha, label="FrontR")
#ax1.scatter(df['cmd_RearL'],df['rpm_RearL'], s=scattersize, alpha=scatteralpha, label="RearL")
#ax1.scatter(df['cmd_RearR'],df['rpm_RearR'], s=scattersize, alpha=scatteralpha, label="RearR")
ax1.set_xlabel('rpm')
ax1.set_ylabel('current (A)')
plt.title('rpm vs current')
ax1.legend(loc='upper left')
plt.show()
#plot_rpmVsCurrent()
rpmDifference()
exit()

View file

@ -0,0 +1,232 @@
import serial
import os
import time
import random
import string
import argparse
chunksize=4096
#LOG0002
#32 = 124 kbps
#128 = 263 kbps
#4096 = 416 kbps
#32768 = 427 kbps
#65536 = failed
serialport = serial.Serial(port='/dev/ttyACM0', baudrate=115200, timeout=1)
def establish_connection():
serialport.write("\n".encode())
serialport.write("echo off\n".encode())
time.sleep(0.1)
while len(serialport.readline())>0:
continue
serialport.write("test\n".encode())
time.sleep(0.1)
response = serialport.readline()
hrresponse=response.rstrip().decode('ascii')
if hrresponse != "OK":
print("Unexpected test response:"+str(response))
exit()
def get_filenames():
filenames=[]
serialport.write("ls\n".encode())
while True:
response = serialport.readline()
hrresponse=response.rstrip().decode('ascii')
if(len(response))>0:
#print(hrresponse)
filenames.append(hrresponse)
else:
break
return filenames
def get_filesize(filename):
filesize=0
serialport.write(("sizeof "+str(filename)+"\n").encode())
time.sleep(0.1)
response = serialport.readline()
hrresponse=response.rstrip().decode('ascii')
if(len(response))>0:
filesize=int(hrresponse)
return filesize
def copy_file(source,destination,expectedsize):
os.makedirs(os.path.dirname(writefilename), exist_ok=True)
transferstarttime=time.time()
chunkstarttime=time.time()
last_print=time.time()
with open(writefilename, 'wb') as writer:
serialport.write(("chunksize "+str(chunksize)+"\n").encode())
serialport.write(("get "+filename+"\n").encode())
time.sleep(0.1)
acc_datalen=0
while True:
'''
response = serialport.readline()
hrresponse=response.rstrip().decode('ascii')
if(len(response))>0:
#print(hrresponse)
writer.write(response)
else:
break
'''
data=serialport.read(chunksize)
if(len(data))>0: #data received
#print("received "+str(len(data))+" bytes")
#hrresponse=data.rstrip().decode('ascii')
#print(hrresponse)
acc_datalen+=len(data)
checksum=(sum(data) & 0xFF)
checksumarray=bytearray([checksum])
writer.write(data)
serialport.write(checksumarray) #request next chunk by sending checksum of last chunk
else:
break
if (time.time()-last_print>0.5):
last_print=time.time()
chunkduration=time.time()-chunkstarttime
chunkstarttime=time.time()
progress=0
if expectedsize>0:
progress=acc_datalen/expectedsize
print(str(round(progress*100,0))+"% \t"+str(round(chunkduration*1000,3))+" ms for "+str(len(data))+" Byte \t = "+str(round((len(data)/chunkduration)/1000,3))+" kB/s")
fileduration=time.time()-transferstarttime
file_stats=os.stat(writefilename)
print("Finished transfer of "+str(acc_datalen)+" B or "+str(file_stats.st_size)+" (os) Byte in "+str(fileduration)+" s \t = "+str(round(file_stats.st_size/fileduration/1000,3))+" kB/s")
return acc_datalen
def log_off():
serialport.write(("log off\n").encode())
time.sleep(0.1)
response = serialport.readline()
hrresponse=response.rstrip().decode('ascii')
if (not hrresponse.startswith("Log disabled")):
print("Unexpected response:"+str(response))
exit()
def delete_file(filename):
serialport.write(("rm "+filename+"\n").encode())
time.sleep(0.1)
response = serialport.readline()
hrresponse=response.rstrip().decode('ascii')
if hrresponse != "OK":
print("Unexpected response:"+str(response))
exit()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Transfers log files from bobbycar over serial')
parser.add_argument('-o', '--output', nargs='?', help="output directory")
parser.add_argument('-d','--delete', action="store_true", help="delete files after transfer")
args = parser.parse_args()
outputfolder="sdcard"
if (args.output is not None):
outputfolder = args.output
if(outputfolder[-1]=='/'):
outputfolder=outputfolder[:-1] #remove last slash
print("Outputfolder:"+outputfolder)
if serialport.isOpen():
establish_connection()
#Get File List
filenames=get_filenames()
#Copy all Files
failed=0
for filename in filenames:
print("Reading file "+filename)
expectedsize=get_filesize(filename)
print("Expecting "+str(expectedsize)+" Byte")
writefilename=outputfolder+'/'+filename
receivedsize=copy_file(filename,writefilename,expectedsize)
if (expectedsize!=receivedsize):
print("Warning: Filesize does not match!")
failed+=1
print("")
print(str(len(filenames))+" Files copied with "+str(failed)+" failed")
#Delete all files
if (args.delete):
if (failed>0):
print("Copy not successful. Files won't be deleted!")
exit()
deletecheckstring=''.join(random.choices(string.ascii_lowercase, k=3))
deletecheck=input("Enter "+deletecheckstring+" to confirm deletion of "+str(len(filenames))+" files on bobbycar:")
if (deletecheck==deletecheckstring):
log_off()
for filename in filenames:
print("Deleting "+filename)
delete_file(filename)
else:
print("Verification failed!")
serialport.write("echo on\n".encode())
time.sleep(0.1)
serialport.close()

View file

@ -2,12 +2,16 @@ import numpy as np
from datetime import datetime
import time
import argparse
import os.path
parser = argparse.ArgumentParser(description='Copys, renames and fixes logfiles written by bobbycar sd logger.')
parser.add_argument('--input', type=argparse.FileType('r'), nargs='+')
parser.add_argument('--output', nargs='?', type=argparse.FileType('w'))
parser.add_argument('-i', '--input', type=argparse.FileType('r'), nargs='+', required=True, help="list of input log files")
parser.add_argument('-o', '--output', nargs='?', type=argparse.FileType('w'), help="output filename")
parser.add_argument('-c','--consecutive', action="store_true", help="add consecutive files to input. If the input file ends with a number the following logfiles will be added.")
args = parser.parse_args()
ok=True
def getTimestamp(plines):
@ -71,8 +75,46 @@ def filterLines(plines,plinesStarttime=None):
return plines,pheader,pcommentlinesMask,pdatalines,pdatalinesFail,pdatalinesOK,pheaderSize,plinesOK,plinesStarttime
inputFilenames=[]
if (args.consecutive):
if(len(args.input)!=1):
parser.error("in consequtive mode exactly one input file is required")
exit()
nextFilename=args.input[0].name
while os.path.isfile(nextFilename):
print(nextFilename+" exists")
inputFilenames.append(nextFilename)
digitStartpos=len(nextFilename)-1
digitEndpos=len(nextFilename)
while (not nextFilename[digitStartpos:digitEndpos].isdigit() and digitStartpos>0 and digitEndpos>0):
digitStartpos-=1
digitEndpos-=1
while (nextFilename[digitStartpos:digitEndpos].isdigit() and digitStartpos>0 and digitEndpos>0):
digitStartpos-=1
digitStartpos+=1
number=int(nextFilename[digitStartpos:digitEndpos])+1
nextFilename=nextFilename[0:digitStartpos]+str(number).zfill(digitEndpos-digitStartpos)+nextFilename[digitEndpos:]
else:
inputFilenames=[x.name for x in args.input]
inputFilenames=[x.name for x in args.input]
outputFilename=None
if args.output is not None:
@ -106,7 +148,7 @@ for inputFilename in inputFilenames:
linesStarttime+=_linesStarttime
print("Line in file="+str(len(inputlines)))
print("Lines in file="+str(len(inputlines)))
assert len(lines)==len(linesStarttime), "Length of lines and linesStarttime does not match"