.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/examples/plot_balanceassistv1.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_gallery_examples_plot_balanceassistv1.py: =========================================================== Balance Assist E-Bike with Roll Rate Feedback Steer Control =========================================================== This example shows how to work with a model that includes a feedback controller and how to use a simple derivative control with it. The TU Delft Bicycle Lab developed a bicycle with a steer motor that can be controlled based on sensor measurements from an inertial measurement unit mounted on the rear frame, a steer angle sensor, and a speed sensor. The bicycle is based on an e-bike model from Royal Dutch Gazelle: .. figure:: https://objects-us-east-1.dream.io/mechmotum/balance-assist-bicycle-400x400.jpg :align: center Gazelle Grenoble/Arroyo E-Bike modified with a steering motor. Battery in the downtube and electronics box on the rear rack. .. GENERATED FROM PYTHON SOURCE LINES 20-27 .. code-block:: Python import numpy as np from bicycleparameters.main import Bicycle from bicycleparameters.io import remove_uncertainties from bicycleparameters.parameter_sets import Meijaard2007ParameterSet from bicycleparameters.models import Meijaard2007WithFeedbackModel .. GENERATED FROM PYTHON SOURCE LINES 28-34 Set Up a Model ============== First, load the physical parameter measurements of the bicycle from a file and create a :class:`~bicycleparameters.parameter_sets.Meijaard2007ParameterSet`. .. GENERATED FROM PYTHON SOURCE LINES 34-43 .. code-block:: Python data_dir = "../../data" bicycle = Bicycle("Balanceassistv1", pathToData=data_dir) par = remove_uncertainties(bicycle.parameters['Benchmark']) par['v'] = 1.0 par_set = Meijaard2007ParameterSet(par, False) par_set .. rst-class:: sphx-glr-script-out .. code-block:: none Found the RawData directory: ../../data/bicycles/Balanceassistv1/RawData Looks like you've already got some parameters for Balanceassistv1, use forceRawCalc to recalculate. .. raw:: html
Meijaard2007
VariableValue
\(I_{Bxx}\)1.120
\(I_{Bxz}\)0.047
\(I_{Byy}\)3.160
\(I_{Bzz}\)2.119
\(I_{Fxx}\)0.100
\(I_{Fyy}\)0.190
\(I_{Hxx}\)0.298
\(I_{Hxz}\)-0.038
\(I_{Hyy}\)0.257
\(I_{Hzz}\)0.057
\(I_{Rxx}\)0.102
\(I_{Ryy}\)0.189
\(c\)0.042
\(g\)9.807
\(\lambda\)0.255
\(m_B\)22.500
\(m_F\)2.235
\(m_H\)4.300
\(m_R\)4.085
\(r_F\)0.352
\(r_R\)0.349
\(v\)1.000
\(w\)1.113
\(x_B\)0.519
\(x_H\)0.921
\(z_B\)-0.521
\(z_H\)-0.860


.. GENERATED FROM PYTHON SOURCE LINES 44-46 The following plot depicts the geometry and inertial parameters with the inertia of the rider included. .. GENERATED FROM PYTHON SOURCE LINES 46-48 .. code-block:: Python par_set.plot_all() .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_001.png :alt: plot balanceassistv1 :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 49-53 Create a :class:`~bicycleparameters.models.Meijaard2007WithFeedbackModel`. The parameter set does not include the feedback gain parameters, but :meth:`~bicycleparameters.parameter_sets.Meijaard2007WithFeedbackParameterSet.to_parameterization` will be used to convert the parameter set into one with the gains. .. GENERATED FROM PYTHON SOURCE LINES 53-56 .. code-block:: Python model = Meijaard2007WithFeedbackModel(par_set) model.parameter_set .. raw:: html
Meijaard2007WithFeedback
VariableValue
\(I_{Bxx}\)1.120
\(I_{Bxz}\)0.047
\(I_{Byy}\)3.160
\(I_{Bzz}\)2.119
\(I_{Fxx}\)0.100
\(I_{Fyy}\)0.190
\(I_{Hxx}\)0.298
\(I_{Hxz}\)-0.038
\(I_{Hyy}\)0.257
\(I_{Hzz}\)0.057
\(I_{Rxx}\)0.102
\(I_{Ryy}\)0.189
\(c\)0.042
\(g\)9.807
\(k_{T_{\delta}\delta}\)0.000
\(k_{T_{\delta}\dot{\delta}}\)0.000
\(k_{T_{\delta}\phi}\)0.000
\(k_{T_{\delta}\dot{\phi}}\)0.000
\(k_{T_{\phi}\delta}\)0.000
\(k_{T_{\phi}\dot{\delta}}\)0.000
\(k_{T_{\phi}\phi}\)0.000
\(k_{T_{\phi}\dot{\phi}}\)0.000
\(\lambda\)0.255
\(m_B\)22.500
\(m_F\)2.235
\(m_H\)4.300
\(m_R\)4.085
\(r_F\)0.352
\(r_R\)0.349
\(v\)1.000
\(w\)1.113
\(x_B\)0.519
\(x_H\)0.921
\(z_B\)-0.521
\(z_H\)-0.860


.. GENERATED FROM PYTHON SOURCE LINES 57-58 The model shows a small self-stable speed range. .. GENERATED FROM PYTHON SOURCE LINES 58-62 .. code-block:: Python speeds = np.linspace(0.0, 10.0, num=501) ax = model.plot_eigenvalue_parts(v=speeds) ax.set_ylim((-10.0, 10.0)) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_002.png :alt: plot balanceassistv1 :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (-10.0, 10.0) .. GENERATED FROM PYTHON SOURCE LINES 63-70 Add a Rider =========== If the data files for a rider are present in the data directory, you can add a rider and the package Yeadon will be used to configure a rider to sit on the bicycle. You can check if a rider is properly configured by plotting the geometry which will now include a stick figure depiction of the rider. .. GENERATED FROM PYTHON SOURCE LINES 70-73 .. code-block:: Python bicycle.add_rider('Jason', reCalc=True) bicycle.plot_bicycle_geometry(inertiaEllipse=False) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_003.png :alt: Balanceassistv1 Bicycle Geometry :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_003.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none There is no rider on the bicycle, now adding Jason. Calculating the human configuration.
.. GENERATED FROM PYTHON SOURCE LINES 74-76 The inertia representation now reflects the larger inertia of the rear frame due to the rigid rider addition. .. GENERATED FROM PYTHON SOURCE LINES 76-81 .. code-block:: Python par = remove_uncertainties(bicycle.parameters['Benchmark']) par['v'] = 1.0 par_set = Meijaard2007ParameterSet(par, True) par_set.plot_all() .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_004.png :alt: plot balanceassistv1 :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_004.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 82-83 The self-stable speed range begins at a higher speed and becomes wider. .. GENERATED FROM PYTHON SOURCE LINES 83-87 .. code-block:: Python model = Meijaard2007WithFeedbackModel(par_set) ax = model.plot_eigenvalue_parts(v=speeds) ax.set_ylim((-10.0, 10.0)) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_005.png :alt: plot balanceassistv1 :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_005.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (-10.0, 10.0) .. GENERATED FROM PYTHON SOURCE LINES 88-94 Add Control =========== It turns out that controlling the steer torque with a positive feedback on roll angular rate, the bicycle can be stabilized over a large speed range. For example, setting :math:`k_{T_\delta \dot{\phi}}=-50` gives this effect: .. GENERATED FROM PYTHON SOURCE LINES 94-97 .. code-block:: Python ax = model.plot_eigenvalue_parts(v=speeds, kTdel_phid=-50.0) ax.set_ylim((-10.0, 10.0)) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_006.png :alt: plot balanceassistv1 :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_006.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (-10.0, 10.0) .. GENERATED FROM PYTHON SOURCE LINES 98-100 The eigenvectors at low speed show that the weave mode has a steer dominated high frequency natural motion. This may not be so favorable. .. GENERATED FROM PYTHON SOURCE LINES 100-103 .. code-block:: Python speed = 2.0 ax = model.plot_eigenvectors(v=speed, kTdel_phid=-50.0) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_007.png :alt: Eigenvalue: -1.817+10.745j, Eigenvalue: -1.817-10.745j, Eigenvalue: -5.815+0.000j, Eigenvalue: -0.231+0.000j :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_007.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 104-107 You can also gain schedule with respect to speed. A linear variation in the roll rate gain can make the weave eigenfrequency have lower magnitude than using simply a constant gain. .. GENERATED FROM PYTHON SOURCE LINES 107-115 .. code-block:: Python vmin, vmin_idx = 1.5, np.argmin(np.abs(speeds - 1.5)) vmax, vmax_idx = 4.7, np.argmin(np.abs(speeds - 4.7)) kappa = 10.0 kphidots = -kappa*(vmax - speeds) kphidots[:vmin_idx] = -kappa*(vmax - vmin)/vmin*speeds[:vmin_idx] kphidots[vmax_idx:] = 0.0 model.plot_gains(v=speeds, kTdel_phid=kphidots) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_008.png :alt: $k_{T_{\phi}\phi}$, $k_{T_{\phi}\delta}$, $k_{T_{\phi}\dot{\phi}}$, $k_{T_{\phi}\dot{\delta}}$, $k_{T_{\delta}\phi}$, $k_{T_{\delta}\delta}$, $k_{T_{\delta}\dot{\phi}}$, $k_{T_{\delta}\dot{\delta}}$ :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_008.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none array([[, , , ], [, , , ]], dtype=object) .. GENERATED FROM PYTHON SOURCE LINES 116-117 Using the gain scheduling gives this effect to the dynamics: .. GENERATED FROM PYTHON SOURCE LINES 117-120 .. code-block:: Python ax = model.plot_eigenvalue_parts(v=speeds, kTdel_phid=kphidots) ax.set_ylim((-10.0, 10.0)) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_009.png :alt: plot balanceassistv1 :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_009.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none (-10.0, 10.0) .. GENERATED FROM PYTHON SOURCE LINES 121-124 .. code-block:: Python kphidot = kphidots[np.argmin(np.abs(speeds - speed))] ax = model.plot_eigenvectors(v=speed, kTdel_phid=kphidot) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_010.png :alt: Eigenvalue: -0.786+7.434j, Eigenvalue: -0.786-7.434j, Eigenvalue: -6.242+0.000j, Eigenvalue: -0.457+0.000j :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_010.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 125-127 We can then simulate the system at a specific low speed and see the effect control has. First, without control: .. GENERATED FROM PYTHON SOURCE LINES 127-131 .. code-block:: Python times = np.linspace(0.0, 2.0, num=201) x0 = np.array([0.0, 0.0, 0.5, 0.0]) ax = model.plot_simulation(times, x0, v=speed) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_011.png :alt: plot balanceassistv1 :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_011.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 132-133 And with control: .. GENERATED FROM PYTHON SOURCE LINES 133-135 .. code-block:: Python times = np.linspace(0.0, 5.0, num=501) ax = model.plot_simulation(times, x0, v=speed, kTdel_phid=kphidot) .. image-sg:: /gallery/examples/images/sphx_glr_plot_balanceassistv1_012.png :alt: plot balanceassistv1 :srcset: /gallery/examples/images/sphx_glr_plot_balanceassistv1_012.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 2.867 seconds) .. _sphx_glr_download_gallery_examples_plot_balanceassistv1.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_balanceassistv1.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_balanceassistv1.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_balanceassistv1.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_