first commit

This commit is contained in:
琉璃月光
2025-09-22 14:19:00 +08:00
commit 2ada26f176
16 changed files with 968 additions and 0 deletions

Binary file not shown.

145
2D/caculate/fkik.py Normal file
View File

@ -0,0 +1,145 @@
import math
import matplotlib.pyplot as plt
# 设置中文字体(防警告)
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
class TwoLinkArm:
def __init__(self, l1=1.0, l2=1.0):
self.l1 = l1
self.l2 = l2
self.theta1 = 0.0 # 弧度
self.theta2 = 0.0 # 弧度
self.end_x = l1 + l2 # 初始末端位置
self.end_y = 0.0
self.joint1 = (l1, 0.0)
self.joint2 = (l1 + l2, 0.0)
self.fig, self.ax = plt.subplots(figsize=(8, 8))
plt.subplots_adjust(bottom=0.2)
self.ax.set_xlim(-l1 - l2 - 0.5, l1 + l2 + 0.5)
self.ax.set_ylim(-l1 - l2 - 0.5, l1 + l2 + 0.5)
self.ax.set_aspect('equal')
self.ax.grid(True)
self.ax.set_title("拖动末端执行器(粉色点)来移动机械臂")
self.ax.set_xlabel("X")
self.ax.set_ylabel("Y")
# 绘制机械臂
self.line_link1, = self.ax.plot([], [], 'b-', linewidth=4, label=f'连杆1 (L1={l1})')
self.line_link2, = self.ax.plot([], [], 'r-', linewidth=4, label=f'连杆2 (L2={l2})')
self.joint_point, = self.ax.plot([], [], 'go', markersize=8, label='关节2')
self.end_point, = self.ax.plot([], [], 'mo', markersize=8, label='末端执行器')
self.base_point, = self.ax.plot(0, 0, 'ko', markersize=10, label='基座')
self.angle_text = self.ax.text(
-l1 - l2 + 0.2,
l1 + l2 - 0.3,
'',
fontsize=10,
bbox=dict(boxstyle="round", facecolor="wheat")
)
self.ax.legend()
# 拖动相关变量
self.dragging = False
self.press_xdata = None
self.press_ydata = None
# 连接事件
self.cid_press = self.fig.canvas.mpl_connect('button_press_event', self.on_press)
self.cid_release = self.fig.canvas.mpl_connect('button_release_event', self.on_release)
self.cid_motion = self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion)
# 初始绘制
self.update_plot()
def fk(self, theta1, theta2):
"""正向运动学"""
x1 = self.l1 * math.cos(theta1)
y1 = self.l1 * math.sin(theta1)
x2 = x1 + self.l2 * math.cos(theta1 + theta2)
y2 = y1 + self.l2 * math.sin(theta1 + theta2)
return (x1, y1), (x2, y2)
def ik(self, x, y, elbow_up=True):
"""逆向运动学"""
d_sq = x*x + y*y
cos_theta2_numerator = d_sq - self.l1**2 - self.l2**2
denominator = 2 * self.l1 * self.l2
if abs(cos_theta2_numerator) > abs(denominator):
return None # 不可达
cos_theta2 = max(-1, min(1, cos_theta2_numerator / denominator))
theta2 = math.acos(cos_theta2) if elbow_up else -math.acos(cos_theta2)
k1 = self.l1 + self.l2 * math.cos(theta2)
k2 = self.l2 * math.sin(theta2)
theta1 = math.atan2(y, x) - math.atan2(k2, k1)
return theta1, theta2
def update_plot(self):
"""根据当前末端位置计算 IK 并更新图像"""
solution = self.ik(self.end_x, self.end_y, elbow_up=True) # 默认肘上解
if solution is not None:
self.theta1, self.theta2 = solution
(x1, y1), (x2, y2) = self.fk(self.theta1, self.theta2)
self.joint1 = (x1, y1)
self.joint2 = (x2, y2)
else:
# 如果不可达,保持上一个有效姿态,但末端显示为红色
x2, y2 = self.end_x, self.end_y
self.end_point.set_color('red')
# 更新线条和点
self.line_link1.set_data([0, self.joint1[0]], [0, self.joint1[1]])
self.line_link2.set_data([self.joint1[0], self.joint2[0]], [self.joint1[1], self.joint2[1]])
self.joint_point.set_data(self.joint1[0], self.joint1[1])
self.end_point.set_data(self.joint2[0], self.joint2[1])
self.end_point.set_color('m') # 恢复正常颜色
# 显示角度(现在是弧度)
angle_str = f"θ1 = {self.theta1:+.3f} rad\nθ2= {self.theta2:+.3f} rad"
self.angle_text.set_text(angle_str)
self.fig.canvas.draw_idle()
def on_press(self, event):
if event.inaxes != self.ax:
return
if self.end_point.contains(event)[0]: # 点中末端点
self.dragging = True
self.press_xdata = event.xdata
self.press_ydata = event.ydata
else:
self.dragging = False
def on_release(self, event):
self.dragging = False
def on_motion(self, event):
if not self.dragging or event.inaxes != self.ax:
return
# 更新末端位置
dx = event.xdata - self.press_xdata
dy = event.ydata - self.press_ydata
self.end_x += dx
self.end_y += dy
self.press_xdata = event.xdata
self.press_ydata = event.ydata
self.update_plot()
def show(self):
plt.show()
# ========================
# 主程序
# ========================
if __name__ == "__main__":
print("拖动末端执行器(粉色点)来交互式控制两连杆机械臂!")
arm = TwoLinkArm(l1=1.0, l2=1.0)
arm.show()

0
2D/caculate/test.py Normal file
View File

99
2D/caculate/trajectory.py Normal file
View File

@ -0,0 +1,99 @@
# trajectory.py
import numpy as np
def circle_trajectory(center=(80, 0), radius=40, num_points=200):
""" 圆形轨迹 """
angles = np.linspace(0, 2 * np.pi, num_points)
x_list = center[0] + radius * np.cos(angles)
y_list = center[1] + radius * np.sin(angles)
return x_list, y_list
def line_trajectory(start=(40, 0), end=(120, 0), num_points=100):
""" 直线轨迹 """
t = np.linspace(0, 1, num_points)
x_list = start[0] + t * (end[0] - start[0])
y_list = start[1] + t * (end[1] - start[1])
return x_list, y_list
def line_trajectory_fix(start=(40, 0), end=(120, 100), vx=0.1, vy=0.1, num_points=20):
"""
生成带速度分量的匀速斜线轨迹
参数:
start: 起始点 (x, y)
end: 终点 (x, y) —— 仅用于估算运行时间(可选)
vx: x方向速度单位/秒)
vy: y方向速度单位/秒)
num_points: 生成的轨迹点数
返回:
x_list, y_list: 轨迹坐标数组
"""
# 速度大小
speed = np.sqrt(vx**2 + vy**2)
if speed == 0:
raise ValueError("速度不能为零")
# 估算从 start 到 end 的距离(用于估算总时间)
if end is not None:
dx = end[0] - start[0]
dy = end[1] - start[1]
distance = np.sqrt(dx**2 + dy**2)
total_time = distance / speed # 理论到达时间
print(total_time)
else:
total_time = 10.0 # 默认运行10秒
# 时间序列:从 0 到 total_time均匀分布 num_points 个点
t = np.linspace(0, total_time, num_points)
# 位置 = 起点 + 速度 × 时间
x_list = start[0] + vx * t
y_list = start[1] + vy * t
return x_list, y_list
def ellipse_trajectory(center=(80, 0), rx=50, ry=25, num_points=200):
""" 椭圆轨迹 """
angles = np.linspace(0, 2 * np.pi, num_points)
x_list = center[0] + rx * np.cos(angles)
y_list = center[1] + ry * np.sin(angles)
return x_list, y_list
def square_trajectory(side=60, num_points=60):
""" 正方形轨迹 """
x_list, y_list = [], []
for i in range(num_points):
t = i / num_points
if t < 0.25:
x = 80 + 60 * t * 4
y = 0
elif t < 0.5:
x = 140
y = 0 + 60 * (t - 0.25) * 4
elif t < 0.75:
x = 140 - 60 * (t - 0.5) * 4
y = 60
else:
x = 80
y = 60 - 60 * (t - 0.75) * 4
x_list.append(x)
y_list.append(y)
return x_list, y_list
def triangle_trajectory(base_length=100, height=80, num_points=60):
""" 三角形轨迹 """
x_list, y_list = [], []
points = [(80, 0), (130, 80), (30, 80), (80, 0)]
for i in range(num_points):
idx = int(i / num_points * 3)
t = (i % (num_points // 3)) / (num_points // 3)
x = points[idx][0] + t * (points[idx+1][0] - points[idx][0])
y = points[idx][1] + t * (points[idx+1][1] - points[idx][1])
x_list.append(x)
y_list.append(y)
return x_list, y_list
def custom_trajectory(custom_x, custom_y):
""" 自定义轨迹,输入两个列表即可 """
return custom_x, custom_y