RSI-PI/examples/advanced_motion/03_path_blending.py

284 lines
9.9 KiB
Python

"""
Path Blending Example
Demonstrates smooth trajectory transitions using cubic interpolation for
eliminating stop-and-go motion at trajectory boundaries.
Usage:
python 03_path_blending.py --config RSI_EthernetConfig.xml
"""
import argparse
import logging
from RSIPI import RSIAPI
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def path_blending_example(config_file: str) -> None:
"""
Demonstrate path blending for smooth trajectory transitions.
Args:
config_file: Path to RSI configuration XML file
"""
api = RSIAPI(config_file)
try:
logging.info("Starting RSI communication...")
api.start()
logging.info("✅ RSI started successfully")
# ==================================================
# Example 1: Sharp Corner vs Blended Corner
# ==================================================
logging.info("\n" + "=" * 60)
logging.info("Example 1: Sharp Corner vs Blended Corner")
logging.info("=" * 60)
# Define three points forming a right angle
p0 = {"X": 100, "Y": 0, "Z": 500}
p1 = {"X": 200, "Y": 0, "Z": 500} # Corner point
p2 = {"X": 200, "Y": 100, "Z": 500}
# Generate two separate trajectories
traj1 = api.motion.generate_trajectory(p0, p1, steps=50)
traj2 = api.motion.generate_trajectory(p1, p2, steps=50)
logging.info("\nWithout blending:")
logging.info(" - Robot will stop at corner point")
logging.info(" - Visible acceleration/deceleration")
logging.info(" - Less smooth motion")
# Execute sharp corner (no blending)
logging.info("\nExecuting sharp corner motion...")
api.motion.execute_trajectory(traj1, space='cartesian', rate=0.02)
api.motion.execute_trajectory(traj2, space='cartesian', rate=0.02)
logging.info("✅ Sharp corner complete")
# Return to start
api.motion.execute_trajectory(
api.motion.generate_trajectory(p2, p0, steps=50),
space='cartesian',
rate=0.02
)
# Now execute with blending
logging.info("\nWith blending:")
logging.info(" - Smooth transition through corner")
logging.info(" - No visible stop at corner point")
logging.info(" - Continuous velocity")
blended = api.motion.blend_trajectories(
traj1,
traj2,
blend_radius=20.0, # Start blending 20mm before corner
blend_steps=20
)
logging.info(f"\nBlended trajectory: {len(blended)} waypoints")
logging.info(f"Original: {len(traj1) + len(traj2)} waypoints")
logging.info(f"Blend zone: 20.0 mm radius")
logging.info("Executing blended corner motion...")
api.motion.execute_trajectory(blended, space='cartesian', rate=0.02)
logging.info("✅ Blended corner complete")
# ==================================================
# Example 2: Multiple Blend Zones (Continuous Path)
# ==================================================
logging.info("\n" + "=" * 60)
logging.info("Example 2: Continuous Path with Multiple Blends")
logging.info("=" * 60)
# Define waypoints for a square pattern
waypoints = [
{"X": 100, "Y": 0, "Z": 500},
{"X": 150, "Y": 0, "Z": 500},
{"X": 150, "Y": 50, "Z": 500},
{"X": 100, "Y": 50, "Z": 500},
{"X": 100, "Y": 0, "Z": 500} # Return to start
]
logging.info(f"Square pattern with {len(waypoints)} waypoints")
# Generate segments
segments = []
for i in range(len(waypoints) - 1):
segment = api.motion.generate_trajectory(
waypoints[i],
waypoints[i + 1],
steps=30
)
segments.append(segment)
logging.info(f"Generated {len(segments)} path segments")
# Blend all segments together
logging.info("Blending all corners...")
blended_path = segments[0]
for i in range(1, len(segments)):
blended_path = api.motion.blend_trajectories(
blended_path,
segments[i],
blend_radius=10.0,
blend_steps=15
)
logging.info(f" Blended corner {i}/{len(segments)-1}")
logging.info(f"\nFinal blended path: {len(blended_path)} waypoints")
logging.info("Executing continuous square pattern...")
api.motion.execute_trajectory(blended_path, space='cartesian', rate=0.02)
logging.info("✅ Continuous square complete")
# ==================================================
# Example 3: Different Blend Radii
# ==================================================
logging.info("\n" + "=" * 60)
logging.info("Example 3: Effect of Different Blend Radii")
logging.info("=" * 60)
# Same trajectories as Example 1
traj1 = api.motion.generate_trajectory(p0, p1, steps=50)
traj2 = api.motion.generate_trajectory(p1, p2, steps=50)
blend_radii = [5.0, 15.0, 30.0]
for radius in blend_radii:
logging.info(f"\n--- Blend Radius: {radius} mm ---")
blended = api.motion.blend_trajectories(
traj1,
traj2,
blend_radius=radius,
blend_steps=20
)
logging.info(f"Blend radius: {radius} mm")
logging.info(f"Blended waypoints: {len(blended)}")
if radius < 10:
logging.info("Effect: Tighter blend, closer to sharp corner")
elif radius < 20:
logging.info("Effect: Moderate blend, balanced smoothness")
else:
logging.info("Effect: Wide blend, very smooth but cuts corner more")
logging.info(f"Executing blend with radius={radius}mm...")
api.motion.execute_trajectory(blended, space='cartesian', rate=0.02)
logging.info(f"✅ Blend radius {radius}mm complete")
# Return to start
api.motion.execute_trajectory(
api.motion.generate_trajectory(p2, p0, steps=50),
space='cartesian',
rate=0.02
)
# ==================================================
# Example 4: Blending with Different Orientations
# ==================================================
logging.info("\n" + "=" * 60)
logging.info("Example 4: Blending Trajectories with Orientation Changes")
logging.info("=" * 60)
# Define points with different orientations
p0_rot = {"X": 100, "Y": 0, "Z": 500, "A": 0, "B": 0, "C": 0}
p1_rot = {"X": 150, "Y": 0, "Z": 500, "A": 0, "B": 0, "C": 45}
p2_rot = {"X": 150, "Y": 50, "Z": 500, "A": 0, "B": 0, "C": 90}
traj1_rot = api.motion.generate_trajectory(p0_rot, p1_rot, steps=50)
traj2_rot = api.motion.generate_trajectory(p1_rot, p2_rot, steps=50)
logging.info("Trajectory with orientation change:")
logging.info(f" Start: C = 0°")
logging.info(f" Corner: C = 45°")
logging.info(f" End: C = 90°")
blended_rot = api.motion.blend_trajectories(
traj1_rot,
traj2_rot,
blend_radius=15.0,
blend_steps=20
)
logging.info(f"\nBlending also smooths orientation transitions")
logging.info(f"Blended waypoints: {len(blended_rot)}")
logging.info("Executing blended motion with rotation...")
api.motion.execute_trajectory(blended_rot, space='cartesian', rate=0.02)
logging.info("✅ Blended rotation complete")
# ==================================================
# Application Examples
# ==================================================
logging.info("\n" + "=" * 60)
logging.info("Application Examples")
logging.info("=" * 60)
logging.info("\nPick and Place Applications:")
logging.info(" - Smooth transitions between pick/place points")
logging.info(" - Reduced cycle time by eliminating stops")
logging.info(" - Lower mechanical stress on robot")
logging.info("\nWelding/Gluing Applications:")
logging.info(" - Continuous bead at corners without stop marks")
logging.info(" - Consistent material deposition rate")
logging.info(" - Professional finish quality")
logging.info("\nMachining Applications:")
logging.info(" - Smooth tool paths without witness marks")
logging.info(" - Reduced vibration and tool wear")
logging.info(" - Better surface finish")
logging.info("\nPainting/Coating Applications:")
logging.info(" - Even coating thickness at corners")
logging.info(" - No overspray from deceleration")
logging.info(" - Faster throughput")
except KeyboardInterrupt:
logging.warning("\n⚠️ Interrupted by user")
except Exception as e:
logging.error(f"❌ Error during path blending: {e}")
finally:
logging.info("Stopping RSI communication...")
api.stop()
logging.info("✅ API stopped successfully")
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(description='Path Blending Example')
parser.add_argument(
'--config',
type=str,
default='RSI_EthernetConfig.xml',
help='Path to RSI configuration file'
)
args = parser.parse_args()
logging.info("=" * 60)
logging.info("RSIPI - Path Blending Example")
logging.info("=" * 60)
logging.info(f"Config: {args.config}")
logging.info("=" * 60)
path_blending_example(args.config)
logging.info("=" * 60)
logging.info("Example complete!")
logging.info("=" * 60)
if __name__ == '__main__':
from multiprocessing import freeze_support
freeze_support()
main()