|
15 | 15 | "\n", |
16 | 16 | "[Open in Google Colab](https://colab.research.google.com/drive/1a9ECA-g4Vfi-D3LtbN21xtV9dLzA2RrF)\n", |
17 | 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 | + "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 introduce the Python Control Systems Toolbox ([python-control](https://python-control.org)) and how it can be used to design a control system.\n", |
19 | 19 | "\n", |
20 | 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", |
21 | 21 | "\n", |
|
27 | 27 | "| | |" |
28 | 28 | ] |
29 | 29 | }, |
| 30 | + { |
| 31 | + "cell_type": "markdown", |
| 32 | + "id": "2c284896-bcff-4c06-b80d-d9d6fbc0690f", |
| 33 | + "metadata": {}, |
| 34 | + "source": [ |
| 35 | + "The python-control toolbox can be installed using `pip` over from conda-forge. The code below will import the control toolbox either from your local installation or via pip. We use the prefix `ct` to access control toolbox commands:" |
| 36 | + ] |
| 37 | + }, |
30 | 38 | { |
31 | 39 | "cell_type": "code", |
32 | 40 | "execution_count": null, |
|
54 | 62 | "source": [ |
55 | 63 | "## System dynamics\n", |
56 | 64 | "\n", |
57 | | - "Consider a simple mechanism for positioning a mechanical arm whose equations of motion are given by\n", |
| 65 | + "Consider a simple mechanism consisting of a spring loaded arm that is driven by a motor, as shown below:\n", |
| 66 | + "\n", |
| 67 | + "<center><img src=\"https://www.cds.caltech.edu/~murray/courses/cds110/sp2024/servomech-diagram.png\" width=200 alt=\"servomech-diagram\"></center>\n", |
| 68 | + "\n", |
| 69 | + "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", |
| 70 | + "\n", |
| 71 | + "The equations of motion for the system are given by\n", |
58 | 72 | "\n", |
59 | 73 | "$$\n", |
60 | 74 | "J \\ddot \\theta = -b \\dot\\theta - k r\\sin\\theta + \\tau_\\text{m},\n", |
|
68 | 82 | " + \\begin{bmatrix} 0 \\\\ 1/J \\end{bmatrix} \\tau_\\text{m}.\n", |
69 | 83 | "$$\n", |
70 | 84 | "\n", |
71 | | - "The system consists of a spring loaded arm that is driven by a motor, as shown below:\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", |
74 | | - "\n", |
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", |
76 | | - "\n", |
77 | 85 | "The system parameters are given by\n", |
78 | 86 | "\n", |
79 | 87 | "$$\n", |
|
203 | 211 | "id": "naH-Nl7V4c2R" |
204 | 212 | }, |
205 | 213 | "source": [ |
206 | | - "Alternatively, we can look at the eigenvalues of the \"dynamics matrix\" for the linearized system (we will learn about this formulation in week 3):" |
| 214 | + "Alternatively, we can look at the eigenvalues of the \"dynamics matrix\" for the linearized system (we will learn about this formulation in [Lecture 3](cds110-L3_lti-systems.ipynb)):" |
207 | 215 | ] |
208 | 216 | }, |
209 | 217 | { |
|
278 | 286 | "plt.plot([0, 0], [0, 2.5], 'k:')\n", |
279 | 287 | "plt.plot([results['SettlingTime'], results['SettlingTime']], [0, 2.5], 'k:')\n", |
280 | 288 | "plt.arrow(0, 1.5, results['SettlingTime'], 0)\n", |
281 | | - "plt.text(results['SettlingTime']/2, 1.6, '$T_s$')\n" |
| 289 | + "plt.text(results['SettlingTime']/2, 1.6, '$T_s$');\n" |
282 | 290 | ] |
283 | 291 | }, |
284 | 292 | { |
|
317 | 325 | "plt.xlabel(\"Time $t$ [ms]\")\n", |
318 | 326 | "plt.ylabel(\"Position $y$ [cm]\")\n", |
319 | 327 | "plt.title(\"Step response for the open-loop system\")\n", |
320 | | - "plt.legend()" |
| 328 | + "plt.legend();" |
321 | 329 | ] |
322 | 330 | }, |
323 | 331 | { |
|
356 | 364 | "\n", |
357 | 365 | "# Find the gains required to place the gains at the desired location\n", |
358 | 366 | "K = ct.place(P.A, P.B, [-10 + 10*1j, -10 - 10*1j])\n", |
359 | | - "print(f\"{K=}\")\n", |
| 367 | + "print(f\"{K=}\\n\")\n", |
360 | 368 | "\n", |
361 | 369 | "# Implement an I/O system implementing this control law\n", |
362 | 370 | "def statefbk_output(t, x, u, params):\n", |
|
370 | 378 | " None, statefbk_output, name='statefbk',\n", |
371 | 379 | " inputs=['y', 'thdot', 'y_d', 'thdot_d'],\n", |
372 | 380 | " outputs=['tau']\n", |
373 | | - ")" |
| 381 | + ")\n", |
| 382 | + "print(statefbk)" |
374 | 383 | ] |
375 | 384 | }, |
376 | 385 | { |
|
404 | 413 | " [servomech, statefbk],\n", |
405 | 414 | " inputs=['y_d', 'thdot_d'],\n", |
406 | 415 | " outputs=['y', 'tau']\n", |
407 | | - ")" |
| 416 | + ")\n", |
| 417 | + "print(clsys)" |
408 | 418 | ] |
409 | 419 | }, |
410 | 420 | { |
|
470 | 480 | "\n", |
471 | 481 | "where the magnitude $M$ and phase $\\phi$ depend on the input frequency.\n", |
472 | 482 | "\n", |
473 | | - "We can plot the magnitude (also called the \"gain\" of the system) and the phase as a function of the frequency $\\omega$ and plot these values on a log-log and log-linear scale (called a *Bode* plot):" |
| 483 | + "We can plot the magnitude (also called the \"gain\") and the phase of the system as a function of the frequency $\\omega$ and plot these values on a log-log and log-linear scale (called a *Bode* plot):" |
474 | 484 | ] |
475 | 485 | }, |
476 | 486 | { |
|
481 | 491 | "outputs": [], |
482 | 492 | "source": [ |
483 | 493 | "# Compute the linearization of the closed loop system\n", |
484 | | - "G = clsys.linearize([theta_e, 0], [0, 0])\n", |
| 494 | + "G = clsys.linearize([theta_e, 0], [0, 0], name=\"G\")\n", |
485 | 495 | "\n", |
486 | 496 | "# Plot the Bode plot (input[0] = yd, outut[0] = y)\n", |
487 | | - "print(\"Bode plot:\")\n", |
488 | 497 | "response = ct.frequency_response(G[0, 0])\n", |
489 | | - "out = response.plot()\n", |
490 | | - "axs = ct.get_plot_axes(out)\n", |
491 | | - "axs[1, 0].set_xlabel(\"Frequency [rad/ms]\");" |
| 498 | + "cplt = response.plot(title=\"Bode plot for G\", freq_label=\"Frequency [rad/ms]\")" |
492 | 499 | ] |
493 | 500 | }, |
494 | 501 | { |
|
508 | 515 | "id": "rocky-hobby" |
509 | 516 | }, |
510 | 517 | "source": [ |
511 | | - "## Trajectory tracking (if time)\n", |
| 518 | + "## Trajectory tracking\n", |
512 | 519 | "\n", |
513 | 520 | "Another type of analysis we might do is to see how well the system can track a more complicated reference trajectory. For the disk drive example, we might move the system from one point on the disk to a second and then to a third (as we read different portions of the disk).\n", |
514 | 521 | "\n", |
|
0 commit comments