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.
Here's a good example, showing how this can be implemented. Here's the guts of it:
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:
Reading an analogue input is fairly simple. Here's a short program that converts a 0-5V input to a blink rate for the inbuilt LED.
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