element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
NanoRama
  • Challenges & Projects
  • Project14
  • NanoRama
  • More
  • Cancel
NanoRama
Blog Hatching a hockey stick hack in a hurry!
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join NanoRama to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: BigG
  • Date Created: 16 May 2020 8:49 PM Date Created
  • Views 2040 views
  • Likes 11 likes
  • Comments 5 comments
  • arduino nano 33 ble
  • nano 33 ble sense
  • nanoramach
Related
Recommended

Hatching a hockey stick hack in a hurry!

BigG
BigG
16 May 2020

image

 

It is 21h00 on Saturday the 16th of May 2020 and I've decided to make a later entry with a project idea I hatched only 30 minutes ago. The reason is that I had read earlier today that the NanoRama competition deadline had been extended and it was only yesterday that I had given up in despair with my original project.

 

image

 

This time the plan is simple.  It starts with a hockey stick...

 

Then prove that you can really rapid prototype with an Arduino Nano 33 BLE board within 48 hours.

So, much like the popular TV series 24, I've got 24 hours to update my progress.

 

To be continued...

 

 

The mission

 

It is 23h00 and the mission requirements for the Hack in a Hurry ("HinaH") Hockey Stick project have now been flushed out.

 

image

The Arduino Nano 33 BLE board comes with a 9DOF motion and orientation-sensing LSM9DS1 SiP (system-in-package) from ST Microelectronics. The mission is to attach the Arduino Nano 33 BLE board to the hockey stick and use BLE to transmit the live motion sensing data (linear acceleration and angular motion) to a remote central controller. The purpose would then be to use this data to evaluate the hockey players technique when trying to hit a target with a hockey ball.

 

The small target area (or goal) will be monitored by a BBC microbit which will have at least 1 or 2 proximity sensors attached. These proximity sensor will determine the degree of accuracy (left or right of a plumb line) of the ball strike. The LED's on the BBC microbit will be used to provide user live feedback. The number of successful strikes and degree of accuracy data can then be related back to the central controller.

 

Mission preparation

 

It's 07h00 Sunday 17th of May 2020. Errr, it's Sunday and the kids are still sleeping so why wake them up...

 

It's now 09h00 Sunday 17th of May 2020. Ah feeling much better. Breakfast is done and the first cup of coffee has been had. It is time to get cracking on with project preparation. First, I needed to work out a quick plan for the morning sprint:

 

1. Kit out the hockey stick with battery pack and the Arduino Nano board.

2. Download the Arduino LSM9DS1 library and run through the examples.

3. Do some research on visual outputs for motion data (had seen some videos before using Processing for graphic output).

 

Completing step 1 did not take too long. I had plenty of packaging foam and duct tape lying around so I was good to go.

 

{gallery:autoplay=false} Arduino Nano 33 BLE on Hockey Stick

image

image

image

image

image

 

Onto step 2.

 

The Arduino IDE provides a very handy Library Manager tool. Typing in "LSM9DS1" gave me a list of options to choose from:

 

image

 

As you can see, I installed the Arduino version.

 

The curious thing I found, following the installation of the library, was where the LSM9DS1 examples are placed when you have the examples list open within the IDE. It took a bit of head scratching... only to find them right under my nose.

 

image

 

I combined the SimpleAccelerometer and SimpleGyroscope examples together and opened up the SerialPlotter tool to review my data. All looked good at face value.

 

image

 

Onto step 3.

 

I wanted to use the rest of my time before a late lunch to explore Processing and 3d rendering as wanted to see if I could create a simple tool to visualise the data. The ultimate aim would be to show data on a web browser and use some JavaScript framework and library to display the data but this would take me too long. The nice thing about Processing is that there are quite a few good libraries about not and there are even a few YouTube videos I found that demonstrated how to visualise IMU data via Processing.

 

Well, it turns out there is more to this than meets the eye and I was not able to get something working straight away from my serial data stream. So I put this on hold.

 

 

Developing the Arduino Nano 33 BLE application

 

For my second sprint of the day, I decided to concentrate my efforts on the BLE side.

 

To create BLE Applications on the Arduino Nano 33 BLE board requires the ArduinoBLE library. This library is based off the BLEPeripheral library, which I was quite familiar with already.

 

My aim was to create a BLE peripheral application which had it's own custom service. I started with the "Button LED" example provided as this used a custom service and two custom characteristics too. All I had to do was modify the variable names to make them more meaningful and then change the properties to suit. The big change for my application was that I wanted to transmit a byte array for all my movement data. For this you have to define your characteristic slightly differently.

 

BLEService MovementService("19B10010-E8F2-537E-4F6C-D104768A1214");   // create our custom GATT service


// create movement data characteristic (this is a Byte Array) and allow remote device to use Notify
BLECharacteristic moveDataCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 24, true);


// create acceleration & gyro sample rate (Hz) characteristic and allow remote device to get notifications
BLEShortCharacteristic SampleRateCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

 

The next challenge was working out how to format the data as the only option provided within BLE for sending multiple amounts of data is in a byte array. Thankfully I had crossed this hurdle before as this is handled for you in the health thermometer BLE service. The BLE health thermometer measurement characteristic is defined by something called "IEEE11073float" and Adafruit had some code for this via one of their Bluefruit library examples.

 

uint32_t float2IEEE11073(double data, uint8_t output[4])
{
  uint32_t result = MDER_NaN;




  if (isnan(data)) {
    goto finally;
  }/* else if (data > MDER_FLOAT_MAX) {
    result = MDER_POSITIVE_INFINITY;
    goto finally;
  } else if (data < MDER_FLOAT_MIN) {
    result = MDER_NEGATIVE_INFINITY;
    goto finally;
  } else if (data >= -MDER_FLOAT_EPSILON &&
    data <= MDER_FLOAT_EPSILON) {
    result = 0;
    goto finally;
  }*/


  double sgn; sgn = data > 0 ? +1 : -1;
  double mantissa; mantissa = fabs(data);
  int32_t exponent; exponent = 0; // Note: 10**x exponent, not 2**x


  // scale up if number is too big
  while (mantissa > MDER_FLOAT_MANTISSA_MAX) {
    mantissa /= 10.0;
    ++exponent;
    if (exponent > MDER_FLOAT_EXPONENT_MAX) {
      // argh, should not happen
      if (sgn > 0) {
        result = MDER_POSITIVE_INFINITY;
      } else {
        result = MDER_NEGATIVE_INFINITY;
      }
      goto finally;
    }
  }


  // scale down if number is too small
  while (mantissa < 1) {
    mantissa *= 10;
    --exponent;
    if (exponent < MDER_FLOAT_EXPONENT_MIN) {
      // argh, should not happen
      result = 0;
      goto finally;
    }
  }


  // scale down if number needs more precision
  double smantissa; smantissa = round(mantissa * MDER_FLOAT_PRECISION);
  double rmantissa; rmantissa = round(mantissa) * MDER_FLOAT_PRECISION;
  double mdiff; mdiff = abs(smantissa - rmantissa);
  while (mdiff > 0.5 && exponent > MDER_FLOAT_EXPONENT_MIN &&
      (mantissa * 10) <= MDER_FLOAT_MANTISSA_MAX) {
    mantissa *= 10;
    --exponent;
    smantissa = round(mantissa * MDER_FLOAT_PRECISION);
    rmantissa = round(mantissa) * MDER_FLOAT_PRECISION;
    mdiff = abs(smantissa - rmantissa);
  }


  uint32_t int_mantissa; int_mantissa = (int) round(sgn * mantissa);
  result = (exponent << 24) | (int_mantissa & 0xFFFFFF);
  
  #ifdef DEBUG
  //Serial.print("E ");Serial.print(exponent);
  //Serial.print(" | M ");Serial.print(int_mantissa);
  //Serial.print(" | R ");Serial.println(result);
  #endif
  
finally:
  if ( output ) memcpy(output, &result, 4);
  return  result;
}

 

Fingers crossed this works as by using this method, I would be saving a huge amount of time.

 

It was time to get stuck in with a bit of coding and some prelim testing for the rest of the day.

 

/**
 *  @filename   :   Element14_NanoRama_Nano33BLE_HinaH_HockeyStick.ino
 *  @brief      :   This software example creates a BLE peripheral with 
 *                  a custom service that contains 2 custom characteristics 
 *                  1. Central to use NOTIFY to receive Acceleration and Gyro data
 *                  2. Central to use READ to receive Acceleration/Gyro sample rate. They are made to be the same
 *                     Central can also use WRITE to change the sampling rate.
 *
 *  @hardware   :   Arduino Nano 33 BLE (nRF52840) + built-in Arduino LSM9DS1 sensor
 *  
 *  @author     :   Gerrikoio
 *
 *  Copyright (C) Gerrikoio for Application     17 May 2020
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documnetation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to  whom the Software is
 * furished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


#include <ArduinoBLE.h>
#include <Arduino_LSM9DS1.h>
#include "IEEE11073float.h"


#define DEBUG


uint16_t SampleRateHz = 0;


BLEService MovementService("19B10010-E8F2-537E-4F6C-D104768A1214");   // create our custom GATT service


// create movement data characteristic (this is a Byte Array) and allow remote device to use Notify
BLECharacteristic moveDataCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 24, true);


// create acceleration & gyro sample rate (Hz) characteristic and allow remote device to get notifications
BLEShortCharacteristic SampleRateCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);


void setup() {
  #ifdef DEBUG
  Serial.begin(38400);
  while (!Serial);
  #endif
  
  //pinMode(LED_PWR, OUTPUT);
  digitalWrite(LED_PWR, HIGH);
  
  // begin BLE module initialization
  if (!BLE.begin()) {
    #ifdef DEBUG
    Serial.println("starting BLE failed!");
    #endif
    while (1);
  }


  // begin IMU module initialization
  if (!IMU.begin()) {
    #ifdef DEBUG
    Serial.println("Failed to initialize IMU!");
    #endif
    while (1);
  }


  SampleRateHz = (uint16_t)IMU.accelerationSampleRate();


  if (SampleRateHz != (uint16_t)IMU.gyroscopeSampleRate()) {
    #ifdef DEBUG
    Serial.print(F("Gyroscope sample is not the same as Accelerometer sample rate = "));
    Serial.print(SampleRateHz);
    Serial.println(" Hz");
    #endif
  }
  else {
    #ifdef DEBUG
    Serial.print(F("The Acceleration & Gyro sample rate is "));
    Serial.print(SampleRateHz);
    Serial.println(" Hz");
    #endif
  }
  #ifdef DEBUG
  Serial.println();
  #endif
  
  // set the local name peripheral advertises
  BLE.setLocalName("HaniH2020");
  // set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(MovementService);


  // add the characteristics to the service
  MovementService.addCharacteristic(moveDataCharacteristic);
  MovementService.addCharacteristic(SampleRateCharacteristic);


  // add the GATT service
  BLE.addService(MovementService);


  // Create a temporary array for the movement data
  uint8_t mArray[24];
  memset(mArray, '\0', 24);
  moveDataCharacteristic.writeValue(mArray, 24);


  SampleRateCharacteristic.writeValue(SampleRateHz);


  // start advertising
  BLE.advertise();


  #ifdef DEBUG
  Serial.println("Bluetooth device active, waiting for connections...");
  #endif
}


void loop() {
  // wait for a BLE central
  BLEDevice central = BLE.central();


  // if a central is connected to the peripheral:
  if (central) {
    #ifdef DEBUG
    Serial.print("Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());
    #endif


    // check the battery level every 200ms
    // while the central is connected:
    while (central.connected()) {
      // Update the BLE data
      updateMovementData();
    }
    #ifdef DEBUG
    // when the central disconnects, turn off the LED:
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
    #endif
  }
}


void updateMovementData() {
  /* Read the current data from the Arduino LSM9DS1 sensor.
  */
  float Mvmnt[6];
  memset(Mvmnt, '\0', 6);
  uint8_t BLE_mArray[24];
  memset(BLE_mArray, '\0', 24);


  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(Mvmnt[0], Mvmnt[1], Mvmnt[2]);
    #ifdef DEBUG
    //Serial.print("Ax ");
    Serial.print(Mvmnt[0]);
    Serial.print(", ");
    Serial.print(Mvmnt[1]);
    Serial.print(", ");
    Serial.print(Mvmnt[2]);
    #endif
  }
  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(Mvmnt[3], Mvmnt[4], Mvmnt[5]);
    #ifdef DEBUG
    Serial.print(", ");
    Serial.print(Mvmnt[3]);
    Serial.print(", ");
    Serial.print(Mvmnt[4]);
    Serial.print(", ");
    Serial.println(Mvmnt[5]);
    #endif
  }
  #ifdef DEBUG
  Serial.flush();
  #endif
  float2IEEE11073(double(Mvmnt[0]), &BLE_mArray[0]);
  float2IEEE11073(double(Mvmnt[1]), &BLE_mArray[4]);
  float2IEEE11073(double(Mvmnt[2]), &BLE_mArray[8]);
  float2IEEE11073(double(Mvmnt[3]), &BLE_mArray[12]);
  float2IEEE11073(double(Mvmnt[4]), &BLE_mArray[16]);
  float2IEEE11073(double(Mvmnt[5]), &BLE_mArray[20]);
  moveDataCharacteristic.writeValue(BLE_mArray, 24);
}

 

Success!

 

I now was able to use my phone to connect with my Arduino Nano 33 BLE board and transmit a data array and inform the user of the sample rate. Here is a screenshot when using the nRFconnect app.

 

image

 

Well, it is now 23h30 and time to call it a day.

 

Completing the Arduino Day Mission

 

It's 09h00 on Monday 18th of May 2020 and there's a ton of other business to get through first but the brain is keen to get working on this again. Naturally, we all get ahead of ourselves with ambition.

 

image

It is now lunchtime on Monday and I was thinking about how best to capture the BLE data using my laptop and decided to keep it within the Arduino family, so to speak, and use an ESP32 device as there is plenty of Arduino code examples about.

 

To create a BLE central device there is an ESP32 example called "bleclient.ino", which you can readily work off. The nice thing about this example is that you can get the ESP32 to scan and automatically connect with peripheral BLE devices that are advertising a particular service UUID. So, this is what I did. Then all you need to do is add in the GATT service and characteristics for my HinaH Hockey Stick nano 33 device and you are good to go. Well, sort of.

 

The ESP32 uses a notify callback function, but here you need to be careful not to overload this function with code as it very quickly gets snarled up and your ESP32 simply freezes. This happened to me a couple of times but once I had it cleaned up it seemed to work fine.

 

/*==================================================
 * CALLBACK FUNCTIONS
 *================================================== */
static void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {

  float MvmtData[6];  // Grab the movement data
  memset(MvmtData, '\0', sizeof(MvmtData));
  if (length == 24) {
    //MvmntCntr++;
    uint8_t y = 0;
    for (uint8_t x = 0; x < length; x+=4) {
      MvmtData[y] = IEEE11073_2float(pData+x);
      y++;
    }
    for (y = 0; y < 6; y++) {
      Serial.print(MvmtData[y], 2);
      if (y < 5) Serial.print(", ");
    }
    Serial.println("");
  }
  
}

 

Then the next big challenge I had today was converting the 4-byte IEEE-11073 back to a float value.

 

I had never really created the full code logic for this (I had taken a short cut previously for temperature where I ignored converting the negative values and this was also done using MIT App Inventor using blocks!). This took me a good few hours to work it out for my ESP32 Arduino code. And here it is. It is rather simple once you know how:

 

/*==================================================
 * LOCAL FUNCTIONS
 *================================================== */
float IEEE11073_2float(uint8_t *dat)
{
  int32_t Mantissa = (dat[2] << 16 | dat[1] << 8 | dat[0]);
  uint8_t Neg = bitRead(dat[2],7);
  int8_t fExp = dat[3];
  if (Neg) Mantissa |= 255 << 24;
  return (float(Mantissa) * pow(10, fExp));
}

 

Then for readability of the serial output, I added in a button which allows the user to manually enable the movement data notifications:

 

  // If we are connected to a peer BLE Server, update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    if (!NotifyEnable) {
      // We wait for a button press
      if (digitalRead(BTN_PIN)) {
        // See if we can enable Notifications for the movement the characteristic.
        if(pHinaMovementCharacteristic->canNotify()) {
          Serial.println("Movement data Notification Enabled");
          Serial.flush();
          NotifyEnable = true;
          pHinaMovementCharacteristic->registerForNotify(notifyCallback);
        }
      }
    }
  }
  else if (doScan) {
    BLEDevice::getScan()->start(0);  // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino
  }

 

And finally, I got to do my first live test:

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

 

I then cut and pasted that serial monitor data into Excel and created two charts, one of Acceleration (g) and one for Angular Velocity (°/s).

 

{gallery} Movement Data

image

image

 

There was nothing untoward that I could see from the BLE data received. I was able to obtain 6DOF data updates every 0.01 seconds or so, which is pretty good in my opinion.

 

So I am rather pleased with the result and how short it took to get this far. The gadget goal device using the BBC microbit can wait for another day as the spotlight needs to remain on the Arduino Nano 33 BLE board. It is tiny and makes movement analysis quick and simple.

 

I really enjoyed this 48 hour journey. Till next time...

  • Sign in to reply

Top Comments

  • dubbie
    dubbie over 5 years ago +1
    I'm sure you can do it! I made a small mobile robot in one 24 hour period for an Element14 project (and I didn't work that hard on it either but schhhh,, that's a secret!). Tiny24hourMoBot #4 : The 24…
  • BigG
    BigG over 5 years ago in reply to dubbie +1
    I feel like a digital flip flop at the moment which has forgotten what state it is in (I'm flipping between learning and doing then fixing and somewhere in between documenting). Still, I'm making progress…
  • ilvyanyatka
    ilvyanyatka over 4 years ago +1
    Hi, It looks really impressive for 2-day project! I have a coupe of questions: 1) In the code BLECharacteristic moveDataCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 24, true…
Parents
  • ilvyanyatka
    ilvyanyatka over 4 years ago

    Hi,

    It looks really impressive for 2-day project!

    I have a coupe of questions:

     

    1) In the code

    BLECharacteristic moveDataCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 24, true);

    You set size to 24. Why is this size is not limited by MTU that is 23? And do you know the maximum limit for it?

     

    2) what software did you use to transfer data from Esp32 to the desktop? Was it Serial Monitor listening to your ESP32 or something else?

     

    Thank you!

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • ilvyanyatka
    ilvyanyatka over 4 years ago

    Hi,

    It looks really impressive for 2-day project!

    I have a coupe of questions:

     

    1) In the code

    BLECharacteristic moveDataCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 24, true);

    You set size to 24. Why is this size is not limited by MTU that is 23? And do you know the maximum limit for it?

     

    2) what software did you use to transfer data from Esp32 to the desktop? Was it Serial Monitor listening to your ESP32 or something else?

     

    Thank you!

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • BigG
    BigG over 4 years ago in reply to ilvyanyatka

    Thanks for your comment.

     

    It is my understanding that you can have the MTU < payload length and still transmit a large byte array. It's just that internally within BLE stack the message is then split into blocks or chunks (this would be similar to other comms protocols where chunked data transfer method is used).

     

    Maybe this explains it a little better: https://www.silabs.com/community/wireless/bluetooth/forum.topic.html/terminology_question-JqSX

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube