Well, we've reached the last day to submit projects for "Build a Present" and my snowman is not finished. In the spirit of participation, I thought I would document my progress...
Here is the link to my first post: Slip Ring Snowman
I ran into all the normal project issues, but primarily too busy with life to get finished. I wish that I had time to create a blooper reel .
I discovered that my use of the continuous servo with the rotating plates was not well thought out (i.e. the slip ring assembly that I used would not have worked in its originally intended application either). I had really not considered what a good gear ratio should be - just had found some gears that were available and easy to print. As a result the assembly cannot achieve a slow rotational speed or position repeatability.
And, I had a funny experience trying to print the "balls" for the snowman's body. I don't use any fancy CAD software to generate my prints (I use OpenScad), so there really isn't any warning if you've done something dumb with your design. I was just printing hollow spheres with the tops and bottoms cut off. I didn't have any problems with the larger ones, but when I went to print the smaller "head" - I ended with a bird's nest of filament (sorry, didn't take pictures). Thinking it was either a filament problem or an adhesion problem, I tried reprinting a couple of times after carefully cleaning the build plate. After repeatable failures, I finally took the time to watch as it printed. I was surprised to see that it was trying to print a support structure within the hollow sphere and because of the thinness of the sphere (1mm), the print was skewing on the build plate. Finally realized that I had a small misalignment when I had cut off the top and bottom in the design tool and that the hole on the bottom ended up being slightly smaller than the hole on the top. That caused the slicer (Cura) to decide it needed to add a support structure which was causing the print to fail. I'm not expert enough to know if that's a configuration setting that I can tweak. Suffice to say, I wasted a lot of time with the printing mishaps.
Here's a quick summary of project features:
Flashing LEDs in base plate
I had some 5mm RGB "Fader" LEDs that I had purchased from Electronic Goldmine. These LEDs are not controllable - apply power and they run through a fixed multi-color flash and fade sequence. I put 4 of these in the base.
MQTT Control
I am using MQTT to send messages to the Nano 33 IoT board to control the servo and audio and LEDs. I am using an RPi4 running Mosquitto MQTT and Node-Red as my MQTT server.
Currently, I only have the servo control implemented on the Node-Red Dashboard. I am using a simple pulldown menu to select the control message and I echo the published message for verification.
MCU
For the controller I am using an Arduino Nano 33 IoT. Its WiFi capability enables the wireless MQTT control. I thought about using a board that had battery capability, but I'll just use set this up with a USB power bank.
MP3 Player
I am using a JQ6500 MP3 player to play the audio clips. I described it in an earlier post: JQ6500 MP3 Player
Servo
I am using a FEETECH FT90R Digital Micro Continuous Rotation Servo which is spec'ed to have an 80 RPM no load speed @ 5V.
LEDs on snowman
This is the part of the project that I have not finished. I have 6 wires on the slip ring. My intention is to control 5 LEDs w/common ground (2 eyes, 3 buttons on body). Hardest part is getting the LEDs mounted and then I just need to add the code for the program and the MQTT dashboard. If I make any progress this weekend, I'll update the post.
Program code
Nano33iot_Snowman_MQTT.ino
/*
MQTT Client for Snowman
the arduino_secrets.h file:
#define SECRET_SSID "" // network name
#define SECRET_PASS "" // network password
#define SECRET_MQTT_USER "public" // broker username - not used
#define SECRET_MQTT_PASS "public" // broker password - not used
created 14 January 2022
by Ralph Yamamoto
*/
#include <Wire.h>
#include <SPI.h>
#include <Servo.h>
#include <WiFiNINA.h>
#include <ArduinoMqttClient.h>
#include "arduino_secrets.h"
#define servoPin 9
#define clockwise 0
#define counterclockwise 180
#define servoStop 90
#define TRACK1 3
#define TRACK2 2
Servo myservo;
unsigned long delayTime;
// initialize WiFi connection:
WiFiClient wifi;
MqttClient mqttClient(wifi);
// details for MQTT client:
char broker[] = "10.0.0.234";
int port = 1883;
char topic[] = "snowman_control";
char clientID[] = "snowman";
void setup() {
// set up pins for audio playback - initialize to high-z
pinMode(TRACK1, INPUT);
pinMode(TRACK2, INPUT);
// set up servo
myservo.attach(servoPin); // attaches the servoPinto the servo object
myservo.write(servoStop); // might need to adjust this value for no movement
// initialize serial:
Serial.begin(115200);
// wait for serial monitor to open:
while (!Serial); // time to get serial running - take out after debug
Serial.println(F("Nano33IoT Snowman test"));
// initialize WiFi, if not connected:
while (WiFi.status() != WL_CONNECTED) {
Serial.print("Connecting to ");
Serial.println(SECRET_SSID);
WiFi.begin(SECRET_SSID, SECRET_PASS);
delay(2000);
}
// print IP address once connected:
Serial.print("Connected. My IP address: ");
Serial.println(WiFi.localIP());
// set the credentials for the MQTT client:
mqttClient.setId(clientID);
//mqttClient.setUsernamePassword(SECRET_MQTT_USER, SECRET_MQTT_PASS);
// try to connect to the MQTT broker once you're connected to WiFi:
while (!connectToBroker()) {
Serial.println("attempting to connect to broker");
delay(1000);
}
Serial.println("connected to broker");
mqttClient.onMessage(onMqttMessage);
}
void loop() {
// if not connected to the broker, try to connect:
if (!mqttClient.connected()) {
Serial.println("reconnecting");
connectToBroker();
}
mqttClient.poll();
}
boolean connectToBroker() {
// if the MQTT client is not connected:
if (!mqttClient.connect(broker, port)) {
// print out the error message:
Serial.print("MOTT connection failed. Error no: ");
Serial.println(mqttClient.connectError());
// return that you're not connected:
return false;
}
// once you're connected, you can proceed:
mqttClient.subscribe(topic);
// return that you're connected:
return true;
}
void onMqttMessage(int messageSize) {
String messageTemp;
int x = 0;
// we received a message, print out the topic and contents
Serial.print("Received a message with topic '");
Serial.print(mqttClient.messageTopic());
Serial.print("', duplicate = ");
Serial.print(mqttClient.messageDup() ? "true" : "false");
Serial.print(", QoS = ");
Serial.print(mqttClient.messageQoS());
Serial.print(", retained = ");
Serial.print(mqttClient.messageRetain() ? "true" : "false");
Serial.print("', length ");
Serial.print(messageSize);
Serial.println(" bytes:");
// use the Stream interface to print the contents
while (mqttClient.available()) {
messageTemp += (char)mqttClient.read();
}
// Serial.print("Message: ");
// Serial.println(messageTemp);
if (messageTemp.equals("Turn_Left")) {
Serial.println("Turn_Left");
for (x = 0; x <= 2; x += 1){
myservo.write(80); // servo ccw
delay(100);
myservo.write(90); // tell servo to stop
delay(20); // waits 15 ms for the servo to reach the position
}
delay(200);
pinMode(TRACK2, OUTPUT);
digitalWrite(TRACK2, 0);
delay(200);
pinMode(TRACK2, INPUT);
}
else if (messageTemp.equals("Turn_Right")) {
Serial.println("Turn_Right");
for (x = 0; x <= 2; x += 1){
myservo.write(110); // servo cw
delay(100);
myservo.write(90); // tell servo to stop
delay(20); // waits 15 ms for the servo to reach the position
}
delay(200);
pinMode(TRACK2, OUTPUT);
digitalWrite(TRACK2, 0);
delay(200);
pinMode(TRACK2, INPUT);
}
else if (messageTemp.equals("Servo_Stop")) {
Serial.println("Servo_Stop");
}
}
Demo video
I had run out of white filament (actually a spool is lost somewhere in my stuff ), so I ended up up printing with black and trying to spray paint it white. Painting kind of accentuates surface defects that you can see. If I had more time I should have tried to smooth out the surface of the "balls". Maybe with with lessons learned, I can do a better job for next Christmas .
Final Update 1/14/2022
I managed to install the 3 LEDs for the snowman's buttons. I realized that I'm not totally sure what I wanted them to do.
Here is a quick demo of a sequential fade pattern:
I've come to realize that installing small parts and wiring in tight spaces is becoming a real challenge for my old arthritic hands, so I gave up on installing the LED eyes (I was going to use blue) and decided to use a Sharpie to draw in the face and declare the project sort of done.
Life is calling again. Another great Project14... Lots of terrific projects!