Pendulum 1-2 Robot Model¶
This sample project includes a model of a underactuated robot structured as a double pendulum with two distal links. The proximal link is actuated with a torque motor, and the distal links use passive pivots with only friction.
This model is demonstrated in the pendulum-1-2-demo.wbt
world.
System Kinematics¶
The bodies are as follows:
name |
color |
notes |
---|---|---|
base |
blue |
massive base resting on ground |
link1 |
red |
pivoting arm, with center of mass offset above the joint axis |
link2A |
green |
upper passively pivoting arm, |
link2B |
green |
lower passively pivoting arm, somewhat shorter than link2A |
The joints are as follows:
name |
parent |
child |
notes |
---|---|---|---|
joint1 |
base |
link1 |
includes motor1 and the joint1 sensor |
joint2A |
link1 |
link2A |
includes joint2A position sensor |
joint2B |
link1 |
link2A |
includes joint2B position sensor |
The axes are as follows:
name |
direction |
notes |
---|---|---|
joint1 |
along X |
located 1.0 meters above the ground plane |
joint2A |
along X |
located 0.5 meters about the joint1 axis |
joint2B |
along X |
located 0.3 meters below the joint1 axis |
Design Notes¶
The robot is directly modeled in the scene tree so all parameters can be visible. In general it is more flexible to transfer models to .proto files so they can be instantiated more than once.
For simplicity, the model uses only primitive shapes (boxes). The same shapes are used for both rendering and contact detection (i.e. bounding objects). This also allows the simulator to automatically calculate inertia properties.
Each Solid node uses the translation vector to place the link body coordinate origin at a logical point on the joint axis. This convention is intended to keep the hinge vectors more legible.
Each Shape node has been wrapped in a Transform node to ease positioning it with the link body coordinates.
The sample controller runs an event loop which calculates joint1 torques based on elapsed time. It could be extended to use joint position data for feedback.
CAD Drawings¶
The following images were generated using a Fusion 360 CAD model independently drawn to the same dimensions as the Webots robot model.
Sample Robot Control Code¶
1# pendulum_1_2.py
2#
3# Sample Webots controller file for driving the
4# underactuated 1-2 pendulum. The robot has a driven
5# base joint between the base and link1, and passive
6# joints between link1 and the two distal links link2A
7# and link2B.
8#
9# No copyright, 2020-2021, Garth Zeglin. This file is
10# explicitly placed in the public domain.
11
12print("loading pendulum_1_2.py...")
13
14# Import the Webots simulator API.
15from controller import Robot
16
17# Import the standard Python math library.
18import math
19
20print("pendulum_1_2.py waking up...")
21
22# Define the time step in milliseconds between
23# controller updates.
24EVENT_LOOP_DT = 20
25
26# Request a proxy object representing the robot to
27# control.
28robot = Robot()
29
30# Fetch handles for the joint sensors.
31j1 = robot.getDevice('joint1')
32j2A = robot.getDevice('joint2A')
33j2B = robot.getDevice('joint2B')
34
35# Specify the sampling rate for the joint sensors.
36j1.enable(EVENT_LOOP_DT)
37j2A.enable(EVENT_LOOP_DT)
38j2B.enable(EVENT_LOOP_DT)
39
40# Fetch handle for the 'base' joint motor. In this
41# example the motor will be controlled as a torque
42# motor, bypassing the lower-level PID control.
43motor1 = robot.getDevice('motor1')
44motor1.setTorque(0.0)
45
46# Run an event loop until the simulation quits,
47# indicated by the step function returning -1.
48while robot.step(EVENT_LOOP_DT) != -1:
49
50 # Read simulator clock time.
51 t = robot.getTime()
52
53 # Read the new joint positions.
54 q1 = j1.getValue()
55 q2A = j2A.getValue()
56 q2B = j2B.getValue()
57
58 # Compute and apply new base joint actuator torque.
59 # In this example, the excitation is only based on
60 # time, but could also be a function of the joint
61 # positions.
62 tau = 3 * math.sin(3*t)
63 motor1.setTorque(tau)
World File¶
1#VRML_SIM R2023b utf8
2EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2023b/projects/objects/floors/protos/RectangleArena.proto"
3EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2023b/projects/appearances/protos/PaintedWood.proto"
4
5WorldInfo {
6}
7Viewpoint {
8 orientation 0.20637375705407857 0.11296232240268078 -0.9719307517085652 2.083640805255243
9 position 1.7870404774717816 3.2844836209794273 2.3418665277932647
10}
11Background {
12 skyColor [
13 0.1 0.1 0.1
14 ]
15}
16DirectionalLight {
17 direction 0.4 -0.5 -1
18 intensity 3
19 castShadows TRUE
20}
21RectangleArena {
22 rotation 1.8366025517039032e-06 -1.836602551703903e-06 0.9999999999966269 1.5707963267982696
23 floorSize 2 2
24}
25Robot {
26 rotation 0 0 1 1.5708
27 children [
28 DEF baseObject Transform {
29 translation 0 0 0.6
30 children [
31 Shape {
32 appearance PaintedWood {
33 colorOverride 0.21529 0.543008 0.99855
34 }
35 geometry Box {
36 size 0.3 0.5 1.2
37 }
38 }
39 ]
40 }
41 HingeJoint {
42 jointParameters HingeJointParameters {
43 anchor 0 0 1
44 }
45 device [
46 PositionSensor {
47 name "joint1"
48 }
49 RotationalMotor {
50 name "motor1"
51 acceleration 2
52 maxVelocity 3.14
53 minPosition -10
54 maxPosition 10
55 maxTorque 20
56 }
57 ]
58 endPoint Solid {
59 translation 0.15 0 1
60 rotation 1 0 0 0
61 children [
62 DEF link1Shape Transform {
63 translation 0.08 0 0.1
64 children [
65 Shape {
66 appearance PaintedWood {
67 colorOverride 0.990494 0.516915 0.468254
68 }
69 geometry Box {
70 size 0.1 0.3 1
71 }
72 }
73 ]
74 }
75 HingeJoint {
76 jointParameters HingeJointParameters {
77 anchor 0 0 0.5
78 dampingConstant 0.1
79 }
80 device [
81 PositionSensor {
82 name "joint2A"
83 }
84 ]
85 endPoint Solid {
86 translation 0.13 0 0.5
87 rotation 1 0 0 0
88 children [
89 DEF link2AShape Transform {
90 translation 0.07 0 0.2
91 children [
92 Shape {
93 appearance PaintedWood {
94 colorOverride 0.413001 1 0.33489
95 }
96 geometry Box {
97 size 0.1 0.1 0.6
98 }
99 }
100 ]
101 }
102 ]
103 name "link2A"
104 boundingObject USE link2AShape
105 physics Physics {
106 density -1
107 mass 0.5
108 }
109 }
110 }
111 HingeJoint {
112 jointParameters HingeJointParameters {
113 anchor 0 0 -0.3
114 dampingConstant 0.1
115 }
116 device [
117 PositionSensor {
118 name "joint2B"
119 }
120 ]
121 endPoint Solid {
122 translation 0.13 0 -0.3
123 rotation 1 0 0 0
124 children [
125 DEF link2BShape Transform {
126 translation 0.07 0 -0.15
127 children [
128 Shape {
129 appearance PaintedWood {
130 colorOverride 0.413001 1 0.33489
131 }
132 geometry Box {
133 size 0.1 0.1 0.4
134 }
135 }
136 ]
137 }
138 ]
139 name "link2B"
140 boundingObject USE link2BShape
141 physics Physics {
142 density -1
143 mass 0.5
144 }
145 }
146 }
147 ]
148 name "link1"
149 boundingObject USE link1Shape
150 physics Physics {
151 density -1
152 mass 0.5
153 }
154 }
155 }
156 ]
157 name "pendulum_1_2"
158 boundingObject USE baseObject
159 physics Physics {
160 density -1
161 mass 20
162 }
163 controller "pendulum_1_2"
164}