|
8 | 8 | }, |
9 | 9 | "source": [ |
10 | 10 | "<center>\n", |
11 | | - "<h4>CDS 110, Lecture 3</h4>\n", |
| 11 | + "<h4>CDS 110, Lecture 1</h4>\n", |
12 | 12 | "<font color=blue><h1>Dynamics and Control of a Servomechanism System using Python-Control</h1></font>\n", |
13 | 13 | "<h3>Richard M. Murray, Winter 2024</h3>\n", |
14 | 14 | "</center>\n", |
15 | | - "<br>\n", |
16 | 15 | "\n", |
17 | | - "In this lecture we show how to model an input/output system and design a controller for the system (using eigenvalue placement).\n", |
| 16 | + "[Open in Google Colab](https://colab.research.google.com/drive/1a9ECA-g4Vfi-D3LtbN21xtV9dLzA2RrF)\n", |
| 17 | + "\n", |
| 18 | + "In this lecture we show how to model an input/output system and design a controller for the system (using eigenvalue placement). This main intent of this lecture is to introduction the Python Control Systems Toolbox ([python-control](https://python-control.org)) and how it can be used to design a control system.\n", |
18 | 19 | "\n", |
19 | 20 | "We consider a class of control systems know as *servomechanisms*. Servermechanisms are mechanical systems that use feedback to provide high precision control of position and velocity. Some examples of servomechanisms are shown below:\n", |
20 | 21 | "\n", |
|
67 | 68 | " + \\begin{bmatrix} 0 \\\\ 1/J \\end{bmatrix} \\tau_\\text{m}.\n", |
68 | 69 | "$$\n", |
69 | 70 | "\n", |
70 | | - "The system consists of a spring loaded arm that is driven by a motor, as shown below\"\n", |
| 71 | + "The system consists of a spring loaded arm that is driven by a motor, as shown below:\n", |
71 | 72 | "\n", |
72 | | - "\n", |
| 73 | + "<center><img src=\"https://www.cds.caltech.edu/~murray/courses/cds110/sp2024/servomech-diagram.png\" width=200 alt=\"servomech-diagram\"></center>\n", |
73 | 74 | "\n", |
74 | 75 | "The motor applies a torque that twists the arm against a linear spring and moves the end of the arm across a rotating platter. The input to the system is the motor torque $\\tau_\\text{m}$. The force exerted by the spring is a nonlinear function of the head position due to the way it is attached.\n", |
75 | 76 | "\n", |
|
80 | 81 | "\\quad r = 1,\\quad l = 2,\\quad \\epsilon = 0.01.\n", |
81 | 82 | "$$\n", |
82 | 83 | "\n", |
83 | | - "and we assume that time is measured in msec and distance in cm. (The constants here are made up and don't necessarily reflect a real disk drive, though the units and time constants are motivated by computer disk drives.)" |
| 84 | + "and we assume that time is measured in milliseconds (ms) and distance in centimeters (cm). (The constants here are made up and don't necessarily reflect a real disk drive, though the units and time constants are motivated by computer disk drives.)" |
84 | 85 | ] |
85 | 86 | }, |
86 | 87 | { |
|
127 | 128 | " # Return the state update law\n", |
128 | 129 | " return np.array([thetadot, dthetadot])\n", |
129 | 130 | "\n", |
130 | | - "# System output (full state)\n", |
| 131 | + "# System output (tip radial position + angular velocity)\n", |
131 | 132 | "def servomech_output(t, x, u, params):\n", |
132 | 133 | " l = params['l']\n", |
133 | 134 | " return np.array([l * x[0], x[1]])\n", |
134 | 135 | "\n", |
135 | 136 | "# System dynamics\n", |
136 | 137 | "servomech = ct.nlsys(\n", |
137 | 138 | " servomech_update, servomech_output, name='servomech',\n", |
138 | | - " params=servomech_params,\n", |
139 | | - " states=['theta_', 'thdot_'],\n", |
| 139 | + " params=servomech_params, states=['theta_', 'thdot_'],\n", |
140 | 140 | " outputs=['y', 'thdot'], inputs=['tau'])\n", |
141 | 141 | "\n", |
142 | 142 | "print(servomech)\n", |
|
171 | 171 | "\n", |
172 | 172 | "# Linearize the system about the equilibrium point\n", |
173 | 173 | "P = servomech.linearize([theta_e, 0], u_e)[0, 0]\n", |
174 | | - "print(\"Linearized dynamics:\", P)" |
| 174 | + "# P.update_names(name='linservo')\n", |
| 175 | + "print(\"Linearized dynamics:\\n\", P)" |
175 | 176 | ] |
176 | 177 | }, |
177 | 178 | { |
|
254 | 255 | "# Plot step response (input 0 to output 0)\n", |
255 | 256 | "plt.plot(timepts, output)\n", |
256 | 257 | "plt.xlabel(\"Time $t$ [ms]\")\n", |
257 | | - "plt.ylabel(\"Position $y$ [m]\")\n", |
| 258 | + "plt.ylabel(\"Position $y$ [cm]\")\n", |
258 | 259 | "plt.title(\"Step response for the linearized, open-loop system\")\n", |
259 | 260 | "\n", |
260 | 261 | "# Compute and print properties of the step response\n", |
|
314 | 315 | "plt.plot(timepts, nl_response.outputs[0], label=\"nonlinear\")\n", |
315 | 316 | "\n", |
316 | 317 | "plt.xlabel(\"Time $t$ [ms]\")\n", |
317 | | - "plt.ylabel(\"Position $y$ [m]\")\n", |
| 318 | + "plt.ylabel(\"Position $y$ [cm]\")\n", |
318 | 319 | "plt.title(\"Step response for the open-loop system\")\n", |
319 | 320 | "plt.legend()" |
320 | 321 | ] |
|
326 | 327 | "id": "7YNmgE2XHmL3" |
327 | 328 | }, |
328 | 329 | "source": [ |
329 | | - "We see that the nonlinear system responses differently. This is because of the fact that the force exerted by the spring is nonlinear due to the kinematics of the mechanism design." |
| 330 | + "We see that the nonlinear system responds differently. This is because the force exerted by the spring is nonlinear due to the kinematics of the mechanism design." |
330 | 331 | ] |
331 | 332 | }, |
332 | 333 | { |
|
338 | 339 | "source": [ |
339 | 340 | "## Feedback control design\n", |
340 | 341 | "\n", |
341 | | - "We next design a feedback controller for the system that that allows the system to track a desired position $y_\\text{d}$ and sets the closed loop eigenvalues of the linearized system to $\\lambda_{1,2} = −10 \\pm 10 i$.\n", |
| 342 | + "We next design a feedback controller for the system that that allows the system to track a desired position $y_\\text{d}$ and sets the closed loop eigenvalues of the linearized system to $\\lambda_{1,2} = −10 \\pm 10 i$. We will learn how to do this more formally in later lectures, so if you aren't familiar with these techniques, that's OK.\n", |
342 | 343 | "\n", |
343 | | - "To do this, we make use of full state feedback of the form $u = -K(x - x_\\text{d})$ where $x_\\text{d}$ is the desired state of the system. The python-control `place` command can be used to compute the state feedback gains $K$ that set the closed loop poles at a desired location:" |
| 344 | + "We make use of full state feedback of the form $u = -K(x - x_\\text{d})$ where $x_\\text{d}$ is the desired state of the system. The python-control `place` command can be used to compute the state feedback gains $K$ that set the closed loop poles at a desired location:" |
344 | 345 | ] |
345 | 346 | }, |
346 | 347 | { |
|
435 | 436 | "# Compute and print properties of the step response\n", |
436 | 437 | "results = ct.step_info(clsys_resp.outputs[0], timepts)\n", |
437 | 438 | "print(\"\")\n", |
438 | | - "print(\"Rise time:\", results['RiseTime'])\n", |
439 | | - "print(\"Settling time:\", results['SettlingTime'])\n", |
440 | | - "print(\"Steady state error (percent):\", abs(results['SteadyStateValue'] - 1) * 100)" |
| 439 | + "print(f\"Rise time: {results['RiseTime']:.2g} ms\")\n", |
| 440 | + "print(f\"Settling time: {results['SettlingTime']:.2g} ms\")\n", |
| 441 | + "print(f\"Steady state error: {abs(results['SteadyStateValue'] - 1) * 100:.2g}%\")" |
441 | 442 | ] |
442 | 443 | }, |
443 | 444 | { |
|
464 | 465 | "Roughly speaking, we set the input of the system to be of the form $u(t) = \\sin(\\omega t)$ and then look at the output signal $y(t)$. For a *linear* system, we can show that the output signal will have the form\n", |
465 | 466 | "\n", |
466 | 467 | "$$\n", |
467 | | - "y(t) = M sin(\\omega t + \\phi)\n", |
| 468 | + "y(t) = M \\sin(\\omega t + \\phi)\n", |
468 | 469 | "$$\n", |
469 | 470 | "\n", |
470 | 471 | "where the magnitude $M$ and phase $\\phi$ depend on the input frequency.\n", |
|
487 | 488 | "response = ct.frequency_response(G[0, 0])\n", |
488 | 489 | "out = response.plot()\n", |
489 | 490 | "axs = ct.get_plot_axes(out)\n", |
490 | | - "axs[1][0].set_xlabel(\"Frequency [rad/ms]\");" |
| 491 | + "axs[1, 0].set_xlabel(\"Frequency [rad/ms]\");" |
491 | 492 | ] |
492 | 493 | }, |
493 | 494 | { |
|
0 commit comments