Suitcase Robot Model¶
The suitcase robot model simulates a testbed for mounting actuation inside a suitcase. It corresponds closely to the physical prototype. It is intended as a basis for exploring hardware to add into the suitcase.
This model is demonstrated in the suitcase-demo.wbt
world.
This model makes use of several objects defined in proto files: suitcase.proto, suitcase-actuators.proto, pedestal.proto, and ball_array.proto. These make use of embedded Lua scripting to parametrically generate world objects.
Sample Performance Script¶
1# script.py
2# Sample abstract performance script for operating the suitcase and lighting hardware on either
3# the Webots simulation or the physical hardware.
4# No copyright, 2023, Garth Zeglin. This file is explicitly placed in the public domain.
5
6print("loading script.py...")
7
8# Standard Python imports.
9import math, random
10
11# Define the abstract performance interface.
12from performance import Performance
13
14# Define an abstract performance controller which can run either the Webots simulation or a physical machine.
15class SuitcasePerformance(Performance):
16 def __init__(self):
17
18 # Initialize the superclass which implements the abstract robot interface.
19 super().__init__()
20
21 # Initialize the controller state machine
22 self.last_t = 0.0
23 self.event_timer = 0.0
24 self.state_index = 'rest'
25
26 # Entry point for periodic updates.
27 def poll(self, t):
28 dt = t - self.last_t
29 self.last_t = t
30
31 # Change the target velocity in a cycle with a two-second period.
32 self.event_timer -= dt
33 if self.event_timer < 0:
34 if self.state_index == 'rest':
35 self.set_spotlight('right', 1.0)
36 self.set_spotlight('left', 0.0)
37 self.state_index = 'moving'
38 self.event_timer += 1.5
39 for j in range(self.num_motors):
40 pos = math.pi * (1 - 2*random.random())
41 self.set_motor_target(j, pos)
42
43 else:
44 self.state_index = 'rest'
45 self.set_spotlight('right', 0.0)
46 self.set_spotlight('left', 1.0)
47 self.event_timer += 0.5
48 for j in range(self.num_motors):
49 self.set_motor_target(j, 0)
50
51 print(f"Switched to state {self.state_index}")
Abstract Performance Interface¶
1# performance.py
2
3# Abstract performance interface for operating the suitcase and lighting hardware on either
4# the Webots simulation or the physical hardware.
5
6# No copyright, 2023, Garth Zeglin. This file is explicitly placed in the public domain.
7
8print("loading performance.py...")
9
10# Standard Python imports.
11import math, random
12
13################################################################
14# Define the superclass for controller objects which can drive either a Webots
15# simulation or a physical machine.
16
17class Performance:
18 def __init__(self):
19 self.lights = {'left' : 1.0, 'right' : 1.0 }
20 self.num_motors = 4
21 self.target = [0, 0, 0, 0]
22
23 def set_spotlight(self, name, intensity):
24 self.lights[name] = intensity
25
26 def set_motor_target(self, motornum, pos):
27 self.target[motornum] = pos
28
29 # Entry point for periodic updates.
30 def poll(self, t):
31 pass
Webots Robot Controller¶
1# suitcase.py
2#
3# Sample Webots controller file for driving the four-motor suitcase actuator insert.
4# The robot also includes two controllable spotlights.
5# No copyright, 2021-2023, Garth Zeglin. This file is explicitly placed in the public domain.
6
7print("loading suitcase.py...")
8
9# Import the Webots simulator API.
10from controller import Robot
11
12# Define the time step in milliseconds between controller updates.
13EVENT_LOOP_DT = 50
14
15# Load the abstract performance script which will drive this simulated show.
16import script
17
18################################################################
19# The sample controller is defined as an class which is then instanced as a
20# singleton control object. This is conventional Python practice and also
21# simplifies the implementation of the interface which connects this
22# code to physical hardware.
23
24class Suitcase(Robot):
25 def __init__(self):
26
27 # Initialize the superclass which implements the Robot API.
28 super().__init__()
29
30 robot_name = self.getName()
31 print("%s: controller connected." % (robot_name))
32
33 # Fetch handle for the four stepper motors.
34 j1 = self.getDevice('motor1')
35 j2 = self.getDevice('motor2')
36 j3 = self.getDevice('motor3')
37 j4 = self.getDevice('motor4')
38
39 # Convenience list of all actuators.
40 self.motors = [j1, j2, j3, j4]
41
42 # Connect to the spotlights.
43 self.right_spotlight = self.getDevice('right_spotlight')
44 self.right_spotlight.set(255)
45 self.left_spotlight = self.getDevice('left_spotlight')
46 self.left_spotlight.set(255)
47
48 # Current light state used for smoothing changes.
49 self.spot_intensity = [0.0, 0.0]
50
51 # Create the abstract controller object implementing the performance.
52 self.controller = script.SuitcasePerformance()
53
54 return
55
56 def run(self):
57 # Run loop to execute a periodic script until the simulation quits.
58 # If the controller returns -1, the simulator is quitting.
59
60 while self.step(EVENT_LOOP_DT) != -1:
61 # Read simulator clock time.
62 t = self.getTime()
63
64 # Update the controller object.
65 self.controller.poll(t)
66
67 # Apply output values to the simulated hardware.
68 for motor, pos in zip(self.motors, self.controller.target):
69 motor.setPosition(pos)
70
71 self.spot_intensity[0] += 0.2 * (self.controller.lights['left'] - self.spot_intensity[0])
72 self.spot_intensity[1] += 0.2 * (self.controller.lights['right'] - self.spot_intensity[1])
73 self.left_spotlight.set(int(255 * self.spot_intensity[0]))
74 self.right_spotlight.set(int(255 * self.spot_intensity[1]))
75
76
77################################################################
78# If running directly from Webots as a script, the following will begin execution.
79# This will have no effect when this file is imported as a module.
80if __name__ == "__main__":
81 robot = Suitcase()
82 robot.run()
Suitcase Actuators Proto¶
1#VRML_SIM R2023b utf8
2# documentation url: https://courses.ideate.cmu.edu/16-375
3# Four actuators mounted to a block intended to fit inside the suitcase body.
4# The visible actuator geometry is defined using STL files.
5# license: No copyright, 2021-2023 Garth Zeglin. This file is explicitly placed in the public domain.
6
7PROTO suitcase-actuators [
8 field SFVec3f translation 0 0 0
9 field SFRotation rotation 1 0 0 0
10 field SFString name "actuators"
11 field SFString controller "suitcase"
12 field SFColor baseColor 0.21529 0.543008 0.99855
13 field SFString contactMaterial "default"
14]
15{
16 Robot {
17 # connect properties to user-visible data fields
18 translation IS translation
19 rotation IS rotation
20 name IS name
21 controller IS controller
22 contactMaterial IS contactMaterial
23
24 children [
25 # define a box to represent the base surface and motor housing block
26 DEF baseObject Transform {
27 translation 0.0045 0 0.04
28 children [
29 Shape {
30 appearance PBRAppearance {
31 baseColor IS baseColor
32 metalness 0
33 }
34 geometry Box {
35 size 0.296 0.438 0.064
36 }
37 }
38 ]
39 }
40 # wrap the motor1 definitions within a translated coordinate frame
41 Pose {
42 translation -0.0695 -0.1095 0.072
43 children [
44 HingeJoint {
45 jointParameters HingeJointParameters {
46 axis 0 0 1
47 }
48 device [
49 RotationalMotor {
50 name "motor1"
51 maxVelocity 5
52 maxTorque 1
53 }
54 ]
55 endPoint Solid {
56 translation 0 0 0.01
57 children [
58 # define the disc used for physics and collision
59 DEF actuator1Disc Pose {
60 rotation 1 0 0 0
61 children [
62 Shape {
63 appearance DEF woodAppearance PBRAppearance {
64 baseColor 0.992157 0.893126 0.601785
65 metalness 0
66 roughness 0.5
67 }
68 geometry DEF actuatorDisc Cylinder {
69 height 0.006
70 radius 0.025
71 }
72 }
73 ]
74 }
75 # define the visible object on top of the disc
76 DEF actuatorObject Pose {
77 translation -0.003 0 0.018
78 children [
79 Shape {
80 appearance USE woodAppearance
81 geometry DEF tagGeometry Mesh {
82 url [
83 "../stl/tag375.stl"
84 ]
85 }
86 }
87 ]
88 }
89 ]
90 name "link1"
91 boundingObject USE actuator1Disc
92 physics DEF actuatorPhysics Physics {
93 density -1
94 mass 0.2
95 }
96 }
97 }
98 ]
99 }
100 Pose {
101 translation -0.0695 0.1095 0.072
102 children [
103 HingeJoint {
104 jointParameters HingeJointParameters {
105 axis 0 0 1
106 }
107 device [
108 RotationalMotor {
109 name "motor2"
110 maxVelocity 5
111 maxTorque 1
112 }
113 ]
114 endPoint Solid {
115 translation 0 0 0.01
116 children [
117 DEF actuator2Disc Pose {
118 rotation 1 0 0 0
119 children [
120 Shape {
121 appearance USE woodAppearance
122 geometry USE actuatorDisc
123 }
124 ]
125 }
126 USE actuatorObject
127 ]
128 name "link2"
129 boundingObject USE actuator2Disc
130 physics USE actuatorPhysics
131 }
132 }
133 ]
134 }
135 Pose {
136 translation 0.0785 -0.1095 0.072
137 children [
138 HingeJoint {
139 jointParameters HingeJointParameters {
140 axis 0 0 1
141 }
142 device [
143 RotationalMotor {
144 name "motor3"
145 maxVelocity 5
146 maxTorque 1
147 }
148 ]
149 endPoint Solid {
150 translation 0 0 0.01
151 children [
152 DEF actuator3Disc Pose {
153 rotation 1 0 0 0
154 children [
155 Shape {
156 appearance USE woodAppearance
157 geometry USE actuatorDisc
158 }
159 ]
160 }
161 USE actuatorObject
162 ]
163 name "link3"
164 boundingObject USE actuator3Disc
165 physics USE actuatorPhysics
166 }
167 }
168 ]
169 }
170 Pose {
171 translation 0.0785 0.1095 0.072
172 children [
173 HingeJoint {
174 jointParameters HingeJointParameters {
175 axis 0 0 1
176 }
177 device [
178 RotationalMotor {
179 name "motor4"
180 maxVelocity 5
181 maxTorque 1
182 }
183 ]
184 endPoint Solid {
185 translation 0 0 0.01
186 children [
187 DEF actuator4Disc Pose {
188 rotation 1 0 0 0
189 children [
190 Shape {
191 appearance USE woodAppearance
192 geometry USE actuatorDisc
193 }
194 ]
195 }
196 USE actuatorObject
197 ]
198 name "link4"
199 boundingObject USE actuator4Disc
200 physics USE actuatorPhysics
201 }
202 }
203 ]
204 }
205 # define first controlled spotlight
206 LED {
207 name "right_spotlight"
208 color [ 1 1 1 ]
209 gradual TRUE
210 children [
211 SpotLight {
212 attenuation 0 0 1
213 beamWidth 0.3
214 cutOffAngle 0.4
215 direction -1 -2 -1
216 intensity 5
217 location 1.0 1.5 1.0
218 castShadows TRUE
219 }
220 ]
221 }
222 # define controlled spotlight
223 LED {
224 name "left_spotlight"
225 color [ 1 1 1 ]
226 gradual TRUE
227 children [
228 SpotLight {
229 attenuation 0 0 1
230 beamWidth 0.3
231 cutOffAngle 0.4
232 direction -1 2 -1
233 intensity 5
234 location 1.0 -1.5 1.0
235 castShadows TRUE
236 }
237 ]
238 }
239 ] # close children of Robot
240 boundingObject USE baseObject
241 physics Physics {
242 }
243 } # close Robot
244}