chebe: (Default)
2025-04-02 01:00 am

Digital Sparkle Collar

History )

Collar )

Circuit )

Attachment )

Putting it all together )

Finishing touches )

Coding )

Testing )


Photo of the neopixel collar, closed, and turned on, with four wires meeting in the middle, leading to the Gemma in a translucent bright green 3d printed circular case, inside yet another in a translucent bright green 3d printed circular case, with the LEDs in various shades of green, yellow, white, and off.

Digital Sparkle Collar, with more robust case situation
Photo by [personal profile] chebe

chebe: (Default)
2025-03-19 02:40 pm

MPU-6050 Arduino libraries code archaeology

Compare and contrast getting normalized accelerometer values, where the raw value is -13248.00. (A.k.a. Please, make it make sense.)

Library 1; jarzebski's Arduino-MPU6050 - https://github.com/jarzebski/Arduino-MPU6050/
Library 2; Adafruit's Adafruit_MPU6050 - https://github.com/adafruit/Adafruit_MPU6050
Library 3; i2cdevlib/ElectronicCats' mpu6050 - https://github.com/ElectronicCats/mpu6050


Library 1;


code )

Formula for normalized acceleration value at MPU6050_RANGE_2G;
raw * rangePerDigit * gravityConst
(raw * (1.0/16384)) * gravityConst
== (raw / 16384) * gravityConst
(-13248.00 * .000061) * 9.80665 = -7.92502845
== (-13248.00 / 16384) * 9.80665 = -7.92959589


Library 2;


code )

Formula for normalized acceleration value at MPU6050_RANGE_2_G;
(raw / accel_scale) * gravityConst
(-13248.00 / 16384) * 9.80665 = -7.92959589


Library 3;


code )

No normalized functions in MPU6050.cpp. Can use MotionApps files, but they go through Quaternions.
code )

Formula for normalized acceleration value at MPU6050_ACCEL_FS_2;
// jarzebski way;
raw * accelerationResolution * gravityConst
-13248.00 * 0.000122 * 9.80665 = -15.850057

// adafruit way;
// (raw * (1.0/16384)) * gravityConst
// (raw * (2.0/16384)) * gravityConst
(-13248.00 / (2.0*16384)) * 9.80665 = -15.85919
((-13248.00*2.0) / 16384) * 9.80665 = -15.85919

Result is twice that of the others. accelerationResolution itself seems to be twice the others, so half it? Not sure if this is a mistake, or I'm missing something about MPU6050_ACCEL_FS_2 vs MPU6050_RANGE_2_G.
raw * (accelerationResolution/2) * gravityConst
-13248.00 * (accelerationResolution/2) * 9.80665 = -7.9250

accelerationResolution and get_acce_resolution() only exist in the ElectronicCats version, they're not accessible in the i2cdevlibs version. That version seems to really want you to use the Quaternion path. But you can always use the range values from the other versions yourself on the raw values.
chebe: (Default)
2025-03-19 12:00 am

MPU-6050 with Arduino and Processing, data visualization code archaeology

The MPU-6050 is an accelerometer and gyroscope (with added thermometer), that contains a Digital Motion Processor (DMP) to handle a lot of the heavy maths lifting of turning the raw sensor values into useful motion values before they reach the microcontroller. It seems (caveat; I'm new to this area) that the original code is only available as a binary, or as some demo code. But some very determined people have pulled a library together.

/* Source is from the InvenSense MotionApps v2 demo code. Original source is
 * unavailable, unless you happen to be amazing as decompiling binary by
 * hand (in which case, please contact me, and I'm totally serious).
 *
 * Also, I'd like to offer many, many thanks to Noah Zerkin for all of the
 * DMP reverse-engineering he did to help make this bit of wizardry
 * possible.
 */


Well, actually, it seems quite a lot of people have pulled libraries together, to different levels of functionality, with very similar names. But the one most people seem to use is this one. Which includes the MotionApps files. This is important, not just for the right function calls, but because you need other libraries from this collection as well, particularly the I2Cdev one. These libraries, although for Arduino, are not findable inside the Arduino IDE's Library Manager. You need to side-load them, old school style. Which means downloading and extracting the .zip file. Then copying the specific libraries (being the folders that contain an 'Examples' folder as a first level child) for MPU6050 and I2Cdev into your Arduino > libraries folder. And restarting the IDE.

(I've also, after the fact, found what seems to be a copy of the MPU6050 library in an ElectronicCats repo, that is in the Library Manager, and seems to have rolled the I2Cdev code into itself. But the oldest change here seems to be 6 years ago. Whereas the i2cdevlib seems to be about 13 years ago. It does seem to have more recent updates than i2cdevlib though. So the choice is yours. I'm telling you, it's a nightmare finding what's what, especially when the code linking to it won't even compile with it.)

To help us get a feel for how the boards movements are interpreted, there's a nice demo we can try out. You can find the MPUTeapot Processing project inside the MPU6050 Arduino library; MPU6050 > examples > MPU6050_DMP6 > Processing > MPUTeapot.

First step is to install Processing. I'm using P4. Copy that MPUTeapot.pde file into a new sketch (or the whole folder to wherever you save your sketches). This sketch requires another stack of libraries, the Toxi/c libraries, which we need to side-load again. Download the newest release, extract the .zip file, and copy the libraries (being the folders that contain an 'examples' folder as a first level child) into your Processing > Libraries folder. Restart Processing.

Illustration of Arduino Mega board wired up to MPU6050 board as described below.

MPU6050 Circuit
Made with Fritzing



Wire up your MPU6050 to your Arduino (I'm using the Mega 2560). You need to connect the Interrupt pin to Digital pin 02 (on most Arduino boards). SDA -> SDA. SCL -> SCL. VCC -> 5V. GND -> GND.

Open the MPU6050 > MPU6050_DMP6 example, and load it onto your Arduino. By default it runs in readable yaw-pitch-roll mode. Open the Serial Monitor at 115200 baud. After finding and initialising your MPU6050 it will await char input. Send any char, and you'll get a lot of lines like;
DMP ready! Waiting for first interrupt...
ypr	0.01	-0.01	0.44
ypr	0.01	-0.01	0.44
ypr	0.01	-0.01	0.44
ypr	0.01	-0.01	0.43

Which are your yaw-pitch-roll Euler angles in degrees.

If you comment out the #define OUTPUT_READABLE_YAWPITCHROLL line, and uncomment the #define OUTPUT_TEAPOT line you'll prepare the code for use with the Processing demo. Instead of nice readable yaw-pitch-roll values the info is packed into a 42-byte FIFO packet buffer; [quat w][][quat x][][quat y][][quat z][][gyro x][][gyro y][][gyro z][][accl x][][accl y][][accl z][][]. Upload to your Arduino.

Moving over to Processing now, open the MPUTeapot demo. I find it nostalgic that this is running in OpenGL mode. If you want to increase the window size, go ahead and do that. Otherwise you just need to set the correct portName. For me that meant commenting out line 72, and uncommenting line 75, while updating line 75 to say "COM7". The demo is straight-forward, handling the drawing of the virtual plane, reading and unpacking the packets back to quaternion w,x,y,z values, and handing off the complications to the Toxi/c libraries. But when it works it's a lot of fun to manipulate the virtual plane by moving your MPU6050. And really helps you connect the board movement to what you want your project to detect/react to, in your mind.

Animation of a block plane (red board, green wings and tail fin, blue nose cone) rotating in 3D space.

MPUTeapot demo
Gif by [personal profile] chebe

chebe: (Default)
2025-03-12 12:00 pm
Entry tags:

MG90D Servos with Arduino

Take one Arduino Uno, and run some servos. Seemed straight-forward. Seemed.

Firstly, I couldn't find any Unos or Duemilanoves, I must have used them all. Guess it's time to finally break out the Mega 2560.

The servos are the MG90D micro servos. And using the Servo.h library.

Basic circuit set up like the sweep tutorial; on a breadboard, using a 100 µF capacitor (servo is 4.8V to 6V DC voltage), and external 9V power supply. Sweep worked fine, but setting exact angles via write() would only sometimes work.

Illustration of Arduino Mega board, with 9V power source, connected to a servo with power through a breadboard with capacitor, and connected to Digital/PWM pin 09.

Servo Circuit
Made with Fritzing



After some poking around I learned that I needed to set the minimum and maximum pulse lengths for these particular servos. (The values from the product description on Adafruit. Also note, this servo will 'hold' the position even when no signal is sent.) And then I could set the degree of rotation (0°-180°) as expected.


#include <Servo.h>

Servo myServo;

int minPulseWidth = 750; // µs == 0.75ms
int maxPulseWidth = 2250; // µs == 2.25ms

void setup()
{
  myServo.attach(9, minPulseWidth, maxPulseWidth); // digital pin (with PWM) 9
}

void loop()
{
  myServo.write(90); // angle in degrees, 0-180
  delay(1000); // ms
  myServo.write(180); // angle in degrees, 0-180
  delay(1000); // ms
  myServo.write(0); // angle in degrees, 0-180
  delay(1000); // ms
}
chebe: (Default)
2024-01-24 12:45 am

Adafruit LED Glasses basics

Some time ago I got myself an Adafruit LED Glasses Starter Kit. But other than turning it on and running the example code I hadn't done much with it. Then with the return of Congress I, of course, wanted all the LEDs, so I dug it out. First things first, how am I going to wear this?

Physical details )


View, from the wearer's point of view, of my glasses, with the LED front panel attached via overclip nose-bridge, and driver case attached via velcro to the left arm.

Front panel and driver attached to my glasses
Photo by [personal profile] chebe



Code details )
chebe: (Default)
2022-10-19 08:05 pm
Entry tags:

Adafruit HalloWing M0 displaying images from SD card through Arduino

I went to an event at the weekend. Which meant I needed an event badge. Time to dust off my HalloWing badge. I finished the last post saying I would update once I got the badge reading images from the SD card shield. Well, dear reader, I was pleasantly surprised to discover that at some point I had gotten it working! At least to the point of auto-rotating through all the images on the card.

I don't really remember what I did to get the SD card working, but from the code the main bits are;
#include <SPI.h>
#include <SD.h>

const int chipSelect = 10;
File root;

void setup(void) {
  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  // List files on the SD card
  root = SD.open("/");
  printDirectory(root, 0);
  root.close();
}

printDirectory(root, 0) uses dir.openNextFile(); which sorts through your files alphabetically. bmpDraw(...) (see code below) is what what reads the bmp file and translates it into what the tft wants. Nice.

But I wanted more. First thing you need to know is that Adafruit have moved on and really want us to use the Arcada library to work with the badges in Arduino. But if I wanted a simple life I would have gone with the CircuitPython option. I travelled the frustrating path instead.

I set up two of the buttons to 'scroll' left/right through the images. The images have overlays that display matching usernames. One of the buttons toggles on/off the tft backlight, and the other button toggles on/off the on-board NeoPixel. For a while things weren't working, and after a lot of digging I discovered that Adafruit had made breaking changes, including deprecating a function they had used in the examples I was working from.

setAddrWindow(...) was changed, from (start_x, start_y, end_x, end_y) to (start_x, start_y, width, height). So the change was from;
tft.setAddrWindow(x, y, x+w-1, y+h-1);
to;
tft.startWrite();
tft.setAddrWindow(x, y, w, h);
tft.endWrite();


pushColor(...) is deprecated. After experimentation I discovered that;
tft.pushColor(tft.color565(r,g,b));
needs to be replaced with;
tft.startWrite();
tft.writePixel(col, row, tft.color565(r,g,b));
tft.endWrite();


For the buttons a library is required;
#include <Adafruit_FreeTouch.h>
Then you need to create each of the four buttons (A2, A3, A4, A5);
Adafruit_FreeTouch qt_1 = Adafruit_FreeTouch(A2, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE);
Each of which you qt_1.begin(); in setup(void), and then read with qt_1.measure() as in;
if (qt_1.measure() > 700) { /* do stuff */ }

The backlight and NeoPixel parts were straight-forward. And the only other thing I did was add an extender to the battery JST connector so it's easier to reach. I wrapped the leads around the shield, and tucked the battery between the shield and board.




Back of the badge, with SD card shield in place, and battery tucked between
Photo by [personal profile] chebe






Front of the badge, displaying an image with overlay, and NeoPixel backlit
Photo by [personal profile] chebe



Messy code dump cobbled together from various tutorials )
chebe: (Default)
2021-04-01 07:07 pm

PicoPlanet Video Call Controller

A while back I picked up a very cute circuit python board with procedurally generated graphics called the PicoPlanet. (I got design number 12.) A few months into the Pandemic, a bunch of projects around making video calls easier to use appeared. Adafruit even has one for circuit python; a video call panic button, for PyRuler. I found their setup, which mutes audio and turns off video at the same time, didn't work for me. Mostly because the controls in these apps are mostly toggles. So if I had my video on, but microphone off, and I hit that button, I'd be turning off my camera but turning on my microphone. Instead I broke the controls down to;
  • button one un/mutes my microphone, in all my most common applications,

  • button two turns on/off my camera, in all my most common applications,

  • button three un/mutes the speakers on my computer.

Code )

Which works great (for Zoom and Discord, Skype is experimental), but the board dangling at the end of a USB cable isn't the easiest to grab. So when I got a 3D printer the first thing I printed was a case.

The PicoPlanet github contains a two-piece frame case, and a link to a bumper case. I went with the bumper case because I didn't want to obscure the design. I printed the closed back version, and it was a snug fit, with some gentle hammering to get it in flat. But it definitely makes it easier to grab.

Photo )



Closed bumper case on PicoPlanet (design #12)
Photo by [personal profile] chebe

chebe: (Default)
2020-12-07 08:15 pm
Entry tags:

Deleting twitter DMs

I wanted to delete my DMs on twitter. (Just because seeing things makes me remember things about them, and it's plenty crowded in this head already.) I saw you can delete (your copy) of DMs, but only message-by-message. I tried to find 3rd party tools to do it for me, and they have all stopped existing and/or working. So, I hit up the API.

It turns out versions are crucially important. I'm using python3, tweepy 3.9.0, and twitter API 1.1.

Following on from my previous adventures I had to add 'Direct Messages' permission to my app and regenerate the keys.

Actually deleting the DM is the easy part;
api.destroy_direct_message(direct_message.id)
(Just remember you are only deleting your copy of the messages.)

Finding the message/id to delete is the hard bit. The best available is list_direct_messages which lists both sent and received direct messages, but only in the last 30 days. It uses cursors for paging through potentially long list of results, and can be rate limited.

Best go ahead and make sure you have tweepy 3.9.0, because the previous version has a bug that means the cursors aren't handled correctly in this call;
pip3 install tweepy --upgrade

Putting it all together you get something like;
code )

As I was manually deleting the DMs older than 30 days I noticed that twitter itself is using version 2 of their API, and doing a circuitous lookup via DM conversations. Something to look into when the new API is supported.

But really, all this could have been avoided if twitter only provided a 'Delete Conversation' button in DMs.
chebe: (Default)
2020-12-02 07:48 pm
Entry tags:

Resizing images in python with pillow

Hello Internet. It's been a while, huh? Like many people, I got caught up in completely reconfiguring my workspace to accommodate a work-from-home station. Just yesterday I got to close all my IKEA tabs. It felt good. But unfortunately I haven't had the opportunity to get much work done on projects.

One of the short things I did manage was an update to my tweet-my-blog script, because my photos got too big so I needed to add handling to downsize before posting.

First, pull in a new library;
pip3 install pillow


Then update the script (changes in strong);

code )
chebe: (Default)
2013-01-01 11:12 pm
Entry tags:

Code for the LED matrix top, version 2

While I wait for LJ to let me log in again (to upload photos), or until I find a better alternative, I thought I'd share some more of the LED-matrix top code with you.

Here's version 2, with the SparkFun wearable keypad functionality added. Let me know if there's any problems, or if you'd simply like to discuss it.

(Version 1 post)
chebe: (You Can Still Be Free)
2012-10-18 11:15 pm
Entry tags:

Code for the LED matrix top

I received a request for clarify some of the code I use in the LED-matrix top, so I've decided to start sharing my code in a more modern way. But before we get to that, if you are thinking of following my adventures in making this top there are a couple of things I want to add.


  1. Please please please use metal snaps instead of metal rings!

  2. Use lithium-ion batteries, more power, much better.

  3. As soon as you have the circuit working as you want, cover each conductive trace with fray-stop glue to prevent oxidation of the conductive coating over time.

  4. Test that you can turn on each LED individually by using a (at least 3V) coin-cell battery and touching the positive side to the trace that connects to the positive side of the LED, and the negative to the negative. If it doesn't light up get a multimeter and check every single trace/LED for short-circuits.



Okay, so the top is physically made up and working fine? Great! Here's the first version of the code, with the LEDs working, and the push-button switch for cycling through patterns, and that's it. It's available through github at https://github.com/chebe/chebe-led-matrix-top. I'll let you know as I clean up and release newer versions.
chebe: (AsciiC)
2011-09-29 05:38 pm
Entry tags:

SparkFun's Wearable Keypad

I admit I can be a bit of a sucker when it comes to electro-textile stuff. I see the word 'wearable' in front of any traditional electronic component and I have to investigate. Which is how I came to possess the Wearable Keypad from SparkFun. I finally got around to using it recently, so here's the low-down.

It's a thick piece of rubber, glued together and sealed with silicon gel type stuff. It has six wires (about a metre long) coming from it. One wire is not connected (NC), one is ground (GND), one is for setting the brightness of the red LEDs behind the keypad (LEDR), and the other three (p5.1, p5.2, p5.3) are for the button presses. And as mentioned in the comments (of the product page) the order of the wires is backwards to that as shown in the datasheet.

Wait, you say, three wires for five buttons? What's going on? Seems to be a bit of fancy multiplexing, although the details are beyond me. I have however, managed to get it all to work for me, and have edited the Example Code provided by SparkFun to, shall we say, neaten up things a bit? Basically, I found that in the provided code I was getting spurious results; when I'd press 'down' I'd often get a 'left' or 'right' for no apparent reason. So I've added a few extra checks, that while they may slow the code down a bit, ensure clean detection of button presses. All the extra stuff to do with the LEDs I've stripped out. You may not need it, but here it is in case you do. (Also, your millage may vary, and as such you may need to edit this code to work just right for you.)

But give the SparkFun example code a go too. It's oddly satisfying to play with the LEDs.

Let's go )

I have to say though, I was a bit surprised that the keypad came with such long wires, and unfinished ones at that. While it works well with an Arduino Uno, it doesn't do so well with the Arduino Lilypad. I'm going to have to come up with a suitable interface to get the two to play well together. (And yes, this is part of a larger project...)
chebe: (South Park)
2011-03-18 12:51 am
Entry tags:

Lilypad Temperature Sensing Scarf, code

Someone asked me for this and I realised I'd never posted it. (I had dealt with reading the temp here but not the rest of it.) It's not fully done. The timing and lights and such could still do with some tweaking, but I guess that comes down to personalisation. If you'd like to try this project the physical construction is here, and what follows is my code. If you do give it a go I'd love to see how it turns out!

code monkey like you )