top of page

SELF-BALANCING
MOTORCYCLE: PART III

1. Introduction

In this section, we'll model our system without deriving and using differential equations. Simscape, a Simulink's dedicated library, will calculate everything for us based on the system's parts, taking into account their geometry, densities, and the way they are connected to each other. We'll first model a simple system, the same one from the previous section, and then the full system, consisting of the real motorcycle 3D parts. To finish, we'll develop the same controller from the previous section and make sure that it works as intended with our model.

2. Modeling a simple system

Let's begin by turning the motorcycle into a simpler system as before, consisting of a block and an inertia disk. We won't consider any friction between the parts as well. We'll add a massless black circle to the wheel in order to visualize its angular displacement:

1. simple model.PNG

To build this model, we use simple geometry objects, in this case a block and a disk. We can specify their dimensions and have Simscape calculate their moments of inertia by using their masses or densities. In this case, we load the parameters into Matlab's workspace using the same script from the previous section, and reference it in the model. For the block, its dimensions are given by l (length), d (width) and h (height), and its mass by mb:

3. simscape body.PNG

Here's the Simscape model:

2. simple model simscape.PNG

We'll briefly explain how this simple system was created in this environment and the basics of how it works. In Simscape, each part has its own coordinates system, and so does the ground, which is called the "world frame". For convention, in every project, we want to use a right-handed coordinate system:

5. right handed coords.png

In this coordinate system, gravity acts negatively on the Z-axis. Simulink also uses this convention, and in the "mechanism configuration" block we can confirm this, as gravity is already set to -9.81 m/s² on the Z-direction:

6. mechanism config.PNG

Next, we have to add a revolute joint to the system, which is the wheel-ground axis. A revolute joint has a base and a follower. In this case, the base is the ground, which is fixed. That's why we have to add the joint before adding any of the physical parts. The revolute joint rotates around its own Z-axis by definition, but our current Z-axis is the world-frame one, which is vertical. To make the revolute joint rotate around a horizontal axis, we have to add a rotation between the ground frame and the revolute joint frame. To do this, we use a "rigid transform" block:

7. rigid transform rotation.PNG

Notice on the image below how by rotating the world-frame axis by -90º (right-hand convention) around Y we put the revolute joint Z-axis where the -X world-frame axis was before, and thus make the rotating join horizontal, with gravity acting perpendicular to it.

8. world frame.PNG

world frame

9. revolute joint frame.PNG

new revolute joint frame

Next, we have to create two rotating frames for the body. One for the wheel-ground axis, and one for the reaction wheel. These frames will have the same coordinate system as the previous revolute joint so that we keep everything logical and neat and don't have to add unnecessary transforms to describe how the parts are connected:

10. body frame 1.PNG

ground frame

11. body frame 2.PNG

inertia wheel frame

We then add another revolute joint, the one for the inertia wheel, to the respective previously created body frame (which in this case is the base), and finally, the inertia wheel (which in this case is the follower), also connected to this joint. Note that the fact that for this joint the body is the base and the reaction wheel the follower is what gives us the joint velocity and being the relative speed between the two, which you may recall is the way we're measuring it in the real model, as opposed to its absolute speed, which would be relative to the ground.

​

You'll see that there's no rigid transform between the body frame and the inertia wheel frame. This is because we were able to define a frame for both the body and the wheel that already accurately defines the way they are connected. That's not the case for the marker, and therefore we have to add a rigid transform to move it 4 cm from the wheel surface center:

12. marker rigid frame.PNG
13. marker pos.PNG

Going forward, we can define initial conditions, inputs, and outputs to the revolute joints. For this simulation, we'll define a starting leaning angle of 4º and a zero speed. Because first we're running a model with no motor torque, we'll only define the outputs, which will be the position and velocity of the wheel-ground axis, and the velocity of the inertia wheel axis. Below we show the block diagram for the first joint just to illustrate how they are defined:

14. revolute joint io.PNG

Lastly, we convert the reads from radians to degrees using the appropriate block, just like we did in the model in the previous chapter. Here, however, there's one additional step. Simulink and Simscape work with two different "unit" types. Simulink works with "Simulink units" and Simscape with "physical units". Therefore, we can't just connect Simscape units to Simulink blocks and vice-versa. First, we need to convert the unit to the right type. To do this, we use the "PS-Simulink converter" and the "Simulink-PS converter" to change between signal types. That's what we do in the model before the "Radians to Degrees" block:

15. rad to deg.PNG

PS-Simulink converter

Now that we understand how the model was built, let's run the simulation. Remember that the initial conditions are a 4º leaning angle and zero speed:

By checking the data inspector, we can see that the system's behavior is exactly the same from the equations model in the previous chapter:

17. free simulation data.PNG

Let's go ahead and add a feedback controller just like we did before. We'll create a state vector and feed it to the gain matrix. Here's the new model:

18. controller model 1.PNG
phiDot2.PNG

The new plants, now with the motor torque input:

19. controller model 2.PNG

(click to enlarge)

We'll use the same gains as the equations model:

20. controller gains.PNG

Let's see how it goes:

22. controller response.PNG
phiDot.PNG

The system behaves as expected and we've got a nice response where all the speeds and torque go to zero in steady-state. Let's see how it goes when we add an angle offset to it. We'll add a 1º bias:

24. controller sim bias.PNG
phiDot.PNG

Here too we got a good response. The system goes to zero even though there's a bias on the leaning angle, and the inertia wheel goes to a constant speed. Here obviously we're more concerned about the system behavior than with the actual values of the torque and wheel speed. We'll better tune those when we get to simulate the real motorcycle model which we'll do shortly.

​

To finish the simulations with this simple model, let's set the bias to zero and add random disturbances to the motorcycle. This could be anything like wind, the bike turning a little bit, or some other type of external force input to the system. This torque will be randomly generated by the "random number" Simulink's block:

25. disturbance model.PNG
phiDot2.PNG

The disturbance goes as an input torque to the wheel-ground axis:

26. disturbance plant.PNG

(click to enlarge)

Let's see how it responds to random perturbations:

28. disturbance sim 2.PNG
phiDot.PNG

The system is able to stay upright as remains stable around 0º. Now we'll move to simulate the real system which will not be made of a block and a disk, but of the real motorcycle components.

3. Modeling a real system

We're going to build a model that is exactly the same as the real-world one using the 3D parts that we've drawn. We've weighted each part and Simscape is going to compute the moment of inertia of each of them with that information, the part's geometry, and the axis around which they are turning. We're not going to go into detail here as to how the connections between the parts were created, but they follow the exact same principles of the simple model that we've explained at the beginning of this chapter. Here's the model:

29. real model 1.PNG

(click to enlarge)

Ground

32. ground sub.PNG

Rear Wheel

33. rear wheel sub.PNG

Battery

34. battery sub.PNG

Servo

35. servo sub.PNG

Fork

36. fork sub.PNG

Front Wheel

37. front wheel sub.PNG

Boards

38. boards sub.PNG

Inertia Wheel

39. inertia wheel sub.PNG

(click to enlarge)

Here's the result:

40. real model 2.PNG
41. real model 3.PNG

We've set up the parts in different colors to make it easy to visualize. Each of those has its own mass and its moment of inertia is being calculated individually. This is a very powerful tool because as we've mentioned before, by working with equations that we write manually it would take a very long time and would be unpractical to calculate the moment of inertia of each component, but here we can do it using the 3D parts that we'd already had to draw anyway.

​

First let's simulate the free-response with an initial angle of 4º and zero speed, just like before:

31. real model free 2.PNG

We can see that the behavior is the same as before, with the reaction wheel velocity being the opposite of the motorcycle's since it's the relative and not the absolute velocity that we're reading. This model, although it doesn't completely represent reality (remember we're not accounting for friction between the parts, for example), shows us some other characteristics of the real system, since it's computing the behavior of all the parts, taking into account their geometries, densities, etc. In other words, the fact that Simscampe calculates the moment of inertia of all parts separately shows us things that we don't see in the "simple model". For example, the fact that the model isn't 100% symmetrical and the wheels are also not perfectly aligned means that the center of mass of the system isn't in the vertical middle point. It's offset to either side:

42. center of mass 1.PNG
43. center of mass 2.PNG

This means that the angle where the motorcycle is balancing upright isn't zero anymore, and we have to account for that as we'll see shortly. Later in the real model we'll also notice this bias and how it affects the motorcycle's behavior.

​

Now let's implement the same controller as before with gains of 1, 0.1, and 0.0002 respectively. We've rearranged the model so that it's intuitive to see the plant and the controller:

44. real model simulink.PNG

In the controller, we now have a bias block that in this simulation is set to zero, so it won't have any effect on the system:

45. real model simulink 2.PNG

The plant is the same as before, with the initial angle set to 4º. Let's see how the system responds:

47. real model controller 2.png

The response is good, however, notice how the settling angle is -1.5º and not zero. This is because the center of mass, in this case, is located to the left, and therefore to stay balanced the motorcycle has to turn to the right so that the weight forces pass through the cm and there's no torque. This also causes the inertia wheel to spin at a high speed of about 7,400 rpm which is something we do not want. To solve this problem we'll add a bias to the system in order to account for this offset. In other words, we'll make sure that the 0º corresponds to the balance angle:

48. bias.PNG

Now let's see what changes regarding the response:

50. real model controller bias 2.png

We've kept the same gains and now there's a little overshoot, which is fine, we can later tune the gains to remove it. The most important thing is that now, with the bias, the motorcycle is settling around 0º and the inertia wheel speed is very low, around 50 RPM. This is the behavior that we want.

​

Let's add some disturbance to the system:

51. disturbance model.PNG

And analyze its behavior as well:

53. disturbance response 2.png

The system responds well to random perturbations. The required torque is never too high, outside the range of our DC motor, and the wheel speed is within acceptable ranges, never settling at a high RPM. Moreover, these perturbations are being generated into the system every 100ms. In the real model this won't be the case as they will be less frequent.

4. Conclusion

In this section, we've modeled a simple and a real system without deriving its differential equations. Simscape allows us to build systems using 3D parts and automatically computes its behavior, making it easier to work with more complex systems, and allowing us to see certain characteristics that would be missed in a simplified model. Now we're ready to test all this in our real-world motorcycle. In the next chapter, we'll implement the exact same controller that we did both here and in the previous part and make the motorcycle self-balance.

1. Introduction
2. Simple model
3. Real model
4. Conclusion

Part II

Part IV

© 2025 by Matheus Lino

bottom of page