Tuesday, 11 February 2025

Arduino time?

Thought process:

I seem to have concluded that I want the following features for my motorised torch head ("Motorhead"):

  • Variable speed of travel
  • Variable "spot welding" time
  • Control of the welder (to achieve the repetitive "stitch" welding behaviour)
  • Reasonably good speed control
This seems to confirm the direction I was heading last time, namely:
  • Use a stepper motor to achieve precise, variable speed control and "4WD"
  • Allow variable on time of the welder for the spot / stitch welding mode
Which pretty much means:
  • Arduino Nano for the microcontroller
  • A4988 stepper driver for the motor
  • NEMA17 motor with dual shafts (for the "4WD")
Let's get started:

So I got myself an Arduino Nano ESP32 - why not? 


Rather than simply have an add-on ESP32 for wifi and Bluetooth, "the Nano ESP32 features the ESP32-S3 system on a chip (SoC) from Espressif, which is embedded in the NORA-W106 module. The ESP32-S3 has a dual-core microprocessor Xtensa® 32-bit LX7".

The downside of this exciting feature set is evident when you compile even the simplest code. The first attempt took almost 5 minutes, leaving me wondering WTF was wrong with my laptop. It appears that there's nothing much you can do to speed it up - it's something to do with the much larger libraries that come with the SoC. Sod that - I've now ordered the more common or garden version of the Nano, aka Nano Every, which features a more conventional ATmega4809 processor.

I have an Arduino Uno R4 Wifi which also incorporates the ESP32 - but only as a peripheral. The microcontroller is a Renesas RA4M1, which is hopefully closer to the Atmel family and sure enough, it compiles much quicker (~20s, as opposed to ~5 minutes). I'm hopeful (hoping) that the Nano Every is similarly quick to compile for.

Also arrived today, what looks like a Chinese clone of the Pololu A4988 driver:


Program elements:

Timer:
Rather than use delays to implement on and off time, it's far better to run an endless loop and evaluate / toggle outputs against the required on and off times. This is referred to as "blink without delay" in the documentation. The issue with using delay is that it actually causes the program to stop execution until the delay has ended. If you wanted to do anything else during that time, you'd be out of luck. By running tasks in a loop, you can run multiple tasks independently and simultaneously. 

This is a common approach, one I seem to recall implementing over 40 years ago when I developed a 16 channel self tuning PID controller for my final year project at uni. That was written in Pascal (!) but to my mind it's actually quite similar to C. In contrast, my old, addled brain struggles with Pascal, which pretty much rules out using a Raspberry Pi.


void loop()

{
  // capture the current time
  currentMillis = millis();
  manageRedLed();
  manageGreenLed();
}

void manageRedLed() {  //check if it's time to change the Red LED yet
  if(currentMillis - previousMillisRed > redLedInterval) {
    //store the time of this change
    previousMillisRed = currentMillis;
    redLedState = (redLedState == HIGH) ? LOW : HIGH;
    digitalWrite(redLedPin, redLedState);
  }
}

void manageGreenLed() {
  //check if it's time to change the green LED yet 
  if(currentMillis - previousMillisGreen > greenLedInterval) {
    //store the time of this change
    previousMillisGreen = currentMillis;
    greenLedState = (greenLedState == HIGH) ? LOW : HIGH;
    digitalWrite(greenLedPin, greenLedState);
  }


I'll bugger about with this and perhaps evolve it into a pulse (stitch) control for the arc control.

Variable frequency pulse generator:

Here's some content that produces a variable frequency output. With some buggerage, I will aim to create a variable frequency output for the A4988 driver.

#include <TimerOne.h>


const int pulsePin = 9;
int inputFreq = 20;//Hz
unsigned long period;//microseconds

void setup(void)
{
  //Freq = (1/inputFreq)*1000000;
  period = 1000000/inputFreq;
  Timer1.initialize(period); 
  Serial.begin(9600);
}

void loop(void)
{
  Serial.println(period);
  Timer1.pwm(pulsePin, 40);//gives duty cycle of 3.9%
}

Analogue input for frequency and duty cycle control:


int sensorPin = A0;   // select the input pin for the potentiometer
int ledPin = 13;      // select the pin for the LED
int sensorValue = 0;  // variable to store the value coming from the sensor

void setup() {
  // declare the ledPin as an OUTPUT:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);
  // turn the ledPin on
  digitalWrite(ledPin, HIGH);
  // stop the program for <sensorValue> milliseconds:
  delay(sensorValue);
  // turn the ledPin off:
  digitalWrite(ledPin, LOW);
  // stop the program for <sensorValue> milliseconds:
  delay(sensorValue);
}


I will bugger about with that and implement it as the input(s) to control the speed and duty cycle.

Trigger input:

I'm looking for a high / low switch status rather than an analogue signal. Here's some example code.

void setup() {
  //start serial connection
  Serial.begin(9600);
  //configure pin 2 as an input and enable the internal pull-up resistor
  pinMode(2, INPUT_PULLUP);
  pinMode(13, OUTPUT);
}

void loop() {
  //read the pushbutton value into a variable
  int sensorVal = digitalRead(2);
  //print out the value of the pushbutton
  Serial.println(sensorVal);

  // Keep in mind the pull-up means the pushbutton's logic is inverted. It goes
  // HIGH when it's open, and LOW when it's pressed. Turn on pin 13 when the
  // button's pressed, and off when it's not:
  if (sensorVal == HIGH) {
    digitalWrite(13, LOW);
  } else {
    digitalWrite(13, HIGH);
  }
}

That's my starting point.

Some quick sums:
  • Motor drive pulses: With a 25mm dia / 75mm circumference wheel and weld spots 5mm apart, fired once per second, I'd want @15 seconds per rev of the wheel. Ignoring the gear ratio between the motor and wheel and assuming 200 steps per rev, I would need a pulse frequency of ~13 pulses per second. Allowing for some adjustment, that might result in 5-25Hz. If I implement microstepping at x16 (to minimise noise etc), that would translate to 80-400Hz.
  • Duty cycle: I'm guessing ~1Hz or so hard coded pulse frequency and 10-100% duty cycle to give good control over the pulse duration.
Releasing the trigger shouldn't result in immediately killing the arc. I'd want the pulse to finish ie not to be followed by another.

Similarly, the trigger should initiate a complete pulse, not a fraction of the steady state output.

No comments:

Post a Comment

Time to start behaving

Well, the endless rabbitholing seems determined to persist. The Waveshare ESP32S3 boards I got from Amazon seem to indeed "share" ...