Inspection¶
Robotic quality inspection systems utilize robots to examine and assess products on a production line according to predefined criteria, such as size, shape, color, and surface defects. These systems have gained popularity in manufacturing, warehousing, and distribution facilities due to their ability to provide faster and more consistent inspections, thereby improving overall product quality and reducing human error. However, the increasing demand for 6 or 7-axis robots, while offering enhanced flexibility in handling complex inspections, also introduces greater complexity in programming and optimization, leading to higher costs for engineering, onsite support, and reprogramming.
In this tutorial, we introduce a short program created using the Jacobi platform, designed to be easily configurable for robotic quality inspection.
Video
Application Code
1from pathlib import Path
2import time
3
4import numpy as np
5
6from jacobi import Frame, Planner, JacobiError, PathFollowingMotion, LinearPath, CircularPath, BlendedPath, Studio
7
8
9class InspectionProject:
10 def __init__(self, planner, studio):
11 self.planner = planner
12 self.studio = studio
13 self.object_list = [planner.environment.get_obstacle(o) for o in ['laptop', 'console', 'phone']]
14
15 def go_home(self):
16 """Move the robot to the home position."""
17
18 home = [1.347, -1.208, 1.759, 4.16, -1.571, -0.224]
19 traj = self.planner.plan(self.studio.get_joint_position(), home)
20 self.studio.run_trajectory(traj)
21 time.sleep(0.1)
22
23 def visualize_path(self, path_type):
24 """Visualize the calculated path of the robot tool with the attached camera in Studio."""
25
26 path = path_type.calculate_path(0.3, 0.01)
27 p = [path[i].translation for i in range(len(path))]
28 self.studio.add_robot_path(p)
29
30 def inspect_laptop(self):
31 """Inspect the laptop object using a blended path."""
32
33 # Move from the home position to the inspection start position
34 start = Frame(x=-0.16, y=0.44, z=0.89, a=-2.3)
35 traj = self.planner.plan(self.studio.get_joint_position(), start)
36 self.studio.run_trajectory(traj)
37
38 # Define the waypoints and robot tool velocity for the inspection path
39 velocity = 0.3 # [m/s]
40 waypoints = [
41 start,
42 Frame(x=0.17, y=0.44, z=0.89, a=-2.3),
43 Frame(x=0.17, y=0.48, z=0.89, a=-2.5),
44 Frame(x=-0.16, y=0.48, z=0.89, a=-2.5),
45 Frame(x=-0.16, y=0.52, z=0.89, a=-2.7),
46 Frame(x=0.17, y=0.52, z=0.89, a=-2.7),
47 Frame(x=0.17, y=0.56, z=0.89, a=-2.9),
48 Frame(x=-0.16, y=0.56, z=0.89, a=-2.9),
49 Frame(x=-0.16, y=0.60, z=0.89, a=-3.10),
50 Frame(x=0.17, y=0.60, z=0.89, a=-3.10),
51 Frame(x=0.17, y=0.64, z=0.89, a=-3.3),
52 Frame(x=-0.16, y=0.64, z=0.89, a=-3.3),
53 Frame(x=-0.16, y=0.68, z=0.89, a=-3.5),
54 Frame(x=0.17, y=0.68, z=0.89, a=-3.5),
55 Frame(x=0.17, y=0.72, z=0.89, a=-3.7),
56 Frame(x=-0.16, y=0.72, z=0.89, a=-3.7),
57 Frame(x=-0.16, y=0.76, z=0.89, a=-3.9),
58 Frame(x=0.17, y=0.76, z=0.89, a=-3.9),
59 ]
60
61 # Create the blended path and visualize it in Studio
62 path = BlendedPath(waypoints, 0.01)
63 self.visualize_path(path)
64
65 # Create the motion object and set the reference configuration
66 motion = PathFollowingMotion(path, velocity)
67 motion.reference_config = self.studio.get_joint_position()
68
69 # Plan the trajectory and run it in Studio
70 traj = self.planner.plan(motion)
71 self.studio.run_trajectory(traj)
72 self.studio.reset()
73 time.sleep(0.4)
74
75 def inspect_console(self):
76 """Inspect the console object using a circular path."""
77
78 # Move from the home position to the inspection start position
79 start = Frame(y=0.45, z=1.0, a=-2.6)
80 traj = self.planner.plan(self.studio.get_joint_position(), start)
81 self.studio.run_trajectory(traj)
82
83 # Define the first circular path parameters and robot tool velocity
84 velocity = 0.12 # [m/s]
85 theta = 2 * np.pi
86 center = [0.0, 0.61, 1.0]
87 normal = [0.0, 0.0, 1.0]
88
89 # Create the circular path and visualize it in Studio
90 path = CircularPath(start, theta, center, normal, True)
91 self.visualize_path(path)
92
93 # Create the motion object, set the reference configuration and plan the first motion
94 motion = PathFollowingMotion(path, velocity)
95 motion.reference_config = self.studio.get_joint_position()
96 traj = self.planner.plan(motion)
97
98 # Create the linear path to move the robot tool to the next inspection position and visualize it
99 pos = self.planner.environment.get_robot().calculate_tcp(traj.positions[-1])
100 path = LinearPath(pos, Frame(y=0.45, z=0.85, a=-2.4))
101 self.visualize_path(path)
102
103 # Create the motion object, set the reference configuration and plan the second motion
104 move_to_next = PathFollowingMotion(path, velocity)
105 move_to_next.reference_config = traj.positions[-1]
106 traj += self.planner.plan(move_to_next)
107
108 # Define the second circular path parameters
109 start = Frame(y=0.45, z=0.85, a=-2.4)
110 center = [0.0, 0.61, 0.85]
111 normal = [0.0, 0.0, -1.0]
112
113 # Create the circular path and visualize it in Studio
114 path = CircularPath(start, theta, center, normal, True)
115 self.visualize_path(path)
116
117 # Create the motion object, set the reference configuration and plan the third motion
118 motion = PathFollowingMotion(path, velocity)
119 motion.reference_config = traj.positions[-1]
120 traj += self.planner.plan(motion)
121
122 # Run the full trajectory in Studio
123 self.studio.run_trajectory(traj)
124 self.studio.reset()
125 time.sleep(0.4)
126
127 def inspect_phone(self):
128 """Inspect the phone case object using a blended path."""
129
130 # Move from the home position to the inspection start position
131 start = Frame(x=-0.05, y=0.55, z=0.85, a=3.14)
132 traj = self.planner.plan(self.studio.get_joint_position(), start)
133 self.studio.run_trajectory(traj)
134
135 # Define the waypoints and robot tool velocity for the inspection path
136 velocity = 0.05 # [m/s]
137 waypoints = [
138 start,
139 Frame(x=0.05, y=0.55, z=0.85, a=3.14),
140 Frame(x=0.05, y=0.6, z=0.85, a=3.14),
141 Frame(x=-0.05, y=0.6, z=0.85, a=3.14),
142 Frame(x=-0.05, y=0.65, z=0.85, a=3.14),
143 Frame(x=0.05, y=0.65, z=0.85, a=3.14),
144 ]
145
146 # Create the blended path and visualize it in Studio
147 path = BlendedPath(waypoints, 0.01)
148 self.visualize_path(path)
149
150 # Create the motion object and set the reference configuration
151 motion = PathFollowingMotion(path, velocity)
152 motion.reference_config = self.studio.get_joint_position()
153
154 # Plan the trajectory and run it in Studio
155 traj = self.planner.plan(motion)
156 self.studio.run_trajectory(traj)
157 self.studio.reset()
158 time.sleep(0.4)
159
160 def switch_obstacle(self, name_visible):
161 """Switch the view and collision checking to the specified obstacle."""
162
163 for o in self.object_list:
164 if o.name == name_visible:
165 o.for_visual = True
166 self.planner.environment.add_obstacle(o)
167 else:
168 try: # noqa: SIM105
169 self.planner.environment.remove_obstacle(self.planner.environment.get_obstacle(o.name))
170 except JacobiError:
171 pass
172 o.for_visual = False
173 self.studio.update_obstacle(o)
174 time.sleep(0.5)
175
176 def run(self):
177 """Run the inspection project."""
178
179 self.go_home()
180
181 self.switch_obstacle('laptop')
182 self.inspect_laptop()
183 self.go_home()
184
185 self.switch_obstacle('console')
186 self.inspect_console()
187 self.go_home()
188
189 self.switch_obstacle('phone')
190 self.inspect_phone()
191 self.go_home()
192
193
194if __name__ == '__main__':
195 # Load project from Studio Download
196 project_path = Path.home() / 'Downloads' / 'Inspection-UR5e.jacobi-project'
197
198 # Run the inspection project
199 inspection = InspectionProject(
200 planner=Planner.load_from_project_file(project_path),
201 studio=Studio(),
202 )
203 inspection.run()