Assembly¶
Within the rapidly transforming world of manufacturing automation, robotic assembly stands out as a crucial technology. It involves the use of 6-axis robots to efficiently position, fit, assemble and construct different components into a wide range of products, with high degree of precision and accuracy. Programming robotic assembly cells remains a challenge when relying on traditional methods, requiring a tedious manual process of tuning motion parameters for each component. This not only makes it time-consuming but also limits the flexibility and adaptability of the assembly process. In this tutorial, we introduce a short program created using the Jacobi platform, designed to be easily configurable for the assembly of various components.
Video
Application Code
1import asyncio
2from pathlib import Path
3
4from jacobi import Frame, Motion, LinearMotion, LinearSection, Planner, Studio
5
6
7class AssemblyApplication:
8 project_path = Path.home() / 'Downloads' / 'assembly.jacobi-project'
9
10 def __init__(self):
11 self.planner = Planner.load_from_project_file(self.project_path)
12 self.environment = self.planner.environment
13 self.robot = self.environment.get_robot()
14
15 self.home = self.environment.get_waypoint('Home')
16 self.assembly = self.environment.get_waypoint('Assembly')
17
18 self.cylinders = [
19 self.environment.get_obstacle('Cylinder 1'),
20 self.environment.get_obstacle('Cylinder 2'),
21 self.environment.get_obstacle('Cylinder 3'),
22 self.environment.get_obstacle('Cylinder 4'),
23 ]
24
25 # Just for visualization
26 self.studio = Studio()
27 self.robot_position = [0, 0, 0, 0, 0, 0] # Initial joint position [rad]
28
29 # TODO: Set up robot driver
30 # self.driver = FanucDriver(host='192.168.1.135')
31
32 async def run_trajectory(self, trajectory, events=Studio.Events()):
33 # TODO: Use actual robot driver
34 # self.driver.run(trajectory)
35
36 self.studio.run_trajectory(trajectory, events) # requires the Studio Live feature
37 self.robot_position = trajectory.positions[-1]
38
39 async def grasp(self):
40 # TODO: Grasp cylinder
41 await asyncio.sleep(0.5) # [s]
42 # TODO: Check input condition
43
44 async def release(self):
45 # TODO: Release cylinder
46 await asyncio.sleep(0.5) # [s]
47 # TODO: Check input condition
48
49 async def assemble_cylinder(self, cylinder, retract_from_start=True):
50 # 1. Move from current position -> Cylinder pick
51 pick_frame = cylinder.origin
52 motion = Motion(self.robot_position, pick_frame)
53 motion.linear_approach = LinearSection(Frame(z=0.1), speed=0.5) # [m]
54 if retract_from_start:
55 motion.linear_retraction = LinearSection(Frame(z=0.05), speed=0.5) # [m]
56 trajectory = self.planner.plan(motion)
57 await self.run_trajectory(trajectory)
58
59 # 2. Grasp cylinder
60 await self.grasp()
61
62 cylinder.origin = Frame.Identity()
63 self.robot.item_obstacle = cylinder
64
65 events = Studio.Events()
66 events[0.0] = Studio.Events.set_item(self.robot.item_obstacle)
67 events[0.0] = Studio.Events.remove_obstacle(cylinder)
68
69 # 3. Move from pick -> Angled assembly approach
70 assembly_frame = self.assembly.position
71 assembly_frame_approach = self.assembly.position * Frame(a=0.18) # [rad]
72
73 motion = Motion(self.robot_position, assembly_frame_approach)
74 motion.linear_retraction = LinearSection(Frame(z=0.1), speed=0.5) # [m]
75 motion.linear_approach = LinearSection(Frame(z=0.05), speed=0.1) # [m]
76 trajectory = self.planner.plan(motion)
77 await self.run_trajectory(trajectory, events)
78
79 # 4. Orient normal to fixture
80 motion = LinearMotion(self.robot_position, assembly_frame)
81 trajectory = self.planner.plan(motion)
82
83 events = Studio.Events()
84 cylinder.origin = self.assembly.position
85 events[trajectory.duration] = Studio.Events.add_obstacle(cylinder)
86 events[trajectory.duration] = Studio.Events.set_item(None)
87 await self.run_trajectory(trajectory, events)
88
89 # 5. Release cylinder
90 await self.release()
91
92 self.robot.item_obstacle = None
93
94 async def run(self):
95 # 0. Move to home position
96 trajectory = self.planner.plan(self.robot_position, self.home)
97 await self.run_trajectory(trajectory)
98
99 for i, cylinder in enumerate(self.cylinders):
100 await self.assemble_cylinder(cylinder, retract_from_start=i > 0)
101
102 # End. Move to home position again
103 motion = Motion(self.robot_position, self.home)
104 motion.linear_retraction = LinearSection(Frame(z=0.1), speed=0.5) # [m]
105 trajectory = self.planner.plan(motion)
106 await self.run_trajectory(trajectory)
107
108 self.studio.reset() # Reset the visualization
109
110
111if __name__ == '__main__':
112 application = AssemblyApplication()
113 asyncio.run(application.run())