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¶
import asyncio
from pathlib import Path
from jacobi import Frame, Motion, LinearMotion, LinearSection, Planner, Studio
class AssemblyApplication:
project_path = Path.home() / 'Downloads' / 'assembly.jacobi-project'
def __init__(self):
self.planner = Planner.load_from_project_file(self.project_path)
self.environment = self.planner.environment
self.robot = self.environment.get_robot()
self.home = self.environment.get_waypoint('Home')
self.assembly = self.environment.get_waypoint('Assembly')
self.cylinders = [
self.environment.get_obstacle('Cylinder 1'),
self.environment.get_obstacle('Cylinder 2'),
self.environment.get_obstacle('Cylinder 3'),
self.environment.get_obstacle('Cylinder 4'),
]
# Just for visualization
self.studio = Studio()
self.robot_position = [0, 0, 0, 0, 0, 0] # Initial joint position [rad]
# TODO: Set up robot driver
# self.driver = FanucDriver(host='192.168.1.135')
async def run_trajectory(self, trajectory, events=Studio.Events()):
# TODO: Use actual robot driver
# self.driver.run(trajectory)
self.studio.run_trajectory(trajectory, events) # requires the Studio Live feature
self.robot_position = trajectory.positions[-1]
async def grasp(self):
# TODO: Grasp cylinder
await asyncio.sleep(0.5) # [s]
# TODO: Check input condition
async def release(self):
# TODO: Release cylinder
await asyncio.sleep(0.5) # [s]
# TODO: Check input condition
async def assemble_cylinder(self, cylinder, retract_from_start=True):
# 1. Move from current position -> Cylinder pick
pick_frame = cylinder.origin
motion = Motion(self.robot_position, pick_frame)
motion.linear_approach = LinearSection(Frame(z=0.1), speed=0.5) # [m]
if retract_from_start:
motion.linear_retraction = LinearSection(Frame(z=0.05), speed=0.5) # [m]
trajectory = self.planner.plan(motion)
await self.run_trajectory(trajectory)
# 2. Grasp cylinder
await self.grasp()
cylinder.origin = Frame.Identity()
self.robot.item_obstacle = cylinder
events = Studio.Events()
events[0.0] = Studio.Events.set_item(self.robot.item_obstacle)
events[0.0] = Studio.Events.remove_obstacle(cylinder)
# 3. Move from pick -> Angled assembly approach
assembly_frame = self.assembly.position
assembly_frame_approach = self.assembly.position * Frame(a=0.18) # [rad]
motion = Motion(self.robot_position, assembly_frame_approach)
motion.linear_retraction = LinearSection(Frame(z=0.1), speed=0.5) # [m]
motion.linear_approach = LinearSection(Frame(z=0.05), speed=0.1) # [m]
trajectory = self.planner.plan(motion)
await self.run_trajectory(trajectory, events)
# 4. Orient normal to fixture
motion = LinearMotion(self.robot_position, assembly_frame)
trajectory = self.planner.plan(motion)
events = Studio.Events()
cylinder.origin = self.assembly.position
events[trajectory.duration] = Studio.Events.add_obstacle(cylinder)
events[trajectory.duration] = Studio.Events.set_item(None)
await self.run_trajectory(trajectory, events)
# 5. Release cylinder
await self.release()
self.robot.item_obstacle = None
async def run(self):
# 0. Move to home position
trajectory = self.planner.plan(self.robot_position, self.home)
await self.run_trajectory(trajectory)
for i, cylinder in enumerate(self.cylinders):
await self.assemble_cylinder(cylinder, retract_from_start=i > 0)
# End. Move to home position again
motion = Motion(self.robot_position, self.home)
motion.linear_retraction = LinearSection(Frame(z=0.1), speed=0.5) # [m]
trajectory = self.planner.plan(motion)
await self.run_trajectory(trajectory)
self.studio.reset() # Reset the visualization
if __name__ == '__main__':
application = AssemblyApplication()
asyncio.run(application.run())