|
|
发表于 2025-7-5 12:04:05
|
显示全部楼层
您提供了更精确的几何描述,这有助于我们进行更准确的分析和模拟。我将基于这些尺寸重新设计模拟代码,并添加力分析功能。
### 精确尺寸俯视图模拟与分析代码
- import pygame
- import pymunk
- import pymunk.pygame_util
- import math
- import numpy as np
- # 初始化
- pygame.init()
- screen = pygame.display.set_mode((1200, 800))
- clock = pygame.time.Clock()
- space = pymunk.Space()
- space.gravity = (0, 0) # 无重力
- draw_options = pymunk.pygame_util.DrawOptions(screen)
- # 实际尺寸参数(单位:米)
- ROLLER_DIAMETER = 0.3 # 辊筒直径
- ROLLER_LENGTH = 1.2 # 辊筒长度
- DISTANCE = 3.0 # 首尾辊距离
- BELT_WIDTH = 1.0 # 皮带宽
- BELT_THICKNESS = 0.01 # 皮带厚度
- # 转换为像素(1米=100像素)
- SCALE = 100
- ROLLER_RADIUS = ROLLER_DIAMETER * SCALE / 2
- ROLLER_LEN_PX = ROLLER_LENGTH * SCALE
- DISTANCE_PX = DISTANCE * SCALE
- BELT_WIDTH_PX = BELT_WIDTH * SCALE
- BELT_THICK_PX = BELT_THICKNESS * SCALE
- # 坐标系设定
- # 首辊位置(右侧)
- HEAD_POS = (900, 400)
- # 尾辊位置(左侧)
- TAIL_POS = (300, 400)
- # 创建辊筒(俯视图为矩形)
- def create_roller(pos, is_driver=False, angle=0, is_head=True):
- body = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
- body.position = pos
-
- # 设置辊筒方向(前进方向为0度)
- body.angle = math.radians(angle)
-
- # 创建矩形形状(长边为轴向-Y方向)
- half_w = ROLLER_RADIUS
- half_l = ROLLER_LEN_PX / 2
- vertices = [
- (-half_w, -half_l), # 左下
- (half_w, -half_l), # 右下
- (half_w, half_l), # 右上
- (-half_w, half_l) # 左上
- ]
- shape = pymunk.Poly(body, vertices)
- shape.elasticity = 0.2
- shape.friction = 1.0
- shape.color = (0, 100, 255, 255) if is_head else (100, 200, 50, 255)
- space.add(body, shape)
-
- # 标记动力辊
- if is_driver:
- # 添加旋转标记
- marker = pymunk.Circle(body, 10, (0, 0))
- marker.color = (255, 0, 0, 255)
- space.add(marker)
-
- return body
- # 创建皮带
- def create_belt(head_roller, tail_roller):
- # 创建皮带主体(矩形)
- body = pymunk.Body(10, pymunk.moment_for_box(10, (DISTANCE_PX, BELT_WIDTH_PX)))
- body.position = ((HEAD_POS[0] + TAIL_POS[0])/2, (HEAD_POS[1] + TAIL_POS[1])/2)
- body.angle = 0
-
- # 计算皮带角度(首尾辊中心连线)
- dx = HEAD_POS[0] - TAIL_POS[0]
- dy = HEAD_POS[1] - TAIL_POS[1]
- belt_angle = math.atan2(dy, dx)
- body.angle = belt_angle
-
- shape = pymunk.Poly.create_box(body, (DISTANCE_PX, BELT_WIDTH_PX))
- shape.friction = 1.5
- shape.color = (200, 150, 50, 200) # 棕色
- space.add(body, shape)
-
- # 添加辊筒与皮带的旋转约束(模拟摩擦力传动)
- head_joint = pymunk.PivotJoint(body, head_roller, HEAD_POS, (0, 0))
- head_joint.max_force = 10000 # 足够大的摩擦力
- space.add(head_joint)
-
- tail_joint = pymunk.PivotJoint(body, tail_roller, TAIL_POS, (0, 0))
- tail_joint.max_force = 10000
- space.add(tail_joint)
-
- # 添加旋转约束(模拟皮带与辊筒的摩擦传动)
- gear_head = pymunk.GearJoint(head_roller, body, 0, 1)
- gear_head.max_force = 5000
- space.add(gear_head)
-
- gear_tail = pymunk.GearJoint(tail_roller, body, 0, 1)
- gear_tail.max_force = 5000
- space.add(gear_tail)
-
- return body
- # 计算力分解
- def calculate_force_decomposition(roller, is_driver, is_head):
- # 获取辊筒角度
- angle = roller.angle
-
- # 基本力大小(假设)
- base_force = 1000 if is_driver else 500
-
- # 力方向(动力辊向前,被动辊向后)
- direction = 1 if (is_head and is_driver) or (not is_head and not is_driver) else -1
-
- # 分解力
- fx = base_force * math.cos(angle) * direction
- fy = base_force * math.sin(angle) * direction
-
- return fx, fy
- # 创建场景
- def create_scenario(scenario):
- # 根据场景设置参数
- if scenario == "A":
- # 首辊动力+偏角,尾辊垂直
- head_angle, tail_angle, head_driver, tail_driver = 15, 0, True, False
- elif scenario == "B":
- # 尾辊动力+首辊偏角,尾辊垂直
- head_angle, tail_angle, head_driver, tail_driver = 15, 0, False, True
- elif scenario == "C":
- # 首辊动力+尾辊偏角,首辊垂直
- head_angle, tail_angle, head_driver, tail_driver = 0, 15, True, False
- elif scenario == "D":
- # 尾辊动力+尾辊偏角,首辊垂直
- head_angle, tail_angle, head_driver, tail_driver = 0, 15, False, True
-
- # 创建首辊(右侧)
- head_roller = create_roller(HEAD_POS, head_driver, head_angle, True)
-
- # 创建尾辊(左侧)
- tail_roller = create_roller(TAIL_POS, tail_driver, tail_angle, False)
-
- # 创建皮带
- belt_body = create_belt(head_roller, tail_roller)
-
- return head_roller, tail_roller, belt_body
- # 主函数
- def main(scenario):
- # 创建场景
- head, tail, belt = create_scenario(scenario)
-
- # 记录初始位置
- initial_y = belt.position.y
-
- # 获取角度参数
- head_angle = math.degrees(head.angle)
- tail_angle = math.degrees(tail.angle)
-
- # 计算喇叭口类型
- flare_type = "首辊上侧喇叭口大" if head_angle > 0 else "首辊下侧喇叭口大"
-
- # 主循环
- running = True
- font = pygame.font.SysFont('Arial', 24)
- while running:
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- running = False
-
- # 物理模拟步进
- space.step(1/60.0)
-
- # 计算跑偏量
- offset_y = belt.position.y - initial_y
- offset_sign = "↑" if offset_y < 0 else "↓"
-
- # 计算力分解
- head_fx, head_fy = calculate_force_decomposition(head, scenario in ["A", "C"], True)
- tail_fx, tail_fy = calculate_force_decomposition(tail, scenario in ["B", "D"], False)
-
- # 渲染
- screen.fill((255, 255, 255))
-
- # 绘制参考线(理想位置)
- pygame.draw.line(screen, (200, 200, 200), TAIL_POS, HEAD_POS, 2)
-
- # 绘制坐标轴
- pygame.draw.line(screen, (255, 0, 0), (100, 400), (1100, 400), 2) # X轴
- pygame.draw.line(screen, (0, 255, 0), (600, 100), (600, 700), 2) # Y轴
-
- # 绘制物理对象
- space.debug_draw(draw_options)
-
- # 绘制力分解箭头
- def draw_force_arrow(pos, fx, fy, color):
- scale = 0.1
- end_pos = (pos[0] + fx * scale, pos[1] + fy * scale)
- pygame.draw.line(screen, color, pos, end_pos, 3)
- # 绘制箭头
- angle = math.atan2(fy, fx)
- arrow_size = 10
- pygame.draw.line(screen, color, end_pos,
- (end_pos[0] - arrow_size * math.cos(angle - math.pi/6),
- end_pos[1] - arrow_size * math.sin(angle - math.pi/6)), 2)
- pygame.draw.line(screen, color, end_pos,
- (end_pos[0] - arrow_size * math.cos(angle + math.pi/6),
- end_pos[1] - arrow_size * math.sin(angle + math.pi/6)), 2)
-
- # 绘制首辊力
- draw_force_arrow(HEAD_POS, head_fx, head_fy, (255, 0, 0))
- # 绘制尾辊力
- draw_force_arrow(TAIL_POS, tail_fx, tail_fy, (255, 0, 0))
-
- # 显示信息
- title = font.render(f"场景 {scenario}: {get_scenario_desc(scenario)}", True, (0, 0, 0))
- flare = font.render(f"喇叭口: {flare_type}", True, (180, 0, 0))
- offset = font.render(f"皮带跑偏: {abs(offset_y):.1f}px {offset_sign}", True, (0, 0, 200))
- advice = font.render(f"调整: {get_adjustment_advice(scenario, offset_y)}", True, (0, 100, 0))
-
- # 显示力分解信息
- head_force_info = font.render(f"首辊力: Fx={head_fx:.0f}, Fy={head_fy:.0f}", True, (200, 0, 0))
- tail_force_info = font.render(f"尾辊力: Fx={tail_fx:.0f}, Fy={tail_fy:.0f}", True, (200, 0, 0))
- side_force = font.render(f"侧向合力: Fy={head_fy + tail_fy:.0f}", True, (150, 0, 150))
-
- screen.blit(title, (20, 20))
- screen.blit(flare, (20, 50))
- screen.blit(offset, (20, 80))
- screen.blit(advice, (20, 110))
- screen.blit(head_force_info, (20, 140))
- screen.blit(tail_force_info, (20, 170))
- screen.blit(side_force, (20, 200))
-
- pygame.display.flip()
- clock.tick(60)
- def get_scenario_desc(scenario):
- return {
- "A": "首辊动力+偏角,尾辊垂直",
- "B": "尾辊动力+首辊偏角,尾辊垂直",
- "C": "首辊动力+尾辊偏角,首辊垂直",
- "D": "尾辊动力+尾辊偏角,首辊垂直"
- }.get(scenario, "")
- def get_adjustment_advice(scenario, offset_y):
- if abs(offset_y) < 5: # 小于5像素视为无跑偏
- return "无需调整"
-
- # 判断跑偏方向
- direction = "上侧" if offset_y < 0 else "下侧"
-
- # 根据场景确定调整策略
- if scenario == "A":
- return f"首辊{direction}调紧"
- elif scenario == "B":
- return f"首辊{direction}调松"
- elif scenario == "C":
- return f"尾辊{direction}调松"
- elif scenario == "D":
- return f"尾辊{direction}调紧"
- if __name__ == "__main__":
- # 选择要模拟的场景 (A, B, C, D)
- main("A")
复制代码
### 关键设计与分析
#### 1. 精确几何表示:
- # 辊筒尺寸
- ROLLER_DIAMETER = 0.3 # 直径0.3米
- ROLLER_LENGTH = 1.2 # 长度1.2米(轴向-Y方向)
- # 皮带尺寸
- BELT_WIDTH = 1.0 # 宽度1.0米(Y方向)
- DISTANCE = 3.0 # 首尾辊距离3.0米(X方向)
- # 俯视图表示:
- # 辊筒:矩形(宽=直径,高=长度)
- # 皮带:矩形(宽=距离,高=宽度)
复制代码
#### 2. 力分解分析:
- def calculate_force_decomposition(roller, is_driver, is_head):
- angle = roller.angle # 辊筒偏角
-
- # 基本力大小(假设)
- base_force = 1000 if is_driver else 500
-
- # 力方向(动力辊向前,被动辊向后)
- direction = 1 if (is_head and is_driver) or (not is_head and not is_driver) else -1
-
- # 力分解:
- fx = base_force * math.cos(angle) * direction # X方向分量(前进/后退)
- fy = base_force * math.sin(angle) * direction # Y方向分量(侧向)
-
- return fx, fy
复制代码
#### 3. 跑偏原理可视化:
- 红色箭头表示辊筒对皮带的力
- X轴分量(红色):驱动皮带前进或产生阻力
- Y轴分量(垂直方向):导致皮带跑偏的关键因素
- 侧向合力 = 首辊Fy + 尾辊Fy
#### 4. 场景A分析(首辊动力+偏角):
1. **几何设置**:
- 首辊:右侧,上端前倾15°
- 尾辊:左侧,垂直
- 形成上侧喇叭口大
2. **力分解**:
- 首辊(动力辊):
- Fx:向前(驱动皮带)
- Fy:向上(偏角方向)
- 尾辊(被动辊):
- Fx:向后(阻力)
- Fy:0(无偏角)
3. **跑偏方向**:
- 侧向合力Fy = 首辊Fy + 尾辊Fy > 0
- 皮带向上(Y正方向)跑偏
4. **调整建议**:
- 皮带向上跑偏(喇叭口大侧)
- 在跑偏侧(上侧)调紧首辊轴承座
#### 5. 跑偏规律总结表:
| 场景 | 动力辊 | 偏角位置 | 跑偏方向 | 调整方法 |
|------|--------|----------|----------|----------|
| A | 首辊 | 首辊 | 偏角方向 | 跑偏侧调紧 |
| B | 尾辊 | 首辊 | 偏角反方向 | 跑偏侧调松 |
| C | 首辊 | 尾辊 | 偏角反方向 | 跑偏侧调松 |
| D | 尾辊 | 尾辊 | 偏角方向 | 跑偏侧调紧 |
#### 6. 八字喇叭口调整原则:
1. **"跑大不跑小"原则**:
- 皮带总是向喇叭口大的一侧跑偏
- 调整目标:使皮带向喇叭口小的一侧移动
2. **调整方法**:
- 在跑偏侧(口大侧)调紧轴承座(增大辊距)
- 或在对侧(口小侧)调松轴承座
3. **调整原理**:
- 调紧侧:增大张力,使皮带向紧边移动
- 调松侧:减小张力,使皮带向紧边移动
#### 7. 力分解公式:
当辊筒有偏角θ时:
- **动力辊作用力**:
$F_{\text{driver}} = F \cdot (\cos\theta \cdot \hat{x} + \sin\theta \cdot \hat{y})$
- **被动辊作用力**:
$F_{\text{idler}} = -f \cdot (\cos\theta \cdot \hat{x} + \sin\theta \cdot \hat{y})$
其中:
- $F$:动力辊驱动力大小
- $f$:被动辊阻力大小
- $\theta$:辊筒偏角(相对于垂直方向)
- $\hat{x}$:皮带前进方向单位向量
- $\hat{y}$:辊筒轴向单位向量
跑偏主要由Y方向分力 $\sum F_y$ 决定,其方向决定了跑偏方向。
> **工程提示**:实际调整时应先停机,每次调整量不超过辊长的1/1000(约1.2mm),调整后需运行观察效果。对于长期使用的输送机,还应检查辊筒磨损和皮带老化情况。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 |
|