├── .gitignore ├── LICENSE.md ├── README.md ├── documentation └── prototype-assembly.jpg ├── firmware └── haptick_proto │ └── haptick_proto.ino ├── hardware ├── electronics │ ├── interface │ │ ├── fp-lib-table │ │ ├── interface.kicad_pcb │ │ ├── interface.kicad_pro │ │ ├── interface.kicad_sch │ │ └── sym-lib-table │ ├── lib │ │ ├── proto.3dshapes │ │ │ └── TE_2328702-8_1x08-1MP_P0.5mm_Horizontal.step │ │ ├── proto.kicad_sym │ │ └── proto.pretty │ │ │ ├── ArmPad.kicad_mod │ │ │ ├── IocesLogo.kicad_mod │ │ │ ├── MountingHole_PEM_M3_Broaching_Nut.kicad_mod │ │ │ ├── NetTie-2_SMD_Pad0.2mm.kicad_mod │ │ │ ├── StrainGauge_BF350-3AA.kicad_mod │ │ │ ├── TE_2328702-8_1x08-1MP_P0.5mm_Horizontal.kicad_mod │ │ │ ├── Teensy_3.2.kicad_mod │ │ │ └── TestPoint_THTPad_D1.6mm_Drill0.9mm.kicad_mod │ ├── platform │ │ ├── fp-lib-table │ │ ├── platform.kicad_pcb │ │ ├── platform.kicad_pro │ │ ├── platform.kicad_sch │ │ └── sym-lib-table │ └── proto │ │ ├── fp-lib-table │ │ ├── proto.kicad_pcb │ │ ├── proto.kicad_pro │ │ ├── proto.kicad_sch │ │ └── sym-lib-table └── mechanics │ ├── assembly.f3z │ └── slot_solve.f3d └── software └── utilities ├── force_analysis ├── animation.py ├── free_body.py └── optimiser.py └── monitor ├── assets ├── blank-icon.svg ├── cube.blend ├── cube.mtl ├── cube.obj ├── tabler-icons │ ├── LICENSE │ ├── README.md │ ├── player-record.svg │ ├── plug-connected-x.svg │ └── plug-connected.svg ├── texture.png └── texture.svg ├── compile_ui.sh ├── cube_control.ui ├── interface.py ├── main.py ├── main_window.ui ├── noise_widget.ui ├── requirements.txt ├── resources.qrc └── visualisers.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Python extras 2 | .venv/ 3 | __pycache__/ 4 | ui_*.py 5 | *_rc.py 6 | 7 | # KiCad extras 8 | *.000 9 | *.bak 10 | *.bck 11 | *.kicad_pcb-bak 12 | *.kicad_sch-bak 13 | *-backups 14 | *.kicad_prl 15 | *.sch-bak 16 | *~ 17 | _autosave-* 18 | *.tmp 19 | *-save.pro 20 | *-save.kicad_pcb 21 | fp-info-cache 22 | *.net 23 | *.dsn 24 | *.ses 25 | *.xml 26 | *.csv 27 | out/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2022-2023 Ioces Pty Ltd 2 | 3 | This project is combined work licensed under multiple separate licenses, outlined below: 4 | * The hardware design and documentation for this project is licensed under the [CERN Open Hardware Licence Version 2 - Strongly Reciprocal](https://ohwr.org/cern_ohl_s_v2.txt) (CERN-OHL-S-2.0). This includes all content under the `/hardware` and `/documentation` folders. 5 | * The software and firmware for the project is licensed under the [GNU General Public License Version 3](https://www.gnu.org/licenses/gpl-3.0.txt) (GPL-3.0-only). This includes all content under the `/software` and `/firmware` folder. 6 | 7 | The design, documentation and source code can be found at https://github.com/ioces/haptick. 8 | 9 | You may redistribute, modify and make products with this design, source and documentation under the specific terms of the applicable licenses. 10 | 11 | This design, source and documentation is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Haptick - a 6DOF force sensitive input device 2 | 3 | This design is a work in progress and is currently in the proof-of-concept prototyping phase. Progress is being documented via a series of [blog posts](https://blog.ioces.com/matt). 4 | 5 | Ultimately the goal is to produce an open source alternative to the various [Spacemice](http://spacemice.org/index.php?title=Main_Page) on the market. 6 | 7 | ![Rendering of a prototype Haptick device](documentation/prototype-assembly.jpg) 8 | 9 | ## License 10 | 11 | This project is licensed under two separate licenses. The hardware design and documentation for this project is licensed under the [CERN Open Hardware Licence Version 2 - Strongly Reciprocal](https://ohwr.org/cern_ohl_s_v2.txt) (CERN-OHL-S-2.0). The software and firmware source code for the project is licensed under the [GNU General Public License Version 3](https://www.gnu.org/licenses/gpl-3.0.txt) (GPL-3.0-only). 12 | 13 | Further details can be found in the [license file](LICENSE.md). 14 | 15 | ### Third Party Libraries 16 | 17 | Various third party libraries are used in this project. These libraries are licensed separately from the Haptick project. -------------------------------------------------------------------------------- /documentation/prototype-assembly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ioces/haptick/087f9f2f937d28ed883d5723eaeef3fd493d213e/documentation/prototype-assembly.jpg -------------------------------------------------------------------------------- /firmware/haptick_proto/haptick_proto.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const int adc_clk_pin = 20; 4 | const int adc_ndrdy_pin = 19; 5 | const int spi_ncs_pin = 10; 6 | 7 | // SPI settings 8 | const SPISettings spi_settings(8000000, MSBFIRST, SPI_MODE1); 9 | 10 | bool buffer_empty = true; 11 | char adc_buffer[24]; 12 | 13 | void adc_data_ready() 14 | { 15 | // If we've sent the last set of results, grab new ones into the buffer 16 | if (buffer_empty) 17 | { 18 | SPI.beginTransaction(spi_settings); 19 | digitalWrite(spi_ncs_pin, LOW); 20 | SPI.transfer(adc_buffer, 24); 21 | digitalWrite(spi_ncs_pin, HIGH); 22 | SPI.endTransaction(); 23 | buffer_empty = false; 24 | } 25 | } 26 | 27 | void setup() 28 | { 29 | // Create an 8 MHz 50% duty cycle clock for the ADC 30 | // This requires overclocking the Teensy to 96 MHz to 31 | // get a 48 MHz PWM clock, which is then divided by 6 32 | // to get the 8 MHz clock. 33 | // 34 | // It puts us in a weird situation where the PWM counter 35 | // can range from 0 - 5, which doesn't nicely map to the 36 | // 0 - 255 range for the analogWrite() call. But the below 37 | // code seems to work. 38 | pinMode(adc_clk_pin, OUTPUT); 39 | analogWriteFrequency(adc_clk_pin, 8000000); 40 | analogWrite(adc_clk_pin, 128); 41 | 42 | // Delay for a bit to make sure the ADC is alive 43 | delay(100); 44 | 45 | // Start SPI and pull !CS high 46 | SPI.begin(); 47 | pinMode(spi_ncs_pin, OUTPUT); 48 | digitalWrite(spi_ncs_pin, HIGH); 49 | 50 | // Configure the ADC to use an oversampling rate of 1024, 51 | // and PGA gains of 64 52 | uint16_t clock_register = 0x3f0e; 53 | SPI.beginTransaction(spi_settings); 54 | digitalWrite(spi_ncs_pin, LOW); 55 | SPI.transfer16(0x6182); 56 | SPI.transfer(0); 57 | SPI.transfer16(clock_register); 58 | SPI.transfer(0); 59 | SPI.transfer16(0x6666); 60 | SPI.transfer(0); 61 | SPI.transfer16(0x0066); 62 | SPI.transfer(0); 63 | SPI.transfer16(0); 64 | SPI.transfer(0); 65 | digitalWrite(spi_ncs_pin, HIGH); 66 | SPI.endTransaction(); 67 | 68 | // Wait for serial to come up 69 | while (!Serial); 70 | 71 | // Set up an interrupt on the ADC_!DRDY pin 72 | attachInterrupt(digitalPinToInterrupt(adc_ndrdy_pin), adc_data_ready, FALLING); 73 | } 74 | 75 | void loop() 76 | { 77 | // Dump values out the serial port every time new readings come in 78 | if (!buffer_empty) 79 | { 80 | Serial.write(adc_buffer, 24); 81 | memset(adc_buffer, 0, 24); 82 | buffer_empty = true; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /hardware/electronics/interface/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name "proto")(type "KiCad")(uri "${KIPRJMOD}/../lib/proto.pretty")(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /hardware/electronics/interface/interface.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "design_settings": { 4 | "defaults": { 5 | "board_outline_line_width": 0.09999999999999999, 6 | "copper_line_width": 0.19999999999999998, 7 | "copper_text_italic": false, 8 | "copper_text_size_h": 1.5, 9 | "copper_text_size_v": 1.5, 10 | "copper_text_thickness": 0.3, 11 | "copper_text_upright": false, 12 | "courtyard_line_width": 0.049999999999999996, 13 | "dimension_precision": 4, 14 | "dimension_units": 3, 15 | "dimensions": { 16 | "arrow_length": 1270000, 17 | "extension_offset": 500000, 18 | "keep_text_aligned": true, 19 | "suppress_zeroes": false, 20 | "text_position": 0, 21 | "units_format": 1 22 | }, 23 | "fab_line_width": 0.09999999999999999, 24 | "fab_text_italic": false, 25 | "fab_text_size_h": 1.0, 26 | "fab_text_size_v": 1.0, 27 | "fab_text_thickness": 0.15, 28 | "fab_text_upright": false, 29 | "other_line_width": 0.15, 30 | "other_text_italic": false, 31 | "other_text_size_h": 1.0, 32 | "other_text_size_v": 1.0, 33 | "other_text_thickness": 0.15, 34 | "other_text_upright": false, 35 | "pads": { 36 | "drill": 4.5, 37 | "height": 4.5, 38 | "width": 4.5 39 | }, 40 | "silk_line_width": 0.15, 41 | "silk_text_italic": false, 42 | "silk_text_size_h": 1.0, 43 | "silk_text_size_v": 1.0, 44 | "silk_text_thickness": 0.15, 45 | "silk_text_upright": false, 46 | "zones": { 47 | "45_degree_only": false, 48 | "min_clearance": 0.19999999999999998 49 | } 50 | }, 51 | "diff_pair_dimensions": [ 52 | { 53 | "gap": 0.0, 54 | "via_gap": 0.0, 55 | "width": 0.0 56 | } 57 | ], 58 | "drc_exclusions": [], 59 | "meta": { 60 | "version": 2 61 | }, 62 | "rule_severities": { 63 | "annular_width": "error", 64 | "clearance": "error", 65 | "copper_edge_clearance": "error", 66 | "courtyards_overlap": "error", 67 | "diff_pair_gap_out_of_range": "error", 68 | "diff_pair_uncoupled_length_too_long": "error", 69 | "drill_out_of_range": "error", 70 | "duplicate_footprints": "warning", 71 | "extra_footprint": "warning", 72 | "footprint_type_mismatch": "error", 73 | "hole_clearance": "error", 74 | "hole_near_hole": "error", 75 | "invalid_outline": "error", 76 | "item_on_disabled_layer": "error", 77 | "items_not_allowed": "error", 78 | "length_out_of_range": "error", 79 | "malformed_courtyard": "error", 80 | "microvia_drill_out_of_range": "error", 81 | "missing_courtyard": "ignore", 82 | "missing_footprint": "warning", 83 | "net_conflict": "warning", 84 | "npth_inside_courtyard": "ignore", 85 | "padstack": "error", 86 | "pth_inside_courtyard": "ignore", 87 | "shorting_items": "error", 88 | "silk_over_copper": "warning", 89 | "silk_overlap": "warning", 90 | "skew_out_of_range": "error", 91 | "through_hole_pad_without_hole": "error", 92 | "too_many_vias": "error", 93 | "track_dangling": "warning", 94 | "track_width": "error", 95 | "tracks_crossing": "error", 96 | "unconnected_items": "error", 97 | "unresolved_variable": "error", 98 | "via_dangling": "warning", 99 | "zone_has_empty_net": "error", 100 | "zones_intersect": "error" 101 | }, 102 | "rules": { 103 | "allow_blind_buried_vias": false, 104 | "allow_microvias": false, 105 | "max_error": 0.005, 106 | "min_clearance": 0.0, 107 | "min_copper_edge_clearance": 0.5, 108 | "min_hole_clearance": 0.25, 109 | "min_hole_to_hole": 0.25, 110 | "min_microvia_diameter": 0.19999999999999998, 111 | "min_microvia_drill": 0.09999999999999999, 112 | "min_silk_clearance": 0.0, 113 | "min_through_hole_diameter": 0.3, 114 | "min_track_width": 0.19999999999999998, 115 | "min_via_annular_width": 0.049999999999999996, 116 | "min_via_diameter": 0.39999999999999997, 117 | "solder_mask_clearance": 0.0, 118 | "solder_mask_min_width": 0.0, 119 | "use_height_for_length_calcs": true 120 | }, 121 | "track_widths": [ 122 | 0.0 123 | ], 124 | "via_dimensions": [ 125 | { 126 | "diameter": 0.0, 127 | "drill": 0.0 128 | } 129 | ], 130 | "zones_allow_external_fillets": false, 131 | "zones_use_no_outline": true 132 | }, 133 | "layer_presets": [] 134 | }, 135 | "boards": [], 136 | "cvpcb": { 137 | "equivalence_files": [] 138 | }, 139 | "erc": { 140 | "erc_exclusions": [], 141 | "meta": { 142 | "version": 0 143 | }, 144 | "pin_map": [ 145 | [ 146 | 0, 147 | 0, 148 | 0, 149 | 0, 150 | 0, 151 | 0, 152 | 1, 153 | 0, 154 | 0, 155 | 0, 156 | 0, 157 | 2 158 | ], 159 | [ 160 | 0, 161 | 2, 162 | 0, 163 | 1, 164 | 0, 165 | 0, 166 | 1, 167 | 0, 168 | 2, 169 | 2, 170 | 2, 171 | 2 172 | ], 173 | [ 174 | 0, 175 | 0, 176 | 0, 177 | 0, 178 | 0, 179 | 0, 180 | 1, 181 | 0, 182 | 1, 183 | 0, 184 | 1, 185 | 2 186 | ], 187 | [ 188 | 0, 189 | 1, 190 | 0, 191 | 0, 192 | 0, 193 | 0, 194 | 1, 195 | 1, 196 | 2, 197 | 1, 198 | 1, 199 | 2 200 | ], 201 | [ 202 | 0, 203 | 0, 204 | 0, 205 | 0, 206 | 0, 207 | 0, 208 | 1, 209 | 0, 210 | 0, 211 | 0, 212 | 0, 213 | 2 214 | ], 215 | [ 216 | 0, 217 | 0, 218 | 0, 219 | 0, 220 | 0, 221 | 0, 222 | 0, 223 | 0, 224 | 0, 225 | 0, 226 | 0, 227 | 2 228 | ], 229 | [ 230 | 1, 231 | 1, 232 | 1, 233 | 1, 234 | 1, 235 | 0, 236 | 1, 237 | 1, 238 | 1, 239 | 1, 240 | 1, 241 | 2 242 | ], 243 | [ 244 | 0, 245 | 0, 246 | 0, 247 | 1, 248 | 0, 249 | 0, 250 | 1, 251 | 0, 252 | 0, 253 | 0, 254 | 0, 255 | 2 256 | ], 257 | [ 258 | 0, 259 | 2, 260 | 1, 261 | 2, 262 | 0, 263 | 0, 264 | 1, 265 | 0, 266 | 2, 267 | 2, 268 | 2, 269 | 2 270 | ], 271 | [ 272 | 0, 273 | 2, 274 | 0, 275 | 1, 276 | 0, 277 | 0, 278 | 1, 279 | 0, 280 | 2, 281 | 0, 282 | 0, 283 | 2 284 | ], 285 | [ 286 | 0, 287 | 2, 288 | 1, 289 | 1, 290 | 0, 291 | 0, 292 | 1, 293 | 0, 294 | 2, 295 | 0, 296 | 0, 297 | 2 298 | ], 299 | [ 300 | 2, 301 | 2, 302 | 2, 303 | 2, 304 | 2, 305 | 2, 306 | 2, 307 | 2, 308 | 2, 309 | 2, 310 | 2, 311 | 2 312 | ] 313 | ], 314 | "rule_severities": { 315 | "bus_definition_conflict": "error", 316 | "bus_entry_needed": "error", 317 | "bus_label_syntax": "error", 318 | "bus_to_bus_conflict": "error", 319 | "bus_to_net_conflict": "error", 320 | "different_unit_footprint": "error", 321 | "different_unit_net": "error", 322 | "duplicate_reference": "error", 323 | "duplicate_sheet_names": "error", 324 | "extra_units": "error", 325 | "global_label_dangling": "warning", 326 | "hier_label_mismatch": "error", 327 | "label_dangling": "error", 328 | "lib_symbol_issues": "warning", 329 | "multiple_net_names": "warning", 330 | "net_not_bus_member": "warning", 331 | "no_connect_connected": "warning", 332 | "no_connect_dangling": "warning", 333 | "pin_not_connected": "error", 334 | "pin_not_driven": "error", 335 | "pin_to_pin": "warning", 336 | "power_pin_not_driven": "error", 337 | "similar_labels": "warning", 338 | "unannotated": "error", 339 | "unit_value_mismatch": "error", 340 | "unresolved_variable": "error", 341 | "wire_dangling": "error" 342 | } 343 | }, 344 | "libraries": { 345 | "pinned_footprint_libs": [], 346 | "pinned_symbol_libs": [] 347 | }, 348 | "meta": { 349 | "filename": "interface.kicad_pro", 350 | "version": 1 351 | }, 352 | "net_settings": { 353 | "classes": [ 354 | { 355 | "bus_width": 12.0, 356 | "clearance": 0.2, 357 | "diff_pair_gap": 0.25, 358 | "diff_pair_via_gap": 0.25, 359 | "diff_pair_width": 0.2, 360 | "line_style": 0, 361 | "microvia_diameter": 0.3, 362 | "microvia_drill": 0.1, 363 | "name": "Default", 364 | "pcb_color": "rgba(0, 0, 0, 0.000)", 365 | "schematic_color": "rgba(0, 0, 0, 0.000)", 366 | "track_width": 0.2, 367 | "via_diameter": 0.6, 368 | "via_drill": 0.3, 369 | "wire_width": 6.0 370 | } 371 | ], 372 | "meta": { 373 | "version": 2 374 | }, 375 | "net_colors": null 376 | }, 377 | "pcbnew": { 378 | "last_paths": { 379 | "gencad": "", 380 | "idf": "", 381 | "netlist": "", 382 | "specctra_dsn": "", 383 | "step": "interface.step", 384 | "vrml": "interface.wrl" 385 | }, 386 | "page_layout_descr_file": "" 387 | }, 388 | "schematic": { 389 | "annotate_start_num": 0, 390 | "drawing": { 391 | "default_line_thickness": 6.0, 392 | "default_text_size": 50.0, 393 | "field_names": [], 394 | "intersheets_ref_own_page": false, 395 | "intersheets_ref_prefix": "", 396 | "intersheets_ref_short": false, 397 | "intersheets_ref_show": false, 398 | "intersheets_ref_suffix": "", 399 | "junction_size_choice": 3, 400 | "label_size_ratio": 0.375, 401 | "pin_symbol_size": 25.0, 402 | "text_offset_ratio": 0.15 403 | }, 404 | "legacy_lib_dir": "", 405 | "legacy_lib_list": [], 406 | "meta": { 407 | "version": 1 408 | }, 409 | "net_format_name": "", 410 | "ngspice": { 411 | "fix_include_paths": true, 412 | "fix_passive_vals": false, 413 | "meta": { 414 | "version": 0 415 | }, 416 | "model_mode": 0, 417 | "workbook_filename": "" 418 | }, 419 | "page_layout_descr_file": "", 420 | "plot_directory": "", 421 | "spice_adjust_passive_values": false, 422 | "spice_external_command": "spice \"%I\"", 423 | "subpart_first_id": 65, 424 | "subpart_id_separator": 0 425 | }, 426 | "sheets": [ 427 | [ 428 | "3599885a-b5e8-45cc-b6d5-43e24cfa1b92", 429 | "" 430 | ] 431 | ], 432 | "text_variables": {} 433 | } 434 | -------------------------------------------------------------------------------- /hardware/electronics/interface/sym-lib-table: -------------------------------------------------------------------------------- 1 | (sym_lib_table 2 | (lib (name "proto")(type "KiCad")(uri "${KIPRJMOD}/../lib/proto.kicad_sym")(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /hardware/electronics/lib/proto.kicad_sym: -------------------------------------------------------------------------------- 1 | (kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor) 2 | (symbol "ADS131M06" (in_bom yes) (on_board yes) 3 | (property "Reference" "U?" (id 0) (at 0 8.89 0) 4 | (effects (font (size 1.27 1.27))) 5 | ) 6 | (property "Value" "ADS131M06" (id 1) (at 0 6.35 0) 7 | (effects (font (size 1.27 1.27))) 8 | ) 9 | (property "Footprint" "Package_DFN_QFN:QFN-32-1EP_4x4mm_P0.4mm_EP2.9x2.9mm" (id 2) (at 0 -36.83 0) 10 | (effects (font (size 1.27 1.27)) hide) 11 | ) 12 | (property "Datasheet" "https://www.ti.com/lit/ds/symlink/ads131m06.pdf" (id 3) (at 0 -39.37 0) 13 | (effects (font (size 1.27 1.27)) hide) 14 | ) 15 | (property "ki_description" "ADS131M06 6-Channel, Simultaneously-Sampling, 24-Bit, Delta-Sigma ADC" (id 4) (at 0 0 0) 16 | (effects (font (size 1.27 1.27)) hide) 17 | ) 18 | (symbol "ADS131M06_0_1" 19 | (rectangle (start -19.05 21.59) (end 19.05 -22.86) 20 | (stroke (width 0.254) (type default) (color 0 0 0 0)) 21 | (fill (type background)) 22 | ) 23 | ) 24 | (symbol "ADS131M06_1_1" 25 | (pin input line (at -21.59 5.08 0) (length 2.54) 26 | (name "AIN2P" (effects (font (size 1.27 1.27)))) 27 | (number "1" (effects (font (size 1.27 1.27)))) 28 | ) 29 | (pin no_connect line (at 21.59 -11.43 180) (length 2.54) hide 30 | (name "NC" (effects (font (size 1.27 1.27)))) 31 | (number "10" (effects (font (size 1.27 1.27)))) 32 | ) 33 | (pin no_connect line (at 21.59 -13.97 180) (length 2.54) hide 34 | (name "NC" (effects (font (size 1.27 1.27)))) 35 | (number "11" (effects (font (size 1.27 1.27)))) 36 | ) 37 | (pin no_connect line (at 21.59 -16.51 180) (length 2.54) hide 38 | (name "NC" (effects (font (size 1.27 1.27)))) 39 | (number "12" (effects (font (size 1.27 1.27)))) 40 | ) 41 | (pin power_in line (at 0 -25.4 90) (length 2.54) 42 | (name "AGND" (effects (font (size 1.27 1.27)))) 43 | (number "13" (effects (font (size 1.27 1.27)))) 44 | ) 45 | (pin input line (at -21.59 -15.24 0) (length 2.54) 46 | (name "REFIN" (effects (font (size 1.27 1.27)))) 47 | (number "14" (effects (font (size 1.27 1.27)))) 48 | ) 49 | (pin power_in line (at -2.54 24.13 270) (length 2.54) 50 | (name "AVDD" (effects (font (size 1.27 1.27)))) 51 | (number "15" (effects (font (size 1.27 1.27)))) 52 | ) 53 | (pin input line (at 21.59 16.51 180) (length 2.54) 54 | (name "~{SYNC}/~{RESET}" (effects (font (size 1.27 1.27)))) 55 | (number "16" (effects (font (size 1.27 1.27)))) 56 | ) 57 | (pin input line (at 21.59 13.97 180) (length 2.54) 58 | (name "~{CS}" (effects (font (size 1.27 1.27)))) 59 | (number "17" (effects (font (size 1.27 1.27)))) 60 | ) 61 | (pin input line (at 21.59 11.43 180) (length 2.54) 62 | (name "~{DRDY}" (effects (font (size 1.27 1.27)))) 63 | (number "18" (effects (font (size 1.27 1.27)))) 64 | ) 65 | (pin input line (at 21.59 8.89 180) (length 2.54) 66 | (name "SCLK" (effects (font (size 1.27 1.27)))) 67 | (number "19" (effects (font (size 1.27 1.27)))) 68 | ) 69 | (pin input line (at -21.59 7.62 0) (length 2.54) 70 | (name "AIN2N" (effects (font (size 1.27 1.27)))) 71 | (number "2" (effects (font (size 1.27 1.27)))) 72 | ) 73 | (pin output line (at 21.59 6.35 180) (length 2.54) 74 | (name "DOUT" (effects (font (size 1.27 1.27)))) 75 | (number "20" (effects (font (size 1.27 1.27)))) 76 | ) 77 | (pin input line (at 21.59 3.81 180) (length 2.54) 78 | (name "DIN" (effects (font (size 1.27 1.27)))) 79 | (number "21" (effects (font (size 1.27 1.27)))) 80 | ) 81 | (pin input line (at 21.59 -3.81 180) (length 2.54) 82 | (name "XTAL2" (effects (font (size 1.27 1.27)))) 83 | (number "22" (effects (font (size 1.27 1.27)))) 84 | ) 85 | (pin input line (at 21.59 -1.27 180) (length 2.54) 86 | (name "XTAL1/CLKIN" (effects (font (size 1.27 1.27)))) 87 | (number "23" (effects (font (size 1.27 1.27)))) 88 | ) 89 | (pin output line (at 2.54 24.13 270) (length 2.54) 90 | (name "CAP" (effects (font (size 1.27 1.27)))) 91 | (number "24" (effects (font (size 1.27 1.27)))) 92 | ) 93 | (pin power_in line (at 2.54 -25.4 90) (length 2.54) 94 | (name "DGND" (effects (font (size 1.27 1.27)))) 95 | (number "25" (effects (font (size 1.27 1.27)))) 96 | ) 97 | (pin power_in line (at 0 24.13 270) (length 2.54) 98 | (name "DVDD" (effects (font (size 1.27 1.27)))) 99 | (number "26" (effects (font (size 1.27 1.27)))) 100 | ) 101 | (pin no_connect line (at 21.59 -19.05 180) (length 2.54) hide 102 | (name "NC" (effects (font (size 1.27 1.27)))) 103 | (number "27" (effects (font (size 1.27 1.27)))) 104 | ) 105 | (pin passive line (at 0 -25.4 90) (length 2.54) hide 106 | (name "AGND" (effects (font (size 1.27 1.27)))) 107 | (number "28" (effects (font (size 1.27 1.27)))) 108 | ) 109 | (pin input line (at -21.59 15.24 0) (length 2.54) 110 | (name "AIN0P" (effects (font (size 1.27 1.27)))) 111 | (number "29" (effects (font (size 1.27 1.27)))) 112 | ) 113 | (pin input line (at -21.59 2.54 0) (length 2.54) 114 | (name "AIN3N" (effects (font (size 1.27 1.27)))) 115 | (number "3" (effects (font (size 1.27 1.27)))) 116 | ) 117 | (pin input line (at -21.59 17.78 0) (length 2.54) 118 | (name "AIN0N" (effects (font (size 1.27 1.27)))) 119 | (number "30" (effects (font (size 1.27 1.27)))) 120 | ) 121 | (pin input line (at -21.59 12.7 0) (length 2.54) 122 | (name "AIN1N" (effects (font (size 1.27 1.27)))) 123 | (number "31" (effects (font (size 1.27 1.27)))) 124 | ) 125 | (pin input line (at -21.59 10.16 0) (length 2.54) 126 | (name "AIN1P" (effects (font (size 1.27 1.27)))) 127 | (number "32" (effects (font (size 1.27 1.27)))) 128 | ) 129 | (pin passive line (at -2.54 -25.4 90) (length 2.54) 130 | (name "EP" (effects (font (size 1.27 1.27)))) 131 | (number "33" (effects (font (size 1.27 1.27)))) 132 | ) 133 | (pin input line (at -21.59 0 0) (length 2.54) 134 | (name "AIN3P" (effects (font (size 1.27 1.27)))) 135 | (number "4" (effects (font (size 1.27 1.27)))) 136 | ) 137 | (pin input line (at -21.59 -5.08 0) (length 2.54) 138 | (name "AIN4P" (effects (font (size 1.27 1.27)))) 139 | (number "5" (effects (font (size 1.27 1.27)))) 140 | ) 141 | (pin input line (at -21.59 -2.54 0) (length 2.54) 142 | (name "AIN4N" (effects (font (size 1.27 1.27)))) 143 | (number "6" (effects (font (size 1.27 1.27)))) 144 | ) 145 | (pin input line (at -21.59 -7.62 0) (length 2.54) 146 | (name "AIN5N" (effects (font (size 1.27 1.27)))) 147 | (number "7" (effects (font (size 1.27 1.27)))) 148 | ) 149 | (pin input line (at -21.59 -10.16 0) (length 2.54) 150 | (name "AIN5P" (effects (font (size 1.27 1.27)))) 151 | (number "8" (effects (font (size 1.27 1.27)))) 152 | ) 153 | (pin no_connect line (at 21.59 -8.89 180) (length 2.54) hide 154 | (name "NC" (effects (font (size 1.27 1.27)))) 155 | (number "9" (effects (font (size 1.27 1.27)))) 156 | ) 157 | ) 158 | ) 159 | (symbol "Teensy_3.2" (in_bom yes) (on_board yes) 160 | (property "Reference" "U?" (id 0) (at 0 -1.27 0) 161 | (effects (font (size 1.27 1.27))) 162 | ) 163 | (property "Value" "Teensy_3.2" (id 1) (at 0 1.27 0) 164 | (effects (font (size 1.27 1.27))) 165 | ) 166 | (property "Footprint" "" (id 2) (at -6.35 30.48 0) 167 | (effects (font (size 1.27 1.27)) hide) 168 | ) 169 | (property "Datasheet" "" (id 3) (at -6.35 30.48 0) 170 | (effects (font (size 1.27 1.27)) hide) 171 | ) 172 | (symbol "Teensy_3.2_0_1" 173 | (rectangle (start -12.7 27.94) (end 12.7 -27.94) 174 | (stroke (width 0.1524) (type default) (color 0 0 0 0)) 175 | (fill (type background)) 176 | ) 177 | ) 178 | (symbol "Teensy_3.2_1_1" 179 | (pin power_out line (at -6.35 -30.48 90) (length 2.54) 180 | (name "GND" (effects (font (size 1.27 1.27)))) 181 | (number "1" (effects (font (size 1.27 1.27)))) 182 | ) 183 | (pin bidirectional line (at -15.24 -1.27 0) (length 2.54) 184 | (name "D8" (effects (font (size 1.27 1.27)))) 185 | (number "10" (effects (font (size 1.27 1.27)))) 186 | ) 187 | (pin bidirectional line (at -15.24 -3.81 0) (length 2.54) 188 | (name "D9" (effects (font (size 1.27 1.27)))) 189 | (number "11" (effects (font (size 1.27 1.27)))) 190 | ) 191 | (pin bidirectional line (at -15.24 -6.35 0) (length 2.54) 192 | (name "D10" (effects (font (size 1.27 1.27)))) 193 | (number "12" (effects (font (size 1.27 1.27)))) 194 | ) 195 | (pin bidirectional line (at -15.24 -8.89 0) (length 2.54) 196 | (name "D11" (effects (font (size 1.27 1.27)))) 197 | (number "13" (effects (font (size 1.27 1.27)))) 198 | ) 199 | (pin bidirectional line (at -15.24 -11.43 0) (length 2.54) 200 | (name "D12" (effects (font (size 1.27 1.27)))) 201 | (number "14" (effects (font (size 1.27 1.27)))) 202 | ) 203 | (pin power_in line (at 6.35 30.48 270) (length 2.54) 204 | (name "VBAT" (effects (font (size 1.27 1.27)))) 205 | (number "15" (effects (font (size 1.27 1.27)))) 206 | ) 207 | (pin power_out line (at -6.35 30.48 270) (length 2.54) 208 | (name "3V3" (effects (font (size 1.27 1.27)))) 209 | (number "16" (effects (font (size 1.27 1.27)))) 210 | ) 211 | (pin power_out line (at -3.81 -30.48 90) (length 2.54) 212 | (name "GND" (effects (font (size 1.27 1.27)))) 213 | (number "17" (effects (font (size 1.27 1.27)))) 214 | ) 215 | (pin input line (at 15.24 -19.05 180) (length 2.54) 216 | (name "Program" (effects (font (size 1.27 1.27)))) 217 | (number "18" (effects (font (size 1.27 1.27)))) 218 | ) 219 | (pin input line (at 15.24 -16.51 180) (length 2.54) 220 | (name "A14" (effects (font (size 1.27 1.27)))) 221 | (number "19" (effects (font (size 1.27 1.27)))) 222 | ) 223 | (pin bidirectional line (at -15.24 19.05 0) (length 2.54) 224 | (name "D0" (effects (font (size 1.27 1.27)))) 225 | (number "2" (effects (font (size 1.27 1.27)))) 226 | ) 227 | (pin bidirectional line (at 15.24 -11.43 180) (length 2.54) 228 | (name "D13" (effects (font (size 1.27 1.27)))) 229 | (number "20" (effects (font (size 1.27 1.27)))) 230 | ) 231 | (pin bidirectional line (at 15.24 -8.89 180) (length 2.54) 232 | (name "D14" (effects (font (size 1.27 1.27)))) 233 | (number "21" (effects (font (size 1.27 1.27)))) 234 | ) 235 | (pin bidirectional line (at 15.24 -6.35 180) (length 2.54) 236 | (name "D15" (effects (font (size 1.27 1.27)))) 237 | (number "22" (effects (font (size 1.27 1.27)))) 238 | ) 239 | (pin bidirectional line (at 15.24 -3.81 180) (length 2.54) 240 | (name "D16" (effects (font (size 1.27 1.27)))) 241 | (number "23" (effects (font (size 1.27 1.27)))) 242 | ) 243 | (pin bidirectional line (at 15.24 -1.27 180) (length 2.54) 244 | (name "D17" (effects (font (size 1.27 1.27)))) 245 | (number "24" (effects (font (size 1.27 1.27)))) 246 | ) 247 | (pin bidirectional line (at 15.24 1.27 180) (length 2.54) 248 | (name "D18" (effects (font (size 1.27 1.27)))) 249 | (number "25" (effects (font (size 1.27 1.27)))) 250 | ) 251 | (pin bidirectional line (at 15.24 3.81 180) (length 2.54) 252 | (name "D19" (effects (font (size 1.27 1.27)))) 253 | (number "26" (effects (font (size 1.27 1.27)))) 254 | ) 255 | (pin bidirectional line (at 15.24 6.35 180) (length 2.54) 256 | (name "D20" (effects (font (size 1.27 1.27)))) 257 | (number "27" (effects (font (size 1.27 1.27)))) 258 | ) 259 | (pin bidirectional line (at 15.24 8.89 180) (length 2.54) 260 | (name "D21" (effects (font (size 1.27 1.27)))) 261 | (number "28" (effects (font (size 1.27 1.27)))) 262 | ) 263 | (pin bidirectional line (at 15.24 11.43 180) (length 2.54) 264 | (name "D22" (effects (font (size 1.27 1.27)))) 265 | (number "29" (effects (font (size 1.27 1.27)))) 266 | ) 267 | (pin bidirectional line (at -15.24 16.51 0) (length 2.54) 268 | (name "D1" (effects (font (size 1.27 1.27)))) 269 | (number "3" (effects (font (size 1.27 1.27)))) 270 | ) 271 | (pin bidirectional line (at 15.24 13.97 180) (length 2.54) 272 | (name "D23" (effects (font (size 1.27 1.27)))) 273 | (number "30" (effects (font (size 1.27 1.27)))) 274 | ) 275 | (pin power_out line (at -3.81 30.48 270) (length 2.54) 276 | (name "3V3" (effects (font (size 1.27 1.27)))) 277 | (number "31" (effects (font (size 1.27 1.27)))) 278 | ) 279 | (pin power_out line (at 6.35 -30.48 90) (length 2.54) 280 | (name "AGND" (effects (font (size 1.27 1.27)))) 281 | (number "32" (effects (font (size 1.27 1.27)))) 282 | ) 283 | (pin power_out line (at 1.27 30.48 270) (length 2.54) 284 | (name "VUSB" (effects (font (size 1.27 1.27)))) 285 | (number "33" (effects (font (size 1.27 1.27)))) 286 | ) 287 | (pin bidirectional line (at -15.24 13.97 0) (length 2.54) 288 | (name "D2" (effects (font (size 1.27 1.27)))) 289 | (number "4" (effects (font (size 1.27 1.27)))) 290 | ) 291 | (pin bidirectional line (at -15.24 11.43 0) (length 2.54) 292 | (name "D3" (effects (font (size 1.27 1.27)))) 293 | (number "5" (effects (font (size 1.27 1.27)))) 294 | ) 295 | (pin bidirectional line (at -15.24 8.89 0) (length 2.54) 296 | (name "D4" (effects (font (size 1.27 1.27)))) 297 | (number "6" (effects (font (size 1.27 1.27)))) 298 | ) 299 | (pin bidirectional line (at -15.24 6.35 0) (length 2.54) 300 | (name "D5" (effects (font (size 1.27 1.27)))) 301 | (number "7" (effects (font (size 1.27 1.27)))) 302 | ) 303 | (pin bidirectional line (at -15.24 3.81 0) (length 2.54) 304 | (name "D6" (effects (font (size 1.27 1.27)))) 305 | (number "8" (effects (font (size 1.27 1.27)))) 306 | ) 307 | (pin bidirectional line (at -15.24 1.27 0) (length 2.54) 308 | (name "D7" (effects (font (size 1.27 1.27)))) 309 | (number "9" (effects (font (size 1.27 1.27)))) 310 | ) 311 | ) 312 | ) 313 | ) 314 | -------------------------------------------------------------------------------- /hardware/electronics/lib/proto.pretty/ArmPad.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "ArmPad" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 0) 4 | (descr "Mounting hole to solder Stewart platform arms") 5 | (attr through_hole) 6 | (fp_text reference "REF**" (at -4.3 0 unlocked) (layer "F.SilkS") 7 | (effects (font (size 1 1) (thickness 0.15))) 8 | (tstamp 2fee2703-8211-4e6c-a780-31ddc6cff8c7) 9 | ) 10 | (fp_text value "ArmPad" (at 0.31 4.01 unlocked) (layer "F.Fab") 11 | (effects (font (size 1 1) (thickness 0.15))) 12 | (tstamp 15bdad0a-3981-43f8-b6b9-f9f0f4d77c92) 13 | ) 14 | (pad "1" thru_hole oval (at 0.194 0.569 17.5) (size 3.6 5.255) (drill oval 1.8 3.455) (layers *.Cu *.Mask) (tstamp 060c218d-5556-4d1f-b1b8-49769efcadbc)) 15 | ) 16 | -------------------------------------------------------------------------------- /hardware/electronics/lib/proto.pretty/MountingHole_PEM_M3_Broaching_Nut.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "MountingHole_PEM_M3_Broaching_Nut" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 56D1B4CB) 4 | (descr "Mounting Hole 4.22mm for PEM M3 broaching nut") 5 | (tags "mounting hole M3 broach") 6 | (attr exclude_from_pos_files exclude_from_bom) 7 | (fp_text reference "REF**" (at 0 -3.81) (layer "F.SilkS") 8 | (effects (font (size 1 1) (thickness 0.15))) 9 | (tstamp ce8e44e6-34a9-47da-8347-47185365a99d) 10 | ) 11 | (fp_text value "MountingHole_PEM_M3_Broaching_Nut" (at 0 3.81) (layer "F.Fab") 12 | (effects (font (size 1 1) (thickness 0.15))) 13 | (tstamp 16093128-a967-47d2-bb21-40c09e85d420) 14 | ) 15 | (fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab") 16 | (effects (font (size 1 1) (thickness 0.15))) 17 | (tstamp 4942f351-6236-4118-907a-a6c3e87ffa3f) 18 | ) 19 | (fp_circle (center 0 0) (end 2.78 0) (layer "Cmts.User") (width 0.15) (fill none) (tstamp 6fd3797d-9493-4fec-a02e-d36c4d86e333)) 20 | (fp_circle (center 0 0) (end 2.9 0) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp b09d5dec-12bb-476f-8f90-ea32fc2c5c2c)) 21 | (pad "" np_thru_hole circle (at 0 0) (size 4.22 4.22) (drill 4.22) (layers F&B.Cu *.Mask) (tstamp 8e0bd25c-cee7-458c-863b-d2f72287e659)) 22 | ) 23 | -------------------------------------------------------------------------------- /hardware/electronics/lib/proto.pretty/NetTie-2_SMD_Pad0.2mm.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "NetTie-2_SMD_Pad0.2mm" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 5A1CF6D3) 4 | (descr "Net tie, 2 pin, 0.2mm round SMD pads") 5 | (tags "net tie") 6 | (attr exclude_from_pos_files exclude_from_bom) 7 | (fp_text reference "REF**" (at 0 -1.2) (layer "F.SilkS") 8 | (effects (font (size 1 1) (thickness 0.15))) 9 | (tstamp eba058f4-175e-4413-b550-93e1748b898d) 10 | ) 11 | (fp_text value "NetTie-2_SMD_Pad0.2mm" (at 0 1.2) (layer "F.Fab") 12 | (effects (font (size 1 1) (thickness 0.15))) 13 | (tstamp 55decc6c-ccba-49a9-9c58-e53b55d22ed2) 14 | ) 15 | (fp_poly (pts 16 | (xy -0.2 -0.1) 17 | (xy 0.2 -0.1) 18 | (xy 0.2 0.1) 19 | (xy -0.2 0.1) 20 | ) (layer "F.Cu") (width 0) (fill solid) (tstamp 4c587801-35de-4fc4-895b-9942aca7f89f)) 21 | (pad "1" smd circle (at -0.2 0) (size 0.2 0.2) (layers "F.Cu") (tstamp 1745e8e7-cb05-4e0c-be57-60ff31465fb9)) 22 | (pad "2" smd circle (at 0.2 0) (size 0.2 0.2) (layers "F.Cu") (tstamp b531e0f4-5d47-4a72-8a54-a3eaafb85b86)) 23 | ) 24 | -------------------------------------------------------------------------------- /hardware/electronics/lib/proto.pretty/StrainGauge_BF350-3AA.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "StrainGauge_BF350-3AA" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 0) 4 | (attr smd) 5 | (fp_text reference "REF**" (at 0 -3.4 unlocked) (layer "F.SilkS") 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | (tstamp 84a20c74-4b73-4ae3-8035-57f6931fc86e) 8 | ) 9 | (fp_text value "StrainGauge_BF350-3AA" (at 0 5.55 unlocked) (layer "F.Fab") 10 | (effects (font (size 1 1) (thickness 0.15))) 11 | (tstamp 8483e737-cb24-420a-b908-23b768b838a4) 12 | ) 13 | (fp_text user "${REFERENCE}" (at 0 0 unlocked) (layer "F.Fab") 14 | (effects (font (size 1 1) (thickness 0.15))) 15 | (tstamp 6c3dacea-7df1-42eb-8740-cee98b98c143) 16 | ) 17 | (fp_line (start -2.45 -2.45) (end -2.45 -1.95) (layer "Dwgs.User") (width 0.05) (tstamp 2924305e-0b59-4b78-bd5d-3e999496159e)) 18 | (fp_line (start 2.45 4.65) (end 2.45 4.15) (layer "Dwgs.User") (width 0.05) (tstamp 6209da56-4ce0-4ef9-8019-025e89e1e305)) 19 | (fp_line (start -2.45 4.65) (end -1.95 4.65) (layer "Dwgs.User") (width 0.05) (tstamp 734697d0-bbe6-4ea8-b4e0-a834405d9cdd)) 20 | (fp_line (start 2.45 -2.45) (end 2.45 -1.95) (layer "Dwgs.User") (width 0.05) (tstamp 7e567c1e-f68d-40d0-8cd1-25791e443b0e)) 21 | (fp_line (start 2.45 4.65) (end 1.95 4.65) (layer "Dwgs.User") (width 0.05) (tstamp 850fb286-3c03-4e6d-a95f-a3f2d803f6f6)) 22 | (fp_line (start 2.45 -2.45) (end 1.95 -2.45) (layer "Dwgs.User") (width 0.05) (tstamp 853b7e54-ab9a-4f8b-80ba-5c60bfa59331)) 23 | (fp_line (start -2.45 4.65) (end -2.45 4.15) (layer "Dwgs.User") (width 0.05) (tstamp 9a34156e-6781-43df-9f3b-1d49cadb59a6)) 24 | (fp_line (start -2.45 -2.45) (end -1.95 -2.45) (layer "Dwgs.User") (width 0.05) (tstamp a0b6b97b-fb14-4d5f-80f4-6265f5a1b96e)) 25 | (fp_rect (start -1.7 -1.7) (end 1.7 1.7) (layer "Dwgs.User") (width 0.1) (fill none) (tstamp 92739da1-1168-4dec-b034-9f4f11d8751a)) 26 | (fp_rect (start -2.55 -2.55) (end 2.55 4.75) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp a34ecd44-2839-4b23-9945-6b737b6cfc9e)) 27 | (pad "1" smd rect (at -1.05 3) (size 1.3 1.7) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 2adcb921-be49-44cd-970d-dcf98fd8c95e)) 28 | (pad "2" smd rect (at 1.05 3) (size 1.3 1.7) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp f87c9e9c-d51c-4233-a5ff-ba60799d7aff)) 29 | ) 30 | -------------------------------------------------------------------------------- /hardware/electronics/lib/proto.pretty/TE_2328702-8_1x08-1MP_P0.5mm_Horizontal.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "TE_2328702-8_1x08-1MP_P0.5mm_Horizontal" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 62E52DDE) 4 | (attr through_hole) 5 | (fp_text reference "REF**" (at -0.025 -3.46) (layer "F.SilkS") 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | (tstamp 4a70a478-4f27-4325-87bb-541920728443) 8 | ) 9 | (fp_text value "TE_2328702-8_1x08-1MP_P0.5mm_Horizontal" (at 0 2.79) (layer "F.Fab") 10 | (effects (font (size 1 1) (thickness 0.15))) 11 | (tstamp b2cf9ff4-91e8-4195-b40f-3c00888f053f) 12 | ) 13 | (fp_line (start 2.15 -1.4) (end 3 -1.4) (layer "F.SilkS") (width 0.12) (tstamp 0b97584b-5347-4c98-8780-51a57f09b3d3)) 14 | (fp_line (start -2.15 -1.4) (end -3 -1.4) (layer "F.SilkS") (width 0.12) (tstamp 10c6816c-01b4-4650-93c5-00fd9d640588)) 15 | (fp_line (start 2.15 -1.4) (end 2.15 -1.8) (layer "F.SilkS") (width 0.12) (tstamp 817e8307-8aa1-4794-9adf-daf294103bdc)) 16 | (fp_line (start -2.4 1.75) (end 2.4 1.75) (layer "F.SilkS") (width 0.12) (tstamp 82221a88-5805-47b0-99d2-2520f241fe94)) 17 | (fp_line (start -3 -1.4) (end -3 0.5) (layer "F.SilkS") (width 0.12) (tstamp 8d4042df-a01d-47a1-ac96-db893e68f8cb)) 18 | (fp_line (start 3 -1.4) (end 3 0.5) (layer "F.SilkS") (width 0.12) (tstamp df2e1e0e-e21c-4615-8752-57bbf5eff2c4)) 19 | (fp_line (start 3.25 2) (end -3.25 2) (layer "F.CrtYd") (width 0.05) (tstamp 1cc0958b-8226-4fc0-9ebb-691b8258a005)) 20 | (fp_line (start -3.25 2) (end -3.25 -2.275) (layer "F.CrtYd") (width 0.05) (tstamp 3e3ee424-cb7e-4843-a5f3-7ede5202b4a0)) 21 | (fp_line (start 3.25 -2.275) (end 3.25 2) (layer "F.CrtYd") (width 0.05) (tstamp 9af87357-bcde-462d-a348-7bfb1e6bdd49)) 22 | (fp_line (start -3.25 -2.275) (end 3.25 -2.275) (layer "F.CrtYd") (width 0.05) (tstamp b16ebe90-c486-4032-85ae-941058da110a)) 23 | (fp_line (start 2.9 -2.03) (end 2.9 -1.4) (layer "F.Fab") (width 0.1) (tstamp 1f8e32e8-9085-48d4-a519-ebdde11b5227)) 24 | (fp_line (start 1.75 -1.8) (end 1.52 -2.03) (layer "F.Fab") (width 0.1) (tstamp 2596fccb-1189-42fe-9c84-60d6d6dbbc0f)) 25 | (fp_line (start 3 -1.4) (end 3 1.75) (layer "F.Fab") (width 0.1) (tstamp 58a6e64e-1604-4583-a3b9-ae03cd8e9c7f)) 26 | (fp_line (start -3 1.75) (end -3 -1.4) (layer "F.Fab") (width 0.1) (tstamp 6399589f-b3ff-4fcb-a099-e08b3bbdd2d5)) 27 | (fp_line (start -2.9 -1.4) (end 2.9 -1.4) (layer "F.Fab") (width 0.1) (tstamp 78d7bd5c-1be2-43ac-aafc-cdc961d5fe82)) 28 | (fp_line (start -2.9 -2.03) (end 2.9 -2.03) (layer "F.Fab") (width 0.1) (tstamp 7ee6fabf-0dc3-4aac-a8d8-ad706a826ffe)) 29 | (fp_line (start 1.75 -1.8) (end 1.98 -2.03) (layer "F.Fab") (width 0.1) (tstamp 822061cb-f128-4ddf-89ff-3f9cc03bf412)) 30 | (fp_line (start -3 -1.4) (end -2.9 -1.4) (layer "F.Fab") (width 0.1) (tstamp a26d9fdf-2ae9-46d6-b17b-7dfa0e99afd1)) 31 | (fp_line (start 3 1.75) (end -3 1.75) (layer "F.Fab") (width 0.1) (tstamp cf8d2c83-267d-4b81-a17c-9232387eaf8e)) 32 | (fp_line (start -2.9 -1.4) (end -2.9 -2.03) (layer "F.Fab") (width 0.1) (tstamp db48f897-2912-4f77-944f-2b5eb649e923)) 33 | (fp_line (start 2.9 -1.4) (end 3 -1.4) (layer "F.Fab") (width 0.1) (tstamp e036dbbf-819a-4456-ab45-ea7b079c14c9)) 34 | (pad "1" smd rect (at 1.75 -1.35) (size 0.3 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 78322bab-5d65-443a-b7d2-e56e340f3013)) 35 | (pad "2" smd rect (at 1.25 -1.35) (size 0.3 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 57d41fe0-f1f1-46d6-acc3-dc66476958c6)) 36 | (pad "3" smd rect (at 0.75 -1.35) (size 0.3 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 549f4bfa-474d-49ff-94db-91437d4b8e5d)) 37 | (pad "4" smd rect (at 0.25 -1.35) (size 0.3 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 8fd2ac06-4de3-4b84-b574-c9168fedf08f)) 38 | (pad "5" smd rect (at -0.25 -1.35) (size 0.3 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 41cc4677-651b-424e-a95e-50a36f717027)) 39 | (pad "6" smd rect (at -0.75 -1.35) (size 0.3 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 389e99e0-aded-42fe-9304-7335f66b2314)) 40 | (pad "7" smd rect (at -1.25 -1.35) (size 0.3 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 4d08ab6d-7b62-4dd0-9c65-2e33d939f47c)) 41 | (pad "8" smd rect (at -1.75 -1.35) (size 0.3 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 79dbbb5b-ed39-496e-9455-1a2ef27126c2)) 42 | (pad "MP" smd rect (at -2.75 1.15) (size 0.4 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp 6cf197b7-d23d-4f05-ab1a-955a68dd3f6a)) 43 | (pad "MP" smd rect (at 2.75 1.15) (size 0.4 0.8) (layers "F.Cu" "F.Paste" "F.Mask") (tstamp c9d7b1ac-c862-43be-adf5-081c5474cf7a)) 44 | (model "${KIPRJMOD}/../lib/proto.3dshapes/TE_2328702-8_1x08-1MP_P0.5mm_Horizontal.step" 45 | (offset (xyz 0 -1.7 0.55)) 46 | (scale (xyz 1 1 1)) 47 | (rotate (xyz -90 0 0)) 48 | ) 49 | ) 50 | -------------------------------------------------------------------------------- /hardware/electronics/lib/proto.pretty/Teensy_3.2.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "Teensy_3.2" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 0) 4 | (descr "PJRC Teensy 3.2 microcontroller module, https://www.pjrc.com/store/teensy32.html") 5 | (attr through_hole) 6 | (fp_text reference "REF**" (at 7.62 16.51 unlocked) (layer "F.SilkS") 7 | (effects (font (size 1 1) (thickness 0.15))) 8 | (tstamp 3b10083a-e534-4f61-9f56-4367cc01882e) 9 | ) 10 | (fp_text value "Teensy_3.2" (at 7.62 13.97 unlocked) (layer "F.Fab") 11 | (effects (font (size 1 1) (thickness 0.15))) 12 | (tstamp ddb3bd5d-d625-49aa-b8a7-bc79982a928f) 13 | ) 14 | (fp_line (start 16.51 34.29) (end 16.51 -1.27) (layer "F.SilkS") (width 0.2) (tstamp 42a874b8-6ece-4807-836e-1934ea66fa2c)) 15 | (fp_line (start 3.556 -2.032) (end 11.684 -2.032) (layer "F.SilkS") (width 0.2) (tstamp 4f581f32-392d-49b1-9f9b-2ca94eb29b8b)) 16 | (fp_line (start 3.556 -1.27) (end 3.556 -2.032) (layer "F.SilkS") (width 0.2) (tstamp 6d21b15f-21ec-406b-ab4d-6cd8df9e538b)) 17 | (fp_line (start 11.684 -2.032) (end 11.684 -1.27) (layer "F.SilkS") (width 0.2) (tstamp 926dc99a-c691-4441-b553-48383adb7305)) 18 | (fp_line (start -1.27 -1.27) (end -1.27 34.29) (layer "F.SilkS") (width 0.2) (tstamp b02d1b57-ee2c-4aa0-9b4e-5cb4ba066260)) 19 | (fp_line (start -1.27 34.29) (end 16.51 34.29) (layer "F.SilkS") (width 0.2) (tstamp d89a0de9-feb3-49e5-b30a-87629423512b)) 20 | (fp_line (start 3.048 -1.778) (end 3.048 -2.54) (layer "F.CrtYd") (width 0.12) (tstamp 15ae57cf-ad20-4f26-9134-4a613a2e894d)) 21 | (fp_line (start 17.018 -1.778) (end 17.018 34.798) (layer "F.CrtYd") (width 0.12) (tstamp 1710a5ef-011e-4b26-a13a-009d1298c561)) 22 | (fp_line (start -1.778 34.798) (end -1.778 -1.778) (layer "F.CrtYd") (width 0.12) (tstamp 204ae696-080d-4bad-bb5f-fecf317b609b)) 23 | (fp_line (start 12.192 -1.778) (end 17.018 -1.778) (layer "F.CrtYd") (width 0.12) (tstamp 25c5426b-e3b6-4c77-bb04-9be0948460b3)) 24 | (fp_line (start 12.192 -2.54) (end 12.192 -1.778) (layer "F.CrtYd") (width 0.12) (tstamp 288e6b66-5379-4978-98db-6b78e1927fec)) 25 | (fp_line (start 17.018 34.798) (end -1.778 34.798) (layer "F.CrtYd") (width 0.12) (tstamp b17581a1-191c-4a53-9611-db2f0cd5663c)) 26 | (fp_line (start -1.778 -1.778) (end 3.048 -1.778) (layer "F.CrtYd") (width 0.12) (tstamp c20302ab-535b-46c6-ba49-ffedd6946b56)) 27 | (fp_line (start 3.048 -2.54) (end 12.192 -2.54) (layer "F.CrtYd") (width 0.12) (tstamp f4ba8430-d4f5-4829-be14-9ae54de075ad)) 28 | (pad "1" thru_hole rect (at 0 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 66fd7903-d8a8-4262-b8b0-1d7a27e20483)) 29 | (pad "2" thru_hole circle (at 0 2.54) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp b7d9f083-7ab3-462b-ae10-ae689e848d99)) 30 | (pad "3" thru_hole circle (at 0 5.08) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp e98c5240-d997-45b6-be96-e0a423bbba81)) 31 | (pad "4" thru_hole circle (at 0 7.62) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 9ed1f923-6284-4623-88ec-f0ea195e7805)) 32 | (pad "5" thru_hole circle (at 0 10.16) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 1f3be1e9-657c-4638-b3ff-be8fdd0866e3)) 33 | (pad "6" thru_hole circle (at 0 12.7) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp d23a4127-5f4a-466e-8ebc-c7c95f05ee24)) 34 | (pad "7" thru_hole circle (at 0 15.24) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp dd851fe4-2754-4cfb-a919-621796c3bdc7)) 35 | (pad "8" thru_hole circle (at 0 17.78) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 63f81dc0-b225-4ce2-9c31-71bca01a25c5)) 36 | (pad "9" thru_hole circle (at 0 20.32) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 754b785d-1e54-4cba-8bd5-9c4cfd61989b)) 37 | (pad "10" thru_hole circle (at 0 22.86) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp f7821b1c-a269-4e13-8ae4-349d4e0d9f8c)) 38 | (pad "11" thru_hole circle (at 0 25.4) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp a15089fc-7288-4456-abc3-86fd1a7bb083)) 39 | (pad "12" thru_hole circle (at 0 27.94) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 4ad6406e-7400-4ca2-b73e-d4902453d9c7)) 40 | (pad "13" thru_hole circle (at 0 30.48) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 62a5d16d-c117-4d73-940b-04de3259234d)) 41 | (pad "14" thru_hole circle (at 0 33.02) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 249f5ba6-86c8-41d4-bd3b-7f2ce55ed356)) 42 | (pad "15" thru_hole circle (at 2.54 33.02) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 4acf1380-3efe-4e7c-a0b7-70e66165bcd9)) 43 | (pad "16" thru_hole circle (at 5.08 33.02) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 14da27cb-e25b-45db-9ff4-84a9af0bbfc3)) 44 | (pad "17" thru_hole circle (at 7.62 33.02) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 7c6a2614-836d-4f53-8a76-0ee9b45c199c)) 45 | (pad "18" thru_hole circle (at 10.16 33.02) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp a9d664f0-402b-4ff6-8315-1233d253d6f0)) 46 | (pad "19" thru_hole circle (at 12.7 33.02) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 32005483-f36a-41d0-a73f-d574561fb2b0)) 47 | (pad "20" thru_hole circle (at 15.24 33.02) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 39be550e-ad50-449c-9e7e-7e27c86583e0)) 48 | (pad "21" thru_hole circle (at 15.24 30.48) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 5df22467-4b73-47fb-b808-091b3cc1da51)) 49 | (pad "22" thru_hole circle (at 15.24 27.94) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 097fbfa8-a07d-461e-85c0-26878a28caeb)) 50 | (pad "23" thru_hole circle (at 15.24 25.4) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp fd8390da-5d90-489d-8d10-72183ca30ff6)) 51 | (pad "24" thru_hole circle (at 15.24 22.86) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 42ed5eb6-f9ed-4ff3-8f5d-2331a5d337ab)) 52 | (pad "25" thru_hole circle (at 15.24 20.32) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 63f3e6c0-c853-434c-bfda-b5ee85b276ce)) 53 | (pad "26" thru_hole circle (at 15.24 17.78) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp ab754b56-7e58-435c-9a47-6a36242b6f5e)) 54 | (pad "27" thru_hole circle (at 15.24 15.24) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 5f4fe115-39e6-4866-9653-c4059f80edaf)) 55 | (pad "28" thru_hole circle (at 15.24 12.7) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 8f853455-6de8-4e32-a7c2-a173a10c060f)) 56 | (pad "29" thru_hole circle (at 15.24 10.16) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 423a64a7-aa31-4403-9353-865a7414a458)) 57 | (pad "30" thru_hole circle (at 15.24 7.62) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 8ca98dfb-cf28-4222-8203-dc498e80f5d0)) 58 | (pad "31" thru_hole circle (at 15.24 5.08) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 917e4bef-d5d0-4ba8-8280-7a4a619042bf)) 59 | (pad "32" thru_hole circle (at 15.24 2.54) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 90681821-1ddb-487a-96db-237b20563c5d)) 60 | (pad "33" thru_hole circle (at 15.24 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 4ab20995-9ff0-4ddb-9dc4-72c4ef8ab727)) 61 | ) 62 | -------------------------------------------------------------------------------- /hardware/electronics/lib/proto.pretty/TestPoint_THTPad_D1.6mm_Drill0.9mm.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "TestPoint_THTPad_D1.6mm_Drill0.9mm" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 5A0F774F) 4 | (descr "THT pad as test Point, diameter 1.6mm, hole diameter 0.9mm") 5 | (tags "test point THT pad") 6 | (attr exclude_from_pos_files exclude_from_bom) 7 | (fp_text reference "REF**" (at 0 -1.998) (layer "F.SilkS") 8 | (effects (font (size 1 1) (thickness 0.15))) 9 | (tstamp 8975eb03-962d-48e7-8695-d3b9e38e5e36) 10 | ) 11 | (fp_text value "TestPoint_THTPad_D1.6mm_Drill0.9mm" (at 0 2.05) (layer "F.Fab") 12 | (effects (font (size 1 1) (thickness 0.15))) 13 | (tstamp d1697e01-4b44-4004-b433-ad9d39cb3729) 14 | ) 15 | (fp_text user "${REFERENCE}" (at 0 -2) (layer "F.Fab") 16 | (effects (font (size 1 1) (thickness 0.15))) 17 | (tstamp 3b9a24ad-d8a8-4e1e-9972-62113e3ec411) 18 | ) 19 | (fp_circle (center 0 0) (end 1 0) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp fb6ad98f-13d7-4593-b78e-e2e5a7be4774)) 20 | (pad "1" thru_hole circle (at 0 0) (size 1.6 1.6) (drill 0.9) (layers *.Cu *.Mask) (tstamp 89e425b7-7ac9-4512-ba98-94aa32b4624a)) 21 | ) 22 | -------------------------------------------------------------------------------- /hardware/electronics/platform/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name "proto")(type "KiCad")(uri "${KIPRJMOD}/../lib/proto.pretty")(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /hardware/electronics/platform/platform.kicad_pcb: -------------------------------------------------------------------------------- 1 | (kicad_pcb (version 20211014) (generator pcbnew) 2 | 3 | (general 4 | (thickness 1.6) 5 | ) 6 | 7 | (paper "A4") 8 | (layers 9 | (0 "F.Cu" signal) 10 | (31 "B.Cu" signal) 11 | (32 "B.Adhes" user "B.Adhesive") 12 | (33 "F.Adhes" user "F.Adhesive") 13 | (34 "B.Paste" user) 14 | (35 "F.Paste" user) 15 | (36 "B.SilkS" user "B.Silkscreen") 16 | (37 "F.SilkS" user "F.Silkscreen") 17 | (38 "B.Mask" user) 18 | (39 "F.Mask" user) 19 | (40 "Dwgs.User" user "User.Drawings") 20 | (41 "Cmts.User" user "User.Comments") 21 | (42 "Eco1.User" user "User.Eco1") 22 | (43 "Eco2.User" user "User.Eco2") 23 | (44 "Edge.Cuts" user) 24 | (45 "Margin" user) 25 | (46 "B.CrtYd" user "B.Courtyard") 26 | (47 "F.CrtYd" user "F.Courtyard") 27 | (48 "B.Fab" user) 28 | (49 "F.Fab" user) 29 | (50 "User.1" user) 30 | (51 "User.2" user) 31 | (52 "User.3" user) 32 | (53 "User.4" user) 33 | (54 "User.5" user) 34 | (55 "User.6" user) 35 | (56 "User.7" user) 36 | (57 "User.8" user) 37 | (58 "User.9" user) 38 | ) 39 | 40 | (setup 41 | (pad_to_mask_clearance 0) 42 | (pcbplotparams 43 | (layerselection 0x00010fc_ffffffff) 44 | (disableapertmacros false) 45 | (usegerberextensions true) 46 | (usegerberattributes true) 47 | (usegerberadvancedattributes true) 48 | (creategerberjobfile true) 49 | (svguseinch false) 50 | (svgprecision 6) 51 | (excludeedgelayer true) 52 | (plotframeref false) 53 | (viasonmask false) 54 | (mode 1) 55 | (useauxorigin false) 56 | (hpglpennumber 1) 57 | (hpglpenspeed 20) 58 | (hpglpendiameter 15.000000) 59 | (dxfpolygonmode true) 60 | (dxfimperialunits true) 61 | (dxfusepcbnewfont true) 62 | (psnegative false) 63 | (psa4output false) 64 | (plotreference true) 65 | (plotvalue true) 66 | (plotinvisibletext false) 67 | (sketchpadsonfab false) 68 | (subtractmaskfromsilk false) 69 | (outputformat 1) 70 | (mirror false) 71 | (drillshape 0) 72 | (scaleselection 1) 73 | (outputdirectory "out/") 74 | ) 75 | ) 76 | 77 | (net 0 "") 78 | (net 1 "unconnected-(A1-Pad1)") 79 | (net 2 "unconnected-(A2-Pad1)") 80 | (net 3 "unconnected-(A3-Pad1)") 81 | (net 4 "unconnected-(A4-Pad1)") 82 | (net 5 "unconnected-(A5-Pad1)") 83 | (net 6 "unconnected-(A6-Pad1)") 84 | 85 | (footprint "proto:ArmPad" (layer "F.Cu") 86 | (tedit 0) (tstamp 0ce6d66a-8e05-4fc3-9cbc-9cef976fe071) 87 | (at 16.889755 18.431933 -47.5) 88 | (descr "Mounting hole to solder Stewart platform arms") 89 | (property "Sheetfile" "File: platform.kicad_sch") 90 | (property "Sheetname" "") 91 | (path "/627b2a8a-12a5-4630-827d-2edae280b953") 92 | (attr through_hole) 93 | (fp_text reference "A1" (at -4.3 0 -47.5 unlocked) (layer "F.SilkS") hide 94 | (effects (font (size 1 1) (thickness 0.15))) 95 | (tstamp 421de68a-dcd8-4c55-b215-70049d1b53fb) 96 | ) 97 | (fp_text value "Arm" (at 0.31 4.01 -47.5 unlocked) (layer "F.Fab") 98 | (effects (font (size 1 1) (thickness 0.15))) 99 | (tstamp e34202bb-bfec-49d2-aa22-4f9da2e4834d) 100 | ) 101 | (pad "1" thru_hole oval locked (at 0.194 0.569 330) (size 3.6 5.255) (drill oval 1.8 3.455) (layers *.Cu *.Mask) 102 | (net 1 "unconnected-(A1-Pad1)") (pinfunction "1") (pintype "input") (tstamp 5181016e-bb09-44f9-83a4-15989a579930)) 103 | ) 104 | 105 | (footprint "MountingHole:MountingHole_6.4mm_M6" (layer "F.Cu") 106 | (tedit 56D1B4CB) (tstamp 0d8c14e8-146b-4366-a73d-a9bc3ff3700e) 107 | (at -5.8 10.045893 -120) 108 | (descr "Mounting Hole 6.4mm, no annular, M6") 109 | (tags "mounting hole 6.4mm no annular m6") 110 | (property "Sheetfile" "File: platform.kicad_sch") 111 | (property "Sheetname" "") 112 | (path "/6859a470-7fb7-4f47-9925-056f0b61f509") 113 | (attr exclude_from_pos_files) 114 | (fp_text reference "H3" (at 0 -7.4 -120) (layer "F.SilkS") hide 115 | (effects (font (size 1 1) (thickness 0.15))) 116 | (tstamp 1956000e-e9ab-4381-9d90-62cc7a8fb497) 117 | ) 118 | (fp_text value "MountingHole" (at 0 7.4 -120) (layer "F.Fab") 119 | (effects (font (size 1 1) (thickness 0.15))) 120 | (tstamp 01a398c6-a986-4643-988d-53f967765eb9) 121 | ) 122 | (fp_text user "${REFERENCE}" (at 0 0 -120) (layer "F.Fab") 123 | (effects (font (size 1 1) (thickness 0.15))) 124 | (tstamp e13fd731-ed96-4d9a-a5d3-c93554e4bab5) 125 | ) 126 | (fp_circle (center 0 0) (end 6.4 0) (layer "Cmts.User") (width 0.15) (fill none) (tstamp 99a059c8-2b06-47dc-ab4b-dc4194e2f437)) 127 | (fp_circle (center 0 0) (end 6.65 0) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp 69f6c2e9-d11d-40e8-8f66-3bb068e2e10b)) 128 | (pad "" np_thru_hole circle (at 0 0 240) (size 6.4 6.4) (drill 6.4) (layers *.Cu *.Mask) (tstamp ee3f5f8f-9649-4c44-88d4-fb84445c3132)) 129 | ) 130 | 131 | (footprint "proto:MountingHole_PEM_M3_Broaching_Nut" (layer "F.Cu") 132 | (tedit 56D1B4CB) (tstamp 11892354-cb45-4d91-93ca-f2162ab89296) 133 | (at 9.25 16.02147) 134 | (descr "Mounting Hole 4.22mm for PEM M3 broaching nut") 135 | (tags "mounting hole M3 broach") 136 | (property "Sheetfile" "File: platform.kicad_sch") 137 | (property "Sheetname" "") 138 | (path "/31eb1bde-4b14-499b-9b41-fc0957a98394") 139 | (attr exclude_from_pos_files) 140 | (fp_text reference "H6" (at 0 -3.81) (layer "F.SilkS") hide 141 | (effects (font (size 1 1) (thickness 0.15))) 142 | (tstamp a8074c25-03e3-46dc-8621-12f15b026c20) 143 | ) 144 | (fp_text value "MountingHole" (at 0 3.81) (layer "F.Fab") 145 | (effects (font (size 1 1) (thickness 0.15))) 146 | (tstamp 2719ac95-5569-48d5-8b36-259799ba7311) 147 | ) 148 | (fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab") 149 | (effects (font (size 1 1) (thickness 0.15))) 150 | (tstamp f4b96279-af6d-4737-a42a-9507c5dc72b1) 151 | ) 152 | (fp_circle (center 0 0) (end 2.78 0) (layer "Cmts.User") (width 0.15) (fill none) (tstamp d211d318-c887-47bd-bd61-c8d73d21223b)) 153 | (fp_circle (center 0 0) (end 2.9 0) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp 3b354026-8e60-4c5d-b454-869e98b8b1f7)) 154 | (pad "" np_thru_hole circle (at 0 0) (size 4.22 4.22) (drill 4.22) (layers F&B.Cu *.Mask) (tstamp 24d175c2-9619-4b05-a549-e68cb1f79301)) 155 | ) 156 | 157 | (footprint "MountingHole:MountingHole_6.4mm_M6" (layer "F.Cu") 158 | (tedit 56D1B4CB) (tstamp 5dd0d301-3804-45ac-908a-eda86d28bb9c) 159 | (at 11.6 0) 160 | (descr "Mounting Hole 6.4mm, no annular, M6") 161 | (tags "mounting hole 6.4mm no annular m6") 162 | (property "Sheetfile" "File: platform.kicad_sch") 163 | (property "Sheetname" "") 164 | (path "/0e527201-f82c-4768-9c2c-fa4b77815938") 165 | (attr exclude_from_pos_files) 166 | (fp_text reference "H1" (at 0 -7.4) (layer "F.SilkS") hide 167 | (effects (font (size 1 1) (thickness 0.15))) 168 | (tstamp 7691b29c-8315-4d9a-8903-4602bbe21120) 169 | ) 170 | (fp_text value "MountingHole" (at 0 7.4) (layer "F.Fab") 171 | (effects (font (size 1 1) (thickness 0.15))) 172 | (tstamp d7534f59-5d52-4873-8f20-b1bb832f2430) 173 | ) 174 | (fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab") 175 | (effects (font (size 1 1) (thickness 0.15))) 176 | (tstamp 22a6bf72-5a32-4152-9bf4-a4b0d045d258) 177 | ) 178 | (fp_circle (center 0 0) (end 6.4 0) (layer "Cmts.User") (width 0.15) (fill none) (tstamp ea65948d-817a-4b5d-88d2-b0ad1ba598c7)) 179 | (fp_circle (center 0 0) (end 6.65 0) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp f4330e8e-13d7-475e-b5a7-55e3ffb62f4a)) 180 | (pad "" np_thru_hole circle (at 0 0) (size 6.4 6.4) (drill 6.4) (layers *.Cu *.Mask) (tstamp 9c307c30-18b8-4334-b04b-c0baf71fff4f)) 181 | ) 182 | 183 | (footprint "proto:MountingHole_PEM_M3_Broaching_Nut" (layer "F.Cu") 184 | (tedit 56D1B4CB) (tstamp 6e7ad04a-70fd-4451-960a-f573cc120283) 185 | (at 9.25 -16.02147) 186 | (descr "Mounting Hole 4.22mm for PEM M3 broaching nut") 187 | (tags "mounting hole M3 broach") 188 | (property "Sheetfile" "File: platform.kicad_sch") 189 | (property "Sheetname" "") 190 | (path "/31eb1bde-4b14-499b-9b41-fc0957a98394") 191 | (attr exclude_from_pos_files) 192 | (fp_text reference "H4" (at 0 -3.81) (layer "F.SilkS") hide 193 | (effects (font (size 1 1) (thickness 0.15))) 194 | (tstamp 98db3de7-ce54-40d1-99f1-13c032aa299c) 195 | ) 196 | (fp_text value "MountingHole" (at 0 3.81) (layer "F.Fab") 197 | (effects (font (size 1 1) (thickness 0.15))) 198 | (tstamp 84e90ac4-e319-41ed-9eb1-f9958d9d5aac) 199 | ) 200 | (fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab") 201 | (effects (font (size 1 1) (thickness 0.15))) 202 | (tstamp b5dee5ee-2c27-435e-93eb-37991d0d87f0) 203 | ) 204 | (fp_circle (center 0 0) (end 2.78 0) (layer "Cmts.User") (width 0.15) (fill none) (tstamp 039d1d53-36da-4a23-a0e6-43b0b78c3b49)) 205 | (fp_circle (center 0 0) (end 2.9 0) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp 54c70cab-801c-46ff-91fe-8b7cdf1d4aef)) 206 | (pad "" np_thru_hole circle (at 0 0) (size 4.22 4.22) (drill 4.22) (layers F&B.Cu *.Mask) (tstamp 4b3acb3f-023b-40e8-bb17-54a76fa9bf73)) 207 | ) 208 | 209 | (footprint "proto:ArmPad" (layer "F.Cu") 210 | (tedit 0) (tstamp 771c4958-79e0-49a9-a6e9-660bfc8cf5c9) 211 | (at 7.517645 -23.842923 72.5) 212 | (descr "Mounting hole to solder Stewart platform arms") 213 | (property "Sheetfile" "File: platform.kicad_sch") 214 | (property "Sheetname" "") 215 | (path "/66be40f9-c0b0-4b73-8cae-4ece38326511") 216 | (attr through_hole) 217 | (fp_text reference "A3" (at -4.3 0 72.5 unlocked) (layer "F.SilkS") hide 218 | (effects (font (size 1 1) (thickness 0.15))) 219 | (tstamp 1ac793cb-85c4-4f48-9b92-139d334aca16) 220 | ) 221 | (fp_text value "Arm" (at 0.31 4.01 72.5 unlocked) (layer "F.Fab") 222 | (effects (font (size 1 1) (thickness 0.15))) 223 | (tstamp 09e09f9c-6f21-477b-a5ec-9dce0c63762d) 224 | ) 225 | (pad "1" thru_hole oval locked (at 0.194 0.569 90) (size 3.6 5.255) (drill oval 1.8 3.455) (layers *.Cu *.Mask) 226 | (net 3 "unconnected-(A3-Pad1)") (pinfunction "1") (pintype "input") (tstamp fa05fd6c-97d2-4e35-9031-f29e6f441eff)) 227 | ) 228 | 229 | (footprint "proto:MountingHole_PEM_M3_Broaching_Nut" (layer "F.Cu") 230 | (tedit 56D1B4CB) (tstamp 78779165-9804-42d3-bedb-623946deb435) 231 | (at -18.5 0) 232 | (descr "Mounting Hole 4.22mm for PEM M3 broaching nut") 233 | (tags "mounting hole M3 broach") 234 | (property "Sheetfile" "File: platform.kicad_sch") 235 | (property "Sheetname" "") 236 | (path "/31eb1bde-4b14-499b-9b41-fc0957a98394") 237 | (attr exclude_from_pos_files) 238 | (fp_text reference "H5" (at 0 -3.81) (layer "F.SilkS") hide 239 | (effects (font (size 1 1) (thickness 0.15))) 240 | (tstamp 0ed77457-5116-48bb-a21e-ee07d969e73f) 241 | ) 242 | (fp_text value "MountingHole" (at 0 3.81) (layer "F.Fab") 243 | (effects (font (size 1 1) (thickness 0.15))) 244 | (tstamp 5a8cb32b-c660-4d11-bf7f-78df39b59835) 245 | ) 246 | (fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab") 247 | (effects (font (size 1 1) (thickness 0.15))) 248 | (tstamp 7705077f-8c88-4e4e-a490-9e8de5d40bd5) 249 | ) 250 | (fp_circle (center 0 0) (end 2.78 0) (layer "Cmts.User") (width 0.15) (fill none) (tstamp 0cfafbc5-ef64-4c9b-8dd8-6e90273239d9)) 251 | (fp_circle (center 0 0) (end 2.9 0) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp 15e83186-ce8c-4ac2-837d-619513e01ebf)) 252 | (pad "" np_thru_hole circle (at 0 0) (size 4.22 4.22) (drill 4.22) (layers F&B.Cu *.Mask) (tstamp 27a892ba-e987-454e-a3cf-4395cc42d8a1)) 253 | ) 254 | 255 | (footprint "MountingHole:MountingHole_6.4mm_M6" (layer "F.Cu") 256 | (tedit 56D1B4CB) (tstamp 9709f3c1-5d91-45f5-b8eb-3c427b76b6fa) 257 | (at -5.8 -10.045895 120) 258 | (descr "Mounting Hole 6.4mm, no annular, M6") 259 | (tags "mounting hole 6.4mm no annular m6") 260 | (property "Sheetfile" "File: platform.kicad_sch") 261 | (property "Sheetname" "") 262 | (path "/d157ce28-e118-4d49-a78c-f097618ec8f8") 263 | (attr exclude_from_pos_files) 264 | (fp_text reference "H2" (at 0 -7.4 120) (layer "F.SilkS") hide 265 | (effects (font (size 1 1) (thickness 0.15))) 266 | (tstamp 63a4999c-c410-4825-bbe5-1fd99ac19161) 267 | ) 268 | (fp_text value "MountingHole" (at 0 7.4 120) (layer "F.Fab") 269 | (effects (font (size 1 1) (thickness 0.15))) 270 | (tstamp 0778c1c9-8be9-45f7-9687-753fdae61cf8) 271 | ) 272 | (fp_text user "${REFERENCE}" (at 0 0 120) (layer "F.Fab") 273 | (effects (font (size 1 1) (thickness 0.15))) 274 | (tstamp 1bee0bca-cb40-4206-83e2-b8c159c93c37) 275 | ) 276 | (fp_circle (center 0 0) (end 6.4 0) (layer "Cmts.User") (width 0.15) (fill none) (tstamp b5c54638-f6a5-4059-8cdc-9fb3613e57aa)) 277 | (fp_circle (center 0 0) (end 6.65 0) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp f6854965-b64b-4127-9f84-95e6ac7c674c)) 278 | (pad "" np_thru_hole circle (at 0 0 120) (size 6.4 6.4) (drill 6.4) (layers *.Cu *.Mask) (tstamp 70d03301-477b-4a47-adde-7226ae36673f)) 279 | ) 280 | 281 | (footprint "proto:ArmPad" (layer "F.Cu") 282 | (tedit 0) (tstamp f3584bd5-0626-4101-ac85-957d9293c548) 283 | (at -24.4074 5.41099 -167.5) 284 | (descr "Mounting hole to solder Stewart platform arms") 285 | (property "Sheetfile" "File: platform.kicad_sch") 286 | (property "Sheetname" "") 287 | (path "/45374bd6-2445-461d-8b61-a1683fe05b49") 288 | (attr through_hole) 289 | (fp_text reference "A5" (at -4.3 0 -167.5 unlocked) (layer "F.SilkS") hide 290 | (effects (font (size 1 1) (thickness 0.15))) 291 | (tstamp c2b01e0e-8d05-4ed7-9e3d-128a969c14ab) 292 | ) 293 | (fp_text value "Arm" (at 0.31 4.01 -167.5 unlocked) (layer "F.Fab") 294 | (effects (font (size 1 1) (thickness 0.15))) 295 | (tstamp 39d7662e-49aa-4423-ab85-9b32711bfe2d) 296 | ) 297 | (pad "1" thru_hole oval locked (at 0.194 0.569 210) (size 3.6 5.255) (drill oval 1.8 3.455) (layers *.Cu *.Mask) 298 | (net 5 "unconnected-(A5-Pad1)") (pinfunction "1") (pintype "input") (tstamp 44c597e6-d5b3-46a9-a03f-071c86285167)) 299 | ) 300 | 301 | (footprint "proto:ArmPad" (layer "B.Cu") 302 | (tedit 0) (tstamp 8eaffbbe-848f-4ae5-b923-c5a6dc8edc3e) 303 | (at 7.517645 23.842925 -72.5) 304 | (descr "Mounting hole to solder Stewart platform arms") 305 | (property "Sheetfile" "File: platform.kicad_sch") 306 | (property "Sheetname" "") 307 | (path "/fd5a9ffd-b0c1-46ad-9568-76d7ce70be19") 308 | (attr through_hole) 309 | (fp_text reference "A6" (at -4.3 0 107.5 unlocked) (layer "B.SilkS") hide 310 | (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) 311 | (tstamp 41b8407e-c59d-4b73-b7fd-427542eef83f) 312 | ) 313 | (fp_text value "Arm" (at 0.31 -4.01 107.5 unlocked) (layer "B.Fab") 314 | (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) 315 | (tstamp 81d15962-bcf8-4839-96f2-0542ec30892b) 316 | ) 317 | (pad "1" thru_hole oval locked (at 0.194 -0.569 270) (size 3.6 5.255) (drill oval 1.8 3.455) (layers *.Cu *.Mask) 318 | (net 6 "unconnected-(A6-Pad1)") (pinfunction "1") (pintype "input") (tstamp 017343d0-3171-463b-af1f-ddcf04a3aecd)) 319 | ) 320 | 321 | (footprint "proto:ArmPad" (layer "B.Cu") 322 | (tedit 0) (tstamp bf464458-7021-47a2-819a-6e60b9efbb45) 323 | (at -24.407401 -5.410991 167.5) 324 | (descr "Mounting hole to solder Stewart platform arms") 325 | (property "Sheetfile" "File: platform.kicad_sch") 326 | (property "Sheetname" "") 327 | (path "/37e9a2f8-4f5e-4594-a66d-31035dc3e6d3") 328 | (attr through_hole) 329 | (fp_text reference "A4" (at -4.3 0 347.5 unlocked) (layer "B.SilkS") hide 330 | (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) 331 | (tstamp 3102bd18-4050-42d4-9447-1e31a3eb8c16) 332 | ) 333 | (fp_text value "Arm" (at 0.31 -4.01 347.5 unlocked) (layer "B.Fab") 334 | (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) 335 | (tstamp 791b2a87-73e5-4f80-bedf-54b8a884ec39) 336 | ) 337 | (pad "1" thru_hole oval locked (at 0.194 -0.569 150) (size 3.6 5.255) (drill oval 1.8 3.455) (layers *.Cu *.Mask) 338 | (net 4 "unconnected-(A4-Pad1)") (pinfunction "1") (pintype "input") (tstamp 9c5ae2c4-9f5b-4eb1-9416-5d8afb6c0b4d)) 339 | ) 340 | 341 | (footprint "proto:ArmPad" (layer "B.Cu") 342 | (tedit 0) (tstamp f28dbe9e-e582-455b-bdfa-07f154059117) 343 | (at 16.889756 -18.431934 47.5) 344 | (descr "Mounting hole to solder Stewart platform arms") 345 | (property "Sheetfile" "File: platform.kicad_sch") 346 | (property "Sheetname" "") 347 | (path "/9fdd110d-a3a9-4886-aa20-e71fd17b2ea9") 348 | (attr through_hole) 349 | (fp_text reference "A2" (at -4.3 0 227.5 unlocked) (layer "B.SilkS") hide 350 | (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) 351 | (tstamp d17b11d9-f6fa-4169-bc29-368f2fffa38e) 352 | ) 353 | (fp_text value "Arm" (at 0.31 -4.01 227.5 unlocked) (layer "B.Fab") 354 | (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) 355 | (tstamp 014b8ca1-1b36-4fff-9cea-630ef0711614) 356 | ) 357 | (pad "1" thru_hole oval locked (at 0.194 -0.569 30) (size 3.6 5.255) (drill oval 1.8 3.455) (layers *.Cu *.Mask) 358 | (net 2 "unconnected-(A2-Pad1)") (pinfunction "1") (pintype "input") (tstamp ca1a03ad-bbf0-4d36-bdb1-e2dc9f11ea76)) 359 | ) 360 | 361 | (gr_circle (center 0 0) (end 30 0) (layer "Edge.Cuts") (width 0.1) (fill none) (tstamp e528dd40-d06b-4f01-b5d1-4a7ed8691b36)) 362 | 363 | ) 364 | -------------------------------------------------------------------------------- /hardware/electronics/platform/platform.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "design_settings": { 4 | "defaults": { 5 | "board_outline_line_width": 0.09999999999999999, 6 | "copper_line_width": 0.19999999999999998, 7 | "copper_text_italic": false, 8 | "copper_text_size_h": 1.5, 9 | "copper_text_size_v": 1.5, 10 | "copper_text_thickness": 0.3, 11 | "copper_text_upright": false, 12 | "courtyard_line_width": 0.049999999999999996, 13 | "dimension_precision": 4, 14 | "dimension_units": 3, 15 | "dimensions": { 16 | "arrow_length": 1270000, 17 | "extension_offset": 500000, 18 | "keep_text_aligned": true, 19 | "suppress_zeroes": false, 20 | "text_position": 0, 21 | "units_format": 1 22 | }, 23 | "fab_line_width": 0.09999999999999999, 24 | "fab_text_italic": false, 25 | "fab_text_size_h": 1.0, 26 | "fab_text_size_v": 1.0, 27 | "fab_text_thickness": 0.15, 28 | "fab_text_upright": false, 29 | "other_line_width": 0.15, 30 | "other_text_italic": false, 31 | "other_text_size_h": 1.0, 32 | "other_text_size_v": 1.0, 33 | "other_text_thickness": 0.15, 34 | "other_text_upright": false, 35 | "pads": { 36 | "drill": 6.0, 37 | "height": 6.0, 38 | "width": 6.0 39 | }, 40 | "silk_line_width": 0.15, 41 | "silk_text_italic": false, 42 | "silk_text_size_h": 1.0, 43 | "silk_text_size_v": 1.0, 44 | "silk_text_thickness": 0.15, 45 | "silk_text_upright": false, 46 | "zones": { 47 | "45_degree_only": false, 48 | "min_clearance": 0.508 49 | } 50 | }, 51 | "diff_pair_dimensions": [], 52 | "drc_exclusions": [], 53 | "meta": { 54 | "version": 2 55 | }, 56 | "rule_severities": { 57 | "annular_width": "error", 58 | "clearance": "error", 59 | "copper_edge_clearance": "error", 60 | "courtyards_overlap": "error", 61 | "diff_pair_gap_out_of_range": "error", 62 | "diff_pair_uncoupled_length_too_long": "error", 63 | "drill_out_of_range": "error", 64 | "duplicate_footprints": "warning", 65 | "extra_footprint": "warning", 66 | "footprint_type_mismatch": "error", 67 | "hole_clearance": "error", 68 | "hole_near_hole": "error", 69 | "invalid_outline": "error", 70 | "item_on_disabled_layer": "error", 71 | "items_not_allowed": "error", 72 | "length_out_of_range": "error", 73 | "malformed_courtyard": "error", 74 | "microvia_drill_out_of_range": "error", 75 | "missing_courtyard": "ignore", 76 | "missing_footprint": "warning", 77 | "net_conflict": "warning", 78 | "npth_inside_courtyard": "ignore", 79 | "padstack": "error", 80 | "pth_inside_courtyard": "ignore", 81 | "shorting_items": "error", 82 | "silk_over_copper": "warning", 83 | "silk_overlap": "warning", 84 | "skew_out_of_range": "error", 85 | "through_hole_pad_without_hole": "error", 86 | "too_many_vias": "error", 87 | "track_dangling": "warning", 88 | "track_width": "error", 89 | "tracks_crossing": "error", 90 | "unconnected_items": "error", 91 | "unresolved_variable": "error", 92 | "via_dangling": "warning", 93 | "zone_has_empty_net": "error", 94 | "zones_intersect": "error" 95 | }, 96 | "rules": { 97 | "allow_blind_buried_vias": false, 98 | "allow_microvias": false, 99 | "max_error": 0.005, 100 | "min_clearance": 0.0, 101 | "min_copper_edge_clearance": 0.0, 102 | "min_hole_clearance": 0.25, 103 | "min_hole_to_hole": 0.25, 104 | "min_microvia_diameter": 0.19999999999999998, 105 | "min_microvia_drill": 0.09999999999999999, 106 | "min_silk_clearance": 0.0, 107 | "min_through_hole_diameter": 0.3, 108 | "min_track_width": 0.19999999999999998, 109 | "min_via_annular_width": 0.049999999999999996, 110 | "min_via_diameter": 0.39999999999999997, 111 | "solder_mask_clearance": 0.0, 112 | "solder_mask_min_width": 0.0, 113 | "use_height_for_length_calcs": true 114 | }, 115 | "track_widths": [], 116 | "via_dimensions": [], 117 | "zones_allow_external_fillets": false, 118 | "zones_use_no_outline": true 119 | }, 120 | "layer_presets": [] 121 | }, 122 | "boards": [], 123 | "cvpcb": { 124 | "equivalence_files": [] 125 | }, 126 | "erc": { 127 | "erc_exclusions": [], 128 | "meta": { 129 | "version": 0 130 | }, 131 | "pin_map": [ 132 | [ 133 | 0, 134 | 0, 135 | 0, 136 | 0, 137 | 0, 138 | 0, 139 | 1, 140 | 0, 141 | 0, 142 | 0, 143 | 0, 144 | 2 145 | ], 146 | [ 147 | 0, 148 | 2, 149 | 0, 150 | 1, 151 | 0, 152 | 0, 153 | 1, 154 | 0, 155 | 2, 156 | 2, 157 | 2, 158 | 2 159 | ], 160 | [ 161 | 0, 162 | 0, 163 | 0, 164 | 0, 165 | 0, 166 | 0, 167 | 1, 168 | 0, 169 | 1, 170 | 0, 171 | 1, 172 | 2 173 | ], 174 | [ 175 | 0, 176 | 1, 177 | 0, 178 | 0, 179 | 0, 180 | 0, 181 | 1, 182 | 1, 183 | 2, 184 | 1, 185 | 1, 186 | 2 187 | ], 188 | [ 189 | 0, 190 | 0, 191 | 0, 192 | 0, 193 | 0, 194 | 0, 195 | 1, 196 | 0, 197 | 0, 198 | 0, 199 | 0, 200 | 2 201 | ], 202 | [ 203 | 0, 204 | 0, 205 | 0, 206 | 0, 207 | 0, 208 | 0, 209 | 0, 210 | 0, 211 | 0, 212 | 0, 213 | 0, 214 | 2 215 | ], 216 | [ 217 | 1, 218 | 1, 219 | 1, 220 | 1, 221 | 1, 222 | 0, 223 | 1, 224 | 1, 225 | 1, 226 | 1, 227 | 1, 228 | 2 229 | ], 230 | [ 231 | 0, 232 | 0, 233 | 0, 234 | 1, 235 | 0, 236 | 0, 237 | 1, 238 | 0, 239 | 0, 240 | 0, 241 | 0, 242 | 2 243 | ], 244 | [ 245 | 0, 246 | 2, 247 | 1, 248 | 2, 249 | 0, 250 | 0, 251 | 1, 252 | 0, 253 | 2, 254 | 2, 255 | 2, 256 | 2 257 | ], 258 | [ 259 | 0, 260 | 2, 261 | 0, 262 | 1, 263 | 0, 264 | 0, 265 | 1, 266 | 0, 267 | 2, 268 | 0, 269 | 0, 270 | 2 271 | ], 272 | [ 273 | 0, 274 | 2, 275 | 1, 276 | 1, 277 | 0, 278 | 0, 279 | 1, 280 | 0, 281 | 2, 282 | 0, 283 | 0, 284 | 2 285 | ], 286 | [ 287 | 2, 288 | 2, 289 | 2, 290 | 2, 291 | 2, 292 | 2, 293 | 2, 294 | 2, 295 | 2, 296 | 2, 297 | 2, 298 | 2 299 | ] 300 | ], 301 | "rule_severities": { 302 | "bus_definition_conflict": "error", 303 | "bus_entry_needed": "error", 304 | "bus_label_syntax": "error", 305 | "bus_to_bus_conflict": "error", 306 | "bus_to_net_conflict": "error", 307 | "different_unit_footprint": "error", 308 | "different_unit_net": "error", 309 | "duplicate_reference": "error", 310 | "duplicate_sheet_names": "error", 311 | "extra_units": "error", 312 | "global_label_dangling": "warning", 313 | "hier_label_mismatch": "error", 314 | "label_dangling": "error", 315 | "lib_symbol_issues": "warning", 316 | "multiple_net_names": "warning", 317 | "net_not_bus_member": "warning", 318 | "no_connect_connected": "warning", 319 | "no_connect_dangling": "warning", 320 | "pin_not_connected": "error", 321 | "pin_not_driven": "error", 322 | "pin_to_pin": "warning", 323 | "power_pin_not_driven": "error", 324 | "similar_labels": "warning", 325 | "unannotated": "error", 326 | "unit_value_mismatch": "error", 327 | "unresolved_variable": "error", 328 | "wire_dangling": "error" 329 | } 330 | }, 331 | "libraries": { 332 | "pinned_footprint_libs": [ 333 | "proto" 334 | ], 335 | "pinned_symbol_libs": [] 336 | }, 337 | "meta": { 338 | "filename": "platform.kicad_pro", 339 | "version": 1 340 | }, 341 | "net_settings": { 342 | "classes": [ 343 | { 344 | "bus_width": 12.0, 345 | "clearance": 0.2, 346 | "diff_pair_gap": 0.25, 347 | "diff_pair_via_gap": 0.25, 348 | "diff_pair_width": 0.2, 349 | "line_style": 0, 350 | "microvia_diameter": 0.3, 351 | "microvia_drill": 0.1, 352 | "name": "Default", 353 | "pcb_color": "rgba(0, 0, 0, 0.000)", 354 | "schematic_color": "rgba(0, 0, 0, 0.000)", 355 | "track_width": 0.25, 356 | "via_diameter": 0.8, 357 | "via_drill": 0.4, 358 | "wire_width": 6.0 359 | } 360 | ], 361 | "meta": { 362 | "version": 2 363 | }, 364 | "net_colors": null 365 | }, 366 | "pcbnew": { 367 | "last_paths": { 368 | "gencad": "", 369 | "idf": "", 370 | "netlist": "", 371 | "specctra_dsn": "", 372 | "step": "platform.step", 373 | "vrml": "platform.wrl" 374 | }, 375 | "page_layout_descr_file": "" 376 | }, 377 | "schematic": { 378 | "annotate_start_num": 0, 379 | "drawing": { 380 | "default_line_thickness": 6.0, 381 | "default_text_size": 50.0, 382 | "field_names": [], 383 | "intersheets_ref_own_page": false, 384 | "intersheets_ref_prefix": "", 385 | "intersheets_ref_short": false, 386 | "intersheets_ref_show": false, 387 | "intersheets_ref_suffix": "", 388 | "junction_size_choice": 3, 389 | "label_size_ratio": 0.375, 390 | "pin_symbol_size": 25.0, 391 | "text_offset_ratio": 0.15 392 | }, 393 | "legacy_lib_dir": "", 394 | "legacy_lib_list": [], 395 | "meta": { 396 | "version": 1 397 | }, 398 | "net_format_name": "", 399 | "ngspice": { 400 | "fix_include_paths": true, 401 | "fix_passive_vals": false, 402 | "meta": { 403 | "version": 0 404 | }, 405 | "model_mode": 0, 406 | "workbook_filename": "" 407 | }, 408 | "page_layout_descr_file": "", 409 | "plot_directory": "", 410 | "spice_adjust_passive_values": false, 411 | "spice_external_command": "spice \"%I\"", 412 | "subpart_first_id": 65, 413 | "subpart_id_separator": 0 414 | }, 415 | "sheets": [ 416 | [ 417 | "ee2a5d63-dd12-40e7-a365-7c07ebcea3ba", 418 | "" 419 | ] 420 | ], 421 | "text_variables": {} 422 | } 423 | -------------------------------------------------------------------------------- /hardware/electronics/platform/platform.kicad_sch: -------------------------------------------------------------------------------- 1 | (kicad_sch (version 20211123) (generator eeschema) 2 | 3 | (uuid ee2a5d63-dd12-40e7-a365-7c07ebcea3ba) 4 | 5 | (paper "A4") 6 | 7 | (lib_symbols 8 | (symbol "Mechanical:MountingHole" (pin_names (offset 1.016)) (in_bom yes) (on_board yes) 9 | (property "Reference" "H" (id 0) (at 0 5.08 0) 10 | (effects (font (size 1.27 1.27))) 11 | ) 12 | (property "Value" "MountingHole" (id 1) (at 0 3.175 0) 13 | (effects (font (size 1.27 1.27))) 14 | ) 15 | (property "Footprint" "" (id 2) (at 0 0 0) 16 | (effects (font (size 1.27 1.27)) hide) 17 | ) 18 | (property "Datasheet" "~" (id 3) (at 0 0 0) 19 | (effects (font (size 1.27 1.27)) hide) 20 | ) 21 | (property "ki_keywords" "mounting hole" (id 4) (at 0 0 0) 22 | (effects (font (size 1.27 1.27)) hide) 23 | ) 24 | (property "ki_description" "Mounting Hole without connection" (id 5) (at 0 0 0) 25 | (effects (font (size 1.27 1.27)) hide) 26 | ) 27 | (property "ki_fp_filters" "MountingHole*" (id 6) (at 0 0 0) 28 | (effects (font (size 1.27 1.27)) hide) 29 | ) 30 | (symbol "MountingHole_0_1" 31 | (circle (center 0 0) (radius 1.27) 32 | (stroke (width 1.27) (type default) (color 0 0 0 0)) 33 | (fill (type none)) 34 | ) 35 | ) 36 | ) 37 | (symbol "Mechanical:MountingHole_Pad" (pin_numbers hide) (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes) 38 | (property "Reference" "H" (id 0) (at 0 6.35 0) 39 | (effects (font (size 1.27 1.27))) 40 | ) 41 | (property "Value" "MountingHole_Pad" (id 1) (at 0 4.445 0) 42 | (effects (font (size 1.27 1.27))) 43 | ) 44 | (property "Footprint" "" (id 2) (at 0 0 0) 45 | (effects (font (size 1.27 1.27)) hide) 46 | ) 47 | (property "Datasheet" "~" (id 3) (at 0 0 0) 48 | (effects (font (size 1.27 1.27)) hide) 49 | ) 50 | (property "ki_keywords" "mounting hole" (id 4) (at 0 0 0) 51 | (effects (font (size 1.27 1.27)) hide) 52 | ) 53 | (property "ki_description" "Mounting Hole with connection" (id 5) (at 0 0 0) 54 | (effects (font (size 1.27 1.27)) hide) 55 | ) 56 | (property "ki_fp_filters" "MountingHole*Pad*" (id 6) (at 0 0 0) 57 | (effects (font (size 1.27 1.27)) hide) 58 | ) 59 | (symbol "MountingHole_Pad_0_1" 60 | (circle (center 0 1.27) (radius 1.27) 61 | (stroke (width 1.27) (type default) (color 0 0 0 0)) 62 | (fill (type none)) 63 | ) 64 | ) 65 | (symbol "MountingHole_Pad_1_1" 66 | (pin input line (at 0 -2.54 90) (length 2.54) 67 | (name "1" (effects (font (size 1.27 1.27)))) 68 | (number "1" (effects (font (size 1.27 1.27)))) 69 | ) 70 | ) 71 | ) 72 | ) 73 | 74 | 75 | (polyline (pts (xy 132.08 66.04) (xy 132.08 92.71)) 76 | (stroke (width 0) (type default) (color 0 0 0 0)) 77 | (uuid 17591105-add4-42e0-bf5d-77fa71b2cd08) 78 | ) 79 | (polyline (pts (xy 171.45 66.04) (xy 171.45 92.71)) 80 | (stroke (width 0) (type default) (color 0 0 0 0)) 81 | (uuid 396f74a5-457d-44f6-8736-c02369f08cc2) 82 | ) 83 | (polyline (pts (xy 177.8 127) (xy 101.6 127)) 84 | (stroke (width 0) (type default) (color 0 0 0 0)) 85 | (uuid 3c6fc2aa-e529-46dc-8431-8eafaeb6fe87) 86 | ) 87 | (polyline (pts (xy 171.45 92.71) (xy 147.32 92.71)) 88 | (stroke (width 0) (type default) (color 0 0 0 0)) 89 | (uuid 5a5aa63a-d020-40be-917f-9f8c4490cbde) 90 | ) 91 | (polyline (pts (xy 101.6 114.3) (xy 101.6 127)) 92 | (stroke (width 0) (type default) (color 0 0 0 0)) 93 | (uuid 621cf285-f4df-45b7-ad04-f927d5fd61a0) 94 | ) 95 | (polyline (pts (xy 147.32 66.04) (xy 171.45 66.04)) 96 | (stroke (width 0) (type default) (color 0 0 0 0)) 97 | (uuid 7322309b-beed-46a8-890e-3f4079eac80f) 98 | ) 99 | (polyline (pts (xy 177.8 114.3) (xy 177.8 127)) 100 | (stroke (width 0) (type default) (color 0 0 0 0)) 101 | (uuid a577db82-e361-4d9d-998f-bd1a0891827a) 102 | ) 103 | (polyline (pts (xy 107.95 66.04) (xy 107.95 92.71)) 104 | (stroke (width 0) (type default) (color 0 0 0 0)) 105 | (uuid ade439bb-d512-43f2-9ac0-f426f5c7f2aa) 106 | ) 107 | (polyline (pts (xy 101.6 114.3) (xy 177.8 114.3)) 108 | (stroke (width 0) (type default) (color 0 0 0 0)) 109 | (uuid b3af440a-36cb-4852-ba74-efaf018621c7) 110 | ) 111 | (polyline (pts (xy 107.95 66.04) (xy 132.08 66.04)) 112 | (stroke (width 0) (type default) (color 0 0 0 0)) 113 | (uuid cb542287-babb-42fc-bbe1-76e4c7c003f7) 114 | ) 115 | (polyline (pts (xy 147.32 66.04) (xy 147.32 92.71)) 116 | (stroke (width 0) (type default) (color 0 0 0 0)) 117 | (uuid e159fe54-f567-42fe-8a5e-0ae20742acd0) 118 | ) 119 | (polyline (pts (xy 132.08 92.71) (xy 107.95 92.71)) 120 | (stroke (width 0) (type default) (color 0 0 0 0)) 121 | (uuid f1a4f037-aa72-416e-8999-01c933d4e6ba) 122 | ) 123 | 124 | (text "Knob Mount" (at 147.32 66.04 0) 125 | (effects (font (size 1.27 1.27)) (justify left bottom)) 126 | (uuid 8e8f68fe-596c-4475-a5d0-f252daa772f1) 127 | ) 128 | (text "Arm Mounts" (at 101.6 114.3 0) 129 | (effects (font (size 1.27 1.27)) (justify left bottom)) 130 | (uuid b1444629-8145-4ed6-aea2-4b61b977ac41) 131 | ) 132 | (text "Base Access" (at 107.95 66.04 0) 133 | (effects (font (size 1.27 1.27)) (justify left bottom)) 134 | (uuid f134c989-a76e-4bfa-9834-f312474fcd81) 135 | ) 136 | 137 | (symbol (lib_id "Mechanical:MountingHole") (at 113.03 71.12 0) (unit 1) 138 | (in_bom yes) (on_board yes) (fields_autoplaced) 139 | (uuid 0e527201-f82c-4768-9c2c-fa4b77815938) 140 | (property "Reference" "H1" (id 0) (at 115.57 70.2853 0) 141 | (effects (font (size 1.27 1.27)) (justify left)) 142 | ) 143 | (property "Value" "MountingHole" (id 1) (at 115.57 72.8222 0) 144 | (effects (font (size 1.27 1.27)) (justify left)) 145 | ) 146 | (property "Footprint" "MountingHole:MountingHole_6.4mm_M6" (id 2) (at 113.03 71.12 0) 147 | (effects (font (size 1.27 1.27)) hide) 148 | ) 149 | (property "Datasheet" "~" (id 3) (at 113.03 71.12 0) 150 | (effects (font (size 1.27 1.27)) hide) 151 | ) 152 | ) 153 | 154 | (symbol (lib_id "Mechanical:MountingHole") (at 152.4 78.74 0) (unit 1) 155 | (in_bom yes) (on_board yes) (fields_autoplaced) 156 | (uuid 31eb1bde-4b14-499b-9b41-fc0957a98394) 157 | (property "Reference" "H5" (id 0) (at 154.94 77.9053 0) 158 | (effects (font (size 1.27 1.27)) (justify left)) 159 | ) 160 | (property "Value" "MountingHole" (id 1) (at 154.94 80.4422 0) 161 | (effects (font (size 1.27 1.27)) (justify left)) 162 | ) 163 | (property "Footprint" "proto:MountingHole_PEM_M3_Broaching_Nut" (id 2) (at 152.4 78.74 0) 164 | (effects (font (size 1.27 1.27)) hide) 165 | ) 166 | (property "Datasheet" "~" (id 3) (at 152.4 78.74 0) 167 | (effects (font (size 1.27 1.27)) hide) 168 | ) 169 | ) 170 | 171 | (symbol (lib_id "Mechanical:MountingHole_Pad") (at 144.78 120.65 0) (unit 1) 172 | (in_bom yes) (on_board yes) (fields_autoplaced) 173 | (uuid 37e9a2f8-4f5e-4594-a66d-31035dc3e6d3) 174 | (property "Reference" "A4" (id 0) (at 147.32 118.5453 0) 175 | (effects (font (size 1.27 1.27)) (justify left)) 176 | ) 177 | (property "Value" "Arm" (id 1) (at 147.32 121.0822 0) 178 | (effects (font (size 1.27 1.27)) (justify left)) 179 | ) 180 | (property "Footprint" "proto:ArmPad" (id 2) (at 144.78 120.65 0) 181 | (effects (font (size 1.27 1.27)) hide) 182 | ) 183 | (property "Datasheet" "~" (id 3) (at 144.78 120.65 0) 184 | (effects (font (size 1.27 1.27)) hide) 185 | ) 186 | (pin "1" (uuid 6425031e-fe49-4c89-98e6-6addf519df66)) 187 | ) 188 | 189 | (symbol (lib_id "Mechanical:MountingHole_Pad") (at 157.48 120.65 0) (unit 1) 190 | (in_bom yes) (on_board yes) (fields_autoplaced) 191 | (uuid 45374bd6-2445-461d-8b61-a1683fe05b49) 192 | (property "Reference" "A5" (id 0) (at 160.02 118.5453 0) 193 | (effects (font (size 1.27 1.27)) (justify left)) 194 | ) 195 | (property "Value" "Arm" (id 1) (at 160.02 121.0822 0) 196 | (effects (font (size 1.27 1.27)) (justify left)) 197 | ) 198 | (property "Footprint" "proto:ArmPad" (id 2) (at 157.48 120.65 0) 199 | (effects (font (size 1.27 1.27)) hide) 200 | ) 201 | (property "Datasheet" "~" (id 3) (at 157.48 120.65 0) 202 | (effects (font (size 1.27 1.27)) hide) 203 | ) 204 | (pin "1" (uuid a32b9595-3b17-4004-94af-d74d7be95da5)) 205 | ) 206 | 207 | (symbol (lib_id "Mechanical:MountingHole") (at 152.4 86.36 0) (unit 1) 208 | (in_bom yes) (on_board yes) (fields_autoplaced) 209 | (uuid 5706a5e5-b815-4c8c-9e49-dd1f52967c85) 210 | (property "Reference" "H6" (id 0) (at 154.94 85.5253 0) 211 | (effects (font (size 1.27 1.27)) (justify left)) 212 | ) 213 | (property "Value" "MountingHole" (id 1) (at 154.94 88.0622 0) 214 | (effects (font (size 1.27 1.27)) (justify left)) 215 | ) 216 | (property "Footprint" "proto:MountingHole_PEM_M3_Broaching_Nut" (id 2) (at 152.4 86.36 0) 217 | (effects (font (size 1.27 1.27)) hide) 218 | ) 219 | (property "Datasheet" "~" (id 3) (at 152.4 86.36 0) 220 | (effects (font (size 1.27 1.27)) hide) 221 | ) 222 | ) 223 | 224 | (symbol (lib_id "Mechanical:MountingHole_Pad") (at 106.68 120.65 0) (unit 1) 225 | (in_bom yes) (on_board yes) (fields_autoplaced) 226 | (uuid 627b2a8a-12a5-4630-827d-2edae280b953) 227 | (property "Reference" "A1" (id 0) (at 109.22 118.5453 0) 228 | (effects (font (size 1.27 1.27)) (justify left)) 229 | ) 230 | (property "Value" "Arm" (id 1) (at 109.22 121.0822 0) 231 | (effects (font (size 1.27 1.27)) (justify left)) 232 | ) 233 | (property "Footprint" "proto:ArmPad" (id 2) (at 106.68 120.65 0) 234 | (effects (font (size 1.27 1.27)) hide) 235 | ) 236 | (property "Datasheet" "~" (id 3) (at 106.68 120.65 0) 237 | (effects (font (size 1.27 1.27)) hide) 238 | ) 239 | (pin "1" (uuid d95b9ae1-d32d-4227-bfdf-b3085760c653)) 240 | ) 241 | 242 | (symbol (lib_id "Mechanical:MountingHole_Pad") (at 132.08 120.65 0) (unit 1) 243 | (in_bom yes) (on_board yes) (fields_autoplaced) 244 | (uuid 66be40f9-c0b0-4b73-8cae-4ece38326511) 245 | (property "Reference" "A3" (id 0) (at 134.62 118.5453 0) 246 | (effects (font (size 1.27 1.27)) (justify left)) 247 | ) 248 | (property "Value" "Arm" (id 1) (at 134.62 121.0822 0) 249 | (effects (font (size 1.27 1.27)) (justify left)) 250 | ) 251 | (property "Footprint" "proto:ArmPad" (id 2) (at 132.08 120.65 0) 252 | (effects (font (size 1.27 1.27)) hide) 253 | ) 254 | (property "Datasheet" "~" (id 3) (at 132.08 120.65 0) 255 | (effects (font (size 1.27 1.27)) hide) 256 | ) 257 | (pin "1" (uuid b495ce7e-d4d7-446b-a9f8-99c83fcf43ca)) 258 | ) 259 | 260 | (symbol (lib_id "Mechanical:MountingHole") (at 113.03 86.36 0) (unit 1) 261 | (in_bom yes) (on_board yes) (fields_autoplaced) 262 | (uuid 6859a470-7fb7-4f47-9925-056f0b61f509) 263 | (property "Reference" "H3" (id 0) (at 115.57 85.5253 0) 264 | (effects (font (size 1.27 1.27)) (justify left)) 265 | ) 266 | (property "Value" "MountingHole" (id 1) (at 115.57 88.0622 0) 267 | (effects (font (size 1.27 1.27)) (justify left)) 268 | ) 269 | (property "Footprint" "MountingHole:MountingHole_6.4mm_M6" (id 2) (at 113.03 86.36 0) 270 | (effects (font (size 1.27 1.27)) hide) 271 | ) 272 | (property "Datasheet" "~" (id 3) (at 113.03 86.36 0) 273 | (effects (font (size 1.27 1.27)) hide) 274 | ) 275 | ) 276 | 277 | (symbol (lib_id "Mechanical:MountingHole_Pad") (at 119.38 120.65 0) (unit 1) 278 | (in_bom yes) (on_board yes) (fields_autoplaced) 279 | (uuid 9fdd110d-a3a9-4886-aa20-e71fd17b2ea9) 280 | (property "Reference" "A2" (id 0) (at 121.92 118.5453 0) 281 | (effects (font (size 1.27 1.27)) (justify left)) 282 | ) 283 | (property "Value" "Arm" (id 1) (at 121.92 121.0822 0) 284 | (effects (font (size 1.27 1.27)) (justify left)) 285 | ) 286 | (property "Footprint" "proto:ArmPad" (id 2) (at 119.38 120.65 0) 287 | (effects (font (size 1.27 1.27)) hide) 288 | ) 289 | (property "Datasheet" "~" (id 3) (at 119.38 120.65 0) 290 | (effects (font (size 1.27 1.27)) hide) 291 | ) 292 | (pin "1" (uuid bc3ea5ef-c42f-4093-827d-f8e92fa5704d)) 293 | ) 294 | 295 | (symbol (lib_id "Mechanical:MountingHole") (at 152.4 71.12 0) (unit 1) 296 | (in_bom yes) (on_board yes) (fields_autoplaced) 297 | (uuid a482982d-a417-4e25-ba2e-8e1b5cbe6752) 298 | (property "Reference" "H4" (id 0) (at 154.94 70.2853 0) 299 | (effects (font (size 1.27 1.27)) (justify left)) 300 | ) 301 | (property "Value" "MountingHole" (id 1) (at 154.94 72.8222 0) 302 | (effects (font (size 1.27 1.27)) (justify left)) 303 | ) 304 | (property "Footprint" "proto:MountingHole_PEM_M3_Broaching_Nut" (id 2) (at 152.4 71.12 0) 305 | (effects (font (size 1.27 1.27)) hide) 306 | ) 307 | (property "Datasheet" "~" (id 3) (at 152.4 71.12 0) 308 | (effects (font (size 1.27 1.27)) hide) 309 | ) 310 | ) 311 | 312 | (symbol (lib_id "Mechanical:MountingHole") (at 113.03 78.74 0) (unit 1) 313 | (in_bom yes) (on_board yes) (fields_autoplaced) 314 | (uuid d157ce28-e118-4d49-a78c-f097618ec8f8) 315 | (property "Reference" "H2" (id 0) (at 115.57 77.9053 0) 316 | (effects (font (size 1.27 1.27)) (justify left)) 317 | ) 318 | (property "Value" "MountingHole" (id 1) (at 115.57 80.4422 0) 319 | (effects (font (size 1.27 1.27)) (justify left)) 320 | ) 321 | (property "Footprint" "MountingHole:MountingHole_6.4mm_M6" (id 2) (at 113.03 78.74 0) 322 | (effects (font (size 1.27 1.27)) hide) 323 | ) 324 | (property "Datasheet" "~" (id 3) (at 113.03 78.74 0) 325 | (effects (font (size 1.27 1.27)) hide) 326 | ) 327 | ) 328 | 329 | (symbol (lib_id "Mechanical:MountingHole_Pad") (at 170.18 120.65 0) (unit 1) 330 | (in_bom yes) (on_board yes) (fields_autoplaced) 331 | (uuid fd5a9ffd-b0c1-46ad-9568-76d7ce70be19) 332 | (property "Reference" "A6" (id 0) (at 172.72 118.5453 0) 333 | (effects (font (size 1.27 1.27)) (justify left)) 334 | ) 335 | (property "Value" "Arm" (id 1) (at 172.72 121.0822 0) 336 | (effects (font (size 1.27 1.27)) (justify left)) 337 | ) 338 | (property "Footprint" "proto:ArmPad" (id 2) (at 170.18 120.65 0) 339 | (effects (font (size 1.27 1.27)) hide) 340 | ) 341 | (property "Datasheet" "~" (id 3) (at 170.18 120.65 0) 342 | (effects (font (size 1.27 1.27)) hide) 343 | ) 344 | (pin "1" (uuid 50038482-a0d0-442f-80cb-296efc931109)) 345 | ) 346 | 347 | (sheet_instances 348 | (path "/" (page "1")) 349 | ) 350 | 351 | (symbol_instances 352 | (path "/627b2a8a-12a5-4630-827d-2edae280b953" 353 | (reference "A1") (unit 1) (value "Arm") (footprint "proto:ArmPad") 354 | ) 355 | (path "/9fdd110d-a3a9-4886-aa20-e71fd17b2ea9" 356 | (reference "A2") (unit 1) (value "Arm") (footprint "proto:ArmPad") 357 | ) 358 | (path "/66be40f9-c0b0-4b73-8cae-4ece38326511" 359 | (reference "A3") (unit 1) (value "Arm") (footprint "proto:ArmPad") 360 | ) 361 | (path "/37e9a2f8-4f5e-4594-a66d-31035dc3e6d3" 362 | (reference "A4") (unit 1) (value "Arm") (footprint "proto:ArmPad") 363 | ) 364 | (path "/45374bd6-2445-461d-8b61-a1683fe05b49" 365 | (reference "A5") (unit 1) (value "Arm") (footprint "proto:ArmPad") 366 | ) 367 | (path "/fd5a9ffd-b0c1-46ad-9568-76d7ce70be19" 368 | (reference "A6") (unit 1) (value "Arm") (footprint "proto:ArmPad") 369 | ) 370 | (path "/0e527201-f82c-4768-9c2c-fa4b77815938" 371 | (reference "H1") (unit 1) (value "MountingHole") (footprint "MountingHole:MountingHole_6.4mm_M6") 372 | ) 373 | (path "/d157ce28-e118-4d49-a78c-f097618ec8f8" 374 | (reference "H2") (unit 1) (value "MountingHole") (footprint "MountingHole:MountingHole_6.4mm_M6") 375 | ) 376 | (path "/6859a470-7fb7-4f47-9925-056f0b61f509" 377 | (reference "H3") (unit 1) (value "MountingHole") (footprint "MountingHole:MountingHole_6.4mm_M6") 378 | ) 379 | (path "/a482982d-a417-4e25-ba2e-8e1b5cbe6752" 380 | (reference "H4") (unit 1) (value "MountingHole") (footprint "proto:MountingHole_PEM_M3_Broaching_Nut") 381 | ) 382 | (path "/31eb1bde-4b14-499b-9b41-fc0957a98394" 383 | (reference "H5") (unit 1) (value "MountingHole") (footprint "proto:MountingHole_PEM_M3_Broaching_Nut") 384 | ) 385 | (path "/5706a5e5-b815-4c8c-9e49-dd1f52967c85" 386 | (reference "H6") (unit 1) (value "MountingHole") (footprint "proto:MountingHole_PEM_M3_Broaching_Nut") 387 | ) 388 | ) 389 | ) 390 | -------------------------------------------------------------------------------- /hardware/electronics/platform/sym-lib-table: -------------------------------------------------------------------------------- 1 | (sym_lib_table 2 | (lib (name "proto")(type "KiCad")(uri "${KIPRJMOD}/../lib/proto.kicad_sym")(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /hardware/electronics/proto/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name "proto")(type "KiCad")(uri "${KIPRJMOD}/../lib/proto.pretty")(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /hardware/electronics/proto/proto.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "design_settings": { 4 | "defaults": { 5 | "board_outline_line_width": 0.09999999999999999, 6 | "copper_line_width": 0.19999999999999998, 7 | "copper_text_italic": false, 8 | "copper_text_size_h": 1.5, 9 | "copper_text_size_v": 1.5, 10 | "copper_text_thickness": 0.3, 11 | "copper_text_upright": false, 12 | "courtyard_line_width": 0.049999999999999996, 13 | "dimension_precision": 4, 14 | "dimension_units": 3, 15 | "dimensions": { 16 | "arrow_length": 1270000, 17 | "extension_offset": 500000, 18 | "keep_text_aligned": true, 19 | "suppress_zeroes": false, 20 | "text_position": 0, 21 | "units_format": 1 22 | }, 23 | "fab_line_width": 0.09999999999999999, 24 | "fab_text_italic": false, 25 | "fab_text_size_h": 1.0, 26 | "fab_text_size_v": 1.0, 27 | "fab_text_thickness": 0.15, 28 | "fab_text_upright": false, 29 | "other_line_width": 0.15, 30 | "other_text_italic": false, 31 | "other_text_size_h": 1.0, 32 | "other_text_size_v": 1.0, 33 | "other_text_thickness": 0.15, 34 | "other_text_upright": false, 35 | "pads": { 36 | "drill": 1.8, 37 | "height": 5.255, 38 | "width": 3.6 39 | }, 40 | "silk_line_width": 0.15, 41 | "silk_text_italic": false, 42 | "silk_text_size_h": 1.0, 43 | "silk_text_size_v": 1.0, 44 | "silk_text_thickness": 0.15, 45 | "silk_text_upright": false, 46 | "zones": { 47 | "45_degree_only": false, 48 | "min_clearance": 0.19999999999999998 49 | } 50 | }, 51 | "diff_pair_dimensions": [ 52 | { 53 | "gap": 0.0, 54 | "via_gap": 0.0, 55 | "width": 0.0 56 | } 57 | ], 58 | "drc_exclusions": [], 59 | "meta": { 60 | "version": 2 61 | }, 62 | "rule_severities": { 63 | "annular_width": "error", 64 | "clearance": "error", 65 | "copper_edge_clearance": "error", 66 | "courtyards_overlap": "error", 67 | "diff_pair_gap_out_of_range": "error", 68 | "diff_pair_uncoupled_length_too_long": "error", 69 | "drill_out_of_range": "error", 70 | "duplicate_footprints": "warning", 71 | "extra_footprint": "warning", 72 | "footprint_type_mismatch": "error", 73 | "hole_clearance": "error", 74 | "hole_near_hole": "error", 75 | "invalid_outline": "error", 76 | "item_on_disabled_layer": "error", 77 | "items_not_allowed": "error", 78 | "length_out_of_range": "error", 79 | "malformed_courtyard": "error", 80 | "microvia_drill_out_of_range": "error", 81 | "missing_courtyard": "ignore", 82 | "missing_footprint": "warning", 83 | "net_conflict": "warning", 84 | "npth_inside_courtyard": "ignore", 85 | "padstack": "error", 86 | "pth_inside_courtyard": "ignore", 87 | "shorting_items": "error", 88 | "silk_over_copper": "warning", 89 | "silk_overlap": "warning", 90 | "skew_out_of_range": "error", 91 | "through_hole_pad_without_hole": "error", 92 | "too_many_vias": "error", 93 | "track_dangling": "warning", 94 | "track_width": "error", 95 | "tracks_crossing": "error", 96 | "unconnected_items": "error", 97 | "unresolved_variable": "error", 98 | "via_dangling": "warning", 99 | "zone_has_empty_net": "error", 100 | "zones_intersect": "error" 101 | }, 102 | "rules": { 103 | "allow_blind_buried_vias": false, 104 | "allow_microvias": false, 105 | "max_error": 0.005, 106 | "min_clearance": 0.0, 107 | "min_copper_edge_clearance": 0.3, 108 | "min_hole_clearance": 0.25, 109 | "min_hole_to_hole": 0.25, 110 | "min_microvia_diameter": 0.19999999999999998, 111 | "min_microvia_drill": 0.09999999999999999, 112 | "min_silk_clearance": 0.0, 113 | "min_through_hole_diameter": 0.3, 114 | "min_track_width": 0.19999999999999998, 115 | "min_via_annular_width": 0.049999999999999996, 116 | "min_via_diameter": 0.39999999999999997, 117 | "solder_mask_clearance": 0.0, 118 | "solder_mask_min_width": 0.0, 119 | "use_height_for_length_calcs": true 120 | }, 121 | "track_widths": [ 122 | 0.0, 123 | 0.5 124 | ], 125 | "via_dimensions": [ 126 | { 127 | "diameter": 0.0, 128 | "drill": 0.0 129 | } 130 | ], 131 | "zones_allow_external_fillets": false, 132 | "zones_use_no_outline": true 133 | }, 134 | "layer_presets": [] 135 | }, 136 | "boards": [], 137 | "cvpcb": { 138 | "equivalence_files": [] 139 | }, 140 | "erc": { 141 | "erc_exclusions": [], 142 | "meta": { 143 | "version": 0 144 | }, 145 | "pin_map": [ 146 | [ 147 | 0, 148 | 0, 149 | 0, 150 | 0, 151 | 0, 152 | 0, 153 | 1, 154 | 0, 155 | 0, 156 | 0, 157 | 0, 158 | 2 159 | ], 160 | [ 161 | 0, 162 | 2, 163 | 0, 164 | 1, 165 | 0, 166 | 0, 167 | 1, 168 | 0, 169 | 2, 170 | 2, 171 | 2, 172 | 2 173 | ], 174 | [ 175 | 0, 176 | 0, 177 | 0, 178 | 0, 179 | 0, 180 | 0, 181 | 1, 182 | 0, 183 | 1, 184 | 0, 185 | 1, 186 | 2 187 | ], 188 | [ 189 | 0, 190 | 1, 191 | 0, 192 | 0, 193 | 0, 194 | 0, 195 | 1, 196 | 1, 197 | 2, 198 | 1, 199 | 1, 200 | 2 201 | ], 202 | [ 203 | 0, 204 | 0, 205 | 0, 206 | 0, 207 | 0, 208 | 0, 209 | 1, 210 | 0, 211 | 0, 212 | 0, 213 | 0, 214 | 2 215 | ], 216 | [ 217 | 0, 218 | 0, 219 | 0, 220 | 0, 221 | 0, 222 | 0, 223 | 0, 224 | 0, 225 | 0, 226 | 0, 227 | 0, 228 | 2 229 | ], 230 | [ 231 | 1, 232 | 1, 233 | 1, 234 | 1, 235 | 1, 236 | 0, 237 | 1, 238 | 1, 239 | 1, 240 | 1, 241 | 1, 242 | 2 243 | ], 244 | [ 245 | 0, 246 | 0, 247 | 0, 248 | 1, 249 | 0, 250 | 0, 251 | 1, 252 | 0, 253 | 0, 254 | 0, 255 | 0, 256 | 2 257 | ], 258 | [ 259 | 0, 260 | 2, 261 | 1, 262 | 2, 263 | 0, 264 | 0, 265 | 1, 266 | 0, 267 | 2, 268 | 2, 269 | 2, 270 | 2 271 | ], 272 | [ 273 | 0, 274 | 2, 275 | 0, 276 | 1, 277 | 0, 278 | 0, 279 | 1, 280 | 0, 281 | 2, 282 | 0, 283 | 0, 284 | 2 285 | ], 286 | [ 287 | 0, 288 | 2, 289 | 1, 290 | 1, 291 | 0, 292 | 0, 293 | 1, 294 | 0, 295 | 2, 296 | 0, 297 | 0, 298 | 2 299 | ], 300 | [ 301 | 2, 302 | 2, 303 | 2, 304 | 2, 305 | 2, 306 | 2, 307 | 2, 308 | 2, 309 | 2, 310 | 2, 311 | 2, 312 | 2 313 | ] 314 | ], 315 | "rule_severities": { 316 | "bus_definition_conflict": "error", 317 | "bus_entry_needed": "error", 318 | "bus_label_syntax": "error", 319 | "bus_to_bus_conflict": "error", 320 | "bus_to_net_conflict": "error", 321 | "different_unit_footprint": "error", 322 | "different_unit_net": "error", 323 | "duplicate_reference": "error", 324 | "duplicate_sheet_names": "error", 325 | "extra_units": "error", 326 | "global_label_dangling": "warning", 327 | "hier_label_mismatch": "error", 328 | "label_dangling": "error", 329 | "lib_symbol_issues": "warning", 330 | "multiple_net_names": "warning", 331 | "net_not_bus_member": "warning", 332 | "no_connect_connected": "warning", 333 | "no_connect_dangling": "warning", 334 | "pin_not_connected": "error", 335 | "pin_not_driven": "error", 336 | "pin_to_pin": "warning", 337 | "power_pin_not_driven": "error", 338 | "similar_labels": "warning", 339 | "unannotated": "error", 340 | "unit_value_mismatch": "error", 341 | "unresolved_variable": "error", 342 | "wire_dangling": "error" 343 | } 344 | }, 345 | "libraries": { 346 | "pinned_footprint_libs": [ 347 | "proto" 348 | ], 349 | "pinned_symbol_libs": [] 350 | }, 351 | "meta": { 352 | "filename": "proto.kicad_pro", 353 | "version": 1 354 | }, 355 | "net_settings": { 356 | "classes": [ 357 | { 358 | "bus_width": 12.0, 359 | "clearance": 0.2, 360 | "diff_pair_gap": 0.2, 361 | "diff_pair_via_gap": 0.25, 362 | "diff_pair_width": 0.2, 363 | "line_style": 0, 364 | "microvia_diameter": 0.3, 365 | "microvia_drill": 0.1, 366 | "name": "Default", 367 | "pcb_color": "rgba(0, 0, 0, 0.000)", 368 | "schematic_color": "rgba(0, 0, 0, 0.000)", 369 | "track_width": 0.2, 370 | "via_diameter": 0.6, 371 | "via_drill": 0.3, 372 | "wire_width": 6.0 373 | } 374 | ], 375 | "meta": { 376 | "version": 2 377 | }, 378 | "net_colors": null 379 | }, 380 | "pcbnew": { 381 | "last_paths": { 382 | "gencad": "", 383 | "idf": "", 384 | "netlist": "", 385 | "specctra_dsn": "", 386 | "step": "proto.step", 387 | "vrml": "proto.wrl" 388 | }, 389 | "page_layout_descr_file": "" 390 | }, 391 | "schematic": { 392 | "annotate_start_num": 0, 393 | "drawing": { 394 | "default_line_thickness": 6.0, 395 | "default_text_size": 50.0, 396 | "field_names": [], 397 | "intersheets_ref_own_page": false, 398 | "intersheets_ref_prefix": "", 399 | "intersheets_ref_short": false, 400 | "intersheets_ref_show": false, 401 | "intersheets_ref_suffix": "", 402 | "junction_size_choice": 3, 403 | "label_size_ratio": 0.375, 404 | "pin_symbol_size": 25.0, 405 | "text_offset_ratio": 0.15 406 | }, 407 | "legacy_lib_dir": "", 408 | "legacy_lib_list": [], 409 | "meta": { 410 | "version": 1 411 | }, 412 | "net_format_name": "", 413 | "ngspice": { 414 | "fix_include_paths": true, 415 | "fix_passive_vals": false, 416 | "meta": { 417 | "version": 0 418 | }, 419 | "model_mode": 0, 420 | "workbook_filename": "" 421 | }, 422 | "page_layout_descr_file": "", 423 | "plot_directory": "./", 424 | "spice_adjust_passive_values": false, 425 | "spice_external_command": "spice \"%I\"", 426 | "subpart_first_id": 65, 427 | "subpart_id_separator": 0 428 | }, 429 | "sheets": [ 430 | [ 431 | "e5eb082e-ed07-4aeb-bf28-635fa498438e", 432 | "" 433 | ] 434 | ], 435 | "text_variables": {} 436 | } 437 | -------------------------------------------------------------------------------- /hardware/electronics/proto/sym-lib-table: -------------------------------------------------------------------------------- 1 | (sym_lib_table 2 | (lib (name "proto")(type "KiCad")(uri "${KIPRJMOD}/../lib/proto.kicad_sym")(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /hardware/mechanics/assembly.f3z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ioces/haptick/087f9f2f937d28ed883d5723eaeef3fd493d213e/hardware/mechanics/assembly.f3z -------------------------------------------------------------------------------- /hardware/mechanics/slot_solve.f3d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ioces/haptick/087f9f2f937d28ed883d5723eaeef3fd493d213e/hardware/mechanics/slot_solve.f3d -------------------------------------------------------------------------------- /software/utilities/force_analysis/animation.py: -------------------------------------------------------------------------------- 1 | from free_body import Haptick 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from matplotlib import animation 5 | from matplotlib import patheffects 6 | from matplotlib.colors import LinearSegmentedColormap 7 | from matplotlib.patches import FancyArrowPatch 8 | from mpl_toolkits.mplot3d import proj3d 9 | from mpl_toolkits.mplot3d.art3d import Poly3DCollection 10 | 11 | COLOURS = plt.rcParams['axes.prop_cycle'].by_key()['color'] 12 | CM = LinearSegmentedColormap.from_list("Test", [COLOURS[0], [1.0, 1.0, 1.0], COLOURS[1]]) 13 | 14 | class Arrow3D(FancyArrowPatch): 15 | def __init__(self, xs, ys, zs, *args, **kwargs): 16 | super().__init__((0,0), (0,0), *args, **kwargs) 17 | self._verts3d = xs, ys, zs 18 | 19 | def do_3d_projection(self, renderer=None): 20 | xs3d, ys3d, zs3d = self._verts3d 21 | xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M) 22 | self.set_positions((xs[0],ys[0]),(xs[1],ys[1])) 23 | 24 | return np.min(zs) 25 | 26 | haptick = Haptick(25e-3, np.deg2rad(25.0) * 25e-3, 25e-3, np.deg2rad(25.0) * 25e-3, 20e-3) 27 | trusses = haptick.trusses 28 | 29 | # Generate some force vectors. 30 | t = np.linspace(0, 2 * np.pi, 100, endpoint=False)[1:] 31 | force_varying = np.sin(t) 32 | forces_varying_z = np.vstack((np.zeros_like(t), np.zeros_like(t), force_varying)).T 33 | forces_varying_y = np.vstack((np.zeros_like(t), force_varying, np.zeros_like(t))).T 34 | forces_varying_x = np.vstack((force_varying, np.zeros_like(t), np.zeros_like(t))).T 35 | forces = np.vstack((forces_varying_x, forces_varying_y, forces_varying_z)) * 8e-3 36 | forces += forces / np.linalg.norm(forces, axis=1)[:,np.newaxis] * 2e-3 37 | 38 | # Generate some torque vectors. 39 | torques = np.vstack((forces_varying_x, forces_varying_y, forces_varying_z)) * 8e-3 40 | torques += torques / np.linalg.norm(torques, axis=1)[:,np.newaxis] * 0.5e-3 41 | 42 | # Calculate forces on trusses for applied forces. 43 | truss_forces_for_forces = haptick.truss_force_components(forces, np.zeros_like(forces))[2] 44 | max_truss_force_for_forces = np.abs(truss_forces_for_forces).max() 45 | 46 | # Calculate forces on trusses for applied torques. 47 | truss_forces_for_torques = haptick.truss_force_components(np.zeros_like(torques), torques)[2] 48 | max_truss_force_for_torques = np.abs(truss_forces_for_torques).max() 49 | 50 | fig = plt.figure() 51 | ax = plt.axes(projection='3d', computed_zorder=False) 52 | ax.xaxis.set_ticklabels([]) 53 | ax.yaxis.set_ticklabels([]) 54 | ax.zaxis.set_ticklabels([]) 55 | 56 | truss_lines = [] 57 | for truss in trusses.transpose((1, 0, 2)): 58 | truss_lines.append(ax.plot(*truss, 59 | color='w', 60 | zorder=4, 61 | linewidth=4.0, 62 | solid_capstyle='round', 63 | path_effects=[patheffects.Stroke(linewidth=5, foreground='k'), patheffects.Normal()])[0]) 64 | 65 | bottom_plane = Poly3DCollection([trusses[..., 1].T], alpha=0.5, linewidths=1, zorder=3) 66 | bottom_plane.set_color('k') 67 | bottom_plane.set_facecolor([0.5, 0.5, 0.5]) 68 | ax.add_collection3d(bottom_plane) 69 | 70 | ax.scatter(*trusses[..., 1], c='gray', s=80, edgecolor='k', depthshade=False, zorder=5) 71 | 72 | top_plane = Poly3DCollection([trusses[..., 0].T], alpha=0.5, linewidths=1, zorder=6) 73 | top_plane.set_color('k') 74 | top_plane.set_facecolor([0.5, 0.5, 0.5]) 75 | ax.add_collection3d(top_plane) 76 | 77 | ax.scatter(*trusses[..., 0], c='gray', s=80, edgecolor='k', depthshade=False, zorder=7) 78 | 79 | # Add a dummy points and set box aspect to ensure a nice 1:1:1 aspect ratio for the 3D plot. 80 | ax.plot([-25e-3, 25e-3], [-25e-3, 25e-3], [0.0, 30e-3], linewidth=0.0) 81 | ax.set_box_aspect((50e-3, 50e-3, 30e-3)) 82 | 83 | # Plot a little dot in the middle of the top platform. 84 | ax.plot(0.0, 0.0, 20e-3, 'o', zorder=9, markeredgecolor='k', color=COLOURS[2]) 85 | 86 | # Create a force arrow. 87 | base = np.array([0.0, 0.0, 20e-3]) 88 | force_arrow = Arrow3D(*np.vstack((base, base)).T, mutation_scale=20, arrowstyle='-|>', shrinkA=0, shrinkB=0, zorder=8, facecolor=COLOURS[2]) 89 | ax.add_artist(force_arrow) 90 | 91 | # Create a torque ring. 92 | torque_ring_upper = ax.plot(0.0, 0.0, 0.0, color='k', zorder=8, linewidth=1)[0] 93 | torque_ring_lower = ax.plot(0.0, 0.0, 0.0, color='k', zorder=5.5, linewidth=1)[0] 94 | torque_arrow = Arrow3D(*np.vstack((base, base)).T, mutation_scale=20, arrowstyle='-|>', shrinkA=0, shrinkB=0, zorder=8, facecolor=COLOURS[2]) 95 | ax.add_artist(torque_arrow) 96 | 97 | # Set the camera angle and expand the plot a little. 98 | ax.view_init(33, -32) 99 | plt.tight_layout() 100 | 101 | def update_force(num, force_arrow, truss_lines, applied_forces, truss_forces_z): 102 | applied_force = applied_forces[num % len(applied_forces)] 103 | truss_force_zs = truss_forces_z.T[num % len(applied_forces)] 104 | if applied_force[2] >= 0.0: 105 | force_arrow.set_zorder(8) 106 | else: 107 | force_arrow.set_zorder(5.5) 108 | force_arrow._verts3d = np.vstack((base, base + applied_force)).T 109 | for truss_line, truss_force_z in zip(truss_lines, truss_force_zs): 110 | truss_line.set_color(CM(0.5 * truss_force_z / max_truss_force_for_forces + 0.5)) 111 | return [force_arrow] + truss_lines 112 | 113 | def update_torque(num, torque_ring_lower, torque_ring_upper, torque_arrow, 114 | truss_lines, applied_torques, truss_forces_z): 115 | applied_torque = applied_torques[num % len(applied_torques)] 116 | truss_force_zs = truss_forces_z.T[num % len(applied_torques)] 117 | torque_magnitude = np.linalg.norm(applied_torque) 118 | 119 | # Make the magnitude negative and reverse the vector to standardise where 120 | # the "ring" starts. 121 | if applied_torque[0] < 0.0 or applied_torque[1] > 0.0: 122 | applied_torque = -applied_torque 123 | torque_magnitude = -torque_magnitude 124 | 125 | # Calculate an coordinate system on a plane perpendicular to the applied 126 | # torque, assuming that the x vector falls on a plane parallel to the XY 127 | # world plane. Note, this falls apart for vectors aligned with the Z world 128 | # axis. 129 | x = np.cross([0, 0, 1], applied_torque) 130 | if np.linalg.norm(x) == 0.0: 131 | x = np.array([0., 1., 0.]) 132 | y = np.cross(applied_torque, x) 133 | y /= np.linalg.norm(y) 134 | x /= np.linalg.norm(x) 135 | 136 | # Calculate a line on a small circle directly proportional to the torque 137 | # magnitude. 138 | t = np.arange(np.sign(torque_magnitude) * 0.075, 2 * np.pi * torque_magnitude / 0.0088, np.sign(torque_magnitude) * 0.075) 139 | points = np.atleast_2d(np.cos(t)).T @ np.atleast_2d(x) + np.atleast_2d(np.sin(t)).T @ np.atleast_2d(y) 140 | points *= 7e-3 141 | 142 | # Find where our arrow is. 143 | if points[-1, 2] >= 0.0: 144 | torque_arrow.set_zorder(8) 145 | else: 146 | torque_arrow.set_zorder(5.5) 147 | torque_arrow._verts3d = (np.vstack((points[0, :] if len(points) < 6 else points[-6, :], points[-1, :])) + base).T 148 | points = points[:-5, :] 149 | 150 | upper_points = points[points[:, 2] >= 0.0] 151 | lower_points = points[points[:, 2] < 0.0] 152 | 153 | if len(upper_points) == 0: 154 | a = 0 155 | 156 | torque_ring_upper.set_data_3d(*(upper_points + base).T) 157 | torque_ring_lower.set_data_3d(*(lower_points + base).T) 158 | 159 | for truss_line, truss_force_z in zip(truss_lines, truss_force_zs): 160 | truss_line.set_color(CM(0.5 * truss_force_z / max_truss_force_for_torques + 0.5)) 161 | 162 | return [torque_ring_upper, torque_ring_lower, torque_arrow] + truss_lines 163 | 164 | def update_angle(num): 165 | ax.view_init(33, -32 + 360 * (num / 300)) 166 | return () 167 | 168 | anim = animation.FuncAnimation(fig, update_angle, frames=300, interval=50) 169 | writer = animation.FFMpegWriter(fps=20, codec='webp', extra_args=["-loop", "0"]) 170 | anim.save('stewart-platform-geometry.webp', writer=writer) 171 | 172 | #anim = animation.FuncAnimation(fig, update_force, fargs=(force_arrow, truss_lines, forces, truss_forces_for_forces), 173 | # frames=len(forces), interval=50) 174 | #anim.save('truss-force-from-applied-force.gif') 175 | 176 | #fargs = (torque_ring_lower, torque_ring_upper, torque_arrow, truss_lines, 177 | # torques, truss_forces_for_torques) 178 | #anim = animation.FuncAnimation(fig, update_torque, fargs=fargs, 179 | # frames=len(torques), interval=50) 180 | #anim.save('truss-force-from-applied-torque.gif') 181 | #plt.show() -------------------------------------------------------------------------------- /software/utilities/force_analysis/free_body.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Haptick: 4 | TRIANGLE = np.linspace(0, 2.0 * np.pi, 3, endpoint = False) 5 | 6 | def __init__(self, top_radius, top_separation, bottom_radius, bottom_separation, height): 7 | self.top_radius = top_radius 8 | self.top_separation = top_separation 9 | self.bottom_radius = bottom_radius 10 | self.bottom_separation = bottom_separation 11 | self.height = height 12 | 13 | self._init_trusses() 14 | 15 | def truss_force_components(self, applied_force, applied_torque): 16 | magnitudes = self.truss_force_magnitudes(applied_force, applied_torque) 17 | return self._unit_forces[..., np.newaxis] * magnitudes[np.newaxis, ...] 18 | 19 | def truss_force_magnitudes(self, applied_force, applied_torque): 20 | return self._inverse_plucker @ -np.atleast_2d(np.hstack((applied_force, applied_torque))).T 21 | 22 | def applied(self, truss_force_magnitudes): 23 | forces_torques = -(self._plucker @ np.atleast_2d(truss_force_magnitudes).T) 24 | return forces_torques[:3, ...], forces_torques[3:, ...] 25 | 26 | def _init_trusses(self): 27 | # Create truss vectors 28 | top_angles = np.empty(6) 29 | top_angles[::2] = self.TRIANGLE - 0.5 * self.top_separation / self.top_radius 30 | top_angles[1::2] = self.TRIANGLE + 0.5 * self.top_separation / self.top_radius 31 | bottom_angles = np.empty(6) 32 | bottom_angles[::2] = self.TRIANGLE - np.deg2rad(60.0) - 0.5 * self.bottom_separation / self.bottom_radius 33 | bottom_angles[1::2] = self.TRIANGLE - np.deg2rad(60.0) + 0.5 * self.bottom_separation / self.bottom_radius 34 | top_joints = self._joint_positions(top_angles, self.top_radius, self.height) 35 | bottom_joints = self._joint_positions(bottom_angles, self.bottom_radius, 0.0) 36 | self.trusses = np.dstack((top_joints, np.roll(bottom_joints, -1, axis=1))) 37 | 38 | # Calculate unit truss forces and Plucker coordinates 39 | self._unit_forces = self.trusses[..., 0] - self.trusses[..., 1] 40 | self._unit_forces /= np.linalg.norm(self._unit_forces, axis=0) 41 | moments = np.cross(self.trusses[..., 0], self._unit_forces, axis=0) 42 | self._plucker = np.vstack((self._unit_forces, moments)) 43 | self._inverse_plucker = np.linalg.inv(self._plucker) 44 | 45 | @staticmethod 46 | def _joint_positions(angles, radius, z): 47 | return np.vstack((radius * np.cos(angles), 48 | radius * np.sin(angles), 49 | np.ones_like(angles) * z)) 50 | 51 | if __name__ == "__main__": 52 | import matplotlib.pyplot as plt 53 | plt.ion() 54 | haptick = Haptick(30e-3, 6e-3, 15e-3, 6e-3, 20e-3) 55 | applied_forces = np.array([[0.0, 0.0, -20e-3*9.81], [0.0, 0.0, 20e-3*9.81]]) 56 | applied_torques = np.zeros((2, 3)) 57 | print(haptick.truss_force_components(applied_forces, applied_torques)) 58 | truss_force_magnitudes = haptick.truss_force_magnitudes(applied_forces, applied_torques) 59 | print(haptick.applied(truss_force_magnitudes.T)[0]) 60 | print(haptick.applied(truss_force_magnitudes.T)[1]) 61 | trusses = haptick.trusses 62 | ax = plt.axes(projection='3d') 63 | ax.scatter3D(*trusses[..., 0]) 64 | ax.scatter3D(*trusses[..., 1]) 65 | for truss in trusses.transpose((1, 0, 2)): 66 | ax.plot3D(*truss, 'k') 67 | ax.set_box_aspect((np.ptp(trusses[0, ...]), np.ptp(trusses[1, ...]), np.ptp(trusses[2, ...]))) -------------------------------------------------------------------------------- /software/utilities/force_analysis/optimiser.py: -------------------------------------------------------------------------------- 1 | from free_body import Haptick 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | plt.ion() 5 | import pyswarms as ps 6 | from pyswarms.utils.functions import single_obj as fx 7 | 8 | class EvennessError: 9 | def __init__(self, nominal_force, nominal_torque, height=20.0e-3, samples=50): 10 | self.nominal_force = nominal_force 11 | self.nominal_torque = nominal_torque 12 | self.height = height 13 | 14 | # Generate a bunch of forces and torques spread across the unit sphere 15 | uniform_sphere = self._fibonacci_sphere(samples) 16 | self.forces = nominal_force * uniform_sphere 17 | self.torques = nominal_torque * uniform_sphere 18 | self._null = np.zeros((samples, 3)) 19 | 20 | def __call__(self, x): 21 | errors = [] 22 | for p in x: 23 | knobby = Haptick(p[0], p[1] * p[0], p[2], p[3] * p[2], self.height) 24 | 25 | # Find the upward reaction force for applied forces and torques 26 | z_for_forces = knobby.truss_force_components(self.forces, self._null)[2, ...] 27 | z_for_torques = knobby.truss_force_components(self._null, self.torques)[2, ...] 28 | 29 | # Calculate the RMS of the reaction forces for each applied force 30 | # and torque 31 | rms = np.linalg.norm(np.vstack((z_for_forces, z_for_torques)), axis=1) 32 | 33 | # Our error is the variation in these. 34 | error = np.std(rms) 35 | errors.append(error) 36 | return errors 37 | 38 | @staticmethod 39 | def _fibonacci_sphere(samples): 40 | phi = np.pi * (3.0 - np.sqrt(5.0)) 41 | y = np.linspace(1, -1, samples) 42 | r = np.sqrt(1 - y ** 2) 43 | t = np.arange(samples) * phi 44 | x = np.cos(t) * r 45 | z = np.sin(t) * r 46 | return np.vstack((x, y, z)).T 47 | 48 | options = {'c1': 0.5, 'c2': 0.3, 'w':0.9} 49 | bounds = ([10e-3, 0.0, 10e-3, 0.0], [25e-3, np.pi / 3.0, 25e-3, np.pi / 3.0]) 50 | optimizer = ps.single.GlobalBestPSO(n_particles=100, dimensions=4, options=options, bounds=bounds) 51 | error_function = EvennessError(20e-3*9.81, 20e-3*9.81*30e-3, height=20e-3, samples=100) 52 | best_cost, best_pos = optimizer.optimize(error_function, iters=1000) 53 | haptick = Haptick(best_pos[0], best_pos[1] * best_pos[0], best_pos[2], best_pos[3] * best_pos[2], error_function.height) 54 | trusses = haptick.trusses 55 | ax = plt.axes(projection='3d') 56 | ax.scatter3D(*trusses[..., 0]) 57 | ax.scatter3D(*trusses[..., 1]) 58 | for truss in trusses.transpose((1, 0, 2)): 59 | ax.plot3D(*truss, 'k') 60 | ax.set_box_aspect((np.ptp(trusses[0, ...]), np.ptp(trusses[1, ...]), np.ptp(trusses[2, ...]))) -------------------------------------------------------------------------------- /software/utilities/monitor/assets/blank-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 36 | 38 | 42 | 43 | -------------------------------------------------------------------------------- /software/utilities/monitor/assets/cube.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ioces/haptick/087f9f2f937d28ed883d5723eaeef3fd493d213e/software/utilities/monitor/assets/cube.blend -------------------------------------------------------------------------------- /software/utilities/monitor/assets/cube.mtl: -------------------------------------------------------------------------------- 1 | # Blender 3.3.1 MTL File: 'cube.blend' 2 | # www.blender.org 3 | 4 | newmtl Material 5 | Ns 250.000000 6 | Ka 1.000000 1.000000 1.000000 7 | Ks 0.500000 0.500000 0.500000 8 | Ke 0.000000 0.000000 0.000000 9 | Ni 1.450000 10 | d 1.000000 11 | illum 2 12 | map_Kd texture.png 13 | -------------------------------------------------------------------------------- /software/utilities/monitor/assets/tabler-icons/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2023 Paweł Kuna 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /software/utilities/monitor/assets/tabler-icons/README.md: -------------------------------------------------------------------------------- 1 | # Tabler Icons 2 | 3 | The Haptick project uses [tabler icons](https://tabler-icons.io/), which are licensed separately under the [MIT License](LICENSE). -------------------------------------------------------------------------------- /software/utilities/monitor/assets/tabler-icons/player-record.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /software/utilities/monitor/assets/tabler-icons/plug-connected-x.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /software/utilities/monitor/assets/tabler-icons/plug-connected.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /software/utilities/monitor/assets/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ioces/haptick/087f9f2f937d28ed883d5723eaeef3fd493d213e/software/utilities/monitor/assets/texture.png -------------------------------------------------------------------------------- /software/utilities/monitor/assets/texture.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 41 | 47 | 48 | 50 | 54 | 56 | 62 | 68 | 69 | 71 | 77 | 81 | 85 | 86 | 89 | 95 | 101 | 102 | 105 | 111 | 115 | 119 | 120 | 123 | 129 | 135 | 136 | 139 | 145 | 149 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /software/utilities/monitor/compile_ui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pyside6-uic main_window.ui -o ui_mainwindow.py 4 | pyside6-uic noise_widget.ui -o ui_noisewidget.py 5 | pyside6-uic cube_control.ui -o ui_cubecontrol.py 6 | pyside6-rcc resources.qrc -o resources_rc.py -------------------------------------------------------------------------------- /software/utilities/monitor/cube_control.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CubeControl 4 | 5 | 6 | 7 | 0 8 | 0 9 | 716 10 | 450 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | 36 | 0 37 | 0 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | QFrame::Raised 46 | 47 | 48 | Qt::Vertical 49 | 50 | 51 | 52 | 53 | 54 | 55 | 6 56 | 57 | 58 | 9 59 | 60 | 61 | 9 62 | 63 | 64 | 9 65 | 66 | 67 | 9 68 | 69 | 70 | 71 | 72 | Sensitivity 73 | 74 | 75 | 76 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 77 | 78 | 79 | 80 | 81 | Rotation 82 | 83 | 84 | 85 | 86 | 87 | 88 | 10 89 | 90 | 91 | Qt::Horizontal 92 | 93 | 94 | 95 | 96 | 97 | 98 | Translation 99 | 100 | 101 | 102 | 103 | 104 | 105 | 10 106 | 107 | 108 | Qt::Horizontal 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | Threshold 121 | 122 | 123 | 124 | 125 | 126 | 127 | 10 128 | 129 | 130 | Qt::Horizontal 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | Qt::Vertical 140 | 141 | 142 | 143 | 20 144 | 40 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | Reset Position/Rotation 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | CubeDisplay 163 | QWidget 164 |
visualisers.h
165 | 1 166 |
167 |
168 | 169 | 170 |
171 | -------------------------------------------------------------------------------- /software/utilities/monitor/interface.py: -------------------------------------------------------------------------------- 1 | import serial 2 | import serial.tools.list_ports 3 | from multiprocessing import Process, Pipe 4 | from select import select 5 | import numpy as np 6 | import scipy.signal as ss 7 | from dataclasses import dataclass 8 | 9 | 10 | @dataclass(frozen=True) 11 | class BiasCorrectionSettings: 12 | enabled: bool = True 13 | threshold: float = 0.5e-6 14 | time: float = 1.0 15 | 16 | 17 | class SerialProcess: 18 | GAIN = (2.4 / 64) / 2.0 ** 24 19 | 20 | def __init__(self, port, filter_cutoff, bias_correction): 21 | self.port = port 22 | 23 | self._bias = None 24 | self._counter = 0 25 | self._cache = np.zeros((15625, 6)) 26 | 27 | self.filter_cutoff = filter_cutoff 28 | self.bias_correction = bias_correction 29 | 30 | def __call__(self, conn): 31 | with serial.Serial(self.port, timeout=0.1) as s: 32 | self.__sync(s) 33 | samples_to_filter = [] 34 | samples_to_send = [] 35 | while True: 36 | # Handle incoming messages 37 | if conn.poll(): 38 | message = conn.recv() 39 | if message["command"] == "close": 40 | return 41 | elif message["command"] == "set_filter_cutoff": 42 | self.filter_cutoff = message["value"] 43 | elif message["command"] == "set_bias_correction": 44 | self.bias_correction = message["value"] 45 | 46 | # Read, parse and (sometimes) filter data 47 | data = s.read(24) 48 | if parsed := self.__parse(data): 49 | samples_to_filter.append(parsed) 50 | if len(samples_to_filter) == 64: 51 | samples_to_send.append(self.__filter(samples_to_filter)) 52 | samples_to_filter = [] 53 | else: 54 | self.__sync(s) 55 | 56 | # Send data 57 | if samples_to_send and not self.__pipe_full(conn): 58 | conn.send(np.vstack(samples_to_send)) 59 | samples_to_send = [] 60 | 61 | def __pipe_full(self, conn): 62 | _, w, _ = select([], [conn], [], 0.0) 63 | return len(w) == 0 64 | 65 | def __sync(self, s): 66 | s.read_until(b'\x05\x3f') 67 | s.read(22) 68 | 69 | def __parse(self, data): 70 | if data[:2] == b"\x05\x3f" and len(data) == 24: 71 | args = [iter(data[3:-3])] * 3 72 | return [int.from_bytes(b, byteorder="big", signed=True) * self.GAIN for b in zip(*args)] 73 | 74 | def __filter(self, samples): 75 | if self._filter_coeff is not None: 76 | if self._filter_state is None: 77 | self._filter_state = np.dstack([ss.sosfilt_zi(self._filter_coeff) * x for x in samples[0]]) 78 | result, self._filter_state = ss.sosfilt(self._filter_coeff, samples, axis=0, zi=self._filter_state) 79 | else: 80 | result = np.vstack(samples) 81 | 82 | self._cache = np.roll(self._cache, result.shape[0], axis=0) 83 | self._cache[:result.shape[0], ...] = result[::-1, ...] 84 | 85 | self._counter += result.shape[0] 86 | 87 | if self._counter > self._cache.shape[0]: 88 | if self._bias is None: 89 | index = int(np.round(3.0 / 256.0e-6)) 90 | self._bias = self._cache[:index, ...].mean(axis=0) 91 | elif self.bias_correction.enabled: 92 | index = int(np.round(self.bias_correction.time / 256.0e-6)) 93 | standard_deviations = self._cache[:index, ...].std(axis=0) 94 | if np.all(standard_deviations < self.bias_correction.threshold): 95 | self._bias = self._cache[:index, ...].mean(axis=0) 96 | 97 | if self._bias is None: 98 | return np.full_like(result, np.nan) 99 | else: 100 | return result - self._bias 101 | 102 | @property 103 | def filter_cutoff(self): 104 | return self.__filter_cutoff 105 | 106 | @filter_cutoff.setter 107 | def filter_cutoff(self, value): 108 | if value is None: 109 | self._filter_coeff = None 110 | else: 111 | self._filter_state = None 112 | self._filter_coeff = ss.butter(4, value, output='sos', fs=1/256e-6) 113 | self.__filter_cutoff = value 114 | 115 | 116 | class Haptick: 117 | def __init__(self): 118 | self._proc = None 119 | self.__filter_cutoff = None 120 | self.__bias_correction = BiasCorrectionSettings() 121 | 122 | def list_ports(self): 123 | return [port.device for port in serial.tools.list_ports.comports()] 124 | 125 | def connect(self, port): 126 | self._conn, conn = Pipe() 127 | proc = SerialProcess(port, self.__filter_cutoff, self.__bias_correction) 128 | self._proc = Process(target=proc, args=(conn, )) 129 | self._proc.start() 130 | 131 | def disconnect(self): 132 | self._send_command("close") 133 | if self._proc: 134 | self._proc.join() 135 | 136 | def get_vals(self): 137 | vals = [] 138 | while self._conn.poll(): 139 | vals.append(self._conn.recv()) 140 | return np.vstack(vals) if vals else None 141 | 142 | @property 143 | def bias_correction(self): 144 | return self.__bias_correction 145 | 146 | @bias_correction.setter 147 | def bias_correction(self, value): 148 | self.__bias_correction = value 149 | self._send_command("set_bias_correction", value=self.__bias_correction) 150 | 151 | @property 152 | def filter_cutoff(self): 153 | return self.__filter_cutoff 154 | 155 | @filter_cutoff.setter 156 | def filter_cutoff(self, value): 157 | self.__filter_cutoff = value 158 | self._send_command("set_filter_cutoff", value=self.__filter_cutoff) 159 | 160 | def _send_command(self, command, **kwargs): 161 | try: 162 | message = kwargs 163 | message.update({"command": command}) 164 | self._conn.send(message) 165 | except (EOFError, BrokenPipeError, AttributeError): 166 | pass 167 | 168 | 169 | if __name__ == "__main__": 170 | import matplotlib.pyplot as plt 171 | plt.ion() 172 | fig = plt.figure() 173 | ax = fig.add_subplot(111) 174 | data = np.zeros((2560, 6)) 175 | lines = ax.plot(data) 176 | ax.set_ylim(-50e-6, 50e-6) 177 | h = Haptick() 178 | h.connect("/dev/ttyACM0") 179 | while True: 180 | if vals := h.get_vals(): 181 | data = np.roll(data, -len(vals), axis=0) 182 | data[-len(vals):, :] = vals 183 | for line, d in zip(lines, data.T): 184 | line.set_ydata(d) 185 | fig.canvas.flush_events() 186 | h.disconnect() -------------------------------------------------------------------------------- /software/utilities/monitor/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PySide6.QtCore import QTimer 3 | from PySide6.QtGui import QIcon 4 | from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog 5 | from ui_mainwindow import Ui_MainWindow 6 | import time 7 | import interface 8 | import numpy as np 9 | 10 | 11 | class MainWindow(QMainWindow): 12 | def __init__(self): 13 | super(MainWindow, self).__init__() 14 | self.ui = Ui_MainWindow() 15 | self.ui.setupUi(self) 16 | self.haptick = interface.Haptick() 17 | 18 | self.ui.serialPortCombo.addItems(self.haptick.list_ports()) 19 | self.ui.serialConnectButton.clicked.connect(self._connect) 20 | 21 | self.ui.recordButton.toggled.connect(self._start_record) 22 | 23 | self.ui.filterCutoffSlider.valueChanged.connect(self._change_filter_cutoff) 24 | self._change_filter_cutoff(self.ui.filterCutoffSlider.value()) 25 | 26 | self.ui.biasGroupBox.clicked.connect(self._change_bias_correction) 27 | self.ui.biasThresholdSlider.valueChanged.connect(self._change_bias_correction) 28 | self.ui.biasTimeSlider.valueChanged.connect(self._change_bias_correction) 29 | self._change_bias_correction() 30 | 31 | self.update_timer = QTimer(self) 32 | self.update_timer.setInterval(20) 33 | self.update_timer.timeout.connect(self._update) 34 | 35 | self.__file = None 36 | 37 | def closeEvent(self, event): 38 | super().closeEvent(event) 39 | if self.__file: 40 | self._stop_record() 41 | self.update_timer.stop() 42 | self.haptick.disconnect() 43 | 44 | def _connect(self): 45 | self.haptick.connect(self.ui.serialPortCombo.currentText()) 46 | self.update_timer.start() 47 | self.ui.serialPortCombo.setDisabled(True) 48 | self.ui.serialConnectButton.setText("Disconnect") 49 | self.ui.serialConnectButton.setIcon(QIcon(":/icons/disconnect")) 50 | self.ui.serialConnectButton.clicked.disconnect(self._connect) 51 | self.ui.serialConnectButton.clicked.connect(self._disconnect) 52 | 53 | def _disconnect(self): 54 | self.update_timer.stop() 55 | self.haptick.disconnect() 56 | self.ui.serialPortCombo.setDisabled(False) 57 | self.ui.serialConnectButton.setText("Connect") 58 | self.ui.serialConnectButton.setIcon(QIcon(":/icons/connect")) 59 | self.ui.serialConnectButton.clicked.disconnect(self._disconnect) 60 | self.ui.serialConnectButton.clicked.connect(self._connect) 61 | 62 | def _start_record(self): 63 | # Temporarily stop the update timer while we get a filename and start 64 | # recording. There are two reasons for this: 65 | # 66 | # 1. With the 20ms timer, some bug in Qt means the save file dialog 67 | # doesn't display, as the event loop spends all its time serving the 68 | # timer. 69 | # 2. We want to start saving data from when the record button is hit. If 70 | # we stop the timer, the interprocess queue will start to buffer all 71 | # samples from when the timer is stopped, which means they'll all get 72 | # written to disk when the timer starts again. 73 | timer_active = self.update_timer.isActive() 74 | self.update_timer.stop() 75 | 76 | # Get a filename and update the button state. 77 | file_name, _ = QFileDialog.getSaveFileName(self, "Record File", "", "Comma Separated Values (*.csv)") 78 | 79 | if file_name: 80 | self.__file = open(file_name, 'w') 81 | self.ui.recordButton.toggled.disconnect(self._start_record) 82 | self.ui.recordButton.toggled.connect(self._stop_record) 83 | else: 84 | # Temporarily block signals, change checked state and unblock. Else 85 | # we get called again when we try and uncheck the button. 86 | self.ui.recordButton.blockSignals(True) 87 | self.ui.recordButton.setChecked(False) 88 | self.ui.recordButton.blockSignals(False) 89 | 90 | # Start the timer again. 91 | if timer_active: 92 | self.update_timer.start() 93 | 94 | def _stop_record(self): 95 | self.__file.close() 96 | self.__file = None 97 | self.ui.recordButton.toggled.disconnect(self._stop_record) 98 | self.ui.recordButton.toggled.connect(self._start_record) 99 | self.ui.recordButton.setIcon(QIcon(":/icons/record")) 100 | 101 | def _update(self): 102 | vals = self.haptick.get_vals() 103 | 104 | if vals is not None: 105 | self.ui.voltagePlot.add_values(vals) 106 | self.ui.psdPlot.add_values(vals) 107 | self.ui.noiseWidget.add_values(vals) 108 | self.ui.cubeControl.add_values(vals) 109 | 110 | if self.__file: 111 | np.savetxt(self.__file, vals, fmt="%.3e", delimiter=",") 112 | 113 | if self.ui.recordButton.isChecked(): 114 | if time.monotonic() % 1 > 0.5: 115 | self.ui.recordButton.setIcon(QIcon(":/icons/blank")) 116 | else: 117 | self.ui.recordButton.setIcon(QIcon(":/icons/record")) 118 | 119 | def _change_filter_cutoff(self, value): 120 | if value == 99: 121 | self.haptick.filter_cutoff = None 122 | self.ui.filterCutoffValue.setText("Disabled") 123 | else: 124 | frequency = 10 ** (value * 4.29 / 98 - 1) 125 | self.haptick.filter_cutoff = frequency 126 | self.ui.filterCutoffValue.setText(f"{frequency:.1f} Hz") 127 | 128 | def _change_bias_correction(self, *_): 129 | time = self.ui.biasTimeSlider.value() / 99.0 * 3.0 + 1.0 130 | threshold = self.ui.biasThresholdSlider.value() / 99.0 * 2.0e-6 131 | enabled = self.ui.biasGroupBox.isChecked() 132 | 133 | settings = interface.BiasCorrectionSettings(enabled, threshold, time) 134 | self.haptick.bias_correction = settings 135 | 136 | 137 | if __name__ == "__main__": 138 | app = QApplication(sys.argv) 139 | 140 | window = MainWindow() 141 | window.show() 142 | 143 | sys.exit(app.exec()) -------------------------------------------------------------------------------- /software/utilities/monitor/main_window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 785 10 | 644 11 | 12 | 13 | 14 | Haptick Monitor 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 0 25 | 40 26 | 27 | 28 | 29 | Connect 30 | 31 | 32 | 33 | :/icons/connect:/icons/connect 34 | 35 | 36 | 37 | 32 38 | 32 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | Low Pass Filter 47 | 48 | 49 | 50 | 51 | 52 | Cutoff 53 | 54 | 55 | 56 | 57 | 58 | 59 | 46 60 | 61 | 62 | Qt::Horizontal 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 80 71 | 0 72 | 73 | 74 | 75 | 10.3 Hz 76 | 77 | 78 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Qt::Horizontal 89 | 90 | 91 | 92 | 40 93 | 20 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Bias Correction 102 | 103 | 104 | true 105 | 106 | 107 | 108 | 109 | 110 | Threshold 111 | 112 | 113 | 114 | 115 | 116 | 117 | 25 118 | 119 | 120 | Qt::Horizontal 121 | 122 | 123 | 124 | 125 | 126 | 127 | Time 128 | 129 | 130 | 131 | 132 | 133 | 134 | Qt::Horizontal 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 0 146 | 0 147 | 148 | 149 | 150 | 151 | 40 152 | 40 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | :/icons/record:/icons/record 161 | 162 | 163 | 164 | 32 165 | 32 166 | 167 | 168 | 169 | true 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | QTabWidget::South 182 | 183 | 184 | 0 185 | 186 | 187 | 188 | Time Series 189 | 190 | 191 | 192 | 193 | Power Spectrum 194 | 195 | 196 | 197 | 0 198 | 199 | 200 | 0 201 | 202 | 203 | 0 204 | 205 | 206 | 0 207 | 208 | 209 | 0 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 0 219 | 0 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | Position 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | ChannelPsd 239 | QWidget 240 |
visualisers.h
241 | 1 242 |
243 | 244 | ChannelVoltage 245 | QWidget 246 |
visualisers.h
247 | 1 248 |
249 | 250 | NoiseWidget 251 | QWidget 252 |
visualisers.h
253 | 1 254 |
255 | 256 | CubeControl 257 | QWidget 258 |
visualisers.h
259 | 1 260 |
261 |
262 | 263 | 264 | 265 | 266 |
267 | -------------------------------------------------------------------------------- /software/utilities/monitor/noise_widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | NoiseWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 426 10 | 74 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 0.00 uV 21 | 22 | 23 | Qt::AlignCenter 24 | 25 | 26 | 27 | 28 | 29 | 30 | 0.00 uV 31 | 32 | 33 | Qt::AlignCenter 34 | 35 | 36 | 37 | 38 | 39 | 40 | 0.00 uV 41 | 42 | 43 | Qt::AlignCenter 44 | 45 | 46 | 47 | 48 | 49 | 50 | 0.00 uV 51 | 52 | 53 | Qt::AlignCenter 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 14 62 | true 63 | 64 | 65 | 66 | RMS Noise 67 | 68 | 69 | Qt::AlignCenter 70 | 71 | 72 | 73 | 74 | 75 | 76 | 0.00 uV 77 | 78 | 79 | Qt::AlignCenter 80 | 81 | 82 | 83 | 84 | 85 | 86 | 0.00 uV 87 | 88 | 89 | Qt::AlignCenter 90 | 91 | 92 | 93 | 94 | 95 | 96 | Qt::Horizontal 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /software/utilities/monitor/requirements.txt: -------------------------------------------------------------------------------- 1 | contourpy==1.0.6 2 | cycler==0.11.0 3 | fonttools==4.38.0 4 | kiwisolver==1.4.4 5 | matplotlib==3.6.2 6 | moderngl==5.5.3 7 | numpy==1.23.5 8 | packaging==21.3 9 | Pillow==9.3.0 10 | pyparsing==3.0.9 11 | pyserial==3.5 12 | PySide6==6.4.1 13 | PySide6-Addons==6.4.1 14 | PySide6-Essentials==6.4.1 15 | python-dateutil==2.8.2 16 | scipy==1.9.3 17 | shiboken6==6.4.1 18 | si-prefix==1.2.2 19 | six==1.16.0 20 | -------------------------------------------------------------------------------- /software/utilities/monitor/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | assets/blank-icon.svg 4 | assets/tabler-icons/plug-connected-x.svg 5 | assets/tabler-icons/plug-connected.svg 6 | assets/tabler-icons/player-record.svg 7 | 8 | 9 | -------------------------------------------------------------------------------- /software/utilities/monitor/visualisers.py: -------------------------------------------------------------------------------- 1 | from matplotlib.backends.backend_qtagg import FigureCanvas 2 | from matplotlib.figure import Figure 3 | import numpy as np 4 | from PySide6.QtWidgets import QWidget 5 | from PySide6.QtOpenGLWidgets import QOpenGLWidget 6 | from PySide6.QtGui import QSurfaceFormat 7 | import moderngl 8 | from pywavefront import Wavefront 9 | from pyrr import Matrix44 10 | from scipy.spatial.transform import Rotation 11 | from PIL import Image 12 | from ui_noisewidget import Ui_NoiseWidget 13 | from si_prefix import si_format 14 | from pathlib import Path 15 | 16 | # Hackish way of importing my free body code without releasing a package 17 | import sys 18 | import pathlib 19 | parent = pathlib.Path(__file__).parent.resolve() 20 | sys.path.append(str(parent / "../force_analysis/")) 21 | import free_body 22 | 23 | 24 | class MplCanvas(FigureCanvas): 25 | def __init__(self, parent=None): 26 | super().__init__(Figure()) 27 | 28 | # Set figure and canvas background to be transparent 29 | self.figure.patch.set_facecolor('None') 30 | self.setStyleSheet("background-color: transparent;") 31 | 32 | def resizeEvent(self, event): 33 | super().resizeEvent(event) 34 | self.figure.tight_layout() 35 | 36 | 37 | class ChannelVoltage(MplCanvas): 38 | def __init__(self, parent=None): 39 | super().__init__(parent) 40 | 41 | # Add some axes 42 | self.axes = self.figure.add_subplot(111) 43 | self.axes.set_ylabel("Voltage (V)") 44 | self.axes.set_ylim(-50e-6, 50e-6) 45 | self.axes.set_xlabel("Time (s)") 46 | self.axes.set_xlim(-4.0, 0.0) 47 | 48 | # Let's plot something 49 | self.x_data = np.linspace(-4 + 256e-6, 0.0, 15625) 50 | self.y_data = np.zeros((15625, 6)) 51 | self.lines = self.axes.plot(self.x_data, self.y_data) 52 | 53 | def add_values(self, values): 54 | value_count = len(values) 55 | prev_x = self.x_data[-1] 56 | self.y_data = np.roll(self.y_data, -value_count, axis=0) 57 | self.x_data = np.roll(self.x_data, -value_count, axis=0) 58 | self.y_data[-value_count:, :] = values[-self.y_data.shape[0]:] 59 | self.x_data[-value_count:] = np.linspace(prev_x + 256e-6, prev_x + 256e-6 + (value_count - 1) * 256e-6, value_count)[-self.x_data.shape[0]:] 60 | if self.isVisible(): 61 | for line, d in zip(self.lines, self.y_data.T): 62 | line.set_ydata(d) 63 | line.set_xdata(self.x_data) 64 | self.axes.set_xlim(self.x_data[0], self.x_data[-1]) 65 | self.draw() 66 | 67 | 68 | class ChannelPsd(MplCanvas): 69 | def __init__(self, parent=None): 70 | super().__init__(parent) 71 | 72 | # Add some axes 73 | self.axes = self.figure.add_subplot(111) 74 | 75 | # Plot something 76 | self.axes.set_ylim(-300.0, -100.0) 77 | self.data = np.random.rand(1024, 6) * 1.2e-6 78 | for d in self.data.T: 79 | self.axes.psd(d, Fs=1/256e-6) 80 | 81 | def add_values(self, values): 82 | value_count = len(values) 83 | self.data = np.roll(self.data, -value_count, axis=0) 84 | self.data[-value_count:, :] = values[-self.data.shape[0]:] 85 | if self.isVisible(): 86 | self.axes.clear() 87 | self.axes.set_ylim(-300.0, -100.0) 88 | for d in self.data.T: 89 | self.axes.psd(d, Fs=1/256e-6) 90 | self.draw() 91 | 92 | 93 | class NoiseWidget(QWidget): 94 | def __init__(self, parent=None): 95 | super().__init__(parent) 96 | self.ui = Ui_NoiseWidget() 97 | self.ui.setupUi(self) 98 | self._channel_labels = [ 99 | self.ui.channel_1, 100 | self.ui.channel_2, 101 | self.ui.channel_3, 102 | self.ui.channel_4, 103 | self.ui.channel_5, 104 | self.ui.channel_6 105 | ] 106 | 107 | self.data = np.zeros((4096, 6)) 108 | 109 | def add_values(self, values): 110 | value_count = len(values) 111 | self.data = np.roll(self.data, -value_count, axis=0) 112 | self.data[-value_count:, :] = values[-self.data.shape[0]:] 113 | if self.isVisible(): 114 | rms = np.std(self.data, axis=0) 115 | for label, value in zip(self._channel_labels, rms): 116 | if np.isnan(value): 117 | label.setText("") 118 | else: 119 | label.setText(f"{si_format(value, precision=2)}V") 120 | 121 | 122 | class CubeDisplay(QOpenGLWidget): 123 | def __init__(self, parent=None): 124 | super().__init__(parent) 125 | 126 | format = QSurfaceFormat() 127 | format.setVersion(3, 3) 128 | format.setProfile(QSurfaceFormat.CoreProfile) 129 | format.setSamples(16) 130 | self.setFormat(format) 131 | 132 | self.ctx = None 133 | 134 | self.scene = Wavefront(Path(__file__).parent / 'assets' / 'cube.obj') 135 | 136 | self.desk_to_eye = Rotation.from_euler('ZX', [3.0 * np.pi / 4.0, -np.pi / 4.0]) 137 | 138 | self._translation = np.zeros(3) 139 | self._rotation = Rotation.from_rotvec([0.0, 0.0, 0.0]) 140 | 141 | def update_cube(self, translation, rotation): 142 | self._translation = translation 143 | self._rotation = rotation 144 | self.update() 145 | 146 | def paintGL(self): 147 | if self.ctx is None: 148 | self.init() 149 | self.render() 150 | 151 | def init(self): 152 | self.ctx = moderngl.create_context() 153 | self.prog = self.ctx.program( 154 | vertex_shader=''' 155 | #version 330 156 | uniform mat4 Mvp; 157 | in vec3 in_position; 158 | in vec3 in_normal; 159 | in vec2 in_texcoord; 160 | out vec3 v_vert; 161 | out vec3 v_norm; 162 | out vec2 v_text; 163 | void main() { 164 | v_vert = in_position; 165 | v_norm = in_normal; 166 | v_text = in_texcoord; 167 | gl_Position = Mvp * vec4(in_position, 1.0); 168 | } 169 | ''', 170 | fragment_shader=''' 171 | #version 330 172 | uniform sampler2D Texture; 173 | uniform vec4 Color; 174 | uniform vec3 Light; 175 | in vec3 v_vert; 176 | in vec3 v_norm; 177 | in vec2 v_text; 178 | out vec4 f_color; 179 | void main() { 180 | float lum = dot(normalize(v_norm), normalize(v_vert - Light)); 181 | lum = acos(lum) / 3.14159265; 182 | lum = clamp(lum, 0.0, 1.0); 183 | lum = lum * lum; 184 | lum = smoothstep(0.0, 1.0, lum); 185 | lum *= smoothstep(0.0, 80.0, v_vert.z) * 0.3 + 0.7; 186 | lum = lum * 0.8 + 0.2; 187 | vec3 color = texture(Texture, v_text).rgb; 188 | color = color * (1.0 - Color.a) + Color.rgb * Color.a; 189 | f_color = vec4(color * lum, 1.0); 190 | } 191 | ''', 192 | ) 193 | 194 | self.light = self.prog['Light'] 195 | self.color = self.prog['Color'] 196 | self.mvp = self.prog['Mvp'] 197 | 198 | self.vbo = self.ctx.buffer(np.array(self.scene.materials['Material'].vertices, dtype=np.float32)) 199 | self.vao = self.ctx.vertex_array( 200 | self.prog, 201 | [ 202 | (self.vbo, '2f 3f 3f', 'in_texcoord', 'in_normal', 'in_position') 203 | ], 204 | ) 205 | 206 | texture_path = Path(__file__).parent / 'assets' / self.scene.materials['Material'].texture.image_name 207 | with Image.open(texture_path) as im: 208 | im = im.transpose(Image.Transpose.FLIP_TOP_BOTTOM) 209 | self.texture = self.ctx.texture(im.size, 4, im.tobytes()) 210 | 211 | def render(self): 212 | self.ctx.clear(1.0, 1.0, 1.0, 1.0) 213 | self.ctx.enable(moderngl.DEPTH_TEST) 214 | 215 | proj = Matrix44.perspective_projection(45.0, self.width() / self.height(), 0.1, 1000.0) 216 | lookat = Matrix44.look_at( 217 | (4.0, 4.0, 4.0), 218 | (0.0, 0.0, 0.0), 219 | (0.0, 0.0, 1.0), 220 | ) 221 | 222 | translate = Matrix44.from_translation(self._translation) 223 | rotate = Matrix44.from_quaternion(self._rotation.inv().as_quat()) 224 | 225 | self.light.write(((translate * rotate) @ np.array([[4.0], [1.0], [6.0], [1.0]]))[:3].astype('f4')) 226 | self.color.value = (1.0, 1.0, 1.0, 0.25) 227 | self.mvp.write((proj * lookat * translate * rotate).astype('f4')) 228 | 229 | self.texture.use() 230 | self.vao.render() 231 | 232 | 233 | from ui_cubecontrol import Ui_CubeControl 234 | 235 | 236 | class CubeControl(QWidget): 237 | def __init__(self, parent=None): 238 | super().__init__(parent) 239 | 240 | # Generate and connect up the UI 241 | self.ui = Ui_CubeControl() 242 | self.ui.setupUi(self) 243 | self.ui.resetButton.clicked.connect(self._reset_position_rotation) 244 | self.ui.thresholdSlider.valueChanged.connect(self._change_threshold) 245 | self.ui.translationSlider.valueChanged.connect(self._change_translation_sensitivity) 246 | self.ui.rotationSlider.valueChanged.connect(self._change_rotation_sensitivity) 247 | 248 | # Create a free body Haptick to be able to calculate forces and torques 249 | separation = 2 * np.pi * 25e-3 * 25.0 / 360.0 250 | self._haptick = free_body.Haptick(25e-3, separation, 25e-3, separation, 20e-3) 251 | 252 | # Create a rotation that takes vectors from Haptick space to real desk 253 | # space. Haptick space has the positive x-axis going into the screen and 254 | # the positive y-axis going directly left. Desk space has the positive 255 | # x-axis going directly right, and the positive y-axis going directly 256 | # into the screen. Both are right-handed coordinate systems. 257 | self._haptick_to_desk = Rotation.from_rotvec([0.0, 0.0, np.pi / 2]) 258 | 259 | # Start at no translation or rotation 260 | self._reset_position_rotation() 261 | 262 | # Default thresholds and sensitivities 263 | self._threshold = 1.0e-6 264 | self._translation_sensitivity = 1.2e6 265 | self._rotation_sensitivity = 1.2e7 266 | 267 | def add_values(self, values): 268 | # Get the most recent arm forces. Base arm index 0 and 1 should be 269 | # immediately either side of the positive x-axis, and indices should 270 | # increase with increasing geometric angle. 271 | arm_forces = np.roll(-values[-1], 1) 272 | 273 | # Bail if the values we get aren't large enough. 274 | if np.all(np.abs(arm_forces) < self._threshold): 275 | return 276 | 277 | if np.any(np.isnan(arm_forces)): 278 | return 279 | 280 | # Use the free body model to calculate the force and torque applied to 281 | # the platform. 282 | force, torque = self._haptick.applied(arm_forces) 283 | 284 | # We know Haptick uses a constant sampling rate, so the elapsed time 285 | # since the last batch of samples is the sampling period times the 286 | # number of samples. 287 | time = len(values) * 256e-6 288 | 289 | # Calculate the translation and rotation from the applied forces and 290 | # torques. We make linear velocity directly proportional to the force 291 | # and rotational velocity directly proportional to the torque. 292 | linear_velocity = self._haptick_to_desk.apply( 293 | force[:, 0] * self._translation_sensitivity) 294 | rotational_velocity = self._haptick_to_desk.apply( 295 | torque[:, 0] * self._rotation_sensitivity) 296 | self._translation += self.ui.cubeDisplay.desk_to_eye.apply(linear_velocity * time) 297 | self._rotation = Rotation.from_rotvec(self.ui.cubeDisplay.desk_to_eye.apply(rotational_velocity * time)) * self._rotation 298 | 299 | # Update the display 300 | self.ui.cubeDisplay.update_cube(self._translation, self._rotation) 301 | 302 | #haptick_to_world = self._haptick_to_desk 303 | #world_to_eye = Rotation.from_euler('ZX', [3.0 * np.pi / 4.0, -np.pi / 4.0]) 304 | #self._translation += (world_to_eye * haptick_to_world).apply(force[:, 0] / 1e-4) 305 | #self._rotation = self._rotation * Rotation.from_rotvec((world_to_eye * haptick_to_world).apply(torque[:, 0] / -1e-5)) 306 | #self.update() 307 | 308 | def _reset_position_rotation(self): 309 | self._translation = np.zeros(3) 310 | self._rotation = Rotation.from_rotvec([0.0, 0.0, 0.0]) 311 | self.ui.cubeDisplay.update_cube(self._translation, self._rotation) 312 | 313 | def _change_threshold(self, value): 314 | self._threshold = value * 1.0e-7 315 | 316 | def _change_rotation_sensitivity(self, value): 317 | self._rotation_sensitivity = value * 1.2e6 318 | 319 | def _change_translation_sensitivity(self, value): 320 | self._translation_sensitivity = value * 1.2e5 --------------------------------------------------------------------------------