Wednesday, December 11, 2024

Nooooo, don't make me reflect on my learning!

 ... I just want to stick wires in breadboards and make froggies dance!!!

Okay, but seriously, that stupid dancing frog was clearly my most proud moment of the semester.  I had to use Tinkercad, which was totally new to me, and it also involved using other people's existing sketches and modifying them for my own.  I also had to use our new 3D printers at MCC, which was also semi-disastrous (I managed to clog the best-working one right after I finished).  I also had to take a breath and realize it was okay if it wasn't "perfect" insofar as getting the math scaling right.

At the beginning, I was irritated we were going to have to learn to use Arduino - I had skillfully made great excuses for not learning it for about 15 years now and had no intent to stop - but here we were.  Ugh.  I will say that Tinkercad was a Godsend because if all I could do was just experiment with the physical equipment I think I would have given up much earlier.  Being able to "prove" to myself that at least, in theory, the circuit should work gave me the courage to try and get it to work in reality.  Then later, when Tinkercad couldn't keep up with what I was doing (I'm looking at you, stupid motor), I was confident enough-ish that I could go straight to the board (having tested out the code in another way in Tinkercad).

I enjoyed looking through the book, and not letting myself just "get by."  Paulina made me take this class (because she's a super-meany), and I absolutely 100% did not have time for it.  But of course as soon as we got into it, I was hooked.  I'm never going to see myself as a "real-life-maker-person" because there are just too many highly-competent individuals around me, but I feel like I can at least be a Poser.  Like, I can say, "Yeah, you know, this one time when I was trying to get this servo working with my Arduino...." but then if anyone asks, "did you try flashing your blahblahblah," I'll just turn into a pile of bubbling garbage.

In general, looking back, I see someone gaining confidence throughout a short 8-week semester, but honestly it would not have been possible had I not already had a strong background in programming and a reasonably-decent background in CAD.  (Paulina is our CAD and 3D printing expert, and I was just trying to channel her.)  

I always tell my students, "You never learn anything until the third time you see something."  I've had two other opportunities where I've programmed an Arduino and had no idea what was going on.  True to form, this is the time I finally yielded and decided, "okay I can't hide anymore, I've got to actually try to learn this."

I don't know what lies ahead for me in my maker world -- probably fixing the 3D printer, which we've named Peanut, before Paulina yells at me (she always makes me cry!!) (no, not really, just checking to see if she's reading this, lol), but she will give me a Disappointing Look if I don't get it working again and I wither under that gaze.  I am really excited about building the Engineering Commons with Paulina and ****maybe**** I might be brave enough to try soldering.  But I still need to attempt it two more times....




Friday, December 6, 2024

Final Maker Challenge: A Dancing Frog!

This week I was inspired by a Tinkercad post about using a motor to make a 3D printed creature move around.  https://www.tinkercad.com/projects/Evolution-Games-Building-Creatures-With-Basic-Elec

The little creatures looked really cute, and I thought I could probably get this working with a photoresistor so they would go faster when it was bright and slower when it was dark.  Ah, me of the beginning of this week, you were so naive....

Clearly I can make this work with this cute little baby Arduino I found in a box!

I had done a PD session a few years ago and I remembered it had some circuit-y stuff in it.  Opening it, it had an Arduino-something but also this teeny-tiny Arduino, called an Arduino Nano.  This is perfect, I thought!  I can mount this directly onto the animal and then make it battery powered and I won't have to worry about wires and stuff.

Seriously, look how cute this is!


Okay, so it actually runs with a mini usb.  Not even a micro, but like one of those ones that looks like two different-sized rectangles on top of each other.  So this was kind of old.


By the time I used my USB to USB-C converter for my laptop, there was too much lost in translation, so I headed over to my daughter's paint-splattered computer.  She still has the old-school USB ports and I got the Arduino IDE working on it.  Without too much effort, I was actually able to load a pre-built program and make the servo work!


I actually still have it connected to the large breadboard, but it worked!  Awesome!  The next step was to move everything to my tiny breadboards that I had and make it work with the motor.  Everything was wired up, the code was ready to go, and .......... nothing.


I uploaded the code, it seemed happy, but then it did nothing.  I went back to the servo code that I knew worked from last week, and still got nothing.  After some extensive troubleshooting, I realized the only code I could get to work on this Nano baby was the pre-built code that came with the Arduino IDE, and if I tried to do anything from scratch it got very, very mad at me.

"Dear ChatGPT, Why would my Arduino Uno code not work on my Arduino Nano?"

There are several reasons your Arduino Uno code might not work on an Arduino Nano. Here are the most common issues to check:

1. Board Selection in Arduino IDE   ... nope

2. Pin Differences  ...nope

3. Voltage Differences   ...nope

4. Memory or Resource Usage   ...nope

5. External Components   ...nope

6. Library Compatibility   ...nope

7. Faulty Nano or Bootloader Issues   

  • Test your Nano with a simple sketch like the "Blink" example to confirm it is functioning correctly.
  • If the Nano has an old or corrupt bootloader, it might fail to execute the code. You can re-burn the bootloader using another Arduino board as a programmer.

...oi, so yeah, I'm not emotionally ready to "re-burn the bootloader"... whatever that means

Guess I'm going back to using the Big Giant Uno Board.

While that's going on, let's try some 3D printing

I went to the Tinkercad website and copied the bunny and frog models.  I deleted the insides because they were built for a differently-shaped motor than the one we have, and took them to the 3D printer.


They came out pretty cute, actually!  I brought them home to play with, and of course, the motor really needed a holder.  I was able to make one in Tinkercad based on what I'd learned when I'd used it for making a model of my Makerspace earlier this semester, so that felt good.


But again, of course when it was time to pull everything together, the holes in the spinner things were too small, and the motor holder was too big for the frog and too small for the bunny.  Another day, another trip to the 3D printers to try a few more designs, until I finally got everything fitting together.



Wiring this just for the motor should be totally easy!

Since I still hadn't gone to pick up the photoresistor yet, I decided just to get it going with the motor.  Problem 1 was again trying to tell the difference between the temperature sensor and the transistors.  I don't know how people did stuff like this without cell phones and zooming in.  I guess magnifying glasses?  Ugh.

I got everything wired up, but dang, it seemed really weak compared to what I had been expecting, and since I had been hoping to decrease the motor speed based on the light, this really didn't seem like it could handle going much slower.  I could hear the motor trying to gear up, but I had to give it a nudge half the time to get it going.



I also had a fun experience watching Bunny say, "No, thank you."


Let's take a look at this wiring

Oh my, it appears I've flipped the diode and the resistor.  My setup was right on Tinkercad, but somehow even though I'd wired it wrong, it was still working.  


What a relief, and what an easy fix!

Right?

       Right???

                     Right???

Of course not, that would be silly.  And how would I ever have any fun practicing all my bad language if everything went right all the time???

Once I flipped the diode and the resistor, the motor stopped spinning entirely. I could hear it engage, but it wouldn't spin.  I thought maybe I'd "fried" something, so I switched out the diode, the resistor (I'd actually had the wrong resistance anyway), and the transistor, but still nothing was working.  I connected the motor directly to the power and ground bars to make sure it still ran, which it did, but man, I could not figure out what was going on.

Then I figured it out.


Let's see this froggy dance!

The motor was clearly much stronger now, and she was dancing like there was no tomorrow!  Since my next goal was to add the photoresistor, I wanted to make sure she'd still run at a lower power.  I adjusted the code to alternate between a low motor speed and a high motor speed.  I also tried getting some of the wires out of the way to see how far she might travel.


I decided to focus on the frog because the motor was a tighter fit for her, so she got better motion.  Given the time constraints, I figured in retrospect I could pretend that's why I was trying two different things at once anyway - just so that I could actually maybe get one working!

Adding the photoresistor should be super easy now....

I confidently moved into the "adding the photoresistor" phase. Wiring it up wasn't too bad because I'd done that before in previous projects.



But when I was playing with it with Tinkercad, I noticed that when the photoresistor was at half, the motor was still close to 255, so I decided to ask ChatGPT.  I copy/pasted my code, and then asked this terribly-worded question:


And it gave me this code snippet to try:

// Apply non-linear correction (example uses square root to flatten high values)
  float normalizedLight = (float)(lightLevel - lightLow) / range; // Normalize to 0-1
  normalizedLight = constrain(normalizedLight, 0.0, 1.0); // Ensure within bounds
  motorLevel = pow(normalizedLight, 0.5) * 255; // Example: sqrt correction for light non-linearity

Yeah, but that didn't quite work.  I thought maybe having it done in "real life" would help, since Tinkercad has become less reliable the more complex my projects have become, so I put together the breadboard.  As a math person, I started to obsess a little much about how when half the photoresistor was covered, it didn't give me half the value, and I spent way too much time trying to "math" myself a solution.



Then I realized that no one was going to care if the frog was dancing at 85% effort when they really should be dancing at 75% effort and I needed to let this one go.  

I did a few more tweaks to the code as well, because when the motor speed was sufficiently low (like below 100), you could hear the motor trying to spin up, but not being able to actually do so.  I added some code to ignore low motor spin values.

  if (motorLevel > 100){
     motorOnThenOff(motorLevel);
  }

It's time for my closeup!

Froggy was ready to party.  I gave her a glam-up in Tinkercad so she wouldn't have such a boxy head, and also made her counterweight a fly, because I thought it was cuter that way.  



I used my daughter's acrylic paints (remember the paint-splattered computer??), and once everything dried we were ready to go!


My husband ran the lights and my puppies provided the background music.  The light-to-motor connection is on an (intentional) three-second delay so it'll still dance a little bit after the lights go off and won't start right away when the lights go on.  You can also tell that it will dance "faster" when the lights are really bright and that it will dance less enthusiastically when the lights are on but dimmer.  Hope you enjoy!



All the extras

Here is the circuit diagram!


And here is the code!

// We'll be controlling the motor from pin 9.
// This must be one of the PWM-capable pins.
const int motorPin = 9;
const int lightInputPin = A0;

int randomNumber;
int buttonPin = 2;
int buttonState = 0;


// We'll also set up some global variables for the light level:
// I initially set them at 300 and 400, but will allow them to
//   change based on what happens in the system
int lightLevel, lightLow = 400, lightHigh = 500;

void setup(){
 
  // Set up the motor pin to be an output:
  pinMode(motorPin, OUTPUT);
  pinMode(buttonPin, INPUT);
 
  Serial.begin(9600);
  randomSeed(analogRead(0));
 
} // end setup()

void loop(){

  Serial.println("Light Level:");  
  Serial.println(lightLow);  

  double motorLevel = lightLoop();
  if (motorLevel > 100){
     motorOnThenOff(motorLevel);
  }
} // end loop

void motorOnThenOff(double speed){
  analogWrite(motorPin, speed); // turn the motor on (full speed)
  delay(3000);

  Serial.println("Off");  
  analogWrite(motorPin, 0);  // turn the motor off
} // end motorOnThenOff


float lightLoop(){
  int range = lightHigh - lightLow;
  float motorLevel;

  lightLevel = analogRead(lightInputPin);
  Serial.println("Light Level:");  
  Serial.println(lightLevel);  

 
  if (lightLevel < lightLow & lightLow > 35) {
    lightLow = lightLevel;
  }
 
  if (lightLevel > lightHigh) {
    lightHigh = lightLevel;
  }

// Apply non-linear correction (example uses square root to flatten high values)
  float normalizedLight = (float)(lightLevel - lightLow) / range; // Normalize to 0-1
  normalizedLight = constrain(normalizedLight, 0.0, 1.0); // Ensure within bounds

  motorLevel = pow(normalizedLight, 0.3) * 255; // Example: sqrt correction for light non-linearity
 
 
  Serial.println("normalizedLight:");  
  Serial.println(normalizedLight);  
  Serial.println(":------:");

  Serial.println("Motor LEvel:");  
  Serial.println(motorLevel);  
  Serial.println(":------:");


  return motorLevel;


} // end lightLoop



Nooooo, don't make me reflect on my learning!

 ... I just want to stick wires in breadboards and make froggies dance!!! Okay, but seriously, that stupid dancing frog was clearly my most ...