├── .gitignore ├── firmware ├── bin │ └── libarm_cortexM4l_math.a ├── test │ └── README ├── src │ ├── services.h │ ├── led_driver.h │ ├── pulse_processor.h │ ├── bluetooth.h │ ├── tracker_gpio.h │ ├── position_calculator.cpp │ ├── led_driver.cpp │ ├── position_calculator.h │ ├── pulse_processor.cpp │ ├── bluetooth.cpp │ ├── tracker_gpio.cpp │ └── main.cpp ├── platformio.ini ├── lib │ └── README ├── include │ └── README └── .travis.yml ├── hardware ├── exports │ ├── 3D-tracker-schema.png │ ├── 3D-tracker_gerber.zip │ ├── 3D-tracker-top-layer.png │ ├── 3D-tracker-top-render.png │ ├── 3D-tracker-bottom-layer.png │ └── 3D-tracker-bottom-render.png └── 3D-tracker.brd └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode 3 | 4 | hardware/*.s#* 5 | hardware/*.b#* 6 | -------------------------------------------------------------------------------- /firmware/bin/libarm_cortexM4l_math.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kacer/3D-Tracker-Vive/HEAD/firmware/bin/libarm_cortexM4l_math.a -------------------------------------------------------------------------------- /hardware/exports/3D-tracker-schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kacer/3D-Tracker-Vive/HEAD/hardware/exports/3D-tracker-schema.png -------------------------------------------------------------------------------- /hardware/exports/3D-tracker_gerber.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kacer/3D-Tracker-Vive/HEAD/hardware/exports/3D-tracker_gerber.zip -------------------------------------------------------------------------------- /hardware/exports/3D-tracker-top-layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kacer/3D-Tracker-Vive/HEAD/hardware/exports/3D-tracker-top-layer.png -------------------------------------------------------------------------------- /hardware/exports/3D-tracker-top-render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kacer/3D-Tracker-Vive/HEAD/hardware/exports/3D-tracker-top-render.png -------------------------------------------------------------------------------- /hardware/exports/3D-tracker-bottom-layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kacer/3D-Tracker-Vive/HEAD/hardware/exports/3D-tracker-bottom-layer.png -------------------------------------------------------------------------------- /hardware/exports/3D-tracker-bottom-render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kacer/3D-Tracker-Vive/HEAD/hardware/exports/3D-tracker-bottom-render.png -------------------------------------------------------------------------------- /firmware/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /firmware/src/services.h: -------------------------------------------------------------------------------- 1 | const static char* coordinatesServiceUUID = "3d000000a000cafe040400451f003d3d"; 2 | const static char* coordinatesCharacteristicUUID = "3d000000a001cafe040400451f003d3d"; 3 | 4 | const static char* baseStationGeometryServiceUUID = "3d000000b000cafe040400451f003d3d"; 5 | const static char* stationNumberCharacteristicUUID = "3d000000b001cafe040400451f003d3d"; 6 | const static char* positionCharacteristicUUID = "3d000000b002cafe040400451f003d3d"; 7 | const static char* rotation1RowCharacteristicUUID = "3d000000b003cafe040400451f003d3d"; 8 | const static char* rotation2RowCharacteristicUUID = "3d000000b004cafe040400451f003d3d"; 9 | const static char* rotation3RowCharacteristicUUID = "3d000000b005cafe040400451f003d3d"; -------------------------------------------------------------------------------- /firmware/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:nrf52840_dk] 12 | platform = nordicnrf52 13 | board = nrf52840_dk 14 | framework = arduino 15 | debug_tool = jlink 16 | monitor_speed = 115200 17 | build_flags = 18 | -D ARDUINO_GENERIC 19 | -D ARM_MATH_CM4 20 | -L bin 21 | -l arm_cortexM4l_math 22 | -D __FPU_PRESENT 23 | -D NRF52_S132 24 | -D USE_LFSYNT 25 | lib_deps = 26 | BLEPeripheral 27 | -------------------------------------------------------------------------------- /firmware/src/led_driver.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tracker_gpio.h" 3 | 4 | const uint8_t STATE_ALL_OFF = 0; 5 | const uint8_t STATE_FAILED = 1; 6 | const uint8_t STATE_TRACKING = 2; 7 | const uint8_t STATE_TRACKING_TIMEOUT = 3; 8 | const uint8_t STATE_GEOMETRY_NOT_SET = 4; 9 | 10 | typedef struct { 11 | uint16_t turnOn; // ms 12 | uint16_t turnOff; // ms 13 | GPIO_PIN led; 14 | } LedTimings; 15 | 16 | const LedTimings failedTimings[] = {{500, 1000, PIN_RED_LED}}; 17 | const LedTimings trackingTimings[] = {{60, 940, PIN_BLUE_LED}}; 18 | const LedTimings trackingTimeoutTimings[] = {{80, 920, PIN_RED_LED}}; 19 | const LedTimings geometryNotSetTimings[] = {{60, 160, PIN_GREEN_LED}, {160, 250, PIN_RED_LED}, {60, 1000, PIN_GREEN_LED}}; 20 | 21 | class LedDriver { 22 | public: 23 | void showFailed(void); 24 | void showGeometryNotSet(void); 25 | void showTracking(void); 26 | void showTrackingTimeout(void); 27 | void turnAllOf(void); 28 | void loop(void); 29 | void setup(void); 30 | private: 31 | uint8_t showingState; 32 | uint32_t startMillis; 33 | bool isLedTurnOn; 34 | uint8_t timingsIndex; 35 | 36 | void reset(void); 37 | }; -------------------------------------------------------------------------------- /firmware/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /firmware/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /firmware/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /firmware/src/pulse_processor.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "arm_math.h" 3 | 4 | #define TICK 0.0625 //us 5 | #define MICROSECS_IN_TICKS(x) (x / TICK) 6 | 7 | #define CYCLES_COUNT 4 8 | #define PULSES_COUNT 10 // ring buffer size 9 | #define ANGLES_COUNT 4 10 | 11 | typedef struct { 12 | uint32_t raising_time_ticks; 13 | uint32_t length_ticks; 14 | } Pulse; 15 | 16 | typedef void (*cb_angle)(float32_t *angles); 17 | 18 | class PulseProcessor { 19 | public: 20 | void loop(void); 21 | void addPulse(Pulse pulse); 22 | PulseProcessor(cb_angle pCallback); 23 | 24 | private: 25 | Pulse pulses[PULSES_COUNT]; 26 | uint32_t pulsesWriteIndex = 0; 27 | uint32_t pulsesReadIndex = 0; 28 | cb_angle angleCb; 29 | float32_t angles[ANGLES_COUNT]; 30 | uint8_t anglesCount = 0; 31 | bool cycleSynchronized = false; 32 | bool startCycleCandidate = false; 33 | uint32_t startOfCycleTime; 34 | uint32_t startTime; // time at rotor reached 0° 35 | uint8_t cycle = 0; // cycle 0 - 3 36 | uint8_t baseStationIndex = 0; 37 | 38 | uint32_t cyclePeriodLengthInTicks = MICROSECS_IN_TICKS(8333); // 8333 us 39 | uint32_t centerCycleLengthInTicks = MICROSECS_IN_TICKS(4000); // 4000 us 40 | uint32_t sweepStartWindowInTicks = MICROSECS_IN_TICKS(1222); // 1222 us 41 | uint32_t sweepEndWindowsInTicks = MICROSECS_IN_TICKS(6777); // 6777 us 42 | 43 | 44 | /** 45 | * @brief Function returns integer number which expresses bits of 46 | * caught pulse. Bits are follows Skip | Data | Axis. 47 | * 48 | * @param pulse 49 | * @return int8_t (0 - 7) for sync pulses, (< 0) for sweeps, (> 7) invalid 50 | */ 51 | int8_t decodePulse(Pulse &pulse); 52 | 53 | /** 54 | * @brief Read pulses from ring buffer. 55 | * 56 | * @param pulse read pulse if function returns true 57 | * @return true if read was successful 58 | */ 59 | bool readPulse(Pulse &pulse); 60 | void computeAngle(Pulse &pulse); 61 | void resetCycle(void); 62 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 3D Tracker compatible with HTC Vive 2 | This little device is capable of tracking its position in the world. The tracked position is then sent over BLE to the smartphone. The [mobile app](https://github.com/kacer/3D-Tracker-Vive-Android) was created for this purpose and renders the positions of all connected 3D trackers. For tracking 3D Tracker uses two HTC Base Stations which are part of the HTC Vive set for VR. For now, the tracker uses HTC Base Station 1.0 but HW is ready for HTC Base Station 2.0. This project came to the world within my master's thesis. The idea of position calculation is based on repo [vive-diy-position-sensor](https://github.com/ashtuchkin/vive-diy-position-sensor). 3 | 4 | The dimensions of the 3D tracker are 6.3x4.7 cm and can be worn like a watch. The 3D tracker itself looks: 5 | | ![Tracker1](https://user-images.githubusercontent.com/22794640/83662220-8237ee80-a5c7-11ea-870d-51db626de94d.jpg) | ![Tracker](https://user-images.githubusercontent.com/22794640/83663033-97f9e380-a5c8-11ea-9039-e5c1b7763fb1.jpg) | 6 | | --- | --- | 7 | 8 | The demo of position tracking by two 3D trackers on YouTube: 9 | [![The demo of position tracking by two 3D trackers](https://img.youtube.com/vi/TOYSWDCKwdk/0.jpg)](https://www.youtube.com/watch?v=TOYSWDCKwdk) 10 | 11 | ## Hardware 12 | The 3D tracker is based on **nRF52840** and uses as a sensor of IR light **TS4231 + photodiode BPW34S**. For now, only one sensor is used and thus calibration of positions of HTC Base Station must be taken from SteamVR through this utility [vive-diy-position-sensor-geometry-getter](https://github.com/ashtuchkin/vive-diy-position-sensor-geometry-getter). This utility prints to console the geometry of HTC Base Stations which is consists of position and rotation matrix. This data are then copied and save to txt file. After that, the txt file with geometry is copied to the smartphone and through the [mobile app](https://github.com/kacer/3D-Tracker-Vive-Android) is sent to 3D trackers. Because nRF52840 was used additional sensors are possible to add. 13 | 14 | ## Getting started 15 | The firmware of 3D Tracker was written in [PlatformIO](https://platformio.org/) with Arduino framework in C++. I recommend using the Visual Studio Code for developing. The installation process of PlatfromIO is pretty simple. Just install it like an extension of the VS Code. Then clone this repository, open it in VS Code, build and upload to your board. 16 | 17 | ### Uploading firmware into board 18 | I used a [development kit with nRF52840](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) from Nordic Semiconductor for burning firmware into a chip. Wiring was following: ![programming-custom-board](https://user-images.githubusercontent.com/22794640/83662332-9ed42680-a5c7-11ea-8593-a381d4ecfa29.jpg) 19 | -------------------------------------------------------------------------------- /firmware/src/bluetooth.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BLEPeripheral.h" 4 | #include "services.h" 5 | #include "position_calculator.h" 6 | 7 | typedef void (*cb_baseStationGeometry)(BaseStation *baseStations); 8 | 9 | typedef struct { 10 | float32_t x; 11 | float32_t y; 12 | float32_t z; 13 | } Vec3; 14 | 15 | typedef struct { 16 | float32_t m11; 17 | float32_t m12; 18 | float32_t m13; 19 | float32_t m21; 20 | float32_t m22; 21 | float32_t m23; 22 | float32_t m31; 23 | float32_t m32; 24 | float32_t m33; 25 | } Mat3; 26 | 27 | class Bluetooth { 28 | public: 29 | void sendPosition(vec3d &position); 30 | void poll(void); 31 | void setBaseStationGeometryCB(cb_baseStationGeometry pCallback); 32 | void setup(void); 33 | 34 | void stationNumberWritten(BLECentral ¢ral, BLECharacteristic &characteristic); 35 | void positionWritten(BLECentral ¢ral, BLECharacteristic &characteristic); 36 | void rotationWritten(BLECentral ¢ral, BLECharacteristic &characteristic); 37 | 38 | static Bluetooth* getInstance(void); 39 | 40 | private: 41 | Bluetooth() {} 42 | 43 | static Bluetooth* instance; 44 | 45 | cb_baseStationGeometry stationCb; 46 | BaseStation baseStations[baseStationsCount]; 47 | uint8_t baseStationIndex = 0; // index of base station where position and rotation will be written 48 | 49 | void setPositionCharValueByIndex(void); 50 | void setRotationCharValueByIndex(void); 51 | 52 | /** 53 | * @brief Set the Row To Rotation Matrix object 54 | * 55 | * @param rowNum range [0 - 2] 56 | * @param row value of row to be set 57 | */ 58 | void setRowToRotationMatrix(uint8_t rowNum, Vec3 row); 59 | 60 | BLEPeripheral peripheral = BLEPeripheral(); 61 | 62 | BLEService coordinatesService = BLEService(coordinatesServiceUUID); 63 | BLETypedCharacteristic coordinatesCharacteristic = 64 | BLETypedCharacteristic(coordinatesCharacteristicUUID, BLERead | BLENotify); 65 | 66 | BLEService baseStationGeometryService = BLEService(baseStationGeometryServiceUUID); 67 | BLECharCharacteristic stationNumberCharacteristic = 68 | BLECharCharacteristic(stationNumberCharacteristicUUID, BLERead | BLEWrite); 69 | BLETypedCharacteristic positionCharacteristic = 70 | BLETypedCharacteristic(positionCharacteristicUUID, BLERead | BLEWrite); 71 | BLETypedCharacteristic rotation1RowCharacteristic = 72 | BLETypedCharacteristic(rotation1RowCharacteristicUUID, BLERead | BLEWrite); 73 | BLETypedCharacteristic rotation2RowCharacteristic = 74 | BLETypedCharacteristic(rotation2RowCharacteristicUUID, BLERead | BLEWrite); 75 | BLETypedCharacteristic rotation3RowCharacteristic = 76 | BLETypedCharacteristic(rotation3RowCharacteristicUUID, BLERead | BLEWrite); 77 | }; -------------------------------------------------------------------------------- /firmware/src/tracker_gpio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define NRF_P1_BASE 0x50000300UL 8 | #define NRF_P1 ((NRF_GPIO_Type *) NRF_P1_BASE) 9 | 10 | #define PIN_RED_LED GPIO_PIN {1, 11} //P1.11 11 | #define PIN_GREEN_LED GPIO_PIN {1, 10} //P1.10 12 | #define PIN_BLUE_LED GPIO_PIN {0, 3} //P0.03 13 | 14 | #define PIN_BTN1 GPIO_PIN {1, 13} //P1.13 15 | 16 | #define PIN_E_TS4231 GPIO_PIN {0, 13} //P0.13 17 | #define PIN_D_TS4231 GPIO_PIN {0, 24} //P0.24 18 | 19 | #define PIN_AI3 GPIO_PIN {0, 5} //P0.05 20 | #define PIN_AI4 GPIO_PIN {0, 28} //P0.28 21 | #define PIN_AI5 GPIO_PIN {0, 29} //P0.29 22 | #define PIN_AI6 GPIO_PIN {0, 30} //P0.30 23 | 24 | #define PIN_RST GPIO_PIN {0, 18} //P0.18 25 | //#define PIN_SWD GPIO_PIN {0, 0} //SWDIO 26 | //#define PIN_SWC GPIO_PIN {0, 0} //SWDCLK 27 | 28 | 29 | #define A_PIN_AI3 20 30 | #define A_PIN_AI4 16 31 | #define A_PIN_AI5 17 32 | #define A_PIN_AI6 18 33 | 34 | #define A_PIN_E_TS4231 2 35 | #define A_PIN_D_TS4231 12 36 | 37 | #define A_PIN_UART_TX A_PIN_AI4 //AI4 38 | #define A_PIN_UART_RX PIN_SERIAL_RX //DEFAULT RX SERIAL PIN 39 | 40 | 41 | typedef struct { 42 | uint8_t port; 43 | uint32_t number; 44 | } GPIO_PIN; 45 | 46 | /** 47 | * \brief Configures the specified pin to behave either as an input or an output. 48 | * 49 | * \param pin The pin whose mode you wish to set 50 | * \param mode Can be INPUT, OUTPUT, INPUT_PULLUP or INPUT_PULLDOWN 51 | */ 52 | extern void pinMode(GPIO_PIN pin, uint32_t mode); 53 | 54 | 55 | /** 56 | * \brief Write a HIGH or a LOW value to a digital pin. 57 | * 58 | * If the pin has been configured as an OUTPUT with pinMode(), its voltage will be set to the 59 | * corresponding value: 5V (or 3.3V on 3.3V boards) for HIGH, 0V (ground) for LOW. 60 | * 61 | * If the pin is configured as an INPUT, writing a HIGH value with digitalWrite() will enable an internal 62 | * 20K pullup resistor (see the tutorial on digital pins). Writing LOW will disable the pullup. The pullup 63 | * resistor is enough to light an LED dimly, so if LEDs appear to work, but very dimly, this is a likely 64 | * cause. The remedy is to set the pin to an output with the pinMode() function. 65 | * 66 | * \note Digital pin PIN_LED is harder to use as a digital input than the other digital pins because it has an LED 67 | * and resistor attached to it that's soldered to the board on most boards. If you enable its internal 20k pull-up 68 | * resistor, it will hang at around 1.7 V instead of the expected 5V because the onboard LED and series resistor 69 | * pull the voltage level down, meaning it always returns LOW. If you must use pin PIN_LED as a digital input, use an 70 | * external pull down resistor. 71 | * 72 | * \param pin the pin 73 | * \param value HIGH or LOW 74 | */ 75 | extern void digitalWrite(GPIO_PIN pin, uint32_t value); 76 | 77 | /** 78 | * \brief Reads the value from a specified digital pin, either HIGH or LOW. 79 | * 80 | * \param pin The digital pin you want to read (int) 81 | * 82 | * \return HIGH or LOW 83 | */ 84 | extern int digitalRead(GPIO_PIN pin); 85 | -------------------------------------------------------------------------------- /firmware/src/position_calculator.cpp: -------------------------------------------------------------------------------- 1 | #include "position_calculator.h" 2 | #include "Arduino.h" 3 | 4 | int PositionCalculator::calcPosition(float32_t *angles, vec3d &position) { 5 | // check whether base stations geometry is set 6 | for(uint8_t b = 0; b < baseStationsCount; b++) { 7 | if(!baseStations[b].isSet()) { 8 | return BASESTATIONS_NOT_SET; 9 | } 10 | } 11 | 12 | vec3d ray1, ray2; 13 | calcRayVector(baseStations[0], angles[0], angles[1], ray1); 14 | calcRayVector(baseStations[1], angles[2], angles[3], ray2); 15 | 16 | return intersectLines(baseStations[0].origin, ray1, baseStations[1].origin, ray2, position); 17 | } 18 | 19 | void PositionCalculator::setBaseStationsGeometry(BaseStation b0, BaseStation b1) { 20 | memcpy(&baseStations[0], &b0, sizeof(BaseStation)); 21 | memcpy(&baseStations[1], &b1, sizeof(BaseStation)); 22 | } 23 | 24 | void PositionCalculator::calcRayVector(BaseStation &baseStation, float32_t angle1, float32_t angle2, vec3d &res) { 25 | vec3d vertical = {0, arm_cos_f32(angle2), arm_sin_f32(angle2)}; 26 | vec3d horizontal = {arm_cos_f32(angle1), 0, -arm_sin_f32(angle1)}; 27 | 28 | vec3d ray = {}; 29 | vectorCrossProduct(vertical, horizontal, ray); 30 | normalizeVector(ray); 31 | 32 | arm_matrix_instance_f32 stationRotMatrix = {3, 3, baseStation.rotationMatrix}; 33 | arm_matrix_instance_f32 rayVector = {3, 1, ray}; 34 | arm_matrix_instance_f32 rotatedRayVector = {3, 1, res}; 35 | arm_mat_mult_f32(&stationRotMatrix, &rayVector, &rotatedRayVector); 36 | } 37 | 38 | int PositionCalculator::intersectLines(vec3d &origin1, vec3d &vec1, vec3d &origin2, vec3d &vec2, vec3d &res) { 39 | vec3d w0 = {}; 40 | arm_sub_f32(origin1, origin2, w0, vec3dSize); 41 | 42 | float32_t a, b, c, d, e; 43 | arm_dot_prod_f32(vec1, vec1, vec3dSize, &a); 44 | arm_dot_prod_f32(vec1, vec2, vec3dSize, &b); 45 | arm_dot_prod_f32(vec2, vec2, vec3dSize, &c); 46 | arm_dot_prod_f32(vec1, w0, vec3dSize, &d); 47 | arm_dot_prod_f32(vec2, w0, vec3dSize, &e); 48 | 49 | float32_t denominator = a * c - b * b; 50 | if(fabsf(denominator) < 1e-5f) 51 | return CALCULATION_FAILED; 52 | 53 | float32_t s = (b * e - c * d) / denominator; 54 | vec3d ps = {}; 55 | arm_scale_f32(vec1, s, ps, vec3dSize); 56 | arm_add_f32(ps, origin1, ps, vec3dSize); 57 | 58 | float32_t t = (a * e - b * d) / denominator; 59 | vec3d pt = {}; 60 | arm_scale_f32(vec2, t, pt, vec3dSize); 61 | arm_add_f32(pt, origin2, pt, vec3dSize); 62 | 63 | vec3d aux = {}; 64 | arm_add_f32(ps, pt, aux, vec3dSize); 65 | arm_scale_f32(aux, 0.5f, res, vec3dSize); 66 | 67 | return CALCULATION_SUCCESS; 68 | } 69 | 70 | bool PositionCalculator::normalizeVector(vec3d &vec) { 71 | float32_t len = vectorLength(vec); 72 | if(len == 0.0) { 73 | return false; 74 | } 75 | 76 | arm_scale_f32(vec, 1 / len, vec, vec3dSize); 77 | 78 | return true; 79 | } 80 | 81 | float32_t PositionCalculator::vectorLength(vec3d &vec) { 82 | float32_t pow, res; 83 | 84 | arm_power_f32(vec, vec3dSize, &pow); 85 | arm_sqrt_f32(pow, &res); 86 | 87 | return res; 88 | } 89 | 90 | void PositionCalculator::vectorCrossProduct(vec3d &vec1, vec3d &vec2, vec3d &res) { 91 | res[0] = vec1[1]*vec2[2] - vec1[2]*vec2[1]; 92 | res[1] = vec1[2]*vec2[0] - vec1[0]*vec2[2]; 93 | res[2] = vec1[0]*vec2[1] - vec1[1]*vec2[0]; 94 | } -------------------------------------------------------------------------------- /firmware/src/led_driver.cpp: -------------------------------------------------------------------------------- 1 | #include "led_driver.h" 2 | 3 | void LedDriver::showFailed(void) { 4 | if(showingState == STATE_FAILED) { 5 | return; 6 | } 7 | 8 | reset(); 9 | showingState = STATE_FAILED; 10 | } 11 | 12 | void LedDriver::showGeometryNotSet(void) { 13 | if(showingState == STATE_GEOMETRY_NOT_SET) { 14 | return; 15 | } 16 | 17 | reset(); 18 | showingState = STATE_GEOMETRY_NOT_SET; 19 | } 20 | 21 | void LedDriver::showTracking(void) { 22 | if(showingState == STATE_TRACKING) { 23 | return; 24 | } 25 | 26 | reset(); 27 | showingState = STATE_TRACKING; 28 | } 29 | 30 | void LedDriver::showTrackingTimeout(void) { 31 | if(showingState == STATE_TRACKING_TIMEOUT) { 32 | return; 33 | } 34 | 35 | reset(); 36 | showingState = STATE_TRACKING_TIMEOUT; 37 | } 38 | 39 | void LedDriver::turnAllOf(void) { 40 | reset(); 41 | } 42 | 43 | void LedDriver::loop(void) { 44 | const LedTimings *ledTiming; 45 | uint8_t totalTimings; 46 | switch(showingState) { 47 | case STATE_ALL_OFF: 48 | return; 49 | case STATE_FAILED: 50 | ledTiming = failedTimings; 51 | totalTimings = sizeof(failedTimings) / sizeof(*ledTiming); 52 | break; 53 | case STATE_TRACKING: 54 | ledTiming = trackingTimings; 55 | totalTimings = sizeof(trackingTimings) / sizeof(*ledTiming); 56 | break; 57 | case STATE_TRACKING_TIMEOUT: 58 | ledTiming = trackingTimeoutTimings; 59 | totalTimings = sizeof(trackingTimeoutTimings) / sizeof(*ledTiming); 60 | break; 61 | case STATE_GEOMETRY_NOT_SET: 62 | ledTiming = geometryNotSetTimings; 63 | totalTimings = sizeof(geometryNotSetTimings) / sizeof(*ledTiming); 64 | break; 65 | default: 66 | return; 67 | } 68 | 69 | uint32_t currentMillis = millis(); 70 | if(!startMillis) { 71 | // the start of whole cycle 72 | startMillis = currentMillis; 73 | isLedTurnOn = true; 74 | } 75 | 76 | if(isLedTurnOn) { 77 | // LED is turned on 78 | digitalWrite(ledTiming[timingsIndex].led, LOW); 79 | if(currentMillis - startMillis > ledTiming[timingsIndex].turnOn) { 80 | // turn off LED 81 | isLedTurnOn = false; 82 | startMillis = currentMillis; 83 | digitalWrite(ledTiming[timingsIndex].led, HIGH); 84 | } 85 | } else { 86 | // LED is turned off 87 | digitalWrite(ledTiming[timingsIndex].led, HIGH); 88 | if(currentMillis - startMillis > ledTiming[timingsIndex].turnOff) { 89 | // turn on LED 90 | isLedTurnOn = true; 91 | startMillis = currentMillis; 92 | //end of cycle -> move index to next led timings 93 | timingsIndex = ++timingsIndex % totalTimings; 94 | digitalWrite(ledTiming[timingsIndex].led, LOW); 95 | } 96 | } 97 | } 98 | 99 | void LedDriver::setup(void) { 100 | reset(); 101 | pinMode(PIN_RED_LED, OUTPUT); 102 | pinMode(PIN_GREEN_LED, OUTPUT); 103 | pinMode(PIN_BLUE_LED, OUTPUT); 104 | } 105 | 106 | void LedDriver::reset(void) { 107 | showingState = STATE_ALL_OFF; 108 | startMillis = 0; 109 | isLedTurnOn = false; 110 | timingsIndex = 0; 111 | digitalWrite(PIN_RED_LED, HIGH); 112 | digitalWrite(PIN_GREEN_LED, HIGH); 113 | digitalWrite(PIN_BLUE_LED, HIGH); 114 | } -------------------------------------------------------------------------------- /firmware/src/position_calculator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "arm_math.h" 4 | 5 | const uint8_t vec3dSize = 3; 6 | typedef float32_t vec3d[vec3dSize]; 7 | 8 | const uint8_t mat3ArraySize = 9; 9 | typedef float32_t mat3Array[mat3ArraySize]; 10 | 11 | const uint8_t baseStationsCount = 2; 12 | typedef struct { 13 | mat3Array rotationMatrix; // rotation matrix by rows 14 | vec3d origin; 15 | 16 | bool isSet() { 17 | vec3d nullVector = {0, 0, 0}; 18 | float32_t nullMatrix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 19 | int posVector = memcmp(origin, nullVector, vec3dSize); 20 | int rotMatrix = memcmp(rotationMatrix, nullMatrix, mat3ArraySize); 21 | 22 | return posVector && rotMatrix; 23 | } 24 | } BaseStation; 25 | 26 | // Position calculation return values 27 | const uint8_t CALCULATION_FAILED = 0; 28 | const uint8_t CALCULATION_SUCCESS = 1; 29 | const uint8_t BASESTATIONS_NOT_SET = 2; 30 | 31 | class PositionCalculator { 32 | public: 33 | /** 34 | * @brief Function will compute position of tracked object from given angles. 35 | * 36 | * @param angles of base stations [M-A0, M-A1, S-A0, S-A1] 37 | * @param position calculated position (x, y, z) 38 | * @return CALCULATION_FAILED or CALCULATION_SUCCESS or BASESTATIONS_NOT_SET 39 | */ 40 | int calcPosition(float32_t *angles, vec3d &position); 41 | 42 | /** 43 | * @brief Set the Base Stations Geometry object. 44 | * 45 | * @param b0 master 46 | * @param b1 slave 47 | */ 48 | void setBaseStationsGeometry(BaseStation b0, BaseStation b1); 49 | 50 | private: 51 | BaseStation baseStations[baseStationsCount]; // 0 - master, 1 - slave 52 | 53 | /** 54 | * @brief Function will compute ray vector from base station to sensor. 55 | * 56 | * @param baseStation struct with base station origin and rotation matrix 57 | * @param angle1 vertical angle 58 | * @param angle2 horizontal angle 59 | * @param res result vector 60 | */ 61 | void calcRayVector(BaseStation &baseStation, float32_t angle1, float32_t angle2, vec3d &res); 62 | 63 | /** 64 | * @brief Function will find intersection between two vectors from base stations 65 | * and therefore compute 3D position of tracked object per this algorithm: 66 | * http://geomalgorithms.com/a07-_distance.html#Distance-between-Lines. 67 | * 68 | * @param origin1 origin of base station 0 (Master) 69 | * @param vec1 vector from base station 0 to sensor of tracked object 70 | * @param origin2 origin of base station 1 (Slave) 71 | * @param vec2 vector from base station 1 to sensor of tracked object 72 | * @param res coordinates (x, y, z) of tracked object 73 | * @return CALCULATION_FAILED or CALCULATION_SUCCESS 74 | */ 75 | int intersectLines(vec3d &origin1, vec3d &vec1, vec3d &origin2, vec3d &vec2, vec3d &res); 76 | 77 | /** 78 | * @brief Function will try to normalize given vector. 79 | * 80 | * @param vec vector 81 | * @return true if vector was normalized 82 | * @return false otherwise 83 | */ 84 | bool normalizeVector(vec3d &vec); 85 | 86 | /** 87 | * @brief Compute length of given vector. 88 | * 89 | * @param vec vector 90 | * @return float32_t length of vector 91 | */ 92 | float32_t vectorLength(vec3d &vec); 93 | 94 | /** 95 | * @brief Function will compute cross product of two given vectors. 96 | * 97 | * @param vec1 vector 1 98 | * @param vec2 vector 2 99 | * @param res cross product of vec1 and vec2 100 | */ 101 | void vectorCrossProduct(vec3d &vec1, vec3d &vec2, vec3d &res); 102 | }; -------------------------------------------------------------------------------- /firmware/src/pulse_processor.cpp: -------------------------------------------------------------------------------- 1 | #include "pulse_processor.h" 2 | 3 | PulseProcessor::PulseProcessor(cb_angle pCallback) { 4 | angleCb = pCallback; 5 | } 6 | 7 | void PulseProcessor::loop(void) { 8 | Pulse pulse; 9 | if(!readPulse(pulse)) return; // nothing to do 10 | 11 | int8_t bits = decodePulse(pulse); 12 | 13 | if(bits < 0) { 14 | // sweep pulse 15 | if(!cycleSynchronized) return; 16 | computeAngle(pulse); 17 | 18 | return; 19 | } 20 | 21 | if(bits > 7) { 22 | // invalid length of pulse 23 | resetCycle(); 24 | 25 | return; 26 | } 27 | 28 | // extract bits 29 | uint8_t skip = ((uint8_t) bits >> 2) & 1; 30 | uint8_t data = ((uint8_t) bits >> 1) & 1; 31 | uint8_t axis = ((uint8_t) bits) & 1; 32 | 33 | // find start of full cycle - situation where master basestation sweeps room in axis 0 34 | if(!cycleSynchronized) { 35 | if(!skip && !axis) { 36 | // candidate for master's lighthouse sync pulse in axis 0 (start of cycle) 37 | startTime = pulse.raising_time_ticks; 38 | startCycleCandidate = true; 39 | baseStationIndex = 1; 40 | 41 | return; 42 | } 43 | if(startCycleCandidate) { 44 | // candidate pulse was detected 45 | uint32_t diff = pulse.raising_time_ticks - startTime; 46 | if(diff >= MICROSECS_IN_TICKS(390) && diff <= MICROSECS_IN_TICKS(430)) { 47 | // start of cycle was detected 48 | cycleSynchronized = true; 49 | baseStationIndex = 2; 50 | 51 | return; 52 | } else { 53 | // start was not detected, reset candidate 54 | startCycleCandidate = false; 55 | } 56 | } 57 | } 58 | if(!cycleSynchronized) return; 59 | 60 | switch(baseStationIndex) { 61 | case 1: 62 | { 63 | uint32_t diff = pulse.raising_time_ticks - startOfCycleTime; 64 | if(!(diff >= MICROSECS_IN_TICKS(390) && diff <= MICROSECS_IN_TICKS(430))) { 65 | // some sync pulses were missed 66 | resetCycle(); 67 | 68 | return; 69 | } 70 | } 71 | break; 72 | case 2: // end of one cycle 73 | cycle++; 74 | baseStationIndex = 0; 75 | break; 76 | } 77 | 78 | if(cycle == CYCLES_COUNT) { // end of full cycle (4 cycles = 4 angles) 79 | if(anglesCount == ANGLES_COUNT) { 80 | angleCb(angles); // let's propagate caught angles 81 | } 82 | cycle = 0; 83 | anglesCount = 0; 84 | } 85 | 86 | if((cycle / 2 == 0 && baseStationIndex == 0) || 87 | (cycle / 2 == 1 && baseStationIndex == 1)) { 88 | startTime = pulse.raising_time_ticks; 89 | } 90 | 91 | if(baseStationIndex == 0) { // start of one cycle 92 | startOfCycleTime = pulse.raising_time_ticks; 93 | } 94 | baseStationIndex++; 95 | } 96 | 97 | void PulseProcessor::addPulse(Pulse pulse) { 98 | uint8_t w = (pulsesWriteIndex + 1) % PULSES_COUNT; 99 | uint8_t r = pulsesReadIndex % PULSES_COUNT; 100 | if(w == r) { 101 | // the data would be overwritten, let's reset cycle 102 | resetCycle(); 103 | // reset read and write indexes too 104 | pulsesReadIndex = 0; 105 | pulsesWriteIndex = 0; 106 | } 107 | pulses[pulsesWriteIndex++ % PULSES_COUNT] = pulse; 108 | } 109 | 110 | bool PulseProcessor::readPulse(Pulse &pulse) { 111 | if(pulsesReadIndex == pulsesWriteIndex) { 112 | return false; 113 | } 114 | 115 | pulse = pulses[pulsesReadIndex++ % PULSES_COUNT]; 116 | 117 | return true; 118 | } 119 | 120 | int8_t PulseProcessor::decodePulse(Pulse &pulse) { 121 | return ((int32_t) pulse.length_ticks - 889) / 165; 122 | } 123 | 124 | void PulseProcessor::computeAngle(Pulse &pulse) { 125 | uint32_t time = (pulse.raising_time_ticks + pulse.length_ticks / 2) - startTime; 126 | if(time < sweepStartWindowInTicks || time > sweepEndWindowsInTicks) { // sweep pulse was in invalid range 127 | return; 128 | } 129 | 130 | if(anglesCount > cycle) { // second "sweep" pulse in one cycle, could be some kind of reflection 131 | return; 132 | } 133 | 134 | angles[cycle] = ((int32_t) time - (int32_t) centerCycleLengthInTicks) * PI / (int32_t) cyclePeriodLengthInTicks; 135 | anglesCount++; 136 | } 137 | 138 | void PulseProcessor::resetCycle(void) { 139 | anglesCount = 0; 140 | cycle = 0; 141 | baseStationIndex = 0; 142 | cycleSynchronized = false; 143 | startCycleCandidate = false; 144 | } -------------------------------------------------------------------------------- /firmware/src/bluetooth.cpp: -------------------------------------------------------------------------------- 1 | #include "bluetooth.h" 2 | 3 | 4 | void charStationNumberWritten(BLECentral ¢ral, BLECharacteristic &characteristic) { 5 | Bluetooth::getInstance()->stationNumberWritten(central, characteristic); 6 | } 7 | 8 | void charPositionWritten(BLECentral ¢ral, BLECharacteristic &characteristic) { 9 | Bluetooth::getInstance()->positionWritten(central, characteristic); 10 | } 11 | 12 | void charRotationWritten(BLECentral ¢ral, BLECharacteristic &characteristic) { 13 | Bluetooth::getInstance()->rotationWritten(central, characteristic); 14 | } 15 | 16 | 17 | Bluetooth* Bluetooth::instance = 0; 18 | 19 | Bluetooth* Bluetooth::getInstance(void) { 20 | if(instance == 0) { 21 | instance = new Bluetooth(); 22 | } 23 | 24 | return instance; 25 | } 26 | 27 | void Bluetooth::setBaseStationGeometryCB(cb_baseStationGeometry pCallback) { 28 | stationCb = pCallback; 29 | } 30 | 31 | void Bluetooth::sendPosition(vec3d &position) { 32 | Vec3 coords = {position[0], position[1], position[2]}; 33 | coordinatesCharacteristic.setValue(coords); 34 | } 35 | 36 | void Bluetooth::poll(void) { 37 | peripheral.poll(); 38 | } 39 | 40 | void Bluetooth::setup(void) { 41 | // at the start zeros base station's values 42 | for(uint8_t b = 0; b < baseStationsCount; b++) { 43 | memset(baseStations[b].origin, 0, sizeof(vec3d)); 44 | memset(baseStations[b].rotationMatrix, 0, sizeof(mat3Array)); 45 | } 46 | 47 | peripheral.setLocalName("3D Tracker"); 48 | peripheral.setAdvertisedServiceUuid(coordinatesService.uuid()); 49 | 50 | peripheral.addAttribute(coordinatesService); 51 | peripheral.addAttribute(coordinatesCharacteristic); 52 | 53 | peripheral.addAttribute(baseStationGeometryService); 54 | peripheral.addAttribute(stationNumberCharacteristic); 55 | peripheral.addAttribute(positionCharacteristic); 56 | peripheral.addAttribute(rotation1RowCharacteristic); 57 | peripheral.addAttribute(rotation2RowCharacteristic); 58 | peripheral.addAttribute(rotation3RowCharacteristic); 59 | 60 | stationNumberCharacteristic.setEventHandler(BLEWritten, charStationNumberWritten); 61 | positionCharacteristic.setEventHandler(BLEWritten, charPositionWritten); 62 | rotation1RowCharacteristic.setEventHandler(BLEWritten, charRotationWritten); 63 | rotation2RowCharacteristic.setEventHandler(BLEWritten, charRotationWritten); 64 | rotation3RowCharacteristic.setEventHandler(BLEWritten, charRotationWritten); 65 | 66 | peripheral.begin(); 67 | } 68 | 69 | void Bluetooth::stationNumberWritten(BLECentral ¢ral, BLECharacteristic &characteristic) { 70 | uint8_t value = characteristic.value()[0]; 71 | 72 | if(value < baseStationsCount && characteristic.valueLength() == sizeof(uint8_t)) { 73 | // set the new written base station index 74 | baseStationIndex = value; 75 | 76 | // update characteristic values 77 | setPositionCharValueByIndex(); 78 | setRotationCharValueByIndex(); 79 | } else { 80 | // restore the previous base station index 81 | stationNumberCharacteristic.setValue(baseStationIndex); 82 | } 83 | } 84 | 85 | void Bluetooth::positionWritten(BLECentral ¢ral, BLECharacteristic &characteristic) { 86 | if(characteristic.valueLength() == sizeof(Vec3)) { 87 | // set the new written position to the base station 88 | Vec3 vec = positionCharacteristic.value(); 89 | memcpy(baseStations[baseStationIndex].origin, &vec, sizeof(Vec3)); 90 | } else { 91 | // restore the previous position from base station 92 | setPositionCharValueByIndex(); 93 | } 94 | } 95 | 96 | void Bluetooth::rotationWritten(BLECentral ¢ral, BLECharacteristic &characteristic) { 97 | if(characteristic.valueLength() != sizeof(Vec3)) { 98 | // restore the previous rotation from base station 99 | setRotationCharValueByIndex(); 100 | 101 | return; 102 | } 103 | 104 | int rot1Row = memcmp(characteristic.uuid(), rotation1RowCharacteristic.uuid(), 16); 105 | int rot2Row = memcmp(characteristic.uuid(), rotation2RowCharacteristic.uuid(), 16); 106 | int rot3Row = memcmp(characteristic.uuid(), rotation3RowCharacteristic.uuid(), 16); 107 | 108 | if(rot1Row == 0) { 109 | Vec3 rot1 = rotation1RowCharacteristic.value(); 110 | setRowToRotationMatrix(0, rot1); 111 | } else if(rot2Row == 0) { 112 | Vec3 rot2 = rotation2RowCharacteristic.value(); 113 | setRowToRotationMatrix(1, rot2); 114 | } else if(rot3Row == 0) { 115 | Vec3 rot3 = rotation3RowCharacteristic.value(); 116 | setRowToRotationMatrix(2, rot3); 117 | } 118 | 119 | // if base station's geometry is set then propagate new geometry 120 | for(uint8_t b = 0; b < baseStationsCount; b++) { 121 | if(!baseStations[b].isSet()) { 122 | return; 123 | } 124 | } 125 | stationCb(baseStations); 126 | } 127 | 128 | void Bluetooth::setPositionCharValueByIndex(void) { 129 | float32_t x = baseStations[baseStationIndex].origin[0]; 130 | float32_t y = baseStations[baseStationIndex].origin[1]; 131 | float32_t z = baseStations[baseStationIndex].origin[2]; 132 | positionCharacteristic.setValue({x, y, z}); 133 | } 134 | 135 | void Bluetooth::setRotationCharValueByIndex(void) { 136 | unsigned char* pRot = (unsigned char*) baseStations[baseStationIndex].rotationMatrix; 137 | Vec3 row1; 138 | Vec3 row2; 139 | Vec3 row3; 140 | memcpy(&row1, pRot, sizeof(Vec3)); 141 | memcpy(&row2, pRot + sizeof(Vec3), sizeof(Vec3)); 142 | memcpy(&row3, pRot + 2 * sizeof(Vec3), sizeof(Vec3)); 143 | rotation1RowCharacteristic.setValue(row1); 144 | rotation2RowCharacteristic.setValue(row2); 145 | rotation3RowCharacteristic.setValue(row3); 146 | } 147 | 148 | void Bluetooth::setRowToRotationMatrix(uint8_t rowNum, Vec3 row) { 149 | unsigned char* pRot = (unsigned char*) baseStations[baseStationIndex].rotationMatrix; 150 | uint8_t j = 0; 151 | for(uint8_t i = rowNum * sizeof(Vec3); i < rowNum * sizeof(Vec3) + sizeof(Vec3); i++) { 152 | pRot[i] = ((unsigned char*) &row)[j++]; 153 | } 154 | } -------------------------------------------------------------------------------- /firmware/src/tracker_gpio.cpp: -------------------------------------------------------------------------------- 1 | #include "tracker_gpio.h" 2 | 3 | void pinMode(GPIO_PIN pin, uint32_t mode) { 4 | if(!(pin.port == 0 || pin.port == 1) || pin.number > 31) { // nRF52840 has P0 or P1 with pin 0 - 31 5 | return; 6 | } 7 | 8 | switch(mode) { 9 | case INPUT: 10 | if(pin.port == 0) { 11 | NRF_GPIO->PIN_CNF[pin.number] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) 12 | | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) 13 | | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) 14 | | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) 15 | | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); 16 | } else { 17 | NRF_P1->PIN_CNF[pin.number] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) 18 | | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) 19 | | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) 20 | | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) 21 | | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); 22 | } 23 | break; 24 | 25 | case INPUT_PULLUP: 26 | if(pin.port == 0) { 27 | NRF_GPIO->PIN_CNF[pin.number] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) 28 | | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) 29 | | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) 30 | | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) 31 | | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); 32 | } else { 33 | NRF_P1->PIN_CNF[pin.number] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) 34 | | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) 35 | | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) 36 | | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) 37 | | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); 38 | } 39 | break; 40 | 41 | case INPUT_PULLDOWN: 42 | if(pin.port == 0) { 43 | NRF_GPIO->PIN_CNF[pin.number] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) 44 | | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) 45 | | ((uint32_t)GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos) 46 | | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) 47 | | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); 48 | } else { 49 | NRF_P1->PIN_CNF[pin.number] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) 50 | | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) 51 | | ((uint32_t)GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos) 52 | | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) 53 | | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); 54 | } 55 | break; 56 | 57 | case OUTPUT: 58 | if(pin.port == 0) { 59 | NRF_GPIO->PIN_CNF[pin.number] = ((uint32_t)GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) 60 | | ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) 61 | | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) 62 | | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) 63 | | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); 64 | } else { 65 | NRF_P1->PIN_CNF[pin.number] = ((uint32_t)GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) 66 | | ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) 67 | | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) 68 | | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) 69 | | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos); 70 | } 71 | break; 72 | } 73 | } 74 | 75 | void digitalWrite(GPIO_PIN pin, uint32_t value) { 76 | if(!(pin.port == 0 || pin.port == 1) || pin.number > 31) { // nRF52840 has P0 or P1 with pin 0 - 31 77 | return; 78 | } 79 | 80 | switch (value) { 81 | case LOW: 82 | if(pin.port == 0) { 83 | NRF_GPIO->OUTCLR = (1UL << pin.number); 84 | } else { 85 | NRF_P1->OUTCLR = (1UL << pin.number); 86 | } 87 | return; 88 | 89 | default: 90 | if(pin.port == 0) { 91 | NRF_GPIO->OUTSET = (1UL << pin.number); 92 | } else { 93 | NRF_P1->OUTSET = (1UL << pin.number); 94 | } 95 | return; 96 | } 97 | } 98 | 99 | int digitalRead(GPIO_PIN pin) { 100 | if(!(pin.port == 0 || pin.port == 1) || pin.number > 31) { // nRF52840 has P0 or P1 with pin 0 - 31 101 | return 0; 102 | } 103 | 104 | if(pin.port == 0) { 105 | return ((NRF_GPIO->IN >> pin.number) & 1UL) ? HIGH : LOW; 106 | } else { 107 | return ((NRF_P1->IN >> pin.number) & 1UL) ? HIGH : LOW; 108 | } 109 | } -------------------------------------------------------------------------------- /firmware/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tracker_gpio.h" 5 | #include "position_calculator.h" 6 | #include "pulse_processor.h" 7 | #include "bluetooth.h" 8 | #include "led_driver.h" 9 | 10 | 11 | void anglesCb(float32_t *angles); 12 | void baseStationGeometryCB(BaseStation *baseStations); 13 | 14 | PulseProcessor pulseProcessor(anglesCb); 15 | PositionCalculator positionCalculator = PositionCalculator(); 16 | Bluetooth* bluetooth = Bluetooth::getInstance(); 17 | LedDriver ledDriver = LedDriver(); 18 | 19 | const uint16_t MAX_POSITION_UPDATE_DELAY = 1000; // 1s 20 | const uint16_t LIGHT_TIMEOUT = 500; // 500 ms 21 | uint32_t lastPositionUpdateMillis; 22 | bool receivingCoordinates = false; 23 | bool lightDetected = false; 24 | 25 | 26 | extern "C" { //important; otherwise irq handler won't be called 27 | void GPIOTE_IRQHandler(void) { 28 | if(NRF_GPIOTE->EVENTS_IN[0] != 0) { 29 | NRF_GPIOTE->EVENTS_IN[0] = 0; 30 | // raising edge 31 | lightDetected = true; 32 | } 33 | 34 | if(NRF_GPIOTE->EVENTS_IN[1] != 0) { 35 | NRF_GPIOTE->EVENTS_IN[1] = 0; 36 | // falling edge 37 | uint32_t raising_time = NRF_TIMER1->CC[0]; 38 | uint32_t falling_time = NRF_TIMER1->CC[1]; 39 | uint32_t pulse_length_ticks = falling_time - raising_time; 40 | 41 | Pulse pulse = {raising_time, pulse_length_ticks}; 42 | pulseProcessor.addPulse(pulse); 43 | } 44 | } 45 | } 46 | 47 | void anglesCb(float32_t *angles) { 48 | vec3d xyz; 49 | uint8_t result = positionCalculator.calcPosition(angles, xyz); 50 | 51 | switch(result) { 52 | case CALCULATION_SUCCESS: 53 | lastPositionUpdateMillis = millis(); 54 | bluetooth->sendPosition(xyz); 55 | ledDriver.showTracking(); 56 | receivingCoordinates = true; 57 | 58 | #ifdef DEBUG 59 | Serial.print(xyz[0], 6); 60 | Serial.print(" "); 61 | Serial.print(xyz[1], 6); 62 | Serial.print(" "); 63 | Serial.println(xyz[2], 6); 64 | #endif 65 | break; 66 | case BASESTATIONS_NOT_SET: 67 | ledDriver.showGeometryNotSet(); 68 | receivingCoordinates = false; 69 | break; 70 | case CALCULATION_FAILED: 71 | ledDriver.showFailed(); 72 | receivingCoordinates = false; 73 | break; 74 | } 75 | } 76 | 77 | void baseStationGeometryCB(BaseStation *baseStations) { 78 | positionCalculator.setBaseStationsGeometry(baseStations[0], baseStations[1]); 79 | // clear state showing that geometry is not set 80 | receivingCoordinates = true; 81 | ledDriver.showTracking(); 82 | } 83 | 84 | bool waitForLight(uint16_t timeout) { 85 | uint32_t startTime = millis(); 86 | 87 | while(millis() - startTime < timeout) { 88 | if(lightDetected) { 89 | return true; 90 | } 91 | } 92 | 93 | return false; 94 | } 95 | 96 | void setup() { 97 | Serial.setPins(A_PIN_UART_RX, A_PIN_UART_TX); 98 | Serial.begin(115200); 99 | 100 | bluetooth->setBaseStationGeometryCB(baseStationGeometryCB); 101 | bluetooth->setup(); 102 | ledDriver.setup(); 103 | 104 | // set pull-down for button to prevent accidental damage 105 | // the button is not used for now 106 | pinMode(PIN_BTN1, INPUT_PULLDOWN); 107 | 108 | // setting GPIOTE channels for raising and falling edge 109 | uint8_t pin_D = PIN_D_TS4231.number; 110 | uint8_t port_pin_D = PIN_D_TS4231.port; 111 | uint8_t gpiote_channel_raising = 0; 112 | uint8_t gpiote_channel_falling = 1; 113 | NRF_GPIOTE->CONFIG[gpiote_channel_raising] = ((uint32_t) GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) 114 | | ((uint32_t) pin_D << GPIOTE_CONFIG_PSEL_Pos) 115 | | ((uint32_t) port_pin_D << 13UL) // Bit PORT starts at 13, could be skipped 116 | | ((uint32_t) GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos); 117 | NRF_GPIOTE->CONFIG[gpiote_channel_falling] = ((uint32_t) GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) 118 | | ((uint32_t) pin_D << GPIOTE_CONFIG_PSEL_Pos) 119 | | ((uint32_t) port_pin_D << 13UL) // Bit PORT starts at 13, could be skipped 120 | | ((uint32_t) GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos); 121 | NRF_GPIOTE->INTENSET = ((uint32_t) GPIOTE_INTENSET_IN0_Enabled << GPIOTE_INTENSET_IN0_Pos) 122 | | ((uint32_t) GPIOTE_INTENSET_IN1_Enabled << GPIOTE_INTENSET_IN1_Pos); 123 | NVIC_EnableIRQ(GPIOTE_IRQn); 124 | 125 | // config TIMER1 for capturing timestamps of rising and falling edges from GPIOTE 126 | NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer; 127 | NRF_TIMER1->PRESCALER = 0; // 16MHz 128 | NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_32Bit; 129 | 130 | // config PPI for transfering events of rising/falling edge on pin D to TIMER1 for capturing timestamps 131 | NRF_PPI->CH[gpiote_channel_raising].EEP = (uint32_t) &NRF_GPIOTE->EVENTS_IN[gpiote_channel_raising]; 132 | NRF_PPI->CH[gpiote_channel_raising].TEP = (uint32_t) &NRF_TIMER1->TASKS_CAPTURE[gpiote_channel_raising]; 133 | NRF_PPI->CH[gpiote_channel_falling].EEP = (uint32_t) &NRF_GPIOTE->EVENTS_IN[gpiote_channel_falling]; 134 | NRF_PPI->CH[gpiote_channel_falling].TEP = (uint32_t) &NRF_TIMER1->TASKS_CAPTURE[gpiote_channel_falling]; 135 | NRF_PPI->CHENSET = ((uint32_t) PPI_CHENSET_CH0_Enabled << PPI_CHENSET_CH0_Pos) 136 | | ((uint32_t) PPI_CHENSET_CH1_Enabled << PPI_CHENSET_CH1_Pos); 137 | 138 | // start TIMER1 139 | NRF_TIMER1->TASKS_START = 1; 140 | 141 | if(!waitForLight(LIGHT_TIMEOUT)) { 142 | ledDriver.showFailed(); 143 | } else { 144 | ledDriver.showGeometryNotSet(); 145 | } 146 | } 147 | 148 | void loop() { 149 | pulseProcessor.loop(); 150 | bluetooth->poll(); 151 | ledDriver.loop(); 152 | 153 | if(receivingCoordinates && (millis() - lastPositionUpdateMillis) > MAX_POSITION_UPDATE_DELAY) { 154 | // tracker was occluded 155 | ledDriver.showTrackingTimeout(); 156 | } 157 | } -------------------------------------------------------------------------------- /hardware/3D-tracker.brd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | - 164 | SWC 165 | SWD 166 | RST 167 | 3V3 168 | GND 169 | 3V3 170 | GND 171 | AI4 172 | AI5 173 | AI6 174 | AI3 175 | D 176 | E 177 | Martin Donát - 2019 178 | 3D Tracker compatible with HTC Vive 179 | 180 | 181 | 182 | Generated from <b>ts4231-breakout-module.sch</b><p> 183 | by exp-lbrs.ulp 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | >NAME 215 | >VALUE 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | >NAME 244 | >VALUE 245 | 246 | 247 | 248 | 249 | <b>Resistors, Capacitors, Inductors</b><p> 250 | Based on the previous libraries: 251 | <ul> 252 | <li>r.lbr 253 | <li>cap.lbr 254 | <li>cap-fe.lbr 255 | <li>captant.lbr 256 | <li>polcap.lbr 257 | <li>ipc-smd.lbr 258 | </ul> 259 | All SMD packages are defined according to the IPC specifications and CECC<p> 260 | <author>Created by librarian@cadsoft.de</author><p> 261 | <p> 262 | for Electrolyt Capacitors see also :<p> 263 | www.bccomponents.com <p> 264 | www.panasonic.com<p> 265 | www.kemet.com<p> 266 | <p> 267 | for trimmer refence see : <u>www.electrospec-inc.com/cross_references/trimpotcrossref.asp</u><p> 268 | 269 | <map name="nav_main"> 270 | <area shape="rect" coords="0,1,140,23" href="../military_specs.asp" title=""> 271 | <area shape="rect" coords="0,24,140,51" href="../about.asp" title=""> 272 | <area shape="rect" coords="1,52,140,77" href="../rfq.asp" title=""> 273 | <area shape="rect" coords="0,78,139,103" href="../products.asp" title=""> 274 | <area shape="rect" coords="1,102,138,128" href="../excess_inventory.asp" title=""> 275 | <area shape="rect" coords="1,129,138,150" href="../edge.asp" title=""> 276 | <area shape="rect" coords="1,151,139,178" href="../industry_links.asp" title=""> 277 | <area shape="rect" coords="0,179,139,201" href="../comments.asp" title=""> 278 | <area shape="rect" coords="1,203,138,231" href="../directory.asp" title=""> 279 | <area shape="default" nohref> 280 | </map> 281 | 282 | <html> 283 | 284 | <title></title> 285 | 286 | <LINK REL="StyleSheet" TYPE="text/css" HREF="style-sheet.css"> 287 | 288 | <body bgcolor="#ffffff" text="#000000" marginwidth="0" marginheight="0" topmargin="0" leftmargin="0"> 289 | <table border=0 cellspacing=0 cellpadding=0 width="100%" cellpaddding=0 height="55%"> 290 | <tr valign="top"> 291 | 292 | </td> 293 | <! <td width="10">&nbsp;</td> 294 | <td width="90%"> 295 | 296 | <b><font color="#0000FF" size="4">TRIM-POT CROSS REFERENCE</font></b> 297 | <P> 298 | <TABLE BORDER=0 CELLSPACING=1 CELLPADDING=2> 299 | <TR> 300 | <TD COLSPAN=8> 301 | <FONT SIZE=3 FACE=ARIAL><B>RECTANGULAR MULTI-TURN</B></FONT> 302 | </TD> 303 | </TR> 304 | <TR> 305 | <TD ALIGN=CENTER> 306 | <B> 307 | <FONT SIZE=3 FACE=ARIAL color="#FF0000">BOURNS</FONT> 308 | </B> 309 | </TD> 310 | <TD ALIGN=CENTER> 311 | <B> 312 | <FONT SIZE=3 FACE=ARIAL color="#FF0000">BI&nbsp;TECH</FONT> 313 | </B> 314 | </TD> 315 | <TD ALIGN=CENTER> 316 | <B> 317 | <FONT SIZE=3 FACE=ARIAL color="#FF0000">DALE-VISHAY</FONT> 318 | </B> 319 | </TD> 320 | <TD ALIGN=CENTER> 321 | <B> 322 | <FONT SIZE=3 FACE=ARIAL color="#FF0000">PHILIPS/MEPCO</FONT> 323 | </B> 324 | </TD> 325 | <TD ALIGN=CENTER> 326 | <B> 327 | <FONT SIZE=3 FACE=ARIAL color="#FF0000">MURATA</FONT> 328 | </B> 329 | </TD> 330 | <TD ALIGN=CENTER> 331 | <B> 332 | <FONT SIZE=3 FACE=ARIAL color="#FF0000">PANASONIC</FONT> 333 | </B> 334 | </TD> 335 | <TD ALIGN=CENTER> 336 | <B> 337 | <FONT SIZE=3 FACE=ARIAL color="#FF0000">SPECTROL</FONT> 338 | </B> 339 | </TD> 340 | <TD ALIGN=CENTER> 341 | <B> 342 | <FONT SIZE=3 FACE=ARIAL color="#FF0000">MILSPEC</FONT> 343 | </B> 344 | </TD><TD>&nbsp;</TD> 345 | </TR> 346 | <TR> 347 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3 > 348 | 3005P<BR> 349 | 3006P<BR> 350 | 3006W<BR> 351 | 3006Y<BR> 352 | 3009P<BR> 353 | 3009W<BR> 354 | 3009Y<BR> 355 | 3057J<BR> 356 | 3057L<BR> 357 | 3057P<BR> 358 | 3057Y<BR> 359 | 3059J<BR> 360 | 3059L<BR> 361 | 3059P<BR> 362 | 3059Y<BR></FONT> 363 | </TD> 364 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 365 | -<BR> 366 | 89P<BR> 367 | 89W<BR> 368 | 89X<BR> 369 | 89PH<BR> 370 | 76P<BR> 371 | 89XH<BR> 372 | 78SLT<BR> 373 | 78L&nbsp;ALT<BR> 374 | 56P&nbsp;ALT<BR> 375 | 78P&nbsp;ALT<BR> 376 | T8S<BR> 377 | 78L<BR> 378 | 56P<BR> 379 | 78P<BR></FONT> 380 | </TD> 381 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 382 | -<BR> 383 | T18/784<BR> 384 | 783<BR> 385 | 781<BR> 386 | -<BR> 387 | -<BR> 388 | -<BR> 389 | 2199<BR> 390 | 1697/1897<BR> 391 | 1680/1880<BR> 392 | 2187<BR> 393 | -<BR> 394 | -<BR> 395 | -<BR> 396 | -<BR></FONT> 397 | </TD> 398 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 399 | -<BR> 400 | 8035EKP/CT20/RJ-20P<BR> 401 | -<BR> 402 | RJ-20X<BR> 403 | -<BR> 404 | -<BR> 405 | -<BR> 406 | 1211L<BR> 407 | 8012EKQ&nbsp;ALT<BR> 408 | 8012EKR&nbsp;ALT<BR> 409 | 1211P<BR> 410 | 8012EKJ<BR> 411 | 8012EKL<BR> 412 | 8012EKQ<BR> 413 | 8012EKR<BR></FONT> 414 | </TD> 415 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 416 | -<BR> 417 | 2101P<BR> 418 | 2101W<BR> 419 | 2101Y<BR> 420 | -<BR> 421 | -<BR> 422 | -<BR> 423 | -<BR> 424 | -<BR> 425 | -<BR> 426 | -<BR> 427 | -<BR> 428 | 2102L<BR> 429 | 2102S<BR> 430 | 2102Y<BR></FONT> 431 | </TD> 432 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 433 | -<BR> 434 | EVMCOG<BR> 435 | -<BR> 436 | -<BR> 437 | -<BR> 438 | -<BR> 439 | -<BR> 440 | -<BR> 441 | -<BR> 442 | -<BR> 443 | -<BR> 444 | -<BR> 445 | -<BR> 446 | -<BR> 447 | -<BR></FONT> 448 | </TD> 449 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 450 | -<BR> 451 | 43P<BR> 452 | 43W<BR> 453 | 43Y<BR> 454 | -<BR> 455 | -<BR> 456 | -<BR> 457 | -<BR> 458 | 40L<BR> 459 | 40P<BR> 460 | 40Y<BR> 461 | 70Y-T602<BR> 462 | 70L<BR> 463 | 70P<BR> 464 | 70Y<BR></FONT> 465 | </TD> 466 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 467 | -<BR> 468 | -<BR> 469 | -<BR> 470 | -<BR> 471 | -<BR> 472 | -<BR> 473 | -<BR> 474 | -<BR> 475 | RT/RTR12<BR> 476 | RT/RTR12<BR> 477 | RT/RTR12<BR> 478 | -<BR> 479 | RJ/RJR12<BR> 480 | RJ/RJR12<BR> 481 | RJ/RJR12<BR></FONT> 482 | </TD> 483 | </TR> 484 | <TR> 485 | <TD COLSPAN=8>&nbsp; 486 | </TD> 487 | </TR> 488 | <TR> 489 | <TD COLSPAN=8> 490 | <FONT SIZE=4 FACE=ARIAL><B>SQUARE MULTI-TURN</B></FONT> 491 | </TD> 492 | </TR> 493 | <TR> 494 | <TD ALIGN=CENTER> 495 | <FONT SIZE=3 FACE=ARIAL><B>BOURN</B></FONT> 496 | </TD> 497 | <TD ALIGN=CENTER> 498 | <FONT SIZE=3 FACE=ARIAL><B>BI&nbsp;TECH</B></FONT> 499 | </TD> 500 | <TD ALIGN=CENTER> 501 | <FONT SIZE=3 FACE=ARIAL><B>DALE-VISHAY</B></FONT> 502 | </TD> 503 | <TD ALIGN=CENTER> 504 | <FONT SIZE=3 FACE=ARIAL><B>PHILIPS/MEPCO</B></FONT> 505 | </TD> 506 | <TD ALIGN=CENTER> 507 | <FONT SIZE=3 FACE=ARIAL><B>MURATA</B></FONT> 508 | </TD> 509 | <TD ALIGN=CENTER> 510 | <FONT SIZE=3 FACE=ARIAL><B>PANASONIC</B></FONT> 511 | </TD> 512 | <TD ALIGN=CENTER> 513 | <FONT SIZE=3 FACE=ARIAL><B>SPECTROL</B></FONT> 514 | </TD> 515 | <TD ALIGN=CENTER> 516 | <FONT SIZE=3 FACE=ARIAL><B>MILSPEC</B></FONT> 517 | </TD> 518 | </TR> 519 | <TR> 520 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 521 | 3250L<BR> 522 | 3250P<BR> 523 | 3250W<BR> 524 | 3250X<BR> 525 | 3252P<BR> 526 | 3252W<BR> 527 | 3252X<BR> 528 | 3260P<BR> 529 | 3260W<BR> 530 | 3260X<BR> 531 | 3262P<BR> 532 | 3262W<BR> 533 | 3262X<BR> 534 | 3266P<BR> 535 | 3266W<BR> 536 | 3266X<BR> 537 | 3290H<BR> 538 | 3290P<BR> 539 | 3290W<BR> 540 | 3292P<BR> 541 | 3292W<BR> 542 | 3292X<BR> 543 | 3296P<BR> 544 | 3296W<BR> 545 | 3296X<BR> 546 | 3296Y<BR> 547 | 3296Z<BR> 548 | 3299P<BR> 549 | 3299W<BR> 550 | 3299X<BR> 551 | 3299Y<BR> 552 | 3299Z<BR></FONT> 553 | </TD> 554 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 555 | -<BR> 556 | 66P&nbsp;ALT<BR> 557 | 66W&nbsp;ALT<BR> 558 | 66X&nbsp;ALT<BR> 559 | 66P&nbsp;ALT<BR> 560 | 66W&nbsp;ALT<BR> 561 | 66X&nbsp;ALT<BR> 562 | -<BR> 563 | 64W&nbsp;ALT<BR> 564 | -<BR> 565 | 64P&nbsp;ALT<BR> 566 | 64W&nbsp;ALT<BR> 567 | 64X&nbsp;ALT<BR> 568 | 64P<BR> 569 | 64W<BR> 570 | 64X<BR> 571 | 66X&nbsp;ALT<BR> 572 | 66P&nbsp;ALT<BR> 573 | 66W&nbsp;ALT<BR> 574 | 66P<BR> 575 | 66W<BR> 576 | 66X<BR> 577 | 67P<BR> 578 | 67W<BR> 579 | 67X<BR> 580 | 67Y<BR> 581 | 67Z<BR> 582 | 68P<BR> 583 | 68W<BR> 584 | 68X<BR> 585 | 67Y&nbsp;ALT<BR> 586 | 67Z&nbsp;ALT<BR></FONT> 587 | </TD> 588 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 589 | 5050<BR> 590 | 5091<BR> 591 | 5080<BR> 592 | 5087<BR> 593 | -<BR> 594 | -<BR> 595 | -<BR> 596 | -<BR> 597 | -<BR> 598 | -<BR> 599 | -<BR> 600 | T63YB<BR> 601 | T63XB<BR> 602 | -<BR> 603 | -<BR> 604 | -<BR> 605 | 5887<BR> 606 | 5891<BR> 607 | 5880<BR> 608 | -<BR> 609 | -<BR> 610 | -<BR> 611 | T93Z<BR> 612 | T93YA<BR> 613 | T93XA<BR> 614 | T93YB<BR> 615 | T93XB<BR> 616 | -<BR> 617 | -<BR> 618 | -<BR> 619 | -<BR> 620 | -<BR></FONT> 621 | </TD> 622 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 623 | -<BR> 624 | -<BR> 625 | -<BR> 626 | -<BR> 627 | -<BR> 628 | -<BR> 629 | -<BR> 630 | -<BR> 631 | -<BR> 632 | -<BR> 633 | 8026EKP<BR> 634 | 8026EKW<BR> 635 | 8026EKM<BR> 636 | 8026EKP<BR> 637 | 8026EKB<BR> 638 | 8026EKM<BR> 639 | 1309X<BR> 640 | 1309P<BR> 641 | 1309W<BR> 642 | 8024EKP<BR> 643 | 8024EKW<BR> 644 | 8024EKN<BR> 645 | RJ-9P/CT9P<BR> 646 | RJ-9W<BR> 647 | RJ-9X<BR> 648 | -<BR> 649 | -<BR> 650 | -<BR> 651 | -<BR> 652 | -<BR> 653 | -<BR> 654 | -<BR></FONT> 655 | </TD> 656 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 657 | -<BR> 658 | -<BR> 659 | -<BR> 660 | -<BR> 661 | -<BR> 662 | -<BR> 663 | -<BR> 664 | -<BR> 665 | -<BR> 666 | -<BR> 667 | 3103P<BR> 668 | 3103Y<BR> 669 | 3103Z<BR> 670 | 3103P<BR> 671 | 3103Y<BR> 672 | 3103Z<BR> 673 | -<BR> 674 | -<BR> 675 | -<BR> 676 | -<BR> 677 | -<BR> 678 | -<BR> 679 | 3105P/3106P<BR> 680 | 3105W/3106W<BR> 681 | 3105X/3106X<BR> 682 | 3105Y/3106Y<BR> 683 | 3105Z/3105Z<BR> 684 | 3102P<BR> 685 | 3102W<BR> 686 | 3102X<BR> 687 | 3102Y<BR> 688 | 3102Z<BR></FONT> 689 | </TD> 690 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 691 | -<BR> 692 | -<BR> 693 | -<BR> 694 | -<BR> 695 | -<BR> 696 | -<BR> 697 | -<BR> 698 | -<BR> 699 | -<BR> 700 | -<BR> 701 | -<BR> 702 | -<BR> 703 | -<BR> 704 | -<BR> 705 | -<BR> 706 | -<BR> 707 | -<BR> 708 | -<BR> 709 | -<BR> 710 | -<BR> 711 | -<BR> 712 | -<BR> 713 | EVMCBG<BR> 714 | EVMCCG<BR> 715 | -<BR> 716 | -<BR> 717 | -<BR> 718 | -<BR> 719 | -<BR> 720 | -<BR> 721 | -<BR> 722 | -<BR></FONT> 723 | </TD> 724 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 725 | 55-1-X<BR> 726 | 55-4-X<BR> 727 | 55-3-X<BR> 728 | 55-2-X<BR> 729 | -<BR> 730 | -<BR> 731 | -<BR> 732 | -<BR> 733 | -<BR> 734 | -<BR> 735 | -<BR> 736 | -<BR> 737 | -<BR> 738 | -<BR> 739 | -<BR> 740 | -<BR> 741 | 50-2-X<BR> 742 | 50-4-X<BR> 743 | 50-3-X<BR> 744 | -<BR> 745 | -<BR> 746 | -<BR> 747 | 64P<BR> 748 | 64W<BR> 749 | 64X<BR> 750 | 64Y<BR> 751 | 64Z<BR> 752 | -<BR> 753 | -<BR> 754 | -<BR> 755 | -<BR> 756 | -<BR></FONT> 757 | </TD> 758 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 759 | RT/RTR22<BR> 760 | RT/RTR22<BR> 761 | RT/RTR22<BR> 762 | RT/RTR22<BR> 763 | RJ/RJR22<BR> 764 | RJ/RJR22<BR> 765 | RJ/RJR22<BR> 766 | RT/RTR26<BR> 767 | RT/RTR26<BR> 768 | RT/RTR26<BR> 769 | RJ/RJR26<BR> 770 | RJ/RJR26<BR> 771 | RJ/RJR26<BR> 772 | RJ/RJR26<BR> 773 | RJ/RJR26<BR> 774 | RJ/RJR26<BR> 775 | RT/RTR24<BR> 776 | RT/RTR24<BR> 777 | RT/RTR24<BR> 778 | RJ/RJR24<BR> 779 | RJ/RJR24<BR> 780 | RJ/RJR24<BR> 781 | RJ/RJR24<BR> 782 | RJ/RJR24<BR> 783 | RJ/RJR24<BR> 784 | -<BR> 785 | -<BR> 786 | -<BR> 787 | -<BR> 788 | -<BR> 789 | -<BR> 790 | -<BR></FONT> 791 | </TD> 792 | </TR> 793 | <TR> 794 | <TD COLSPAN=8>&nbsp; 795 | </TD> 796 | </TR> 797 | <TR> 798 | <TD COLSPAN=8> 799 | <FONT SIZE=4 FACE=ARIAL><B>SINGLE TURN</B></FONT> 800 | </TD> 801 | </TR> 802 | <TR> 803 | <TD ALIGN=CENTER> 804 | <FONT SIZE=3 FACE=ARIAL><B>BOURN</B></FONT> 805 | </TD> 806 | <TD ALIGN=CENTER> 807 | <FONT SIZE=3 FACE=ARIAL><B>BI&nbsp;TECH</B></FONT> 808 | </TD> 809 | <TD ALIGN=CENTER> 810 | <FONT SIZE=3 FACE=ARIAL><B>DALE-VISHAY</B></FONT> 811 | </TD> 812 | <TD ALIGN=CENTER> 813 | <FONT SIZE=3 FACE=ARIAL><B>PHILIPS/MEPCO</B></FONT> 814 | </TD> 815 | <TD ALIGN=CENTER> 816 | <FONT SIZE=3 FACE=ARIAL><B>MURATA</B></FONT> 817 | </TD> 818 | <TD ALIGN=CENTER> 819 | <FONT SIZE=3 FACE=ARIAL><B>PANASONIC</B></FONT> 820 | </TD> 821 | <TD ALIGN=CENTER> 822 | <FONT SIZE=3 FACE=ARIAL><B>SPECTROL</B></FONT> 823 | </TD> 824 | <TD ALIGN=CENTER> 825 | <FONT SIZE=3 FACE=ARIAL><B>MILSPEC</B></FONT> 826 | </TD> 827 | </TR> 828 | <TR> 829 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 830 | 3323P<BR> 831 | 3323S<BR> 832 | 3323W<BR> 833 | 3329H<BR> 834 | 3329P<BR> 835 | 3329W<BR> 836 | 3339H<BR> 837 | 3339P<BR> 838 | 3339W<BR> 839 | 3352E<BR> 840 | 3352H<BR> 841 | 3352K<BR> 842 | 3352P<BR> 843 | 3352T<BR> 844 | 3352V<BR> 845 | 3352W<BR> 846 | 3362H<BR> 847 | 3362M<BR> 848 | 3362P<BR> 849 | 3362R<BR> 850 | 3362S<BR> 851 | 3362U<BR> 852 | 3362W<BR> 853 | 3362X<BR> 854 | 3386B<BR> 855 | 3386C<BR> 856 | 3386F<BR> 857 | 3386H<BR> 858 | 3386K<BR> 859 | 3386M<BR> 860 | 3386P<BR> 861 | 3386S<BR> 862 | 3386W<BR> 863 | 3386X<BR></FONT> 864 | </TD> 865 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 866 | 25P<BR> 867 | 25S<BR> 868 | 25RX<BR> 869 | 82P<BR> 870 | 82M<BR> 871 | 82PA<BR> 872 | -<BR> 873 | -<BR> 874 | -<BR> 875 | 91E<BR> 876 | 91X<BR> 877 | 91T<BR> 878 | 91B<BR> 879 | 91A<BR> 880 | 91V<BR> 881 | 91W<BR> 882 | 25W<BR> 883 | 25V<BR> 884 | 25P<BR> 885 | -<BR> 886 | 25S<BR> 887 | 25U<BR> 888 | 25RX<BR> 889 | 25X<BR> 890 | 72XW<BR> 891 | 72XL<BR> 892 | 72PM<BR> 893 | 72RX<BR> 894 | -<BR> 895 | 72PX<BR> 896 | 72P<BR> 897 | 72RXW<BR> 898 | 72RXL<BR> 899 | 72X<BR></FONT> 900 | </TD> 901 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 902 | -<BR> 903 | -<BR> 904 | -<BR> 905 | T7YB<BR> 906 | T7YA<BR> 907 | -<BR> 908 | -<BR> 909 | -<BR> 910 | -<BR> 911 | -<BR> 912 | -<BR> 913 | -<BR> 914 | -<BR> 915 | -<BR> 916 | -<BR> 917 | -<BR> 918 | -<BR> 919 | TXD<BR> 920 | TYA<BR> 921 | TYP<BR> 922 | -<BR> 923 | TYD<BR> 924 | TX<BR> 925 | -<BR> 926 | 150SX<BR> 927 | 100SX<BR> 928 | 102T<BR> 929 | 101S<BR> 930 | 190T<BR> 931 | 150TX<BR> 932 | 101<BR> 933 | -<BR> 934 | -<BR> 935 | 101SX<BR></FONT> 936 | </TD> 937 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 938 | ET6P<BR> 939 | ET6S<BR> 940 | ET6X<BR> 941 | RJ-6W/8014EMW<BR> 942 | RJ-6P/8014EMP<BR> 943 | RJ-6X/8014EMX<BR> 944 | TM7W<BR> 945 | TM7P<BR> 946 | TM7X<BR> 947 | -<BR> 948 | 8017SMS<BR> 949 | -<BR> 950 | 8017SMB<BR> 951 | 8017SMA<BR> 952 | -<BR> 953 | -<BR> 954 | CT-6W<BR> 955 | CT-6H<BR> 956 | CT-6P<BR> 957 | CT-6R<BR> 958 | -<BR> 959 | CT-6V<BR> 960 | CT-6X<BR> 961 | -<BR> 962 | -<BR> 963 | 8038EKV<BR> 964 | -<BR> 965 | 8038EKX<BR> 966 | -<BR> 967 | -<BR> 968 | 8038EKP<BR> 969 | 8038EKZ<BR> 970 | 8038EKW<BR> 971 | -<BR></FONT> 972 | </TD> 973 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 974 | -<BR> 975 | -<BR> 976 | -<BR> 977 | 3321H<BR> 978 | 3321P<BR> 979 | 3321N<BR> 980 | 1102H<BR> 981 | 1102P<BR> 982 | 1102T<BR> 983 | RVA0911V304A<BR> 984 | -<BR> 985 | RVA0911H413A<BR> 986 | RVG0707V100A<BR> 987 | RVA0607V(H)306A<BR> 988 | RVA1214H213A<BR> 989 | -<BR> 990 | -<BR> 991 | -<BR> 992 | -<BR> 993 | -<BR> 994 | -<BR> 995 | -<BR> 996 | -<BR> 997 | -<BR> 998 | 3104B<BR> 999 | 3104C<BR> 1000 | 3104F<BR> 1001 | 3104H<BR> 1002 | -<BR> 1003 | 3104M<BR> 1004 | 3104P<BR> 1005 | 3104S<BR> 1006 | 3104W<BR> 1007 | 3104X<BR></FONT> 1008 | </TD> 1009 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1010 | EVMQ0G<BR> 1011 | EVMQIG<BR> 1012 | EVMQ3G<BR> 1013 | EVMS0G<BR> 1014 | EVMQ0G<BR> 1015 | EVMG0G<BR> 1016 | -<BR> 1017 | -<BR> 1018 | -<BR> 1019 | EVMK4GA00B<BR> 1020 | EVM30GA00B<BR> 1021 | EVMK0GA00B<BR> 1022 | EVM38GA00B<BR> 1023 | EVMB6<BR> 1024 | EVLQ0<BR> 1025 | -<BR> 1026 | EVMMSG<BR> 1027 | EVMMBG<BR> 1028 | EVMMAG<BR> 1029 | -<BR> 1030 | -<BR> 1031 | EVMMCS<BR> 1032 | -<BR> 1033 | -<BR> 1034 | -<BR> 1035 | -<BR> 1036 | -<BR> 1037 | EVMM1<BR> 1038 | -<BR> 1039 | -<BR> 1040 | EVMM0<BR> 1041 | -<BR> 1042 | -<BR> 1043 | EVMM3<BR></FONT> 1044 | </TD> 1045 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1046 | -<BR> 1047 | -<BR> 1048 | -<BR> 1049 | 62-3-1<BR> 1050 | 62-1-2<BR> 1051 | -<BR> 1052 | -<BR> 1053 | -<BR> 1054 | -<BR> 1055 | -<BR> 1056 | -<BR> 1057 | -<BR> 1058 | -<BR> 1059 | -<BR> 1060 | -<BR> 1061 | -<BR> 1062 | 67R<BR> 1063 | -<BR> 1064 | 67P<BR> 1065 | -<BR> 1066 | -<BR> 1067 | -<BR> 1068 | -<BR> 1069 | 67X<BR> 1070 | 63V<BR> 1071 | 63S<BR> 1072 | 63M<BR> 1073 | -<BR> 1074 | -<BR> 1075 | 63H<BR> 1076 | 63P<BR> 1077 | -<BR> 1078 | -<BR> 1079 | 63X<BR></FONT> 1080 | </TD> 1081 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1082 | -<BR> 1083 | -<BR> 1084 | -<BR> 1085 | RJ/RJR50<BR> 1086 | RJ/RJR50<BR> 1087 | RJ/RJR50<BR> 1088 | -<BR> 1089 | -<BR> 1090 | -<BR> 1091 | -<BR> 1092 | -<BR> 1093 | -<BR> 1094 | -<BR> 1095 | -<BR> 1096 | -<BR> 1097 | -<BR> 1098 | -<BR> 1099 | -<BR> 1100 | -<BR> 1101 | -<BR> 1102 | -<BR> 1103 | -<BR> 1104 | -<BR> 1105 | -<BR> 1106 | -<BR> 1107 | -<BR> 1108 | -<BR> 1109 | -<BR> 1110 | -<BR> 1111 | -<BR> 1112 | -<BR> 1113 | -<BR> 1114 | -<BR> 1115 | -<BR></FONT> 1116 | </TD> 1117 | </TR> 1118 | </TABLE> 1119 | <P>&nbsp;<P> 1120 | <TABLE BORDER=0 CELLSPACING=1 CELLPADDING=3> 1121 | <TR> 1122 | <TD COLSPAN=7> 1123 | <FONT color="#0000FF" SIZE=4 FACE=ARIAL><B>SMD TRIM-POT CROSS REFERENCE</B></FONT> 1124 | <P> 1125 | <FONT SIZE=4 FACE=ARIAL><B>MULTI-TURN</B></FONT> 1126 | </TD> 1127 | </TR> 1128 | <TR> 1129 | <TD> 1130 | <FONT SIZE=3 FACE=ARIAL><B>BOURNS</B></FONT> 1131 | </TD> 1132 | <TD> 1133 | <FONT SIZE=3 FACE=ARIAL><B>BI&nbsp;TECH</B></FONT> 1134 | </TD> 1135 | <TD> 1136 | <FONT SIZE=3 FACE=ARIAL><B>DALE-VISHAY</B></FONT> 1137 | </TD> 1138 | <TD> 1139 | <FONT SIZE=3 FACE=ARIAL><B>PHILIPS/MEPCO</B></FONT> 1140 | </TD> 1141 | <TD> 1142 | <FONT SIZE=3 FACE=ARIAL><B>PANASONIC</B></FONT> 1143 | </TD> 1144 | <TD> 1145 | <FONT SIZE=3 FACE=ARIAL><B>TOCOS</B></FONT> 1146 | </TD> 1147 | <TD> 1148 | <FONT SIZE=3 FACE=ARIAL><B>AUX/KYOCERA</B></FONT> 1149 | </TD> 1150 | </TR> 1151 | <TR> 1152 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1153 | 3224G<BR> 1154 | 3224J<BR> 1155 | 3224W<BR> 1156 | 3269P<BR> 1157 | 3269W<BR> 1158 | 3269X<BR></FONT> 1159 | </TD> 1160 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1161 | 44G<BR> 1162 | 44J<BR> 1163 | 44W<BR> 1164 | 84P<BR> 1165 | 84W<BR> 1166 | 84X<BR></FONT> 1167 | </TD> 1168 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1169 | -<BR> 1170 | -<BR> 1171 | -<BR> 1172 | ST63Z<BR> 1173 | ST63Y<BR> 1174 | -<BR></FONT> 1175 | </TD> 1176 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1177 | -<BR> 1178 | -<BR> 1179 | -<BR> 1180 | ST5P<BR> 1181 | ST5W<BR> 1182 | ST5X<BR></FONT> 1183 | </TD> 1184 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1185 | -<BR> 1186 | -<BR> 1187 | -<BR> 1188 | -<BR> 1189 | -<BR> 1190 | -<BR></FONT> 1191 | </TD> 1192 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1193 | -<BR> 1194 | -<BR> 1195 | -<BR> 1196 | -<BR> 1197 | -<BR> 1198 | -<BR></FONT> 1199 | </TD> 1200 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1201 | -<BR> 1202 | -<BR> 1203 | -<BR> 1204 | -<BR> 1205 | -<BR> 1206 | -<BR></FONT> 1207 | </TD> 1208 | </TR> 1209 | <TR> 1210 | <TD COLSPAN=7>&nbsp; 1211 | </TD> 1212 | </TR> 1213 | <TR> 1214 | <TD COLSPAN=7> 1215 | <FONT SIZE=4 FACE=ARIAL><B>SINGLE TURN</B></FONT> 1216 | </TD> 1217 | </TR> 1218 | <TR> 1219 | <TD> 1220 | <FONT SIZE=3 FACE=ARIAL><B>BOURNS</B></FONT> 1221 | </TD> 1222 | <TD> 1223 | <FONT SIZE=3 FACE=ARIAL><B>BI&nbsp;TECH</B></FONT> 1224 | </TD> 1225 | <TD> 1226 | <FONT SIZE=3 FACE=ARIAL><B>DALE-VISHAY</B></FONT> 1227 | </TD> 1228 | <TD> 1229 | <FONT SIZE=3 FACE=ARIAL><B>PHILIPS/MEPCO</B></FONT> 1230 | </TD> 1231 | <TD> 1232 | <FONT SIZE=3 FACE=ARIAL><B>PANASONIC</B></FONT> 1233 | </TD> 1234 | <TD> 1235 | <FONT SIZE=3 FACE=ARIAL><B>TOCOS</B></FONT> 1236 | </TD> 1237 | <TD> 1238 | <FONT SIZE=3 FACE=ARIAL><B>AUX/KYOCERA</B></FONT> 1239 | </TD> 1240 | </TR> 1241 | <TR> 1242 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1243 | 3314G<BR> 1244 | 3314J<BR> 1245 | 3364A/B<BR> 1246 | 3364C/D<BR> 1247 | 3364W/X<BR> 1248 | 3313G<BR> 1249 | 3313J<BR></FONT> 1250 | </TD> 1251 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1252 | 23B<BR> 1253 | 23A<BR> 1254 | 21X<BR> 1255 | 21W<BR> 1256 | -<BR> 1257 | 22B<BR> 1258 | 22A<BR></FONT> 1259 | </TD> 1260 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1261 | ST5YL/ST53YL<BR> 1262 | ST5YJ/5T53YJ<BR> 1263 | ST-23A<BR> 1264 | ST-22B<BR> 1265 | ST-22<BR> 1266 | -<BR> 1267 | -<BR></FONT> 1268 | </TD> 1269 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1270 | ST-4B<BR> 1271 | ST-4A<BR> 1272 | -<BR> 1273 | -<BR> 1274 | -<BR> 1275 | ST-3B<BR> 1276 | ST-3A<BR></FONT> 1277 | </TD> 1278 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1279 | -<BR> 1280 | EVM-6YS<BR> 1281 | EVM-1E<BR> 1282 | EVM-1G<BR> 1283 | EVM-1D<BR> 1284 | -<BR> 1285 | -<BR></FONT> 1286 | </TD> 1287 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1288 | G4B<BR> 1289 | G4A<BR> 1290 | TR04-3S1<BR> 1291 | TRG04-2S1<BR> 1292 | -<BR> 1293 | -<BR> 1294 | -<BR></FONT> 1295 | </TD> 1296 | <TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3> 1297 | -<BR> 1298 | -<BR> 1299 | DVR-43A<BR> 1300 | CVR-42C<BR> 1301 | CVR-42A/C<BR> 1302 | -<BR> 1303 | -<BR></FONT> 1304 | </TD> 1305 | </TR> 1306 | </TABLE> 1307 | <P> 1308 | <FONT SIZE=4 FACE=ARIAL><B>ALT =&nbsp;ALTERNATE</B></FONT> 1309 | <P> 1310 | 1311 | &nbsp; 1312 | <P> 1313 | </td> 1314 | </tr> 1315 | </table> 1316 | </BODY></HTML> 1317 | 1318 | 1319 | <b>CAPACITOR</b><p> 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | 1328 | >NAME 1329 | >VALUE 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | <b>ELECTROLYTIC CAPACITOR</b><p> 1336 | grid 2.032 mm, diameter 5 mm 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | >NAME 1350 | >VALUE 1351 | 1352 | 1353 | 1354 | <b>RESISTOR</b><p> 1355 | 1356 | 1357 | 1358 | 1359 | 1360 | 1361 | 1362 | 1363 | >NAME 1364 | >VALUE 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | CAPACITOR 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | ELECTROLYTIC CAPACITOR 1379 | grid 2.032 mm, diameter 5 mm 1380 | 1381 | 1382 | 1383 | 1384 | 1385 | RESISTOR 1386 | 1387 | 1388 | 1389 | 1390 | 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 | 1402 | 1403 | >NAME 1404 | >VALUE 1405 | 1406 | 1407 | 1408 | 1409 | 1410 | <b>Small Outline Transistor</b> 1411 | 1412 | 1413 | 1414 | 1415 | 1416 | 1417 | 1418 | 1419 | 3 1420 | 4 1421 | 1 1422 | 2 1423 | >NAME 1424 | >VALUE 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 | 1436 | 1437 | 1438 | 1439 | 1440 | 1441 | 1442 | 1443 | 1444 | 1445 | 1446 | 1447 | 1448 | 1449 | >NAME 1450 | >VALUE 1451 | 1452 | 1453 | 1454 | 1455 | 1456 | 1457 | 1458 | 1459 | 1460 | 1461 | 1462 | 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | 1469 | 1470 | >NAME 1471 | >VALUE 1472 | 1473 | 1474 | 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | 1481 | 1482 | 1483 | 1484 | 1485 | 1486 | 1487 | 1488 | 1489 | 1490 | 1491 | 1492 | 1493 | 1494 | 1495 | >NAME 1496 | >VALUE 1497 | 1498 | 1499 | <h3>20mm Coin Cell Battery (CR2032) Holder - SMD (Single Pad)</h3> 1500 | <p>Part number: CR2032-THM</p> 1501 | <h4>Devices Using</h4> 1502 | <ul><li>BATTERY</li></ul> 1503 | 1504 | 1505 | 1506 | 1507 | 1508 | 1509 | 1510 | 1511 | 1512 | 1513 | 1514 | 1515 | 1516 | 1517 | >NAME 1518 | >VALUE 1519 | 1520 | 1521 | 1522 | 1523 | Imported from Altium Designer&reg; library: E73系列-PcbLib(1).PcbLib 1524 | 1525 | 1526 | 1527 | 1528 | 1529 | 1530 | 1531 | 1532 | 1533 | 1534 | 1535 | 1536 | 1537 | 1538 | 1539 | 1540 | 1541 | 1542 | 1543 | 1544 | 1545 | 1546 | 1547 | 1548 | 1549 | 1550 | 1551 | 1552 | 1553 | 1554 | 1555 | 1556 | 1557 | 1558 | 1559 | 1560 | 1561 | 1562 | 1563 | 1564 | 1565 | 1566 | 1567 | 1568 | 1569 | 1570 | 1571 | 1572 | 1573 | 1574 | 1575 | 1576 | 1577 | 1578 | 1579 | 1580 | 1581 | 1582 | 1583 | 1584 | 1585 | 1586 | 1587 | 1588 | 1589 | 1590 | 1591 | 1592 | 1593 | 1594 | 1595 | 1596 | 1597 | 1598 | 1599 | 1600 | 1601 | 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1610 | 1611 | E73(2G4M08S1C) 1612 | RST 1613 | VBS 1614 | D- 1615 | D+ 1616 | P0.13 1617 | P0.24 1618 | SWD 1619 | SWC 1620 | NF1 1621 | NF2 1622 | P1.06 1623 | P1.04 1624 | P1.02 1625 | P1.00 1626 | P0.22 1627 | P0.20 1628 | P17 1629 | P15 1630 | AI6 1631 | AI7 1632 | AI5 1633 | AI0 1634 | P1.13 1635 | GND 1636 | AI4 1637 | P0.03 1638 | P1.10 1639 | P1.11 1640 | DCH 1641 | VDH 1642 | GND 1643 | VDD 1644 | P1.09 1645 | AI3 1646 | XL2 1647 | XL1 1648 | P0.07 1649 | P12 1650 | AI2 1651 | P0.08 1652 | P0.06 1653 | P0.26 1654 | GND 1655 | >NAME 1656 | >VALUE 1657 | 1658 | 1659 | 1660 | 1661 | 1662 | 1663 | 1664 | 1665 | 1666 | 1667 | 1668 | <b>Pin Header Connectors</b><p> 1669 | <author>Created by librarian@cadsoft.de</author> 1670 | 1671 | 1672 | <b>PIN HEADER</b> 1673 | 1674 | 1675 | 1676 | 1677 | 1678 | 1679 | 1680 | 1681 | 1682 | 1683 | 1684 | 1685 | 1686 | 1687 | 1688 | 1689 | 1690 | >NAME 1691 | >VALUE 1692 | 1693 | 1694 | 1695 | 1696 | <b>PIN HEADER</b> 1697 | 1698 | 1699 | 1700 | 1701 | 1702 | 1703 | 1704 | 1705 | 1706 | 1707 | 1708 | 1709 | 1710 | 1711 | 1712 | 1713 | 1714 | 1715 | 1716 | 1717 | 1718 | 1719 | 1720 | 1721 | 1722 | 1723 | 1724 | 1725 | 1726 | 1727 | 1728 | 1729 | 1730 | 1731 | 1732 | 1733 | 1734 | 1735 | 1736 | 1737 | 1738 | >NAME 1739 | >VALUE 1740 | 1741 | 1742 | 1743 | 1744 | 1745 | 1746 | 1747 | <b>PIN HEADER</b> 1748 | 1749 | 1750 | 1751 | 1752 | 1753 | 1754 | 1755 | 1756 | 1757 | 1758 | 1759 | 1760 | 1761 | 1762 | 1763 | 1764 | 1765 | 1766 | 1767 | 1768 | 1769 | 1770 | 1771 | 1772 | 1773 | 1774 | 1775 | 1776 | 1777 | 1778 | 1779 | 1780 | 1781 | 1782 | 1783 | 1784 | 1785 | 1786 | 1787 | 1788 | 1789 | 1790 | 1791 | 1792 | 1793 | 1794 | 1795 | 1796 | 1797 | >NAME 1798 | >VALUE 1799 | 1800 | 1801 | 1802 | 1803 | 1804 | 1805 | 1806 | 1807 | 1808 | 1809 | PIN HEADER 1810 | 1811 | 1812 | 1813 | 1814 | 1815 | PIN HEADER 1816 | 1817 | 1818 | 1819 | 1820 | 1821 | PIN HEADER 1822 | 1823 | 1824 | 1825 | 1826 | 1827 | 1828 | 1829 | <b>Small Signal Transistors</b><p> 1830 | Packages from :<br> 1831 | www.infineon.com; <br> 1832 | www.semiconductors.com;<br> 1833 | www.irf.com<p> 1834 | <author>Created by librarian@cadsoft.de</author> 1835 | 1836 | 1837 | <b>SOT-23</b> 1838 | 1839 | 1840 | 1841 | 1842 | 1843 | 1844 | 1845 | >NAME 1846 | >VALUE 1847 | 1848 | 1849 | 1850 | 1851 | 1852 | 1853 | 1854 | SOT-23 1855 | 1856 | 1857 | 1858 | 1859 | 1860 | 1861 | 1862 | <b>Jumpers</b><p> 1863 | <author>Created by librarian@cadsoft.de</author> 1864 | 1865 | 1866 | <b>Solder jumper</b> 1867 | 1868 | 1869 | 1870 | 1871 | 1872 | 1873 | 1874 | 1875 | 1876 | 1877 | 1878 | 1879 | 1880 | 1881 | >NAME 1882 | >VALUE 1883 | 1884 | 1885 | 1886 | 1887 | 1888 | Solder jumper 1889 | 1890 | 1891 | 1892 | 1893 | 1894 | 1895 | 1896 | 1897 | 1898 | 1899 | 1900 | 1901 | 1902 | 1903 | 1904 | 1905 | <b>EAGLE Design Rules</b> 1906 | <p> 1907 | Die Standard-Design-Rules sind so gewählt, dass sie für 1908 | die meisten Anwendungen passen. Sollte ihre Platine 1909 | besondere Anforderungen haben, treffen Sie die erforderlichen 1910 | Einstellungen hier und speichern die Design Rules unter 1911 | einem neuen Namen ab. 1912 | <b>EAGLE Design Rules</b> 1913 | <p> 1914 | The default Design Rules have been set to cover 1915 | a wide range of applications. Your particular design 1916 | may have different requirements, so please make the 1917 | necessary adjustments and save your customized 1918 | design rules under a new name. 1919 | 1920 | 1921 | 1922 | 1923 | 1924 | 1925 | 1926 | 1927 | 1928 | 1929 | 1930 | 1931 | 1932 | 1933 | 1934 | 1935 | 1936 | 1937 | 1938 | 1939 | 1940 | 1941 | 1942 | 1943 | 1944 | 1945 | 1946 | 1947 | 1948 | 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1955 | 1956 | 1957 | 1958 | 1959 | 1960 | 1961 | 1962 | 1963 | 1964 | 1965 | 1966 | 1967 | 1968 | 1969 | 1970 | 1971 | 1972 | 1973 | 1974 | 1975 | 1976 | 1977 | 1978 | 1979 | 1980 | 1981 | 1982 | 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 | 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 | 2027 | 2028 | 2029 | 2030 | 2031 | 2032 | 2033 | 2034 | 2035 | 2036 | 2037 | 2038 | 2039 | 2040 | 2041 | 2042 | 2043 | 2044 | 2045 | 2046 | 2047 | 2048 | 2049 | 2050 | 2051 | 2052 | 2053 | 2054 | 2055 | 2056 | 2057 | 2058 | 2059 | 2060 | 2061 | 2062 | 2063 | 2064 | 2065 | 2066 | 2067 | 2068 | 2069 | 2070 | 2071 | 2072 | 2073 | 2074 | 2075 | 2076 | 2077 | 2078 | 2079 | 2080 | 2081 | 2082 | 2083 | 2084 | 2085 | 2086 | 2087 | 2088 | 2089 | 2090 | 2091 | 2092 | 2093 | 2094 | 2095 | 2096 | 2097 | 2098 | 2099 | 2100 | 2101 | 2102 | 2103 | 2104 | 2105 | 2106 | 2107 | 2108 | 2109 | 2110 | 2111 | 2112 | 2113 | 2114 | 2115 | 2116 | 2117 | 2118 | 2119 | 2120 | 2121 | 2122 | 2123 | 2124 | 2125 | 2126 | 2127 | 2128 | 2129 | 2130 | 2131 | 2132 | 2133 | 2134 | 2135 | 2136 | 2137 | 2138 | 2139 | 2140 | 2141 | 2142 | 2143 | 2144 | 2145 | 2146 | 2147 | 2148 | 2149 | 2150 | 2151 | 2152 | 2153 | 2154 | 2155 | 2156 | 2157 | 2158 | 2159 | 2160 | 2161 | 2162 | 2163 | 2164 | 2165 | 2166 | 2167 | 2168 | 2169 | 2170 | 2171 | 2172 | 2173 | 2174 | 2175 | 2176 | 2177 | 2178 | 2179 | 2180 | 2181 | 2182 | 2183 | 2184 | 2185 | 2186 | 2187 | 2188 | 2189 | 2190 | 2191 | 2192 | 2193 | 2194 | 2195 | 2196 | 2197 | 2198 | 2199 | 2200 | 2201 | 2202 | 2203 | 2204 | 2205 | 2206 | 2207 | 2208 | 2209 | 2210 | 2211 | 2212 | 2213 | 2214 | 2215 | 2216 | 2217 | 2218 | 2219 | 2220 | 2221 | 2222 | 2223 | 2224 | 2225 | 2226 | 2227 | 2228 | 2229 | 2230 | 2231 | 2232 | 2233 | 2234 | 2235 | 2236 | 2237 | 2238 | 2239 | 2240 | 2241 | 2242 | 2243 | 2244 | 2245 | 2246 | 2247 | 2248 | 2249 | 2250 | 2251 | 2252 | 2253 | 2254 | 2255 | 2256 | 2257 | 2258 | 2259 | 2260 | 2261 | 2262 | 2263 | 2264 | 2265 | 2266 | 2267 | 2268 | 2269 | 2270 | 2271 | 2272 | 2273 | 2274 | 2275 | 2276 | 2277 | 2278 | 2279 | 2280 | 2281 | 2282 | 2283 | 2284 | 2285 | 2286 | 2287 | 2288 | 2289 | 2290 | 2291 | 2292 | 2293 | 2294 | 2295 | 2296 | 2297 | 2298 | 2299 | 2300 | 2301 | 2302 | 2303 | 2304 | 2305 | 2306 | 2307 | 2308 | 2309 | 2310 | 2311 | 2312 | 2313 | 2314 | 2315 | 2316 | 2317 | 2318 | 2319 | 2320 | 2321 | 2322 | 2323 | 2324 | 2325 | 2326 | 2327 | 2328 | 2329 | 2330 | 2331 | 2332 | 2333 | 2334 | 2335 | 2336 | 2337 | 2338 | 2339 | 2340 | 2341 | 2342 | 2343 | 2344 | 2345 | 2346 | 2347 | 2348 | 2349 | 2350 | 2351 | 2352 | 2353 | 2354 | 2355 | 2356 | 2357 | 2358 | 2359 | 2360 | 2361 | 2362 | 2363 | 2364 | 2365 | 2366 | 2367 | 2368 | 2369 | 2370 | 2371 | 2372 | 2373 | 2374 | 2375 | 2376 | 2377 | 2378 | 2379 | 2380 | 2381 | 2382 | 2383 | 2384 | 2385 | 2386 | 2387 | 2388 | 2389 | 2390 | 2391 | 2392 | 2393 | 2394 | 2395 | 2396 | 2397 | 2398 | 2399 | 2400 | 2401 | 2402 | 2403 | 2404 | 2405 | 2406 | 2407 | 2408 | 2409 | 2410 | 2411 | 2412 | 2413 | 2414 | 2415 | 2416 | 2417 | 2418 | 2419 | 2420 | 2421 | 2422 | 2423 | 2424 | 2425 | 2426 | 2427 | 2428 | 2429 | 2430 | 2431 | 2432 | 2433 | 2434 | 2435 | 2436 | 2437 | 2438 | 2439 | 2440 | 2441 | 2442 | 2443 | 2444 | 2445 | 2446 | 2447 | 2448 | 2449 | 2450 | 2451 | 2452 | 2453 | 2454 | 2455 | 2456 | 2457 | 2458 | 2459 | 2460 | 2461 | 2462 | 2463 | 2464 | 2465 | 2466 | 2467 | 2468 | 2469 | 2470 | 2471 | 2472 | 2473 | 2474 | 2475 | 2476 | 2477 | 2478 | 2479 | 2480 | 2481 | 2482 | 2483 | 2484 | 2485 | 2486 | 2487 | 2488 | 2489 | 2490 | 2491 | 2492 | 2493 | 2494 | 2495 | 2496 | 2497 | 2498 | 2499 | 2500 | 2501 | 2502 | 2503 | 2504 | 2505 | 2506 | 2507 | 2508 | 2509 | 2510 | 2511 | 2512 | 2513 | 2514 | 2515 | 2516 | 2517 | 2518 | 2519 | 2520 | 2521 | 2522 | 2523 | 2524 | 2525 | 2526 | 2527 | 2528 | 2529 | 2530 | 2531 | 2532 | 2533 | 2534 | 2535 | 2536 | 2537 | 2538 | 2539 | 2540 | 2541 | 2542 | 2543 | 2544 | 2545 | 2546 | 2547 | 2548 | 2549 | 2550 | 2551 | 2552 | 2553 | 2554 | 2555 | 2556 | 2557 | 2558 | 2559 | 2560 | 2561 | 2562 | 2563 | 2564 | 2565 | 2566 | 2567 | 2568 | 2569 | 2570 | 2571 | 2572 | 2573 | 2574 | 2575 | 2576 | 2577 | 2578 | 2579 | 2580 | 2581 | 2582 | 2583 | 2584 | 2585 | 2586 | 2587 | 2588 | 2589 | 2590 | 2591 | 2592 | 2593 | 2594 | 2595 | 2596 | 2597 | 2598 | 2599 | 2600 | 2601 | 2602 | 2603 | 2604 | 2605 | 2606 | 2607 | 2608 | 2609 | 2610 | 2611 | 2612 | 2613 | 2614 | 2615 | 2616 | 2617 | 2618 | Since Version 8.2, EAGLE supports online libraries. The ids 2619 | of those online libraries will not be understood (or retained) 2620 | with this version. 2621 | 2622 | 2623 | Since Version 8.3, EAGLE supports URNs for individual library 2624 | assets (packages, symbols, and devices). The URNs of those assets 2625 | will not be understood (or retained) with this version. 2626 | 2627 | 2628 | Since Version 8.3, EAGLE supports the association of 3D packages 2629 | with devices in libraries, schematics, and board files. Those 3D 2630 | packages will not be understood (or retained) with this version. 2631 | 2632 | 2633 | 2634 | --------------------------------------------------------------------------------