Introduction

I suppose you noted that the opening image of this episode has changed. For a strange coincidence, the Art-a-Tronic exhibition started past April 5th ends this week At Depot09 – Ghent (BE). The same day the PiCasso Challenge ends too. I should say the results were better than the expectations; a couple of weeks ago the event has been appreciated by one of the coordinators of another nice place, the Kolder Art Space in Ghent and after a couple of meetings we agreed for an Art-a-Tronic second edition from next June 8th until the end of July. The above image is the invitation card for the new event.

 

There will be some interesting changes it is worth to mention; next two months Seven Of Nine will be visible by the public through the gallery showcase open to the road in the very center of the town. The most important thing, in my opinion, is the workshop activity we are also organizing: every weekend, inside the exhibition place it will take place a "Saturday workshop" for kids interested to be introduced to the art of programming.

For more details and to follow the event, visit, like and follow the official Kolder Facebook Page.

 

This 16th episode is the last technical post of the last project upgrade. I plan to publish also a final post next days to present all the features we saw in the past posts during these last two months. In the meantime, before going in depth to the technical stuff, take a look at the video below, showing the birth of the Borg. In the meantime, for a couple of week Seven of Nine will stop sending tweets and some other features; she remains in her alcove waiting for the new site ready. In the meantime, you can chat on twee with her anyway as while she is restoring the Borg Access Terminal remains awake and connected.

 

 

Carousel IoT

Starting from the cage based on The Christmas Joy Spreading Machine project of past Christmas 2018 I have upgraded the electronics, hardware, and mechanics. This became an attracting, trap-machine very helpful to the Borg to attract humans; it's well-known and not only in the Alpha Sector, that humans are easy to be hypnotized by colored lights, nice sounds, and very repetitive motion. Nothing better than a cage resembling a carousel!

 

Mechanics Improvements

After a considerable number of hours running at the exhibition in Depot09, I saw that some parts were too weak to be stressed for a long time. So first of all, I designed and 3D printed a new kind of support of the top free-wheel gear, that keeps in place the main rotating wheel. Another defect I discovered with usage (the entire structure of the first version were done with cardboard) was the sphere collector spiral; sometimes, one of the balls was falling out of the guide despite the rotation speed. I have also designed a small guide glued on the top of the spiral collector to right address the spheres when exiting from the rotating wheel.

Another small issue: the big rotating wheel is not 100% stable (as expected), so sometimes the spheres are not pushed out to the collector; the third upgrade has been a small semispheric element glued to the opposite side of the spiral collector to force all the spheres to exit when the wheel drive them on top. Last, I have designed four supports to add a protective base to cover the electronic boards assembled and wired to the bottom of the carousel platform.

Above: the top gear side-locks to optimize the motion control and increase the big wheel stability

Below: the drive of the collector of the spiral

Below: The spherical block to push the spheres outside of the big wheel

As the carousel will detect the human presence through a PIR motion detector, together with the four supports I have also designed a small box for the PIR as shown in the renderings below.

The images below show some detail of the final result.

 

Revisiting the Technology and Upgrading hardware

The first version of the carousel has been developed around the features of the BBC micro:bit. Two key aspects imposed to replace the original board with a couple of Arduino: adding new features to make the project complete (I discovered later I missed something essential) and adding connectivity and IoT capabilities to the carousel cage, as well as different kind of interactivity that should coexist together.

To avoid excessive complexity, after experimenting with the limits and incompatibilities of some Arduino libraries with others, I decided to split the architecture in two separate parts:

  • Arduino Nano 328pArduino Nano 328p to control the carousel music (that revealed a relatively complex software)
  • Arduino MKR1000Arduino MKR1000 to control the servos, WiFi connectivity, and IoT data via the MQTT protocol (and more, read below)

In addition, I had to use two separate power supply lines and a DC-DC power regulator. The scheme below shows the architecture of the carousel components and wiring

The four light spot – every light is built with six high-intensity white LEDs – are mounted on four micro servosfour micro servos to continuously change the spot direction. Lights are powered by 6.5V 2.5 A power supply, while their intensity is controlled by four pins (one very light) by four MKR1000 PWM signals, connected to two L298N half bridges. The same 6.5V power line power the servos through a DC-DC power regulator, to avoid powering the servos with a current higher than 4.5V. Note that the 470 uF capacitor is used to filter the current to the servos and avoid unwanted vibration when a specific positioning angle is sent. The servos signal instead is controlled by other six PWM pins on the Arduino MKR1000.

The carousel activity is started by the PIR motion detector (My Elegoo sensor kit seems endless ) or by the Seven Of Nine Raspberry PI 3B+Raspberry PI 3B+  remotely through the MQTT protocol on the WiFi LAN.

Using a very cheap microSD mp3 player I have programmed an Arduino Nano to control all the features of the player through the serial interface (the most complete available on the mp3 player). The player also includes a microSD card reader where I put a series of classical carousel samples. The Arduino Nano can execute a series of automatic player functions when a pin is triggered – in our case by the MKR1000 board –

The player includes a low power amplifier that can connect directly to a less than 1W power speaker, as well as a couple of earplug outputs.

 

Making the Sound Loud

To reach the necessary power without adding an amplifier, in-style with the carousel features I have designed a passive amplifier, one of those cones just used to make the music loud thanks to the physics of sound. In this context we don't care about the quality of the sound, it is not needed a HiFi sound output but an outdoor carousel music simulation. Below the render of the loud cone and the 3D printed version.

Above: the testing prototype of the Arduino Nano connected to the mp3 player and the MKR1000 controlling the system

The video below shows the first test of the loudness amplifier with the Arduino Nano prototype. After the first couple of hours writing the software and going ahead to complete this part of the project, I have also added a 4.7 K trimmer to the Nano analog input to set up the maximum output volume of the music...

 

Few Words on the Software

 

The software setup of the Arduino Nano is detailed in the CarouselSound sketch. For this subproject, I have created a dedicated GitHub repository including the rendered images and the STL components described above. As a matter of fact, this project is part of the features extensions of Seven Of Nine (the main subject of the Art-a-Tronic project) but can be developed (or inspire some new creation or hacking) as an IoT stand-alone project itself.

Above: carousel bottom view with the implementation of the electronics and wiring. From top to bottom: PIR sensor (exposed), L298N light controls, the Arduino MKR1000 and the Arduino Nano with the mp3 player.

 

To integrate the carousel I followed two steps, creating three different sketches. The first version – can run on any other Arduino like the UNO R3, Mega, etc. is the control software. To make all the parts (servos, rotating wheel, sound triggering and lights working together I had to set a loop() function of the sketch as event-driven. This approach (also available on the mentioned alicemirror/Carousel GitHub repository) is a well-known methodology to control different and concurrent events on the same microcontroller I have already used in other cases and in my opinion the most efficient approach when for some reasons there are limitations using interrupts.

The StateMachine class is a set of methods controlled by three kinds of events: the MQTT requests (that have priority over the other events), the PIR sensor, and the Seven Of Nine MQTT requests. Every method is a sort of "black box" without input or output parameters; the logic is controlled by the states of the machine, changing values and flags of a control structure, managed and altered by all the StateMachine class methods.

 

//! Structure defining the status flags of the machine
typedef struct {
    boolean music;             ///< The status of the mp3 player
    boolean pir;               ///< The status of the PIR sensor
    int wheel;                 ///< The rotating wheel speed
    boolean isRotating;        ///< Wheel status
    int light;                 ///< The current light intensity
    int servoPos[NUMLIGHTS];   ///< Last positon of the light rotating servos
    /** 
     * Rotation direction of type "A". 
     * 
     * To rotate the light crossing the colors here are used to directions
     * initially set to the opposite starting points and with opposite
     * increments (+1 / -2)
     */
    int rotationDirA;          
    /** 
     * Rotation direction of type "A". 
     * 
     * To rotate the light crossing the colors here are used to directions
     * initially set to the opposite starting points and with opposite
     * increments (+1 / -2)
     */
    int rotationDirB;
    /**
     * Reading of the timer when the PIR status has been detected
     * It is reset everytime the pir status is read positive
     */
    unsigned long timerStart;
    /**
     * Laset millis read to temporize the servo lights rotation
     * continuously. The value is checked/updated everytime the 
     * updateHardware() is called.
     */
    unsigned long timerServo;
} MachineStatus;

 

This approach not only is very efficient but it is also very easy to maintain and upgrade, also in cases where there are drastic changes or new parts to controls. The resulting loop() function is incredibly simple as shown in the pieces of code below:

 

// Create an instance of the state machine class
StateMachine carousel;

//! Setup and initialization
void setup() {
  carousel.initHardware();
  carousel.initStatus();
}

//! Main loop
void loop() {
  if(carousel.isPir() ) {
    // Sensor PIR has been activated, check if
    // it is time to disable it
    if(carousel.getElapsed() > CAROUSEL_CYCLE) {
      // The cycle should stop
      carousel.endCarousel();
    } // Time elapsed
  } // Pir is active
  else {
    // Check if there is a movement detection
    carousel.checkPirStatus();
    // If Pir status is true, the music is starting and we shoud
    // start the other stuff
  } // Movement detection

  // Update the hardware components, accordingly with 
  // the machine status
  carousel.updateHardware();
}

 

Cloud Integration and Borg Assimilation

After the experience with the Arduino IoT Cloud and the strong limitations met with the Beta version of the platform (based on the AWS IoT) – and also considering that I already own an AWS account by years, as well as an EC3 machine, some virtual storage disks and other AWS stuff – I have decided to enable the carousel on the IoT cloud using the AWS IoT platform.

This solution revealed the best choice and, as far as I have tried until now the AWS IoT remains the most versatile and performing IoT cloud platform I ever used.

I moved directly to the IoT thing creation; I tried to see some tutorial available online on how to set up the platform and I should say that I strongly discourage to try to follow some of them. The real problem is that the AWS IoT is growing fast, and continuously evolving; if you are not so lucky to find a very recent tutorial probably it is out of date. By the other side, AWS is updating contextually to the changes the large documentation and series of examples and how-to you can access directly from the site so it is definitely the best way to approach the system.

Above: the entry point for the AWS IoT (after registering and setting your credentials) is the creation of a thing, in this case (right) the carouselMKR1000 thing.

Below: the ARN (Amazon Resource Name) and the other information related to the thing. This is the identity card of your thing inside the AWS cloud. To the right, how the thing certificate (used to identify in the program your IoT cloud object as it appears opened by the certificate reader on the PC.

Setting the Arduino MKR1000

The value-added of the Arduino IoT cloud is that using the chip included in the MKR family all the certificate mechanism is done automatically from the Arduino server on your board, with advantages and disadvantages, IMHO. Making the thing by yourself it is not so difficult as it seems and a very good tutorial on this part can be found on the Arduino site: https://create.arduino.cc/projecthub/Arduino_Genuino/securely-connecting-an-arduino-mkr-wifi-1010-to-aws-iot-core-a9f365 Consider that also this tutorial is outdated regarding the screenshots and the exact procedure for the AWS side (for this, please consult the AWS helpful hints and descriptions available on the AWS IoT core site).

 

Following the state-machine approach, the ideal solution was adding the IoT methods to the StateMachine class. Unfortunately, due to the architecture of the already available Arduino libraries for the MQTT protocol, it has not been possible; excluding to partially redesign the libraries, I have opted for a series of functions written directly on the main sketch, available on the GitHub repository.

 

  /**
   * Get the current time from the WiFi module (network time)
   */
  unsigned long getTime() {
      return WiFi.getTime();
  }

//! Try to connect to the WiFi and retry after a delay if connection is not possible
void connectWiFi() {
#ifdef _DEBUG
  Serial << "Attempting to connect to SSID: " << ssid << " ";
#endif

  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
#ifdef _DEBUG
    Serial << ".";
#endif
    delay(CONN_DELAY);
  }
#ifdef _DEBUG
  Serial << endl << "You're connected to the network" << endl;
#endif
}

void connectMQTT() {
#ifdef _DEBUG
  Serial << "Attempting to MQTT broker: " << broker << " ";
#endif

  while (!mqttClient.connect(broker, MQTT_BROKER_PORT)) {
    // failed, retry
#ifdef _DEBUG
    Serial << ".";
#endif
    delay(CONN_DELAY);
  }

#ifdef _DEBUG
  Serial << endl << "MQTT broker connection established" << endl;
#endif

  // subscribe to a topic
  mqttClient.subscribe(MQTT_CLIENT_SUBSCRIBER);
}

//! Message reeived callback function
void onMessageReceived(int messageSize) {
#ifdef _DEBUG
  Serial << "Received a message '" << mqttClient.messageTopic() <<
  "', length " << messageSize << " bytes:" << endl;
#endif

  // use the Stream interface to print the contents
  while (mqttClient.available()) {
#ifdef _DEBUG
    Serial << (char)mqttClient.read();
#endif
  }

  // Empty the message buffer
  mqttClient.flush();
  
#ifdef _DEBUG
  Serial << endl << endl;
#endif

  publishJsonIoTStatus();
}

 

Instead, a new state structure has been created to manage the state of the carousel and send data to the MQTT broker (the AWS IoT cloud thing). A couple of functions keep track of every change of the states and progressively update counters, reset at every power-on:

 

//! MQTT message structure
typedef struct IoTmessage {
  //! Number of detections by the last power on
  int detections;
  //! Start playing the carousel (ms)
  //! Updated after everydetection cycle starts
  unsigned long timerStart;
  //! Total number of minutes played by the last power on
  float timePlayedUntilNow;
  //! Number of wheels rotations (including partial rotations)
  //! by the last power on
  float wheelRotations;
  //! Total number of spheres cycles in the carousel
  unsigned long numSpheres;  
};

 

Every time a request is sent to the MKR1000 the current state of the counters is converted in a Json object and send to the broker. Below a screenshot of what is published on the AWS IoT cloud

Working Locally: Sending to Seven Of Nine

The last step has been converting the version communicating to the cloud broker, to the Seven Of Nine Raspberry PI broker, that already has a server setup for the Magic Mirror published messages, as described in the Art-a-Tronic Episode 12 using the LAN MQTT connection with Mosquitto.

The Mosquitto library is also available for Arduino MKR1000 and the final version of the carousel, communicating with the Raspberry PI over the LAN is available on GitHub repository as well.

For the Arduino conversion – easier than the AWS Cloud – I should thank jomoenginer (John Morss) who published the very useful and well documented post MKR WiFi 1010 - MQTT Remote Relay Board Control

 

Previous Episodes

Next Episodes