Introduction: Strangely Attractive - an Electrified Fidget Spinner

What can you find in the attic of an old school? Strange things used for demonstration of scientific phenomena. Also newer equipment that is hopelessly passed the best-before-date, like matrix printers (please, google that, if you think a matrix printer is a 3D printer capable of printing alternative worlds inside of which you can exist), fax machines or even CD players. What do you get, when you use stuff from all this trash and combine it with some new electronics? An eye catching steampunk office toy named Strangely Attractive.

What I got

  • A hobby Morse telegraph built in a wooden cigar box
  • A mahogany wood box meant for some galvanic experiments
  • A trashed CD player
  • A telephone
  • Knobs and switches
  • Lots of PCB components from trashed electronics
  • A lot of AC/DC converters from trashed electronics
  • Whatnot

What else is trash?

Short trend toys. That's simply trending toys that are a trend only for a short time. Oh yes, they all are. So, all trending toys are trash after a year or two. Tamagotchis, Furbies, fingerboards, Pokemon Balls. And fidget spinners.

I'm going to use a nice looking wooden box, that has been used for something. I'm going to add electronics from trashed equipment. I'm going to add control knobs that look as steampunk as possible. I'm going to have a fidget spinner rotate by itself, when placed on the box. A few leds might do a bit harm to the steampunk image, but they will add to the user experience.

And I'm going to use some brand new stuff, too. People create amazing stuff using only trash. This project is more about giving a new life to trash by mixing it with new technology.

List of trash parts I chose for the final product

  • The mahogany wood box used for galvanic experiments
  • An electromagnet I took out of the CD player
  • Two potentiometers from the CD player
  • A piezo element from the telephone
  • A rotary switch from some strange printer switch (from the time before network printers)
  • A knob from an old drawer
  • A knob from some old electric device for heat regulation
  • A fidget spinner
  • A 12 V 1.5 A power source from a led strip

What I added to the product

  • An Arduino Nano
  • A motor driver
  • A breadboard
  • A KY-003 Hall sensor
  • Wires
  • Some leds and resistors (leds are so cheap I couldn't resist buying some new instead of reusing, that way I got a set of 6 identical leds)
  • Some magnets (again I chose to use new neodymium ones to get as strong magnets as possible, and identical ones)

Latest add on

From the old crafts classroom I found more trash. I found two similar circuit boards, probably taken from a soldering station. The board transforms 240 V to 18 V. The transformer itself seems interesting, but what I picked to my project was two trimpots. This made me add some more details to my project. From the same place I also found a piece of sheet metal. The potentiometers and the rotary switch need to be attached to sheet metal, due to too short threads. The wall of the wooden box is too thick.

From this trash and from these new components arises Strangely Attractive!

Strangely Attractive

Strangely Attractive consists of a fidget spinner with a permanent magnet in each arm. An electromagnet makes the spinner rotate. Two potentiometers control the electromagnet, one sets the frequency of the magnet switching polarity, the other adjusts the duty cycle of the magnetic pulse (the percentage of how much the pulse is on over time). Depending on the potentiometers, the fidget spinner will either

  • oscillate between two positions
  • rotate in one direction in a constant speed, or
  • behave completely chaotically

It's the chaotic behaviour that becomes interesting. The name of this device honours the work of David Ruelle, Floris Takens and Edward Lorentz, scientists, who contributed a lot to modern chaos theory. The Strangely Attractive suits well on your desktop along with your Newton's cradle, Drinking bird and other office toys.

To bring order to chaos, a Hall sensor is added. It will demonstrate the principle of a brushless motor, where the sensor will take care of switching the magnetic field at the right moment to maximise the torque and speed of the spinning motor.

So, Strangely Attractive demonstrates two concepts, chaotic behaviour and a brushless motor, just like other office toys base on some peculiar science. A Newton's cradle demonstrate conservation of momentum and shock or compression waves inside metallic masses, a Drinking Bird is a heat engine. Strangely Attractive will have four programs, mainly because I reused a rotary switch with four positions.

  1. The electromagnet switches polarity at a constant frequency, which makes the fidget spinner behave chaotically
  2. The electromagnet switches polarity according to the position of the fidget spinner, which turns the device into a brushless motor
  3. A preset program, blending different chaotic patterns
  4. A preset program, where the fidget spinner accelerates to the top speed, brakes and switches direction

Some of the components explained

Arduino Nano

Any microcontroller will do, as long as you can connect it to a motor board, it can read two potentiometers and it can control a few leds. Further, it should be able to read a rotary switch or similar. And it should fit inside your box.

I have an Arduino Nano with header pins underneath. It fits perfectly on a standard prototyping breadboard, which gives you access to the pins using the breadboard and jumper wires. I recommend strongly to use a prototype breadboard instead of a perma breadboard, where you solder the components. Once you have replicated this project, you might want to do changes and improvements, before you solder everything on a permanent circuit board.

Motor driver

The microcontroller should control a motor driver, which will control an electromagnet. The motor driver must be able to switch current direction, it must also handle the needed amount of current for the electromagnet. My schematics show an L298N motor driver, which is capable of driving two DC motors or two inductive loads. The L298N works ok, but it loses a lot of power. Powering it with 12 V will get only some 9 V to the motors - or to the electromagnet in this case. You might want to consider another motor driver. An L298N is cheap, though.

If you want to go pro, search for a motor driver chip inside a trashed printer. Inside a matrix printer I found the very same L298N IC chip, which is the central chip in the motor driver I use. Unfortunately it was so heavily soldered onto its circuit board that I couldn't get it detached without breaking it. A motor driver chip is recognisable by its heat sink, a metallic piece glued onto the chip, the purpose of which is to keep the chip cooled. If you find such chip, check the type and google for the specifications, if you intend to re-use it.

A great alternative to an Arduino Nano and L298N is a 4duino Uno Pro, an Arduino UNO clone with built in motor driver.

Electromagnet

The electromagnet might as well be a salvaged part from any electronics. I'm using a linear actuator I took from an old CD player. It's important that the electromagnet won't draw more current than what the motor board can provide. My motor driver works in the range of 3.5 V - 12 V. It can handle 1.5 A current. The resistance of my electromagnet is 18 Ohm. If I use a power source of 12 V (my power source for LED stripes), I would ideally have a max current of 0.5 A. It will get warm, but won't harm anything. I'm using heat resistant epoxy putty instead of a hot glue gun to attach the magnet to the lid of the box.

A piezo elelment

Telephone, what an arcaic word. The telephone I found was not very old. It had push buttons instead of a rotary disc. Yet it hopelessly belonged to an ancient era. One wire connected to a wall socket, the other wire to the handheld device containing a microphone and a loudspeaker. But the microphone and the loudspeaker were usually exactly identical piezo elements. Put an alternating voltage to them and they buzz. Yell into them and they output an electric signal.

The fidget spinner

I believe all spinners have more or less the same design. They all have a quality bearing in the middle. Then they have something in the three arms. Mine has just a steel ring with a 10 mm inner diameter in each arm.

The permanent magnets

I have button magnets with a 10 mm diameter, which fit perfectly in the steel rings. I even have two models of the magnets, one has axial magnetization and the other has diametral magnetization.

The box

The box is made of teak or mahogany, which looks nice, especially after rubbing some oil into it. It used to contain strange electric stuff for school experiments from the 1950's. It has strange brass buttons on the front panel, one of which I'm going to attach to one of the potentiometers. Check what parts you are going to use and pick a box that suits you. The microcontroller, the motor driver, the electromagnet and the potentiometers must fit in the box. If your power source is a battery pack, say six AA batteries, you want that in the box, too.

The power source

Typically the power source is connected to the motor board and the motor board provides the power both to the motor (here the electromagnet) and the microcontroller.
I'm using a 12 V 1.5 A wall adapter meant for led strips. The led strips I used for a completely different project, so this power source was totally useless at the moment. Not exactly trash, though.

The switches

You might want a simple on-off switch for the system and another switch for selecting the program. I have a four position switch, which connects three separate inputs to four separate outputs. One of the positions could be the off position, the rest could be for three different programs. But I simply decided to have the device run all the time, as long as the power adapter was plugged into the wall socket. This way I could have four different programs for the Strangely Attractive.

The potentiometers and trimpots

The potentiometers are typically 10 kOhm. They only connect to the microcontroller analog inputs. So any potentiometers you are familiar with will do, as long as your microcontroller can read them.

There are mainly two kind of potentiometers, linear and logarithmic. For a microcontroller to read them, you usually want linear. But if you pick potentiometers from trashed audio equipment, you might get logarithmic potentiometers, which you have to take in consideration when writing the code. Simply put, you have to turn the logarithmic response of the potentiometer back into linear response with some mathematics. This is subject for a separate instructable.

The trimpots are potentiometers, too. But they are usually meant to be soldered onto the circuit board and they are adjusted only once before shutting everything inside the box.

The potentiometers with their knobs in the front panel are for runtime control by the user, mainly for the first and second program. The trimpots are for the third and fourth programs, which will be pre-adjusted.

The Hall sensor

The Hall sensor is preferably of the adjustable digital type. No extra electronics is needed. Its purpose is to trigger an interrupt routine on the microcontroller. Adjustability means you can adjust the sensibility of it.

The KY-003 has three pins. You connect a voltage to two of them. The third one gives a digital HIGH signal when no magnet is near. The signal goes LOW, when a magnet gets near. The sensor is also picky about what magnetic pole it is. Just turn around your magnets or turn around the sensor, if you get it the wrong way around.

Step 1: Magnetizing the Fidget Spinner

Place the electromagnet underneath the lid of the box you are using. The fidget spinner lies on the top, precisely above the electromagnet. The idea is that one end of the electromagnet attracts one arm of the Fidget Spinner, while the other end of the electromagnet repels the two other arms. Imagine how the magnetic field lines go. Your permanent magnets should be attached to the fidget spinner arms to match the lines. My educated guess about my setup is shown in the image. I have two magnet models, each is a button magnet with 10 mm diameter and 5 mm thickness, but one model has an axial magnetization and the other one has a diametral magnetization. The axial one seems to work better and according to my drawing, the axial one seems to follow the electromagnet field lines better.

If you can choose how to align the magnetic fields, you might want to check the direction of the electromagnet field. Connect the electromagnet directly to a power source. Place your permanent magnet at the spot on the box lid, where the magnet would pass over the electromagnet when attached to the fidget spinner and find out which position the magnet wants to turn itself into. That would be the optimal position of the magnet when attached to the Fidget Spinner. Be careful to attach all three magnets exactly in the same position and direction.

In my case I just chose the axial button magnet and attached it straight into the holes in the fidget spinner arm, not caring of the field lines not being quite in the same direction. They were close enough and the magnetic attraction was strong.

Any magnet you use here you have to test for best performance. Use sticky tack or duct tape to hold your magnets while testing before gluing them on place.

Step 2: Go Pro! Find the Exact Direction of the Magnetic Field

If you really want to find the exact direction of the magnetic field at any spot above the box lid, prepare a tool out of some sewing thread, a magnet and some duct tape. Have two strings of thread, about 10 cm. Put them together and make two knots near the middle of the double thread. Divide the threads between the knots and place your magnet between the threads. Fix the magnet with a piece of duct tape on both sides of the magnet.

Turn on your electromagnet - just provide it with some power from a battery. Keep the thread ends tightly, letting the magnet hover over the lid of the box. The magnet will rotate in its thread trap revealing the direction of the magnetic field of the electromagnet. Note the position of the magnet at the spot where it would pass over the electromagnet when attached to the fidget spinner. It should be attached in that very same position.

Step 3: Schematics

Here's a full list of components used according to the images above.

Main components

  • B1 - power source, a 12 V battery or any 12 V 1.5 A source
  • SW4 - a switch to turn everything on (handy if you have a battery and not a wall adaptor
  • L298N motor driver
  • ARDUINO NANO
  • KY-003 Hall sensor
  • a piezo buzzer
  • a 3P4T rotary switch
  • four leds for the rotary switch
  • two potentiometers (10k - 100k)
  • an electromagnet
  • two leds for the electromagnet

Other components

  • two trimpots (10k - 100k)
  • three resistors (R2 - R4, 150k)
  • one resistor (R1, depends on your piezo buzzer)

The rotary switch I use has 4 positions, but it has three separate circuits. I use one circuit to tell the Arduino which of the four program is on, through GPIO pins D7 - D10. One circuit lights up the leds showing which program is selected. These four leds are not lit by the Arduino, but by the switch directly. The third circuit of the switch is unused. Just figure out how to do the circuit, if you happen to have another kind of switch. I found this switch somewhere and therefore decided to implement four different programs for the Strangely Attractive. This rotary switch is rather complicated. If you have a simpler switch, but still want to implement four different programs, it's quite possible to have the microcontroller control the four led lights telling which program is on, as well as having the microcontroller output the buzz sound to the piezzo.

The right image shows the final circuit. The switch next to the power source is optional. If you build this using a battery pack (say 9 V or 12 V, depending on how much power you want for your electromagnet), you want that switch for convenience. I use a wall adapter and my Strangely Attractive simply turns on when I plug it in.

The trimpots connecting to analog pins A3 and A4 turned out to be 2 MOhm pots. That's a lot of resistance, but the Arduino seemed to be able to read them. And it is a nice trimpot with a large disk to be turned by hand. No screwdriver needed. The fourth program will run the Fidget Spinner att highest speed in both directions, back and forth. For that, I need preset parameters for the switching timing. The trimpots will hold the preset parameters, one for each direction. It is easily accessible under the lid, if one needs to adjust it afterwards.

A typical DC motor driver has outputs for two motors. In my circuit, one output goes to the electromagnet, the other one goes to the piezo buzzer. I have no ideas about the specifications of the buzzer I found in the telephone, I don't even remember if it was the speaker or the microphone, because they were practically identical piezo elements. Anyway, it gives a buzzing sound, when the motor driver outputs an alternating square wave timed with the switching of the electromagnet polarity. It might need the resistor R1 to limit the current drawn from the motor driver (which usually can provide a lot of current). Also, components like capacitors or inductors may be used here, but that lies outside the focus of this project.

Piezos are high voltage and dangerous - to other electronics, not to you. If you don't dare to risk your electronics, just leave the piezo circuit out. Its only purpose is to give acoustic feedback to the user about the rotation speed. What might cause a high voltage peak is if you drop the device or if you hit the piezo with a hard tool.

Step 4: Putting the Parts Together

Place all parts where you want them without gluing anything. Just check that they all fit. You want the electromagnet inside the box, preferably under the lid. Attach it temporarily with duct tape. Place your Arduino, your circuit board and your motor board inside the box. Check that you have space for the potentiometers and the switches. Check also that you have space for all wires. Check also that the Arduino won't be too close to the electromagnet.

When you are sure all parts fit, attach them with any method you find suitable. Hot glue is your friend. But it becomes your enemy, if you use it for hot parts like the electromagnet or the motor driver. Consider using screws or heat resistent epoxy putty instead.

Parts you want to solder

You may want to solder the leds, the resistors, the switch and the potentiometers. Figure out the right order how you do things. Do you want to solder the wires before placing all parts on their place or are you going to place all parts so that soldering will be easy while the parts are steady on their place?

How I solved some problems

The potentiometers had only some 10 mm of thread. The wall of the box was some 8 mm. That's why I needed a piece of sheet metal inside the box, as an inner wall, to attach the potentiometers on. The turnable axis of the potentiometers was as well too short to reach outside the box. I drilled a small hole in the end of the turnable axis of the potentiometers, put some epoxy glue in the hole, attached a wood screw in the hole, cut the head of the screw and attached my knob to the end of the screw with some more epoxy glue.

The threads of the screw got a good grip of the hardened epoxy. Also the cut head end of the screw got a shape that ensured a good grip of the epoxy inside the knob. The sheet metal could as well be glued with epoxy to the bottom. Better that, than having screws going through the bottom of the box.

Step 5: The Code

The code, when opened in the Arduino IDE, consists of five tabs (or five .ino files).

sketch_strangely_attractive

This is the main program containing jumps to all four specific programs of the Strangely Attractive

/*
 *   Define pins
 */

// Four modes, these attach to the rotary switch
#define mode1p 7   // no hall program (chaotic)
#define mode2p 8   // hall program (brushless motor)
#define mode3p 9   // caotico-tico (chaotic with some preset parameters)
#define mode4p 10  // accelerando-ritardando (back and forth spinning)

// These go to the leds in the lid,
// showing the polarity (or accel/retard in mode 4)
#define pole1 11
#define pole2 12

// These go to the first motor channel for the electromagnet 
#define coil1 5
#define coil2 6
#define duty_pin 3 // This is the on-off signal to the motor driver

// These go to the second motor channel for the piezo
#define piezo1 A5
#define piezo2 A6

#define hall_pin 2 // This reads the Hall sensor
#define timer_pin A1     // This reads the timer potentiometer
#define throttle_pin A2  // This reads the throttle potentiometer
#define trimpotN_pin A3  // These two read the trimpots
#define trimpotS_pin A4  // on the breadboard


void hall_programme(void);
void no_hall_programme(void);
void caotico_tico(void);
void accelerando_ritardando(void);
void swap(void);
void duty(bool du);

bool on_duty;
bool swapper;

int mode;
unsigned long hall_time = 0;
unsigned long last_hall_time = 1;

void setup() {
    pinMode(coil1, OUTPUT);
    pinMode(coil2, OUTPUT);
    pinMode(pole1, OUTPUT);
    pinMode(pole2, OUTPUT);
    pinMode(A5, OUTPUT);
    pinMode(A6, OUTPUT);
    
    pinMode(LED_BUILTIN, OUTPUT);
    pinMode(mode1p, INPUT_PULLUP);
    pinMode(mode2p, INPUT_PULLUP);
    pinMode(mode3p, INPUT_PULLUP);
    pinMode(mode4p, INPUT_PULLUP);
  
  attachInterrupt(digitalPinToInterrupt(hall_pin), time_hall, FALLING);
}

void time_hall(void)
{
  hall_time = millis();
 
}

void loop() {
  if (digitalRead(mode1p) == LOW)
    mode = 1;
  if (digitalRead(mode2p) == LOW)
    mode = 2;
  if (digitalRead(mode3p) == LOW)
    mode = 3;
  if (digitalRead(mode4p) == LOW)
    mode = 4;
  
  switch (mode)
  {
    case 1 :
      no_hall_programme();
      break;
    case 2 :
      hall_programme();
      break;
    case 3 : 
      caotico_tico();
      break;
    case 4 :
      accelerando_ritardando();
      break;
    default :
      break;
  }
}

no_hall_programme

The first program, where the magnet polarity switches to a rate determined by the first potentiometer in the front panel. The second potentiometer determines how many percent of the time the magnet field is on and off. The main activity of the fidget spinner is chaotic movement back and forth.

void no_hall_programme(void)
{
  long timer_reading;
  long throttle_reading;

  static unsigned long last_swap = 0;
  unsigned long now;

  long deltatime;  // time between swaps, max 3000 ms
  long duty_promille;  // 0 - 1000, how long the electromagnet is on

  do
  {
    timer_reading = analogRead(timer_pin);
    throttle_reading = analogRead(throttle_pin);
    deltatime = map(timer_reading, 0, 1023, 50, 3000);
    duty_promille = throttle_reading * 1000 / 1024;
    
    now = millis();
    if (now > last_swap + deltatime)
    {
      swap(!swapper);
      if (swapper)
      {
        digitalWrite(pole1, HIGH);
        digitalWrite(pole2, LOW);
      }
      else
      {
        digitalWrite(pole2, HIGH);
        digitalWrite(pole1, LOW);
      }
      last_swap = now;
      duty(true);
      digitalWrite(LED_BUILTIN, HIGH);
    }
    if (now > last_swap + duty_promille * deltatime / 1000)
    {
      duty(false);
      digitalWrite(pole1, LOW);
      digitalWrite(pole2, LOW);
    }
  }
  while (digitalRead(mode1p) == LOW);
}

void swap(bool direc)
{
  swapper = direc;
  if (direc)
  {
    digitalWrite(coil1, HIGH);
    digitalWrite(coil2, LOW);
  }
  else
  {
    digitalWrite(coil1, LOW);
    digitalWrite(coil2, HIGH);
  }
  
  
}

hall_programme

The second program, where the magnet polarity switches according to the moment when one arm of the fidget spinner is exactly over the Hall sensor. From this moment there's a delay until the exact swap of the polarity happens. The delay is determined by the first potentiometer. The second swap happens when half of the time has elapsed to the estimated next Hall sensor reading. The second potentiometer determines how many percent of the time the magnet field is on and off. The main activity of the fidget spinner is accelerating rotating up to a maximum rotation speed.

#define speed_cnt 30
#define speed_delta 4


void hall_programme(void)
{
  int timer_reading;
  int throttle_reading;

  unsigned long last_swap = 0;
  unsigned long now;

  unsigned long swap1;
  unsigned long swap2;
  unsigned long t1;
  unsigned long t2;
  int phase = 0;
  unsigned long dt;
  unsigned long comp, comp2;
  
  long deltatime;
  long last_deltatime = 0;
  long duty_promille;

  long speeder[speed_cnt];
  for (int i = 0; i < speed_cnt; i++)
    speeder[i] = 0;
  int speed_ptr;
  long speed_sum = 0;
  
  delay(500);
  t1 = millis() - 300;
  t2 = millis() - 100;
  swap1 = millis() + 50;
  swap2 = millis() + 100;
  bool my_flag = false;
  
  while (digitalRead(mode2p) == LOW)
  {
    timer_reading = analogRead(timer_pin);
    throttle_reading = analogRead(throttle_pin);
    duty_promille = throttle_reading;
    now = millis();
  
    comp = hall_time; // comp holds the value of hall_time during the whole loop,
                      // we don't want a changing value during the loop.
                      // (hall_time gets updated in an interrupt)
    
    // When a signal comes from the Hall sensor,
    // it is time to update the last timestamps
    if (t2 != comp)
    {
      t1 = t2;
      t2 = comp;
      my_flag = false;
      deltatime = t2 - t1;
      speed_sum -= speeder[speed_ptr];
      speed_sum += (deltatime - last_deltatime);
      speeder[speed_ptr] = (deltatime - last_deltatime);
      last_deltatime = deltatime;
      speed_ptr++;
      speed_ptr %= speed_cnt;
      if (speed_sum > 2)
      {
        digitalWrite(pole1, HIGH);
        digitalWrite(pole2, LOW);
      }
      else 
      {
        if (speed_sum < -2)
        {
          digitalWrite(pole2, HIGH);
          digitalWrite(pole1, LOW);
        }
        else 
        {
          digitalWrite(pole1, LOW);
          digitalWrite(pole2, LOW);
        }
      }
    }
    
  
    // Apart from updating the timestamps, check
    // whether it's time to do the two swaps.
    switch (phase)
    {
      case 0: // waiting for the first swap
        if (now > swap1)
        {
          swap(true);
          duty(true);
          last_swap = now;
          
          phase = 1;
          my_flag = true;
        }
        break;
      case 1: // waiting for the second swap
        if (now > swap2)
        {
          swap(false);
          duty(true);
          
          last_swap = now;
          phase = 2;
        }
        break;
      case 2: // second swap has happened
        if (!my_flag)
        {
          swap1 = t2 + (t2 - t1) * timer_reading / 1024;
          swap2 = swap1 + (t2 - t1) / 2;
          
          phase = 0; 
        }
        break;
    }
  
    if (on_duty && (now > last_swap + duty_promille * deltatime / 1024))
      duty(false);
  }
}

void duty(bool du)
{
  on_duty = du;
  if (du)
    digitalWrite(duty_pin, HIGH);
  else
    digitalWrite(duty_pin, LOW);
  
}

caotico_tico_programme

The third program has some 15 to 30 seconds cycles where the rate of the magnet polarity swaps as well as the duty cycles vary. The main activity of the fidget spinner is chaotic movement back and forth.

  /*
   *    Have the timer change between 100 ms and 2000 ms
   *    in 17 s periods
   *    Have the duty change between 10 % and 80 %
   *    in 13 s periods
   */

#define timer_min 100
#define timer_max 2000
#define timer_time 17000
#define duty_min 100
#define duty_max 800
#define duty_time 13000



void caotico_tico(void)
{
  unsigned long last_time;
  unsigned long next_time = 0;
  unsigned long last_duty;
  unsigned long next_duty = 0;
  bool time_step = false;
  bool duty_step = true;
  
  long timer_reading;
  long throttle_reading;

  static unsigned long last_swap = 0;
  unsigned long now;

  long deltatime;  
  long duty_promille;  

  last_time = millis();
  last_duty = millis();
  
  do
  {
    now = millis();
    if (now > next_time)
    {
      last_time = next_time;
      next_time = now + timer_time;
      time_step = !time_step; 
    }
    if (now > next_duty)
    {
      last_duty = next_duty;
      next_duty = now + duty_time;
      duty_step = !duty_step; 
    }
    if (time_step)
    {
      deltatime = map(now, last_time, next_time, timer_min, timer_max);
    }
    else
    {
      deltatime = map(now, last_time, next_time, timer_max, timer_min);
    }
    if (duty_step)
    {
      duty_promille = map(now, last_duty, next_duty, duty_min, duty_max);
    }
    else
    {
      duty_promille = map(now, last_duty, next_duty, duty_max, duty_min);
    }
    
    if (now > last_swap + deltatime)
    {
      swap(!swapper);
      if (swapper)
      {
        digitalWrite(pole1, HIGH);
        digitalWrite(pole2, LOW);
      }
      else
      {
        digitalWrite(pole2, HIGH);
        digitalWrite(pole1, LOW);
      }
      last_swap = now;
      duty(true);
      digitalWrite(LED_BUILTIN, HIGH);
    }
    if (now > last_swap + duty_promille * deltatime / 1000)
    {
      duty(false);
      digitalWrite(pole1, LOW);
      digitalWrite(pole2, LOW);
    }
  }
  while (digitalRead(mode3p) == LOW);

  
}

accelerando_ritardando_programme

The fourth program runs the fidget spinner one minute in one direction, then it changes the direction. The electromagnet runs on full duty. The timing is adjusted with the two trimpots. Any change in the setup (using another fidget spinner with different magnetsy, placing the fidget spinner differently, moving the Hall sensor) would need new tuning of the trimpots.

When the direction changes, the electronics just swaps the polarity and starts to use the other trimpot setting for the timing. This works as a brake for the fidget spinner. When it stops, it might instantly start rotating in the opposite direction. If not, if it stops and doesn't seem to do anything for 4 seconds, random magnetic pulses try to get it spinning in the right direction.

#define interval 45000 // Switch rotation direction in 45 s intervals

void accelerando_ritardando(void)
{
  int timer_reading;

  unsigned long last_swap = 0;
  unsigned long now;

  unsigned long swap1;
  unsigned long swap2;
  unsigned long t1;
  unsigned long t2;
  int phase = 0;
  unsigned long dt;
  unsigned long comp, comp2;
  
  long deltatime;
  long last_deltatime = 0;
  long duty_promille;

  delay(500);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  
  unsigned long swap_timer;
  bool swappy = true;
  swap_timer = millis() + interval; 
  digitalWrite(pole1, HIGH);
  digitalWrite(pole2, LOW);
  
  t1 = millis() - 300;
  t2 = millis() - 100;
  swap1 = millis() + 50;
  swap2 = millis() + 100;
  bool my_flag = false;

  duty_promille = 1023;
  
  while (digitalRead(mode4p) == LOW)
  {
    if (swappy)
      timer_reading = analogRead(trimpotN_pin);
    else
      timer_reading = analogRead(trimpotS_pin);
    
    comp = hall_time; // comp holds the value of hall_time during the whole loop,
                      // we don't want a changing value during the loop.
                      // (hall_time gets updated in an interrupt)
    now = millis();
    
    // When a signal comes from the Hall sensor,
    // it is time to update the last timestamps
    if (t2 != comp)
    {
      t1 = t2;
      t2 = comp;
      my_flag = false;
      deltatime = t2 - t1;
    }
    
  
    // Apart from updating the timestamps, check
    // whether it's time to do the two swaps.
    switch (phase)
    {
      case 0: // waiting for the first swap
        if (now > swap1)
        {
          swap(swappy);
          duty(true);
          
          digitalWrite(piezo1, HIGH);
          digitalWrite(piezo2, LOW);
          
          last_swap = now;
          phase = 1;
          my_flag = true;
        }
        break;
      case 1: // waiting for the second swap
        if (now > swap2)
        {
          swap(!swappy);
          duty(true);
          digitalWrite(piezo2, HIGH);
          digitalWrite(piezo1, LOW);
          last_swap = now;
          phase = 2;
        }
        break;
      case 2: // second swap has happened
        if (!my_flag)
        {
          swap1 = t2 + (t2 - t1) * timer_reading / 1080;
          swap2 = swap1 + (t2 - t1) / 2;
          phase = 0; 
        }
        break;
    }

    if (now > swap_timer)
    {
      swappy = !swappy;
      swap_timer = millis() + interval; //millis() + map(analogRead(timer_pin), 0, 1023, 20000, 60000);
      if (swappy)
      {
        digitalWrite(pole1, HIGH);
        digitalWrite(LED_BUILTIN, HIGH);
        digitalWrite(pole2, LOW);
      }
      else
      {
        digitalWrite(pole2, HIGH);
        digitalWrite(LED_BUILTIN, LOW);
        digitalWrite(pole1, LOW);
      }

    }

    // check if spinner has stopped
    if (now - hall_time > 4000)
    {
      // Give it two 200 - 400 millisecond kicks
      // with a pause of 600 - 1000 milliseconds inbetween
      duty(true);
      swap(!swapper);
      delay(random(200, 400));
      duty(false);
      delay(random(600, 1000));

      duty(true);
      swap(!swapper);
      delay(random(200, 400));
      duty(false);

      // This is just random poking to hope it gets a kick in
      // the right direction. The trimpots are set to give maximal
      // speed in each direction. A kick in the wrong direction
      // wont get it running, but a kick in the right direction will.
      // Sooner or later it succeeds.
    }

  }
}

Step 6: The Hall Sensor

Simply put, the Hall sensor is an electronic sensor that senses the presence of a magnetic field. Typically it's a tiny semiconductor component with three legs. You provide it with a voltage over two legs, like 5 V and 0 V from your microcontroller. Then the third leg gives you some 5 V, when no magnetic field is present, and near 0 V when a strong N pole is present. The KY-003 shouldn't be picky about whether it's N or S, according to some documents, but my sensor was picky. Turning the Fidget Spinner upside down won't work with the Hall sensor.

There are other types of Hall sensors. The KY-024 has a fourth leg telling the polarity and strength of the magnetic field and a trimpot for the sensitivity of the digital output. The KY-035 has no digital output, only the analog output.

A brushless motor

The image shows the optimal place for the Hall sensor to turn the chaotic fidget spinner into a brushless motor. The electromagnet should not affect the Hall sensor a lot, but the magnets in the fidget spinner arms should, as they pass over the sensor. The purpose of the sensor is to provide information to the microcontoller when to swap the electromagnet polarity. The optimal moment might not be exactly at the time of the sensor signal, but the microcontroller can take care of any delay needed.

The cycle

Imagine the fidget spinner spinning clockwise in the image. One spinner arm is approaching the left end of the electromagnet, which is pulling it. At the same time, the right end of the electromagnet is pushing the arm that has just passed the right end. When this arm reaches the Hall sensor, our microcontroller will know it. Now is the time to switch polarity of the electromagnet. The right end starts pulling the arm at the top, the left end starts pushing the arm at the left.

When will the next swap happen? Do we need another Hall sensor for that? It would be placed at the opposite side of this sensor. But here we will rely on the logics in our microcontroller. Imagine the fidget spinner just spinning around and the Hall sensor sending signalsto the microcontroller. The microcontroller can record the time when an arm is passing by. It can now decide when to do the swap. The logic could go as follows:

  1. t1 and t2 are the time stamps of two consecutive signals from the Hall sensor
  2. after t2, wait dt untill you swap
    dt is a fraction of (t2 - t1)
  3. after that, wait (t2 - t1) / 2 until you swap again
  4. let t1 = t2
  5. wait for next signal and set t2 to present time
  6. jump to 2

So the swapping happens two times between consecutive signals from the Hall sensor. You just have to know the right time for it to optimise the spinning motion. For this, we will sett up our two control knobs (potentiometers). One knob is the timing control and it will control the dt fraction. The other knob is the throttle control and it will set the duty cycle, namely how many percent of the time the electromagnet will be effective.

How to control

With low throttle, try to adjust the timing to get as high speed as possible. Increase the throttle in small steps and see if you have to adjust the timing for maximum speed.

A word of warning

My build won't reach very high speeds. But if I'd try to optimise everything by choosing a strong enough electromagnet, a strong enough motor driver and a strong enough power source and I'd optimise the magnetic interference between the components, I might reach dangerous speeds. A fidget spinner is safe as long as you spin it by hand. But this toy has extra weight (the magnets) and if you manage to reach higher speeds than by spinning by hand, the toy might break. You don't want a metallic object hit your face, your thumb or your stomach at almost a rifle bullet speed!

Step 7: Test Run and Things to Consider

So you have everything ready! Congrats! You have probably tested everything. Just in case you still wonder how to use the Strangely Attractive, here are some thoughts.

Program 1, Strangely Chaotic
(no_hall_programme.ino)

Place your magnetized fidget spinner on the top of the box. Turn on the electronics and select the first program. Twist the potentiometers so that you get the slowest rate and the full duty cycle. Either led should be on all the time, showing which end is the N pole. You should see the fidget spinner turn either back and forth, slowly rotating or rotating but changing direction chaotically. In any of the cases, it should be obvious which end of the electromagnet attracts at each turn. If at this point the wrong led lights up, turn around your fidget spinner. Or switch the lines going to the electromagnet. Or switch the D5 and D6 lines of the Arduino, which control the motor driver. Or switch the D11 and D12 lines of the Arduino, which control the led lights.

At this point, if the magnetic interaction seems too weak, you might consider adding more power by raising the power supply voltage, replacing the motor board with one with better specifications (L298N really is bad at keeping voltage high), searching for a better electromagnet or checking the position and direction of the magnets in the fidget spinner.

Raising slowly the frequency, you might succeed in getting the spinner rotate in the same direction all the time. At low frequencies you might want to lower the duty. If you are lucky and you got a very strong magnetic interaction, the fidget spinner moves very fast to the attracting end of the electromagnet. By lowering the duty rate you get only short magnetic pulses, short enough to merely get the spinner rotate. And when the moment of inertia has rotated the spinner far enough, the next short pulse comes. Try now to raise the frequency slowly while you also raise the duty rate. The fidget spinner will have a highest speed, where you have full duty rate and a frequency that matches the rotation speed, where the added energy equals the energy loss in friction. At that point the direction changes exactly when one spinner arm has reached the attracting end of the electromagnet. At that point this end starts repelling and the other end starts attracting.

Program 2, Brushless Motor
(hall_programme.ino)

In this mode, the Hall sensor gives a signal whenever a magnet passes over it. The idea is to be able to switch the polarity of the electromagnet at the right moment. It's not necessarily at the moment when the Hall sensor gives a signal, unless you search the optimal place for the Hall sensor. Instead, the Arduino measures the time between two consecutive signals and triggers the polarity switch according to that. The polarity switches occur twice per each interval between two signals from the Hall sensor. So the time between the switches is half the time of two consecutive Hall sensor signals. But the actual moment of the first switch after a received Hall sensor signal is controlled with one of the potentiometers. The other potentiometer just controls the on/off ratio of the electromagnet.

A real electric motor, brushless or brushed, has something to secure the start. This one hasn't. You may have to give the fidget spinner a soft start to get it running. Turn the throttle full on. Try to get the spinner rotating. It might catch on, or it might not. Try the other way around. If it doesn't start, it should at least react randomly to the electromagnet. Try to adjust the timing potentiometer.

When you get it running, turn down the throttle to avoid too fast spinning. At this point you should know the limits. Spin it too fast and you will have flying magnets and fidget spinner parts all around the room. But if you're sure about what you are doing, try to find the optimal settings of the timer for each level of the throttle. At this point, if you didn't glue the Hall sensor on, you might want to adjust its place to maximise the rotation speed.

The piezo element gives a weak buzz, telling how fast the spinner spins. Instead of having your Arduino telling the RPM in an extra display or in a serial monitor on your computer (which would require a connected USB cable and most probably a messed up timing for the whole program due to the serial data traffic), download a guitar tuner app on your mobile phone and measure the sound frequency. Say it measures 102 Hz. That would mean 34 rotations per second or 2040 RPM.

Program 3, Cao-ticotico
(cao_ticotico_programme.ino)

This is a program adapted and adjusted for my own Strangely Attractive. The same program might not work as such for your own device, without changing parameters. It selects randomly some parameters for the timing of the polarity switches, the on/off ratio of the electromagnet and whether or not to let the Hall sensor interfere.

Program 4, Accelerando e ritardando
(accelerando_ritardando_programme.ino)

This is another program adapted and adjusted for my own Strangely Attractive. It is simply supposed to accelerate the fidget spinner in one direction, then brake it and run it in the opposite direction. The timer pot sets the length of the intervals and the throttle pot sets the on/off ratio of the electromagnet.

The piezo element gives a weak buzz, telling how fast the spinner spins, just like in program 2.

Things to try

  • Try make the spinner rotate as slowly as possible, yet with a smooth motion (easier in program 2 than in program 1)
  • Try make the spinner oscillate between two positions (program 1)
  • Find interesting slow chaotic motion (program 1)
  • Find the top speed (program 2) either by listening to the buzz or by looking at interference patterns in the Fidget Spinner, when you light it up with a 50 Hz or 60 Hz light source
  • Find your favourite "office toy settings", where the fidget spinner
    just makes peculiar movements, catching everybody's attention
  • Rewrite the code for program 3 and 4 to suit your own implementation of the Strangely Attractive