|
44 | 44 | " Accelerometer,\n", |
45 | 45 | " Environment,\n", |
46 | 46 | " Flight,\n", |
47 | | - " Function,\n", |
48 | | - " GnssReceiver,\n", |
49 | 47 | " Gyroscope,\n", |
50 | 48 | " Rocket,\n", |
51 | 49 | ")\n", |
52 | 50 | "from rocketpy.motors import CylindricalTank, Fluid, HybridMotor\n", |
53 | 51 | "from rocketpy.motors.tank import MassFlowRateBasedTank\n", |
54 | | - "from rocketpy.tools import quaternions_to_spin\n", |
55 | 52 | "\n", |
56 | 53 | "plt.style.use(\"seaborn-v0_8-colorblind\")" |
57 | 54 | ] |
|
284 | 281 | "outputs": [], |
285 | 282 | "source": [ |
286 | 283 | "def tvc_controller_function(\n", |
287 | | - " time, sampling_rate, state, state_history, observed_variables, tvc, sensors\n", |
| 284 | + " time,\n", |
| 285 | + " sampling_rate,\n", |
| 286 | + " state,\n", |
| 287 | + " state_history,\n", |
| 288 | + " observed_variables,\n", |
| 289 | + " thrust_vector_control,\n", |
| 290 | + " sensors,\n", |
288 | 291 | "):\n", |
289 | 292 | " # state = [x, y, z, vx, vy, vz, e0, e1, e2, e3, wx, wy, wz]\n", |
290 | 293 | "\n", |
291 | 294 | " # print(time)\n", |
292 | 295 | "\n", |
293 | | - " tvc.gimbal_angle_x = 0\n", |
294 | | - " tvc.gimbal_angle_y = 0\n", |
| 296 | + " thrust_vector_control.gimbal_angle_x = 0\n", |
| 297 | + " thrust_vector_control.gimbal_angle_y = 0\n", |
295 | 298 | " # Return variables of interest to be saved in the observed_variables list\n", |
296 | 299 | " return (\n", |
297 | 300 | " time,\n", |
298 | | - " tvc.gimbal_angle_x,\n", |
299 | | - " tvc.gimbal_angle_y,\n", |
| 301 | + " thrust_vector_control.gimbal_angle_x,\n", |
| 302 | + " thrust_vector_control.gimbal_angle_y,\n", |
300 | 303 | " )\n", |
301 | 304 | "\n", |
302 | 305 | "\n", |
303 | | - "tvc, tvc_controller = HALCYON.add_tvc(\n", |
304 | | - " gimbal_range=10,\n", |
| 306 | + "thrust_vector_control, tvc_controller = HALCYON.add_thrust_vector_control(\n", |
| 307 | + " controller_function=tvc_controller_function,\n", |
305 | 308 | " sampling_rate=100,\n", |
| 309 | + " max_gimbal_angle=10,\n", |
306 | 310 | " gimbal_rate_limit=100,\n", |
307 | | - " controller_function=tvc_controller_function,\n", |
308 | 311 | " return_controller=True,\n", |
309 | 312 | ")\n", |
310 | | - "tvc.info()\n", |
| 313 | + "thrust_vector_control.x.info()\n", |
311 | 314 | "tvc_controller.info()" |
312 | 315 | ] |
313 | 316 | }, |
|
373 | 376 | " )\n", |
374 | 377 | "\n", |
375 | 378 | " # Return variables of interest to be saved in the observed_variables list\n", |
376 | | - " return (\n", |
377 | | - " time,\n", |
378 | | - " roll_control.roll_torque,\n", |
379 | | - " )\n", |
| 379 | + " return (time, roll_control.roll_torque, gyro_data, accel_data)\n", |
380 | 380 | "\n", |
381 | 381 | "\n", |
382 | 382 | "roll_control, roll_controller = HALCYON.add_roll_control(\n", |
383 | | - " max_roll_torque=10,\n", |
384 | | - " sampling_rate=100,\n", |
385 | | - " torque_rate_limit=100,\n", |
386 | 383 | " controller_function=roll_controller_function,\n", |
| 384 | + " sampling_rate=100,\n", |
| 385 | + " max_roll_torque=10,\n", |
| 386 | + " torque_rate_limit=1000,\n", |
387 | 387 | " return_controller=True,\n", |
388 | 388 | ")\n", |
389 | 389 | "roll_control.info()\n", |
|
408 | 408 | " # state = [x, y, z, vx, vy, vz, e0, e1, e2, e3, wx, wy, wz]\n", |
409 | 409 | "\n", |
410 | 410 | " # Throttle command: 0.5 Hz sinusoid, centered at 0.8, amplitude 0.2\n", |
411 | | - " throttle_control.throttle = 0.8 + 0.2 * np.sin(2 * np.pi * 0.5 * time)\n", |
| 411 | + " throttle_command = 0.8 + 0.2 * np.sin(2 * np.pi * 0.5 * time)\n", |
| 412 | + " throttle_control.throttle = throttle_command\n", |
| 413 | + " throttle_actual = throttle_control.throttle\n", |
412 | 414 | "\n", |
413 | 415 | " # Return variables of interest to be saved in the observed_variables list\n", |
414 | 416 | " return (\n", |
415 | 417 | " time,\n", |
416 | | - " throttle_control.throttle,\n", |
417 | | - " )" |
418 | | - ] |
419 | | - }, |
420 | | - { |
421 | | - "cell_type": "code", |
422 | | - "execution_count": null, |
423 | | - "metadata": {}, |
424 | | - "outputs": [], |
425 | | - "source": [ |
| 418 | + " throttle_command,\n", |
| 419 | + " throttle_actual,\n", |
| 420 | + " )\n", |
| 421 | + "\n", |
| 422 | + "\n", |
426 | 423 | "throttle_obj, throttle_controller = HALCYON.add_throttle_control(\n", |
427 | 424 | " controller_function=throttle_controller_function,\n", |
428 | 425 | " sampling_rate=100,\n", |
429 | 426 | " throttle_range=(0.0, 1.0),\n", |
430 | 427 | " throttle_rate_limit=100,\n", |
431 | | - " initial_throttle=1.0,\n", |
| 428 | + " throttle_time_constant=0.5,\n", |
432 | 429 | " return_controller=True,\n", |
433 | | - " clamp=True,\n", |
434 | | - ")\n", |
435 | | - "print(\"has add_throttle_control:\", hasattr(HALCYON, \"add_throttle_control\"))\n", |
436 | | - "print(\"has throttle_control:\", hasattr(HALCYON, \"throttle_control\"))\n", |
437 | | - "print(\"throttle_control:\", getattr(HALCYON, \"throttle_control\", None))" |
| 430 | + ")" |
438 | 431 | ] |
439 | 432 | }, |
440 | 433 | { |
|
461 | 454 | " verbose=False,\n", |
462 | 455 | ")\n", |
463 | 456 | "# test_flight.plots.attitude_data()\n", |
464 | | - "# ===== 先看 throttle 有沒有真的變 =====\n", |
| 457 | + "# ===== Plot commanded throttle vs filtered actuator output =====\n", |
465 | 458 | "obs = np.array(throttle_controller.observed_variables)\n", |
466 | 459 | "\n", |
467 | 460 | "t_cmd = obs[:, 0]\n", |
468 | 461 | "th_cmd = obs[:, 1]\n", |
| 462 | + "th_act = obs[:, 2]\n", |
469 | 463 | "\n", |
470 | 464 | "plt.figure()\n", |
471 | | - "plt.plot(t_cmd, th_cmd, label=\"Throttle\")\n", |
| 465 | + "plt.plot(t_cmd, th_cmd, label=\"Throttle command\")\n", |
| 466 | + "plt.plot(t_cmd, th_act, label=\"Filtered throttle\")\n", |
472 | 467 | "plt.xlabel(\"Time (s)\")\n", |
473 | 468 | "plt.ylabel(\"Throttle\")\n", |
474 | | - "plt.title(\"Throttle Command\")\n", |
| 469 | + "plt.title(\"Throttle Command vs Actuator Output\")\n", |
475 | 470 | "plt.legend()\n", |
476 | 471 | "plt.grid()\n", |
477 | 472 | "plt.show()\n", |
478 | 473 | "\n", |
479 | | - "# ===== 再看推力有沒有跟著變 =====\n", |
| 474 | + "# ===== Then check thrust response =====\n", |
480 | 475 | "plt.figure()\n", |
481 | 476 | "plt.plot(\n", |
482 | 477 | " test_flight.net_thrust[:, 0], test_flight.net_thrust[:, 1], label=\"Effective Thrust\"\n", |
|
491 | 486 | "time1, ax, ay, az = zip(*accelerometer_clean.measured_data)\n", |
492 | 487 | "time2, gx, gy, gz = zip(*gyro_clean.measured_data)\n", |
493 | 488 | "\n", |
494 | | - "# plt.plot(time1, ax, label=\"Accelerometer X\")\n", |
495 | | - "# plt.plot(time1, ay, label=\"Accelerometer Y\")\n", |
496 | | - "# plt.plot(time1, az, label=\"Accelerometer Z\")\n", |
497 | | - "# plt.xlabel(\"Time (s)\")\n", |
498 | | - "# plt.ylabel(\"Acceleration (m/s^2)\")\n", |
499 | | - "# plt.legend()\n", |
500 | | - "# plt.grid()\n", |
501 | | - "# plt.show()\n", |
502 | | - "\n", |
503 | 489 | "plt.plot(time2, gx, label=\"Gyroscope X\")\n", |
504 | 490 | "plt.plot(time2, gy, label=\"Gyroscope Y\")\n", |
505 | 491 | "plt.plot(time2, gz, label=\"Gyroscope Z\")\n", |
|
532 | 518 | ], |
533 | 519 | "metadata": { |
534 | 520 | "kernelspec": { |
535 | | - "display_name": "Python 3", |
| 521 | + "display_name": ".venv (3.14.3.final.0)", |
536 | 522 | "language": "python", |
537 | 523 | "name": "python3" |
538 | 524 | }, |
|
546 | 532 | "name": "python", |
547 | 533 | "nbconvert_exporter": "python", |
548 | 534 | "pygments_lexer": "ipython3", |
549 | | - "version": "3.12.10" |
| 535 | + "version": "3.14.3" |
550 | 536 | } |
551 | 537 | }, |
552 | 538 | "nbformat": 4, |
|
0 commit comments