OpenAI solves its mistakes, but it needs guidance
I was playing with OpenAI to create a model of an inverted pendulum in Python, and realized that it can, with appropriate guidance, correct mistakes when developing these mathematical models.
Can you write python code to animate an inverted pendulum PID control system?
to which chatGPT replied:
Sure, here’s some sample code to animate an inverted pendulum system with PID control in Python:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# Define the system dynamics
def inverted_pendulum(y, t, m, l, b, k, F):
theta, omega = y
dthetadt = omega
domegadt = (F(t) - b*omega - m*g*l*np.sin(theta))/ (m*l**2)
return [dthetadt, domegadt]
# PID controller
def pid_controller(theta_desired, theta, omega, Kp, Ki, Kd, integral, dt):
error = theta_desired - theta
integral += error*dt
derivative = -omega
return Kp*error + Ki*integral + Kd*derivative
# Initial conditions
theta0 = np.pi/6 # Initial angle
omega0 = 0 # Initial angular velocity
# System parameters
m = 1 # Mass of the pendulum
l = 1 # Length of the pendulum
b = 0.1 # Damping coefficient
g = 9.81 # Acceleration due to gravity
# PID controller parameters
Kp = 0.2
Ki = 0.01
Kd = 0.01
integral = 0
dt = 0.01
# Desired angle
theta_desired = 0
# Time points for the simulation
t = np.linspace(0, 10, 1000)
# Solve the system dynamics
solution = odeint(inverted_pendulum, [
this output is clearly incomplete, probably due to the current token restriction in chatGPT Output. I therefore insisted:
Can you write the code again only from what follows “# Solve the system dynamics”
to which chatGPT replied:
Sure, here’s the code after the line “# Solve the system dynamics”:
solution = odeint(inverted_pendulum, [theta0, omega0], t, args=(m, l, b, g, lambda t: pid_controller(theta_desired, solution[:, 0], solution[:, 1], Kp, Ki, Kd, integral, dt)))
# Create the animation
fig, ax = plt.subplots()
ax.set_xlim(-1, 1)
ax.set_ylim(-2, 2)
pendulum, = ax.plot([], [], 'o-', markersize=10, linewidth=2)
def init():
pendulum.set_data([], [])
return pendulum,
def animate(i):
x = l*np.sin(solution[i, 0])
y = -l*np.cos(solution[i, 0])
pendulum.set_data([0, x], [0, y])
return pendulum,
ani = FuncAnimation(fig, animate, frames=len(t), interval=10, blit=True, init_func=init)
plt.show()
This code uses odeint
function to solve the system dynamics of an inverted pendulum and pid_controller
function to control the angle of the pendulum. It creates an animation by creating a figure and axes, then it defines the pendulum object, the init()
function sets the initial position of the pendulum in the plot and animate(i)
function updates the position of the pendulum at each time step based on the solution array. The FuncAnimation
class creates the animation and it takes several arguments: the figure and axes to draw on, the function that updates the animation at each frame, the number of frames to draw, the interval between frames in milliseconds, whether to use blitting to optimize the drawing and the function to call when the animation starts. The last line `plt.
I then tried this with Python, yet I got an error back. I asked chatGPT about this error:
with respect to the previouys code, I get the following error: “NameError: name ‘solution’ is not defined”
to which chatGPT replied:
I apologize for the confusion, you are getting an error because the pid_controller
function is trying to use the solution
array before it has been defined. One way to fix this issue is to pass the current angle and angular velocity as additional arguments to the pid_controller
function, and then use those values inside the function instead of trying to access solution
. Here's an example of how this could be done:
# PID controller
def pid_controller(theta_desired, theta, omega, Kp, Ki, Kd, integral, dt):
error = theta_desired - theta
integral += error*dt
derivative = -omega
return Kp*error + Ki*integral + Kd*derivative
# ...
# Time points for the simulation
t = np.linspace(0, 10, 1000)
# Solve the system dynamics
solution = odeint(inverted_pendulum, [theta0, omega0], t, args=(m, l, b, g, lambda t, theta, omega: pid_controller(theta_desired, theta, omega, Kp, Ki, Kd, integral, dt)))
# ...
This way, the current angle and angular velocity is passed to the pid_controller
function at each time step during the integration, so it doesn't require the solution
array to be defined before the integration.
I implemented this in Python again, with another error call. Back to ChatGPT:
With respect to the code modified with your las suggestion, I am getting the following error: “TypeError: <lambda>() missing 2 required positional arguments: ‘theta’ and ‘omega’”
to which chatGPT replied:
I apologize for the confusion, the error message is indicating that the lambda function passed as the last argument to odeint
is missing 2 required arguments: theta
and omega
. This error occurs because in the lambda function, I am trying to pass theta
and omega
as arguments, but I didn't provide them when I called the function odeint
.
Here is how you can fix the error:
# Time points for the simulation
t = np.linspace(0, 10, 1000)
# Solve the system dynamics
solution = odeint(inverted_pendulum, [theta0, omega0], t, args=(m, l, b, g, lambda t, y: pid_controller(theta_desired, y[0], y[1], Kp, Ki, Kd, integral, dt)))
Here, I’m passing y
as an argument to the lambda function, which represents the current state of the system, y[0] is the current angle and y[1] is the current angular velocity and then passed them to the pid_controller
function. Also, I removed the previous argument theta
and omega
from the lambda function.
This way, odeint
will pass the current state y
to the lambda function, which can then extract the angle and angular velocity from that state and pass them to the pid_controller
function.
When running this in Python I got a different error which I run by chatGPT again:
With respect to the code modified with all your suggestions, I am getting the following error: “domegadt = (F(t) — b*omega — m*g*l*np.sin(theta))/ (m*l**2) TypeError: <lambda>() missing 1 required positional argument: ‘y’”
to which chatGPT replied:
I apologize for the confusion. I made a mistake in the inverted_pendulum function definition. The error message is indicating that the lambda function passed as the last argument to odeint
is missing 1 required argument: y
.
Here is how you can fix the error:
# Define the system dynamics
def inverted_pendulum(y, t, m, l, b, g, F):
theta, omega = y
dthetadt = omega
domegadt = (F(t, y) - b*omega - m*g*l*np.sin(theta))/ (m*l**2)
return [dthetadt, domegadt]
Here, I added the y
argument to the lambda function definition, so the current state of the system is passed as an argument to the pid_controller
function, which can then extract the angle and angular velocity from that state.
Now the inverted_pendulum function can call the F function with the correct argument, so it will not raise an error.
When running this in Python, it did run. This is the full code:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# Define the system dynamics
def inverted_pendulum(y, t, m, l, b, k, F):
theta, omega = y
dthetadt = omega
domegadt = (F(t, y) - b*omega - m*g*l*np.sin(theta))/ (m*l**2)
return [dthetadt, domegadt]
# PID controller
def pid_controller(theta_desired, theta, omega, Kp, Ki, Kd, integral, dt):
error = theta_desired - theta
integral += error*dt
derivative = -omega
return Kp*error + Ki*integral + Kd*derivative
# Initial conditions
theta0 = np.pi/6 # Initial angle
omega0 = 0 # Initial angular velocity
# System parameters
m = 1 # Mass of the pendulum
l = 1 # Length of the pendulum
b = 0.1 # Damping coefficient
g = 9.81 # Acceleration due to gravity
# PID controller parameters
Kp = 0.2
Ki = 0.01
Kd = 0.01
integral = 0
dt = 0.01
# Desired angle
theta_desired = 0
# Time points for the simulation
t = np.linspace(0, 10, 1000)
# Solve the system dynamics
solution = odeint(inverted_pendulum, [theta0, omega0], t, args=(m, l, b, g, lambda t, y: pid_controller(theta_desired, y[0], y[1], Kp, Ki, Kd, integral, dt)), rtol=1e-5, atol=1e-5)
# Create the animation
fig, ax = plt.subplots()
ax.set_xlim(-1, 1)
ax.set_ylim(-2, 2)
pendulum, = ax.plot([], [], 'o-', markersize=10, linewidth=2)
def init():
pendulum.set_data([], [])
return pendulum,
def animate(i):
x = l*np.sin(solution[i, 0])
y = -l*np.cos(solution[i, 0])
pendulum.set_data([0, x], [0, y])
return pendulum,
ani = FuncAnimation(fig, animate, frames=len(t), interval=10, blit=True, init_func=init)
ani.save('animation.gif', writer='imagemagick', fps=15)
plt.show()
chatGPT helped me create a code from scratch, and correct it along the way. With the proper guidance, chatGPT is extremely powerful, with the only visible restriction being the number of questions per hour and, to a certain extent, the maximum length (tokens)of the responses.