Compare commits

..

10 Commits

Author SHA1 Message Date
078f20eb38 ready to publish code 2024-09-08 18:28:14 +08:00
bf1c864823 accurately calculated max v 2024-09-08 12:17:58 +08:00
c201220e04 fix error of wrong speed 2024-09-08 09:15:10 +08:00
eef587ca52 update task4 2024-09-07 23:52:51 +08:00
34250d6344 write kinematics check 2024-09-07 23:16:53 +08:00
095f63d154 get more accurate 2024-09-07 16:47:14 +08:00
4c409ace18 write task5 2024-09-07 15:52:12 +08:00
cd429d4abf basically finished calc 2024-09-07 15:05:46 +08:00
ad195eca76 Orbit OK 2024-09-07 14:30:20 +08:00
caa0a9e2a1 write orbit 2024-09-07 12:35:43 +08:00
15 changed files with 532 additions and 78 deletions

3
.gitignore vendored
View File

@@ -5,4 +5,5 @@
*.log *.log
*.gif *.gif
__pycache__/ __pycache__/
.idea/ .idea/
/setup.cfg

View File

@@ -1,7 +1,7 @@
import mpmath as mp import mpmath as mp
import json import json
mp.dps = 15 # 设置精度为15位小数 mp.dps = 50 # 设置精度为15位小数
kSegLength1 = mp.mpf('2.86') kSegLength1 = mp.mpf('2.86')
kSegLength2 = mp.mpf('1.65') kSegLength2 = mp.mpf('1.65')

View File

@@ -1,7 +1,7 @@
import mpmath as mp import mpmath as mp
import json import json
mp.dps = 15 # 设置精度为15位小数 mp.dps = 50 # 设置精度为50位小数
kSegLength1 = mp.mpf('2.86') kSegLength1 = mp.mpf('2.86')
kSegLength2 = mp.mpf('1.65') kSegLength2 = mp.mpf('1.65')

View File

@@ -9,7 +9,7 @@ import threading
import numba import numba
import multiprocessing import multiprocessing
mp.dps = 15 # 设置精度为15位小数 mp.dps = 50 # 设置精度为50位小数
kSegLength1 = mp.mpf('2.86') kSegLength1 = mp.mpf('2.86')
kSegLength2 = mp.mpf('1.65') kSegLength2 = mp.mpf('1.65')
@@ -35,7 +35,7 @@ def GenerateFollowNodeTheta(cur_node_theta, expected_distance):
test_node_dot = Theta2Dot(theta) test_node_dot = Theta2Dot(theta)
actual_distance = mp.sqrt((cur_node_dot[0]-test_node_dot[0])**2 + (cur_node_dot[1]-test_node_dot[1])**2) actual_distance = mp.sqrt((cur_node_dot[0]-test_node_dot[0])**2 + (cur_node_dot[1]-test_node_dot[1])**2)
return actual_distance - expected_distance return actual_distance - expected_distance
return mp.findroot(f, cur_node_theta + 0.1, solver='secant',tol=1e-20) return mp.findroot(f, cur_node_theta + 0.1, solver='secant')
kPointsConsidered=50 kPointsConsidered=50
def CalcMoveList(time_point): def CalcMoveList(time_point):

View File

@@ -8,7 +8,7 @@ import numpy as np
if __name__ != "__main__": if __name__ != "__main__":
sys.exit() sys.exit()
mp.dps = 15 # 设置精度为15位小数 mp.dps = 50 # 设置精度为15位小数
kSegLength1 = mp.mpf('2.86') kSegLength1 = mp.mpf('2.86')
kSegLength2 = mp.mpf('1.65') kSegLength2 = mp.mpf('1.65')

View File

@@ -11,7 +11,7 @@ import multiprocessing
import io import io
from PIL import Image from PIL import Image
mp.dps = 15 # 设置精度为15位小数 mp.dps = 50 # 设置精度为50位小数
kSegLength1 = mp.mpf('2.86') kSegLength1 = mp.mpf('2.86')
kSegLength2 = mp.mpf('1.65') kSegLength2 = mp.mpf('1.65')
@@ -37,7 +37,7 @@ class Dragon:
test_node_dot = self.Theta2Dot(theta) test_node_dot = self.Theta2Dot(theta)
actual_distance = mp.sqrt((cur_node_dot[0]-test_node_dot[0])**2 + (cur_node_dot[1]-test_node_dot[1])**2) actual_distance = mp.sqrt((cur_node_dot[0]-test_node_dot[0])**2 + (cur_node_dot[1]-test_node_dot[1])**2)
return actual_distance - expected_distance return actual_distance - expected_distance
return mp.findroot(f, cur_node_theta + 0.1, solver='secant',tol=1e-20) return mp.findroot(f, cur_node_theta + 0.1, solver='secant')
def CalcMoveList(self, delta_theta=0): def CalcMoveList(self, delta_theta=0):

View File

@@ -1,15 +1,15 @@
from dragon import * from dragon import *
kPitchToTest=0.450338 kPitchToTest=mp.mpf("0.45033740")
kDeltaThetaBeg=0 kDeltaThetaBeg=0
kDeltaThetaEnd=2*2*3.1415926 kDeltaThetaEnd=2*2*3.1415926
kTotalSteps=100000 kTotalSteps=10000
kStepDeltaTheta=(kDeltaThetaEnd-kDeltaThetaBeg)/kTotalSteps kStepDeltaTheta=(kDeltaThetaEnd-kDeltaThetaBeg)/kTotalSteps
kParallelNum=24 kParallelNum=24
tasks_list=[i for i in np.arange(kDeltaThetaBeg, kDeltaThetaEnd, kStepDeltaTheta)] tasks_list=[i for i in np.arange(kDeltaThetaBeg, kDeltaThetaEnd, kStepDeltaTheta)]
task_list_per_process=[tasks_list[i::kParallelNum] for i in range(kParallelNum)] task_list_per_process=[tasks_list[i::kParallelNum] for i in range(kParallelNum)]
print(f"len(task_list_per_thread)={len(task_list_per_process)}",file=sys.stderr) print(f"len(task_list_per_thread)={len(task_list_per_process)}",file=sys.stderr)
def ProcessEntryPoint(arg): def ProcessEntryPoint(arg):
dragen = Dragon(mp.mpf(kPitchToTest)/(2*mp.pi)) dragen = Dragon(kPitchToTest/(2*mp.pi))
delta_theta_list, process_id = arg delta_theta_list, process_id = arg
logf=open(f"sufficiency_test_{process_id}.log","w") logf=open(f"sufficiency_test_{process_id}.log","w")
print(f"calculating delta_theta_list={delta_theta_list} with process_id={process_id}",file=logf) print(f"calculating delta_theta_list={delta_theta_list} with process_id={process_id}",file=logf)
@@ -29,7 +29,7 @@ if __name__ == "__main__":
else: else:
print("OK") print("OK")
# Now generate an gif for human to check # Now generate an gif for human to check
dragen = Dragon(mp.mpf(kPitchToTest)/(2*mp.pi)) dragen = Dragon(kPitchToTest/(2*mp.pi))
kTotalFrames=100 kTotalFrames=100
kStepDeltaTheta=(kDeltaThetaEnd-kDeltaThetaBeg)/kTotalFrames kStepDeltaTheta=(kDeltaThetaEnd-kDeltaThetaBeg)/kTotalFrames
frame_list=[] frame_list=[]

View File

@@ -2,7 +2,7 @@ from dragon import *
kBegPitch = 0.3 kBegPitch = 0.3
kEndPitch = 0.55 kEndPitch = 0.55
kTotalSteps = 10000 kTotalSteps = 250000
kStepPitch = (kEndPitch - kBegPitch) / kTotalSteps kStepPitch = (kEndPitch - kBegPitch) / kTotalSteps
kParallelNum=24 kParallelNum=24
tasks_list = [kBegPitch + kStepPitch * i for i in range(kTotalSteps)] tasks_list = [kBegPitch + kStepPitch * i for i in range(kTotalSteps)]
@@ -19,6 +19,8 @@ def ProcessEntryPoint(arg):
status = CheckCollision(status2blocks(dragen.CalcMoveList())) status = CheckCollision(status2blocks(dragen.CalcMoveList()))
tmp_res[pitch]=status tmp_res[pitch]=status
print(f"res={status}",file=logf) print(f"res={status}",file=logf)
if status == -1:
break
with lock: # 添加锁保护对共享字典的操作 with lock: # 添加锁保护对共享字典的操作
shared_dict.update(tmp_res) shared_dict.update(tmp_res)

View File

@@ -1,7 +1,7 @@
from dragon import * from dragon import *
kBegPitch = 0.4503 kBegPitch = 0.45033
kEndPitch = 0.4504 kEndPitch = 0.45034
kTotalSteps = 100 kTotalSteps = 10
kStepPitch = (kEndPitch - kBegPitch) / kTotalSteps kStepPitch = (kEndPitch - kBegPitch) / kTotalSteps
kParallelNum=24 kParallelNum=24
tasks_list = [kBegPitch + kStepPitch * i for i in range(kTotalSteps)] tasks_list = [kBegPitch + kStepPitch * i for i in range(kTotalSteps)]
@@ -9,7 +9,7 @@ task_list_per_process=[tasks_list[i::kParallelNum] for i in range(kParallelNum)]
kDeltaThetaBeg=0 kDeltaThetaBeg=0
kDeltaThetaEnd=5*2*3.1415926 kDeltaThetaEnd=5*2*3.1415926
kStepDeltaTheta=(kDeltaThetaEnd-kDeltaThetaBeg)/1000 kStepDeltaTheta=(kDeltaThetaEnd-kDeltaThetaBeg)/10000
print(f"len(task_list_per_thread)={len(task_list_per_process)}",file=sys.stderr) print(f"len(task_list_per_thread)={len(task_list_per_process)}",file=sys.stderr)
def ProcessEntryPoint(arg): def ProcessEntryPoint(arg):
pitch_list, process_id, shared_dict, lock = arg pitch_list, process_id, shared_dict, lock = arg

19
A/4/A4_to_csv.py Normal file
View File

@@ -0,0 +1,19 @@
import json
with open("A4_res.json", "r") as file:
content=json.load(file)
fout1=open("tmp1.dat","w")
for node_point in range(224):
for time_point in range(201):
v=content[time_point][node_point]["v"]
print(v,'\t',file=fout1,sep="",end="")
print('\n',file=fout1,end="",sep="")
fout2=open("tmp2.dat","w")
for node_point in range(224):
for time_point in range(201):
x=content[time_point][node_point]["node"][0]
print(x,'\t',file=fout2,sep="",end="")
print('\n',file=fout2,end="",sep="")
for time_point in range(201):
y=content[time_point][node_point]["node"][1]
print(y,'\t',file=fout2,sep="",end="")
print('\n',file=fout2,end="",sep="")

View File

@@ -1,2 +1,207 @@
import loong from loong import *
loong.kPointsConsidered = 2 # Just Check the first 2 blocks to see whether it will be stuck import json
import numpy as np
import sys
import matplotlib.pyplot as plt
import io
from PIL import Image
from matplotlib.patches import Rectangle
import multiprocessing
class BetterOrbit(Orbit):
def __init__(self):
self.kAlpha = mp.mpf("1.7") / (2 * mp.pi)
def f(x):
r=(1/3)*self.kAlpha*mp.sqrt(1+x**2)
phi=mp.atan(x)
L=mp.mpf("2.86")
return (r+3*r*mp.cos(mp.pi-2*phi)-L)**2+(3*r*mp.sin(mp.pi-2*phi))**2-L**2
self.kCriticalTheta = mp.findroot(f, 15, solver='secant')
print(f"CriticalTheta={self.kCriticalTheta}", file=sys.stderr)
self.r = (1 / 3) * self.kAlpha * mp.sqrt(1 + self.kCriticalTheta**2)
self.point_A_cartesian = (
self.kAlpha * self.kCriticalTheta * mp.cos(self.kCriticalTheta),
self.kAlpha * self.kCriticalTheta * mp.sin(self.kCriticalTheta),
)
self.point_B_cartesian = (-self.kAlpha * self.kCriticalTheta * mp.cos(self.kCriticalTheta),
-self.kAlpha * self.kCriticalTheta * mp.sin(self.kCriticalTheta))
self.kPhi = mp.atan(self.kCriticalTheta)
print(f"Phi={self.kPhi}", file=sys.stderr)
dx, dy = self.point_A_cartesian[0] - self.point_B_cartesian[0], self.point_A_cartesian[1] - self.point_B_cartesian[1]
self.angle = mp.atan2(dy, dx)
print(f"angle={self.angle}", file=sys.stderr)
self.point_C1_cartesian = (self.point_A_cartesian[0] + 2 * self.r * mp.cos(self.angle + 0.5 * mp.pi + self.kPhi),
self.point_A_cartesian[1] + 2 * self.r * mp.sin(self.angle + 0.5 * mp.pi + self.kPhi))
self.point_C2_cartesian = (self.point_B_cartesian[0] + 1 * self.r * mp.cos(self.angle - 0.5 * mp.pi + self.kPhi),
self.point_B_cartesian[1] + 1 * self.r * mp.sin(self.angle - 0.5 * mp.pi + self.kPhi))
self.radius_of_C1 = 2 * self.r
self.radius_of_C2 = 1 * self.r
self.arclength = 6 * self.r * self.kPhi
self.edge_k = self.kAlpha * mp.sqrt(1 + self.kCriticalTheta * self.kCriticalTheta)
self.n = -1
for i in range(3, 20, 2):
self.a = (self.arclength - 2 * self.edge_k * self.kCriticalTheta) / (2 * (1 - i) * self.kCriticalTheta**i)
self.b = (i * self.arclength - 2 * self.edge_k * self.kCriticalTheta) / (2 * (i - 1) * self.kCriticalTheta)
if self.a > 0 and self.b > 0:
self.n = i
break
print(f"arclength={self.arclength}", file=sys.stderr)
print(f"edge_k={self.edge_k}", file=sys.stderr)
print(f"a={self.a}", file=sys.stderr)
print(f"b={self.b}", file=sys.stderr)
print(f"n={self.n}", file=sys.stderr)
print(f"now k={self.n*self.a*self.kCriticalTheta**(self.n-1)+self.b}", file=sys.stderr)
if self.n == -1:
raise Exception("n must be set")
self.edge_raw_C = self.kAlpha * 0.5 * (
self.kCriticalTheta * mp.sqrt(1 + self.kCriticalTheta * self.kCriticalTheta) -
mp.log(-self.kCriticalTheta + mp.sqrt(1 + self.kCriticalTheta * self.kCriticalTheta)))
def InitIdx(self):
return mp.mpf("0.0")
def InitC(self):
return mp.mpf("0.0")
def Idx2C(self, idx): # this function must be monotonically increasing
if idx >= 0:
theta = idx + self.kCriticalTheta
tmp = mp.sqrt(1 + theta * theta)
return self.kAlpha * 0.5 * (theta * tmp - mp.log(-theta + tmp)) - self.edge_raw_C
elif idx >= -2 * self.kCriticalTheta:
x = idx + self.kCriticalTheta
y = (self.a * (x**self.n) + self.b * x) - 0.5 * self.arclength
return y
else:
theta = -idx - self.kCriticalTheta
tmp = mp.sqrt(1 + theta * theta)
return -self.kAlpha * 0.5 * (theta * tmp - mp.log(-theta + tmp)) + self.edge_raw_C - self.arclength
def Idx2Cartesian(self, idx):
if idx >= 0:
theta = idx + self.kCriticalTheta
return [self.kAlpha * theta * mp.cos(theta), self.kAlpha * theta * mp.sin(theta)]
elif idx >= -2 * self.kCriticalTheta:
c = self.Idx2C(idx) + self.arclength
# if c < 0 or c > self.arclength:
# raise Exception(f"idx={idx}, c={c}")
if c <= self.arclength / 3:
# In C2
delta_angle = c / self.radius_of_C2
actual_angle = self.angle + 0.5 * mp.pi + self.kPhi - delta_angle
return [
self.point_C2_cartesian[0] + self.radius_of_C2 * mp.cos(actual_angle),
self.point_C2_cartesian[1] + self.radius_of_C2 * mp.sin(actual_angle)
]
else:
delta_angle = (c - self.arclength / 3) / self.radius_of_C1
actual_angle = self.angle - 0.5 * mp.pi - self.kPhi + delta_angle
return [
self.point_C1_cartesian[0] + self.radius_of_C1 * mp.cos(actual_angle),
self.point_C1_cartesian[1] + self.radius_of_C1 * mp.sin(actual_angle)
]
else:
theta = -idx - self.kCriticalTheta
return [-self.kAlpha * theta * mp.cos(theta), -self.kAlpha * theta * mp.sin(theta)]
def C2Idx(self, C):
def f(idx):
return self.Idx2C(idx) - C
return mp.findroot(f, (-100*2*mp.pi,100*2*mp.pi), solver='bisect')
def GenerateNextPointIdx(self, cur_point_idx, expected_distance, guess=None):
if guess is None:
cur_point_C = self.Idx2C(cur_point_idx)
guess = self.C2Idx(cur_point_C + expected_distance)
cur_point_dot = self.Idx2Cartesian(cur_point_idx)
def f(idx):
test_point_dot = self.Idx2Cartesian(idx)
return mp.sqrt((cur_point_dot[0] - test_point_dot[0])**2 +
(cur_point_dot[1] - test_point_dot[1])**2) - expected_distance
return mp.findroot(f, guess, solver='secant')
def GenerateImg(self, node_list):
fig = plt.figure(figsize=(12, 12))
# 绘制轨道线
idx_list = np.linspace(-12 * 2 * np.pi, 8 * 2 * np.pi, 10000)
x = [float(self.Idx2Cartesian(t)[0]) for t in idx_list]
y = [float(self.Idx2Cartesian(t)[1]) for t in idx_list]
plt.plot(x, y, color='gray', linewidth=0.5)
# 绘制节点、连接线和木板
for i in range(len(node_list) - 1):
x1, y1 = [float(coord) for coord in node_list[i]["node"]]
x2, y2 = [float(coord) for coord in node_list[i + 1]["node"]]
# 绘制红色节点
plt.plot(x1, y1, 'ro', markersize=3)
# 绘制蓝色连接线
plt.plot([x1, x2], [y1, y2], 'b-', linewidth=0.5)
# 计算并绘制木板(长方形)
dx = x2 - x1
dy = y2 - y1
length = np.sqrt(dx**2 + dy**2)
angle = np.arctan2(dy, dx)
rect_length = length + 0.55 # 总长度加上两端各延伸的0.275m
rect_width = 0.3
# 计算长方形的中心点
center_x = (x1 + x2) / 2
center_y = (y1 + y2) / 2
# 计算长方形的左下角坐标
rect_x = center_x - rect_length / 2 * np.cos(angle) + rect_width / 2 * np.sin(angle)
rect_y = center_y - rect_length / 2 * np.sin(angle) - rect_width / 2 * np.cos(angle)
rect = Rectangle((rect_x, rect_y), rect_length, rect_width, angle=angle * 180 / np.pi, fill=False, edgecolor='g')
plt.gca().add_patch(rect)
# 绘制最后一个节点
x, y = [float(coord) for coord in node_list[-1]["node"]]
plt.plot(x, y, 'ro', markersize=3)
plt.axis('equal')
# 创建一个 BytesIO 对象来存储图像
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
# 清除当前图形,释放内存
plt.close(fig)
# 返回图像对象
return Image.open(buf)
if __name__ == "__main__":
orbit = BetterOrbit()
loong = Loong(orbit, 224, mp.mpf("1.0"), mp.mpf("1e-8"))
res_list = []
for ti in np.arange(10, 20, 0.025):
print(f"calculating time_point={ti}", file=sys.stderr)
res_list.append(loong.CalcStatusListByTime(mp.mpf(ti), res_list[-1] if res_list else None))
# 转换成内置浮点数并保留6位
float_res_list = [[{
"idx": round(float(node["idx"]), 6),
"node": [
round(float(node["node"][0]), 6),
round(float(node["node"][1]), 6),
],
"C": round(float(node["C"]), 6),
"v": round(float(node["v"]), 6),
} for node in res] for res in res_list]
with open("A4_res.json", "w") as file:
json.dump(float_res_list, file, indent=4)
img_list = [orbit.GenerateImg(res) for res in res_list]
img_list[0].save("A4.gif", save_all=True, append_images=img_list[1:], duration=25, loop=0)

View File

@@ -1,7 +1,7 @@
import mpmath as mp import mpmath as mp
import numba as nb import numba as nb
mp.dps = 25 # 设置精度为25位小数 mp.dps = 50 # 设置精度为50位小数
class Orbit: class Orbit:
def __init__(self): def __init__(self):
@@ -16,7 +16,7 @@ class Orbit:
raise NotImplementedError raise NotImplementedError
def C2Idx(self, C:[mp.mpf, mp.mpf]) -> mp.mpf: def C2Idx(self, C:[mp.mpf, mp.mpf]) -> mp.mpf:
raise NotImplementedError raise NotImplementedError
def GenerateNextPointIdx(self, cur_point_idx:mp.mpf, expected_distance:mp.mpf)->mp.mpf: def GenerateNextPointIdx(self, cur_point_idx:mp.mpf, expected_distance:mp.mpf, guess=None)->mp.mpf:
raise NotImplementedError raise NotImplementedError
class Loong: class Loong:
@@ -27,28 +27,28 @@ class Loong:
self.delta_idx = delta_idx self.delta_idx = delta_idx
self.kSegLength1 = mp.mpf('2.86') self.kSegLength1 = mp.mpf('2.86')
self.kSegLength2 = mp.mpf('1.65') self.kSegLength2 = mp.mpf('1.65')
def CalcStatusListByIdx(self, cur_idx:mp.mpf): def CalcStatusListByIdx(self, cur_idx:mp.mpf, last_time_status=None):
first_node_idx=cur_idx first_node_idx=cur_idx
first_node_C=self.orbit.Idx2C(first_node_idx) first_node_C=self.orbit.Idx2C(first_node_idx)
first_node_dot = self.orbit.Idx2Cartesian(first_node_idx) first_node_dot = self.orbit.Idx2Cartesian(first_node_idx)
virtual_first_node_idx = first_node_idx + self.delta_idx virtual_first_node_idx = first_node_idx + self.delta_idx
virtual_first_node_C = self.orbit.Idx2C(virtual_first_node_idx) virtual_first_node_C = self.orbit.Idx2C(virtual_first_node_idx)
delta_T = (virtual_first_node_C - first_node_C) / self.speed delta_T = (virtual_first_node_C - first_node_C) / self.speed
node_list = [{"idx": first_node_idx, "node": first_node_dot, "C": first_node_C, "v": mp.mpf('1.0')}] node_list = [{"idx": first_node_idx, "node": first_node_dot, "C": first_node_C, "v": self.speed}]
for i in range(1, self.total_points): for i in range(1, self.total_points):
expected_distance = self.kSegLength1 if i == 1 else self.kSegLength2 expected_distance = self.kSegLength1 if i == 1 else self.kSegLength2
cur_node_idx = self.orbit.GenerateNextPointIdx(node_list[-1]["idx"], expected_distance) cur_node_idx = self.orbit.GenerateNextPointIdx(node_list[-1]["idx"], expected_distance, guess=last_time_status[i]["idx"] if last_time_status else None)
cur_node_dot = self.orbit.Idx2Cartesian(cur_node_idx) cur_node_dot = self.orbit.Idx2Cartesian(cur_node_idx)
cur_node_C = self.orbit.Idx2C(cur_node_idx) cur_node_C = self.orbit.Idx2C(cur_node_idx)
virtual_cur_node_idx = self.orbit.GenerateNextPointIdx(virtual_first_node_idx, expected_distance) virtual_cur_node_idx = self.orbit.GenerateNextPointIdx(virtual_first_node_idx, expected_distance, guess=last_time_status[i]["idx"] if last_time_status else None)
virtual_cur_node_C = self.orbit.Idx2C(virtual_cur_node_idx) virtual_cur_node_C = self.orbit.Idx2C(virtual_cur_node_idx)
v = (virtual_cur_node_C - cur_node_C) / delta_T v = (virtual_cur_node_C - cur_node_C) / delta_T
node_list.append({"idx": cur_node_idx, "node": cur_node_dot, "C": cur_node_C, "v": v}) node_list.append({"idx": cur_node_idx, "node": cur_node_dot, "C": cur_node_C, "v": v})
virtual_first_node_idx = virtual_cur_node_idx virtual_first_node_idx = virtual_cur_node_idx
return node_list return node_list
def CalcStatusListByTime(self, time_point:mp.mpf): def CalcStatusListByTime(self, time_point:mp.mpf, last_time_status=None):
first_node_C = self.orbit.InitC() - time_point * self.speed first_node_C = self.orbit.InitC() - time_point * self.speed
first_node_idx = self.orbit.C2Idx(first_node_C) first_node_idx = self.orbit.C2Idx(first_node_C)
return self.CalcStatusListByIdx(first_node_idx) return self.CalcStatusListByIdx(first_node_idx, last_time_status)

52
A/4/seek_max.py Normal file
View File

@@ -0,0 +1,52 @@
from simulator import *
kTiBeg = -100
kTiEnd = 100
kSampleNum = 1000
kStep = (kTiEnd - kTiBeg) / kSampleNum
kParallelNum=24
tasks_list = [i for i in np.arange(kTiBeg, kTiEnd, kStep)]
for i in np.arange(10, 20, 1/1000):
tasks_list.append(i)
for i in np.arange(12, 14.2, 1/10000):
tasks_list.append(i)
for i in np.arange(13.085,13.095,1/1000000):
tasks_list.append(i)
task_list_per_process=[tasks_list[i::kParallelNum] for i in range(kParallelNum)]
print(f"len(task_list_per_thread)={len(task_list_per_process)}",file=sys.stderr)
def ProcessEntryPoint(arg):
ti_list, process_id = arg
orbit = GoodOrbit()
loong = Loong(orbit, 224, mp.mpf("1.0"), mp.mpf("1e-8"))
max_speed_found=mp.mpf("0.0")
max_speed_time=0
last_status = None
last_ti = ti_list[0]
for ti in ti_list:
print(f"calculating time_point={ti}",file=sys.stderr)
try:
res = loong.CalcStatusListByTime(mp.mpf(ti), last_status if (last_status and abs(ti-last_ti)<=0.1) else None)
for node in res:
if node["v"] > max_speed_found:
max_speed_found = node["v"]
max_speed_time = ti
last_status = res
last_ti = ti
except ValueError as e:
print(f"Error: {e}",file=sys.stdout)
return max_speed_found, max_speed_time
if __name__ == "__main__":
manager = multiprocessing.Manager()
task_args_list = [(task_list_per_process[i], i) for i in range(kParallelNum)]
with multiprocessing.Pool(processes=kParallelNum) as pool:
res_list=pool.map(ProcessEntryPoint, task_args_list)
max_speed_found=mp.mpf("0.0")
max_speed_time=0
for res in res_list:
if res[0]>max_speed_found:
max_speed_found=res[0]
max_speed_time=res[1]
valid_head_speed = mp.mpf("1.0") * (mp.mpf("2.0")/max_speed_found)
print(f"max_speed_found={max_speed_found} at {max_speed_time}, valid_head_speed={valid_head_speed}")

View File

@@ -1,40 +1,207 @@
from loong import * from loong import *
import json import json
class BestOrbit(Orbit): import numpy as np
import sys
import matplotlib.pyplot as plt
import io
from PIL import Image
from matplotlib.patches import Rectangle
import multiprocessing
class GoodOrbit(Orbit):
def __init__(self): def __init__(self):
self.kAlpha = mp.mpf('1.7') / (2 * mp.pi) self.kAlpha = mp.mpf("1.7") / (2 * mp.pi)
def f(x):
r=(1/3)*self.kAlpha*mp.sqrt(1+x**2)
phi=mp.atan(x)
L=mp.mpf("2.86")
return (r+3*r*mp.cos(mp.pi-2*phi)-L)**2+(3*r*mp.sin(mp.pi-2*phi))**2-L**2
self.kCriticalTheta = mp.findroot(f, 15, solver='secant')
print(f"CriticalTheta={self.kCriticalTheta}", file=sys.stderr)
self.r = (1 / 3) * self.kAlpha * mp.sqrt(1 + self.kCriticalTheta**2)
self.point_A_cartesian = (
self.kAlpha * self.kCriticalTheta * mp.cos(self.kCriticalTheta),
self.kAlpha * self.kCriticalTheta * mp.sin(self.kCriticalTheta),
)
self.point_B_cartesian = (-self.kAlpha * self.kCriticalTheta * mp.cos(self.kCriticalTheta),
-self.kAlpha * self.kCriticalTheta * mp.sin(self.kCriticalTheta))
self.kPhi = mp.atan(self.kCriticalTheta)
print(f"Phi={self.kPhi}", file=sys.stderr)
dx, dy = self.point_A_cartesian[0] - self.point_B_cartesian[0], self.point_A_cartesian[1] - self.point_B_cartesian[1]
self.angle = mp.atan2(dy, dx)
print(f"angle={self.angle}", file=sys.stderr)
self.point_C1_cartesian = (self.point_A_cartesian[0] + 2 * self.r * mp.cos(self.angle + 0.5 * mp.pi + self.kPhi),
self.point_A_cartesian[1] + 2 * self.r * mp.sin(self.angle + 0.5 * mp.pi + self.kPhi))
self.point_C2_cartesian = (self.point_B_cartesian[0] + 1 * self.r * mp.cos(self.angle - 0.5 * mp.pi + self.kPhi),
self.point_B_cartesian[1] + 1 * self.r * mp.sin(self.angle - 0.5 * mp.pi + self.kPhi))
self.radius_of_C1 = 2 * self.r
self.radius_of_C2 = 1 * self.r
self.arclength = 6 * self.r * self.kPhi
self.edge_k = self.kAlpha * mp.sqrt(1 + self.kCriticalTheta * self.kCriticalTheta)
self.n = -1
for i in range(3, 20, 2):
self.a = (self.arclength - 2 * self.edge_k * self.kCriticalTheta) / (2 * (1 - i) * self.kCriticalTheta**i)
self.b = (i * self.arclength - 2 * self.edge_k * self.kCriticalTheta) / (2 * (i - 1) * self.kCriticalTheta)
if self.a > 0 and self.b > 0:
self.n = i
break
print(f"arclength={self.arclength}", file=sys.stderr)
print(f"edge_k={self.edge_k}", file=sys.stderr)
print(f"a={self.a}", file=sys.stderr)
print(f"b={self.b}", file=sys.stderr)
print(f"n={self.n}", file=sys.stderr)
print(f"now k={self.n*self.a*self.kCriticalTheta**(self.n-1)+self.b}", file=sys.stderr)
if self.n == -1:
raise Exception("n must be set")
self.edge_raw_C = self.kAlpha * 0.5 * (
self.kCriticalTheta * mp.sqrt(1 + self.kCriticalTheta * self.kCriticalTheta) -
mp.log(-self.kCriticalTheta + mp.sqrt(1 + self.kCriticalTheta * self.kCriticalTheta)))
def InitIdx(self): def InitIdx(self):
return mp.mpf('0.0') return mp.mpf("0.0")
def InitC(self): def InitC(self):
return mp.mpf('0.0') return mp.mpf("0.0")
def Idx2C(self, idx):
return idx / self.kAlpha def Idx2C(self, idx): # this function must be monotonically increasing
if idx >= 0:
theta = idx + self.kCriticalTheta
tmp = mp.sqrt(1 + theta * theta)
return self.kAlpha * 0.5 * (theta * tmp - mp.log(-theta + tmp)) - self.edge_raw_C
elif idx >= -2 * self.kCriticalTheta:
x = idx + self.kCriticalTheta
y = (self.a * (x**self.n) + self.b * x) - 0.5 * self.arclength
return y
else:
theta = -idx - self.kCriticalTheta
tmp = mp.sqrt(1 + theta * theta)
return -self.kAlpha * 0.5 * (theta * tmp - mp.log(-theta + tmp)) + self.edge_raw_C - self.arclength
def Idx2Cartesian(self, idx): def Idx2Cartesian(self, idx):
return mp.matrix([mp.cos(idx), mp.sin(idx)]) if idx >= 0:
theta = idx + self.kCriticalTheta
return [self.kAlpha * theta * mp.cos(theta), self.kAlpha * theta * mp.sin(theta)]
elif idx >= -2 * self.kCriticalTheta:
c = self.Idx2C(idx) + self.arclength
# if c < 0 or c > self.arclength:
# raise Exception(f"idx={idx}, c={c}")
if c <= self.arclength / 3:
# In C2
delta_angle = c / self.radius_of_C2
actual_angle = self.angle + 0.5 * mp.pi + self.kPhi - delta_angle
return [
self.point_C2_cartesian[0] + self.radius_of_C2 * mp.cos(actual_angle),
self.point_C2_cartesian[1] + self.radius_of_C2 * mp.sin(actual_angle)
]
else:
delta_angle = (c - self.arclength / 3) / self.radius_of_C1
actual_angle = self.angle - 0.5 * mp.pi - self.kPhi + delta_angle
return [
self.point_C1_cartesian[0] + self.radius_of_C1 * mp.cos(actual_angle),
self.point_C1_cartesian[1] + self.radius_of_C1 * mp.sin(actual_angle)
]
else:
theta = -idx - self.kCriticalTheta
return [-self.kAlpha * theta * mp.cos(theta), -self.kAlpha * theta * mp.sin(theta)]
def C2Idx(self, C): def C2Idx(self, C):
return C * self.kAlpha
def GenerateNextPointIdx(self, cur_point_idx, expected_distance): def f(idx):
return cur_point_idx + expected_distance return self.Idx2C(idx) - C
return mp.findroot(f, (-100*2*mp.pi,100*2*mp.pi), solver='bisect')
def GenerateNextPointIdx(self, cur_point_idx, expected_distance, guess=None):
if guess is None:
cur_point_C = self.Idx2C(cur_point_idx)
guess = self.C2Idx(cur_point_C + expected_distance)
cur_point_dot = self.Idx2Cartesian(cur_point_idx)
def f(idx):
test_point_dot = self.Idx2Cartesian(idx)
return mp.sqrt((cur_point_dot[0] - test_point_dot[0])**2 +
(cur_point_dot[1] - test_point_dot[1])**2) - expected_distance
return mp.findroot(f, guess, solver='secant')
def GenerateImg(self, node_list):
fig = plt.figure(figsize=(12, 12))
# 绘制轨道线
idx_list = np.linspace(-12 * 2 * np.pi, 8 * 2 * np.pi, 10000)
x = [float(self.Idx2Cartesian(t)[0]) for t in idx_list]
y = [float(self.Idx2Cartesian(t)[1]) for t in idx_list]
plt.plot(x, y, color='gray', linewidth=0.5)
# 绘制节点、连接线和木板
for i in range(len(node_list) - 1):
x1, y1 = [float(coord) for coord in node_list[i]["node"]]
x2, y2 = [float(coord) for coord in node_list[i + 1]["node"]]
# 绘制红色节点
plt.plot(x1, y1, 'ro', markersize=3)
# 绘制蓝色连接线
plt.plot([x1, x2], [y1, y2], 'b-', linewidth=0.5)
# 计算并绘制木板(长方形)
dx = x2 - x1
dy = y2 - y1
length = np.sqrt(dx**2 + dy**2)
angle = np.arctan2(dy, dx)
rect_length = length + 0.55 # 总长度加上两端各延伸的0.275m
rect_width = 0.3
# 计算长方形的中心点
center_x = (x1 + x2) / 2
center_y = (y1 + y2) / 2
# 计算长方形的左下角坐标
rect_x = center_x - rect_length / 2 * np.cos(angle) + rect_width / 2 * np.sin(angle)
rect_y = center_y - rect_length / 2 * np.sin(angle) - rect_width / 2 * np.cos(angle)
rect = Rectangle((rect_x, rect_y), rect_length, rect_width, angle=angle * 180 / np.pi, fill=False, edgecolor='g')
plt.gca().add_patch(rect)
# 绘制最后一个节点
x, y = [float(coord) for coord in node_list[-1]["node"]]
plt.plot(x, y, 'ro', markersize=3)
plt.axis('equal')
# 创建一个 BytesIO 对象来存储图像
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
# 清除当前图形,释放内存
plt.close(fig)
# 返回图像对象
return Image.open(buf)
if __name__ == "__main__": if __name__ == "__main__":
orbit=BestOrbit() orbit = GoodOrbit()
loong=Loong(orbit, 224, mp.mpf('2.0'), mp.mpf('1e-8')) loong = Loong(orbit, 224, mp.mpf("1.0"), mp.mpf("1e-8"))
res_list=[] res_list = []
for ti in range(-100,101): for ti in range(-100, 101):
print(f"calculating time_point={ti}") print(f"calculating time_point={ti}", file=sys.stderr)
res_list.append(loong.CalcStatusListByTime(mp.mpf(ti))) res_list.append(loong.CalcStatusListByTime(mp.mpf(ti)))
# 转换成内置浮点数并保留6位 # 转换成内置浮点数并保留6位
float_res_list = [ float_res_list = [[{
[ "idx": round(float(node["idx"]), 6),
{ "node": [
"idx": round(float(node["idx"]),6), round(float(node["node"][0]), 6),
"node": [round(float(node["node"][0]),6), round(float(node["node"][1]),6)], round(float(node["node"][1]), 6),
"C": round(float(node["C"]),6), ],
"v": round(float(node["v"]),6) "C": round(float(node["C"]), 6),
} "v": round(float(node["v"]), 6),
for node in res } for node in res] for res in res_list]
]
for res in res_list
]
with open("A4_res.json", "w") as file: with open("A4_res.json", "w") as file:
json.dump(float_res_list, file, indent=4) json.dump(float_res_list, file, indent=4)
img_list = [orbit.GenerateImg(res) for res in res_list]
img_list[0].save("A4.gif", save_all=True, append_images=img_list[1:], duration=100, loop=0)

View File

@@ -1,14 +1,20 @@
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
import mpmath as mp
kPitch = 1.7 kPitch = 1.7
kAlpha = kPitch / (2 * np.pi) kAlpha = kPitch / (2 * np.pi)
kCriticalRadius = 4.5 kCriticalRadius = 4.5
theta_max = (kCriticalRadius) / kAlpha + 2*2*np.pi theta_max = (kCriticalRadius) / kAlpha + 2 * 2 * np.pi
kPlotingRadius = theta_max * kAlpha kPlotingRadius = theta_max * kAlpha
kCriticalTheta = 2.86 / ((2/3)*kAlpha) def f(x):
r=(1/3)*kAlpha*mp.sqrt(1+x**2)
phi=mp.atan(x)
L=mp.mpf("2.86")
return (r+3*r*mp.cos(mp.pi-2*phi)-L)**2+(3*r*mp.sin(mp.pi-2*phi))**2-L**2
kCriticalTheta = float(mp.findroot(f, 15, solver='secant'))
# 生成角度数组 # 生成角度数组
theta = np.linspace(kCriticalTheta, theta_max, 1000) theta = np.linspace(kCriticalTheta, theta_max, 1000)
@@ -34,36 +40,40 @@ circle_theta = np.linspace(0, 2 * np.pi, 1000)
circle_r = np.full_like(circle_theta, kCriticalRadius) circle_r = np.full_like(circle_theta, kCriticalRadius)
ax.plot(circle_theta, circle_r, linestyle='--') ax.plot(circle_theta, circle_r, linestyle='--')
point_A_cartesian = (kAlpha*kCriticalTheta*np.cos(kCriticalTheta),kAlpha*kCriticalTheta*np.sin(kCriticalTheta)) point_A_cartesian = (kAlpha * kCriticalTheta * np.cos(kCriticalTheta), kAlpha * kCriticalTheta * np.sin(kCriticalTheta))
point_B_cartesian = (-kAlpha*kCriticalTheta*np.cos(kCriticalTheta),-kAlpha*kCriticalTheta*np.sin(kCriticalTheta)) point_B_cartesian = (-kAlpha * kCriticalTheta * np.cos(kCriticalTheta),
-kAlpha * kCriticalTheta * np.sin(kCriticalTheta))
kPhi = np.arctan(kCriticalTheta) kPhi = np.arctan(kCriticalTheta)
r = (1/3) * kAlpha * np.sqrt(1 + kCriticalTheta**2) r = (1 / 3) * kAlpha * np.sqrt(1 + kCriticalTheta**2)
dx, dy = point_A_cartesian[0] - point_B_cartesian[0], point_A_cartesian[1] - point_B_cartesian[1] dx, dy = point_A_cartesian[0] - point_B_cartesian[0], point_A_cartesian[1] - point_B_cartesian[1]
angle = np.arctan2(dy, dx) angle = np.arctan2(dy, dx)
dx, dy = np.cos(angle - (0.5*np.pi-kPhi)), np.sin(angle - (0.5*np.pi-kPhi)) dx, dy = np.cos(angle - (0.5 * np.pi - kPhi)), np.sin(angle - (0.5 * np.pi - kPhi))
point_C1_cartesian = (point_A_cartesian[0] - 2*r*dx, point_A_cartesian[1] - 2*r*dy) point_C1_cartesian = (point_A_cartesian[0] - 2 * r * dx, point_A_cartesian[1] - 2 * r * dy)
point_C2_cartesian = (point_B_cartesian[0] + 1*r*dx, point_B_cartesian[1] + 1*r*dy) point_C2_cartesian = (point_B_cartesian[0] + 1 * r * dx, point_B_cartesian[1] + 1 * r * dy)
radius_of_C1 = 2*r radius_of_C1 = 2 * r
radius_of_C2 = 1*r radius_of_C2 = 1 * r
# 定义用于绘制圆的函数 # 定义用于绘制圆的函数
def draw_circle(ax, center, radius, num_points, beg_angle, span_angle): def draw_circle(ax, center, radius, num_points, beg_angle, span_angle):
t = np.linspace(beg_angle, beg_angle+span_angle, num_points) t = np.linspace(beg_angle, beg_angle + span_angle, num_points)
x = center[0] + radius * np.cos(t) x = center[0] + radius * np.cos(t)
y = center[1] + radius * np.sin(t) y = center[1] + radius * np.sin(t)
r, theta = np.sqrt(x**2 + y**2), np.arctan2(y, x) r, theta = np.sqrt(x**2 + y**2), np.arctan2(y, x)
ax.plot(theta, r) ax.plot(theta, r)
# 绘制圆C1 # 绘制圆C1
draw_circle(ax, point_C1_cartesian, radius_of_C1, 100, angle+0.5*np.pi-kPhi-np.pi, 2*kPhi) draw_circle(ax, point_C1_cartesian, radius_of_C1, 100, angle + 0.5 * np.pi - kPhi - np.pi, 2 * kPhi)
# 绘制圆C2 # 绘制圆C2
draw_circle(ax, point_C2_cartesian, radius_of_C2, 100, angle+0.5*np.pi-kPhi, 2*kPhi) draw_circle(ax, point_C2_cartesian, radius_of_C2, 100, angle + 0.5 * np.pi - kPhi, 2 * kPhi)
print(f"Total length={6*r*kPhi}") print(f"Total length={6*r*kPhi}")
print(f"kCriticalTheta={kCriticalTheta}")
x_ticks = np.arange(-int(kPlotingRadius)-1, int(kPlotingRadius)+1, 1) x_ticks = np.arange(-int(kPlotingRadius) - 1, int(kPlotingRadius) + 1, 1)
y_ticks = np.arange(-int(kPlotingRadius)-1, int(kPlotingRadius)+1, 1) y_ticks = np.arange(-int(kPlotingRadius) - 1, int(kPlotingRadius) + 1, 1)
X, Y = np.meshgrid(x_ticks, y_ticks) X, Y = np.meshgrid(x_ticks, y_ticks)
X = X.flatten() X = X.flatten()
Y = Y.flatten() Y = Y.flatten()
@@ -76,7 +86,5 @@ theta_grid = np.arctan2(Y, X)
valid_points = r_grid <= kPlotingRadius valid_points = r_grid <= kPlotingRadius
ax.scatter(theta_grid[valid_points], r_grid[valid_points], color='grey', s=10) # 灰色小点 ax.scatter(theta_grid[valid_points], r_grid[valid_points], color='grey', s=10) # 灰色小点
plt.title("The Moving Path")
# 显示图像 # 显示图像
plt.show() plt.show()