Yet another one of those semi-serious conversations last year that had ended with: "Let's try to solve this with ChatGPT". The problem seemed a perfect fit. A friend and railroad enthusiast struggeled to program a specific behaviour for a model railroad crossing with a microcontroller.
"Given a railroad crossing, can you come up with a function describing the angle of the railroad crossing bar when moving from the horizontal (closed) position into the vertical open position?"
Certainly, ... and we got an answer for a simple linear and a more realistic sinusoidal movement.
Let's add one of the small details to make the simulation mimic the real world like the bar bumping back a bit when hitting the bumper.
"Could you add a damped oscillation towards the end of the movement, simulating the bar colliding with the end bumper and slowly getting into its final vertical position?"
🤪 almost...seems we were not precise enough.
"The bar should bump back to around 80 degrees when hitting the bumper, not straight into the bumper."
🥳 This one looks promising! Let's take it to the next level:
"I want to run this using an Arduino Uno; could you write a function openCrossRoadBar()?"
Certainly, ...
#include <Servo.h>
Servo crossingBarServo; // Create a servo object
int servoPin = 9; // PWM pin connected to the servo
// Parameters for the function
const float T = 5.0; // Time when the bar reaches near-vertical in seconds
const float A = 10.0; // Amplitude of the oscillation
const float b = 0.8; // Damping coefficient
const float c = 10.0; // Frequency of oscillation
void setup() {
crossingBarServo.attach(servoPin); // Attach the servo to the correct pin
Serial.begin(9600); // Initialize serial communication at 9600 baud
}
void loop() {
openCrossRoadBar(); // Call function to open the railroad crossing bar
delay(10000); // Wait 10 seconds before the next operation (for demonstration purposes)
}
void openCrossRoadBar() {
unsigned long startTime = millis();
float t, angle;
while(true) {
t = (millis() - startTime) / 1000.0; // Current time in seconds since start
if (t < T) {
// Initial smooth rise
angle = 90 * sin(PI / 2 * t / T);
} else if (t >= T) {
// Damped oscillation after reaching near-vertical
angle = 90 - A * exp(-b * (t - T)) * abs(sin(c * (t - T)));
}
// Check if the movement should continue
if (t > T + 2) {
break; // End the function after a sufficient time has passed
}
// Update the servo position
crossingBarServo.write((int)angle);
delay(20); // Short delay for smoother motion
// Optional: output current angle to the Serial Monitor
Serial.print("Time: ");
Serial.print(t);
Serial.print(" seconds, Angle: ");
Serial.println(angle);
}
}
...Okey-dokey, ready for the WOKWI test. (WOKWI is an online platform to simulate IoT projects in the browser)!
Well done! The code contained no errors, and we just finished our first iteration... Motivated by the quick results, we
- asked our chat partner to replace the serial output with LCD,
- and add a flashing light to the simulation.
Tip: You can find the project on WOKWI as Railroad Crossing. Play with it, and tune the function parameters to your liking.
I'm excited to see the almost unlimited possibilities of ChatGPT (and friends) to help hobbyists solve their problems without the need to dive deep into the world of physics, mathematics and programming.
Happy coding!
DALL-E Prompt: A black and white sketch featuring a model-sized bar-type railroad gate, designed to open vertically, placed beside a breadboard with an Arduino Uno and a small motor driver board connected to the gate motor. The sketch also shows a close-up of the motor driver board, with the Arduino pins labelled.