python中学物理实验模拟:杠杆平衡条件
杠杆原理(平衡条件):
动力 × 动力臂 = 阻力 × 阻力臂
或
F₁ × L₁ = F₂ × L₂
其中,F₁为动力,L₁为动力臂;F₂为阻力,L₂为阻力臂。
核心含义:
- 省力: 如果 L₁ > L₂(动力臂大于阻力臂),那么 F₁ < F₂。这意味着我们可以用较小的动力克服较大的阻力,但代价是动力作用点移动的距离会比阻力作用点移动的距离更大(省力费距离)。例如:撬棍撬石头、开瓶器开瓶盖。
- 费力: 如果 L₁ < L₂(动力臂小于阻力臂),那么 F₁ > F₂。这意味着我们需要用较大的动力克服较小的阻力,但好处是动力作用点移动的距离比阻力作用点移动的距离更小(费力省距离)。例如:镊子夹东西、钓鱼竿钓鱼。
- 等臂: 如果 L₁ = L₂(动力臂等于阻力臂),那么 F₁ = F₂。这时杠杆既不省力也不费力,但可以改变力的方向或方便操作。例如:天平、跷跷板(当两边重量相等时)。
杠杆原理的本质:
杠杆原理是能量守恒定律在简单机械中的具体体现。虽然它可以改变力的大小(放大或缩小),但遵循“功的原理”:动力 × 动力作用点移动距离 = 阻力 × 阻力作用点移动距离。省力必然费距离,费力必然省距离,不能省功。
根据支点位置杠杆通常分为三类:
第一类杠杆(支点在中间)
例子: 跷跷板、剪刀、天平、撬棍、钳子(夹持端)、手推车的抬起动作(支点是轮轴)。
特点: 可以省力(当 L₁ > L₂),可以费力(当 L₁ < L₂),也可以等臂(当 L₁ = L₂),还可以改变用力方向。
第二类杠杆(阻力点在中间)
例子: 独轮手推车(阻力是货物重力在中间)、核桃夹(夹核桃的部位在中间)、开瓶器(瓶盖在中间)、船桨(水对桨的阻力在中间)。
特点: 总是省力(因为 L₁ 总是大于 L₂),但费距离。动力方向与阻力方向通常相同(向下)。
第三类杠杆(动力点在中间)
例子: 镊子、筷子、钓鱼竿(手持端在中间)、人的前臂(肘关节是支点,肱二头肌发力点在中间,手拿东西是阻力点)、铲子(手握的地方在中间)。
特点: 总是费力(因为 L₁ 总是小于 L₂),但省距离(动力作用点移动一小段距离,阻力作用点会移动较大距离)。可以放大移动的速度或距离,常用于需要精细操作或速度放大的场合。
运行效果截图
源码如下:
import tkinter as tk
from tkinter import ttk
import mathclass LeverSimulator:def __init__(self):self.root = tk.Tk()self.root.title("杠杆原理模拟器 - 三类杠杆演示")self.root.geometry("1200x960")self.root.configure(bg='lightblue')# 杠杆参数self.canvas_width = 1100self.canvas_height = 400self.fulcrum_y = 200 # 支点Y坐标# 杠杆类型和参数self.lever_type = tk.StringVar(value="first") # first, second, third# 力和力臂参数self.power_force = tk.StringVar(value="20") # 动力self.resistance_force = tk.StringVar(value="40") # 阻力self.power_arm = tk.StringVar(value="150") # 动力臂self.resistance_arm = tk.StringVar(value="75") # 阻力臂# 动画控制self.is_animating = Falseself.lever_angle = 0self.animation_speed = 0.05# 预设示例self.examples = {"first": [("剪刀", {"power": "15", "resistance": "30", "power_arm": "120", "resistance_arm": "60"}),("跷跷板", {"power": "25", "resistance": "50", "power_arm": "200", "resistance_arm": "100"}),("天平", {"power": "10", "resistance": "10", "power_arm": "150", "resistance_arm": "150"})],"second": [("开瓶器", {"power": "20", "resistance": "60", "power_arm": "150", "resistance_arm": "50"}),("胡桃钳", {"power": "25", "resistance": "100", "power_arm": "180", "resistance_arm": "45"}),("手推车", {"power": "30", "resistance": "120", "power_arm": "160", "resistance_arm": "40"})],"third": [("镊子", {"power": "40", "resistance": "10", "power_arm": "30", "resistance_arm": "120"}),("筷子", {"power": "30", "resistance": "12", "power_arm": "50", "resistance_arm": "150"}),("钓鱼竿", {"power": "50", "resistance": "15", "power_arm": "40", "resistance_arm": "160"})]}self.setup_ui()self.update_lever()def setup_ui(self):# 主标题title_label = tk.Label(self.root, text="杠杆原理模拟器 - 三类杠杆演示", font=("Arial", 18, "bold"), bg='lightblue', fg='darkblue')title_label.pack(pady=10)# 控制面板control_frame = tk.LabelFrame(self.root, text="控制参数", font=("Arial", 12), bg='lightblue')control_frame.pack(pady=5, padx=10, fill='x')# 杠杆类型选择type_frame = tk.Frame(control_frame, bg='lightblue')type_frame.pack(pady=10)tk.Label(type_frame, text="杠杆类型:", bg='lightblue', font=("Arial", 12, "bold")).pack(side='left', padx=10)type_radio1 = tk.Radiobutton(type_frame, text="第一类杠杆\n(支点在中间)", variable=self.lever_type, value="first",bg='lightblue', font=("Arial", 10),command=self.change_lever_type, justify='center')type_radio1.pack(side='left', padx=15)type_radio2 = tk.Radiobutton(type_frame, text="第二类杠杆\n(阻力点在中间)", variable=self.lever_type, value="second",bg='lightblue', font=("Arial", 10),command=self.change_lever_type, justify='center')type_radio2.pack(side='left', padx=15)type_radio3 = tk.Radiobutton(type_frame, text="第三类杠杆\n(动力点在中间)", variable=self.lever_type, value="third",bg='lightblue', font=("Arial", 10),command=self.change_lever_type, justify='center')type_radio3.pack(side='left', padx=15)# 参数设置和示例选择param_main_frame = tk.Frame(control_frame, bg='lightblue')param_main_frame.pack(pady=10)# 参数输入区域param_frame = tk.LabelFrame(param_main_frame, text="参数设置", font=("Arial", 11), bg='lightblue')param_frame.pack(side='left', padx=20)# 动力tk.Label(param_frame, text="动力 F1 (N):", bg='lightblue', font=("Arial", 10)).grid(row=0, column=0, sticky='w', padx=5, pady=5)power_entry = tk.Entry(param_frame, textvariable=self.power_force, width=10)power_entry.grid(row=0, column=1, padx=5, pady=5)power_entry.bind('<KeyRelease>', lambda e: self.update_lever())# 动力臂tk.Label(param_frame, text="动力臂 L1 (cm):", bg='lightblue', font=("Arial", 10)).grid(row=1, column=0, sticky='w', padx=5, pady=5)power_arm_entry = tk.Entry(param_frame, textvariable=self.power_arm, width=10)power_arm_entry.grid(row=1, column=1, padx=5, pady=5)power_arm_entry.bind('<KeyRelease>', lambda e: self.update_lever())# 阻力tk.Label(param_frame, text="阻力 F2 (N):", bg='lightblue', font=("Arial", 10)).grid(row=2, column=0, sticky='w', padx=5, pady=5)resistance_entry = tk.Entry(param_frame, textvariable=self.resistance_force, width=10)resistance_entry.grid(row=2, column=1, padx=5, pady=5)resistance_entry.bind('<KeyRelease>', lambda e: self.update_lever())# 阻力臂tk.Label(param_frame, text="阻力臂 L2 (cm):", bg='lightblue', font=("Arial", 10)).grid(row=3, column=0, sticky='w', padx=5, pady=5)resistance_arm_entry = tk.Entry(param_frame, textvariable=self.resistance_arm, width=10)resistance_arm_entry.grid(row=3, column=1, padx=5, pady=5)resistance_arm_entry.bind('<KeyRelease>', lambda e: self.update_lever())# 示例选择区域example_frame = tk.LabelFrame(param_main_frame, text="典型示例", font=("Arial", 11), bg='lightblue')example_frame.pack(side='left', padx=20)self.example_listbox = tk.Listbox(example_frame, height=6, width=20, font=("Arial", 10))self.example_listbox.pack(padx=5, pady=5)self.example_listbox.bind('<<ListboxSelect>>', self.load_example)# 控制按钮button_frame = tk.Frame(control_frame, bg='lightblue')button_frame.pack(pady=10)tk.Button(button_frame, text="开始动画", command=self.start_animation,font=("Arial", 11), bg='lightgreen', width=12).pack(side='left', padx=8)tk.Button(button_frame, text="停止动画", command=self.stop_animation,font=("Arial", 11), bg='lightcoral', width=12).pack(side='left', padx=8)tk.Button(button_frame, text="重置参数", command=self.reset_lever,font=("Arial", 11), bg='lightyellow', width=12).pack(side='left', padx=8)# 画布self.canvas = tk.Canvas(self.root, width=self.canvas_width, height=self.canvas_height, bg='white', relief='sunken', bd=2)self.canvas.pack(pady=10)# 信息显示区域info_frame = tk.LabelFrame(self.root, text="计算结果与分析", font=("Arial", 12), bg='lightblue')info_frame.pack(pady=5, padx=10, fill='x')# 分两列显示信息info_left_frame = tk.Frame(info_frame, bg='lightblue')info_left_frame.pack(side='left', fill='both', expand=True)info_right_frame = tk.Frame(info_frame, bg='lightblue')info_right_frame.pack(side='right', fill='both', expand=True)self.moment_label = tk.Label(info_left_frame, text="", bg='lightblue', font=("Arial", 11), fg='darkgreen')self.moment_label.pack(anchor='w', padx=10, pady=2)self.balance_label = tk.Label(info_left_frame, text="", bg='lightblue', font=("Arial", 12, "bold"))self.balance_label.pack(anchor='w', padx=10, pady=2)self.advantage_label = tk.Label(info_right_frame, text="", bg='lightblue', font=("Arial", 11), fg='darkblue')self.advantage_label.pack(anchor='w', padx=10, pady=2)self.type_description = tk.Label(info_right_frame, text="", bg='lightblue', font=("Arial", 10), fg='purple')self.type_description.pack(anchor='w', padx=10, pady=2)def change_lever_type(self):"""改变杠杆类型"""self.update_example_list()self.reset_to_default()self.update_lever()def update_example_list(self):"""更新示例列表"""self.example_listbox.delete(0, tk.END)lever_type = self.lever_type.get()for name, params in self.examples[lever_type]:self.example_listbox.insert(tk.END, name)def load_example(self, event):"""加载选中的示例"""selection = self.example_listbox.curselection()if selection:lever_type = self.lever_type.get()example_name, params = self.examples[lever_type][selection[0]]self.power_force.set(params["power"])self.resistance_force.set(params["resistance"])self.power_arm.set(params["power_arm"])self.resistance_arm.set(params["resistance_arm"])self.update_lever()def reset_to_default(self):"""重置为默认参数"""defaults = {"first": {"power": "20", "resistance": "40", "power_arm": "150", "resistance_arm": "75"},"second": {"power": "20", "resistance": "60", "power_arm": "150", "resistance_arm": "50"},"third": {"power": "40", "resistance": "10", "power_arm": "30", "resistance_arm": "120"}}lever_type = self.lever_type.get()params = defaults[lever_type]self.power_force.set(params["power"])self.resistance_force.set(params["resistance"])self.power_arm.set(params["power_arm"])self.resistance_arm.set(params["resistance_arm"])def calculate_positions(self):"""计算各点位置"""try:power_arm = float(self.power_arm.get())resistance_arm = float(self.resistance_arm.get())lever_type = self.lever_type.get()center_x = self.canvas_width // 2if lever_type == "first":# 第一类杠杆:支点在中间fulcrum_x = center_xpower_x = fulcrum_x - power_armresistance_x = fulcrum_x + resistance_armelif lever_type == "second":# 第二类杠杆:阻力点在中间power_x = center_x - (power_arm - resistance_arm) // 2resistance_x = power_x + resistance_armfulcrum_x = power_x + power_armelse: # third# 第三类杠杆:动力点在中间fulcrum_x = center_x - (power_arm + resistance_arm) // 2power_x = fulcrum_x + power_armresistance_x = fulcrum_x + power_arm + resistance_armreturn fulcrum_x, power_x, resistance_xexcept ValueError:return self.canvas_width//2, self.canvas_width//2-100, self.canvas_width//2+100def calculate_lever_angle(self):"""计算杠杆倾斜角度"""try:power_force = float(self.power_force.get())resistance_force = float(self.resistance_force.get())power_arm = float(self.power_arm.get())resistance_arm = float(self.resistance_arm.get())# 计算力矩power_moment = power_force * power_armresistance_moment = resistance_force * resistance_arm# 计算力矩差moment_diff = power_moment - resistance_momentmax_angle = math.pi / 8 # 最大倾斜角度22.5度if abs(moment_diff) < 0.1:return 0else:# 根据力矩差计算角度max_moment = max(power_moment, resistance_moment, 1)angle = (moment_diff / max_moment) * max_anglereturn max(-max_angle, min(max_angle, angle))except ValueError:return 0def draw_lever(self):"""绘制杠杆系统"""self.canvas.delete("all")# 绘制背景网格self.draw_grid()# 计算各点位置fulcrum_x, power_x, resistance_x = self.calculate_positions()# 计算倾斜后的Y坐标lever_length = max(abs(power_x - fulcrum_x), abs(resistance_x - fulcrum_x)) * 2# 动力点位置power_angle = math.atan2(0, power_x - fulcrum_x) + self.lever_anglepower_y = self.fulcrum_y - (power_x - fulcrum_x) * math.tan(self.lever_angle)# 阻力点位置resistance_angle = math.atan2(0, resistance_x - fulcrum_x) + self.lever_angleresistance_y = self.fulcrum_y - (resistance_x - fulcrum_x) * math.tan(self.lever_angle)# 杠杆两端点left_most = min(power_x, resistance_x, fulcrum_x) - 50right_most = max(power_x, resistance_x, fulcrum_x) + 50left_y = self.fulcrum_y - (left_most - fulcrum_x) * math.tan(self.lever_angle)right_y = self.fulcrum_y - (right_most - fulcrum_x) * math.tan(self.lever_angle)# 绘制杠杆self.canvas.create_line(left_most, left_y, right_most, right_y, width=8, fill='brown', capstyle='round')# 绘制支点self.draw_fulcrum(fulcrum_x, self.fulcrum_y)# 绘制力self.draw_forces(power_x, power_y, resistance_x, resistance_y)# 绘制力臂标注self.draw_arms(fulcrum_x, power_x, resistance_x)# 绘制标示点self.canvas.create_oval(power_x-6, power_y-6, power_x+6, power_y+6, fill='blue', outline='darkblue', width=2)self.canvas.create_oval(resistance_x-6, resistance_y-6, resistance_x+6, resistance_y+6, fill='red', outline='darkred', width=2)# 添加类型说明self.draw_type_explanation(fulcrum_x, power_x, resistance_x)def draw_grid(self):"""绘制背景网格"""for i in range(0, self.canvas_width, 50):self.canvas.create_line(i, 0, i, self.canvas_height, fill='lightgray', width=1)for i in range(0, self.canvas_height, 50):self.canvas.create_line(0, i, self.canvas_width, i, fill='lightgray', width=1)def draw_fulcrum(self, fulcrum_x, fulcrum_y):"""绘制支点"""# 支点三角形self.canvas.create_polygon(fulcrum_x-20, fulcrum_y+15,fulcrum_x+20, fulcrum_y+15,fulcrum_x, fulcrum_y-5,fill='gray', outline='black', width=2)# 支点标记self.canvas.create_text(fulcrum_x, fulcrum_y+35, text="支点", fill='black', font=("Arial", 10, "bold"))def draw_forces(self, power_x, power_y, resistance_x, resistance_y):"""绘制力箭头"""try:power_force = float(self.power_force.get())resistance_force = float(self.resistance_force.get())arrow_scale = 2.5# 动力箭头power_arrow_length = power_force * arrow_scaleif self.lever_type.get() == "second":# 第二类杠杆动力向上self.canvas.create_line(power_x, power_y, power_x, power_y - power_arrow_length,width=4, fill='blue', arrow=tk.LAST, arrowshape=(10,12,4))text_y = power_y - power_arrow_length - 15else:# 其他情况动力向下self.canvas.create_line(power_x, power_y, power_x, power_y + power_arrow_length,width=4, fill='blue', arrow=tk.LAST, arrowshape=(10,12,4))text_y = power_y + power_arrow_length + 15self.canvas.create_text(power_x, text_y, text=f"动力F1={power_force}N", fill='blue', font=("Arial", 10, "bold"))# 阻力箭头(总是向下)resistance_arrow_length = resistance_force * arrow_scaleself.canvas.create_line(resistance_x, resistance_y, resistance_x, resistance_y + resistance_arrow_length,width=4, fill='red', arrow=tk.LAST, arrowshape=(10,12,4))self.canvas.create_text(resistance_x, resistance_y + resistance_arrow_length + 15, text=f"阻力F2={resistance_force}N", fill='red', font=("Arial", 10, "bold"))except ValueError:passdef draw_arms(self, fulcrum_x, power_x, resistance_x):"""绘制力臂标注"""try:power_arm = float(self.power_arm.get())resistance_arm = float(self.resistance_arm.get())arm_y = self.fulcrum_y - 60# 动力臂self.canvas.create_line(fulcrum_x, arm_y, power_x, arm_y,width=3, fill='blue', arrow=tk.BOTH, arrowshape=(8,10,3))self.canvas.create_text((fulcrum_x + power_x)/2, arm_y-20, text=f"动力臂L1={power_arm}cm", fill='blue', font=("Arial", 10, "bold"))# 阻力臂self.canvas.create_line(fulcrum_x, arm_y-15, resistance_x, arm_y-15,width=3, fill='red', arrow=tk.BOTH, arrowshape=(8,10,3))self.canvas.create_text((fulcrum_x + resistance_x)/2, arm_y-35, text=f"阻力臂L2={resistance_arm}cm", fill='red', font=("Arial", 10, "bold"))except ValueError:passdef draw_type_explanation(self, fulcrum_x, power_x, resistance_x):"""绘制杠杆类型说明"""positions = [("支点", fulcrum_x, 'black'),("动力点", power_x, 'blue'),("阻力点", resistance_x, 'red')]# 按X坐标排序positions.sort(key=lambda x: x[1])explanation_y = 50explanation_text = f"从左到右:{positions[0][0]} → {positions[1][0]} → {positions[2][0]}"self.canvas.create_text(self.canvas_width//2, explanation_y, text=explanation_text, fill='darkgreen', font=("Arial", 12, "bold"))def update_info(self):"""更新信息显示"""try:power_force = float(self.power_force.get())resistance_force = float(self.resistance_force.get())power_arm = float(self.power_arm.get())resistance_arm = float(self.resistance_arm.get())power_moment = power_force * power_armresistance_moment = resistance_force * resistance_arm# 力矩信息moment_text = f"动力矩: M1 = F1 × L1 = {power_force} × {power_arm} = {power_moment:.1f} N·cm\n"moment_text += f"阻力矩: M2 = F2 × L2 = {resistance_force} × {resistance_arm} = {resistance_moment:.1f} N·cm"self.moment_label.config(text=moment_text)# 平衡状态diff = abs(power_moment - resistance_moment)if diff < 0.1:self.balance_label.config(text="✓ 杠杆平衡! (M1 = M2)", fg='green')elif power_moment > resistance_moment:self.balance_label.config(text=f"↺ 逆时针转动 (M1 > M2)", fg='orange')else:self.balance_label.config(text=f"↻ 顺时针转动 (M2 > M1)", fg='orange')# 机械效益分析mechanical_advantage = resistance_force / power_force if power_force != 0 else 0if mechanical_advantage > 1:advantage_text = f"机械效益: {mechanical_advantage:.2f} > 1 (省力杠杆)"elif mechanical_advantage < 1:advantage_text = f"机械效益: {mechanical_advantage:.2f} < 1 (费力杠杆)"else:advantage_text = f"机械效益: {mechanical_advantage:.2f} = 1 (等臂杠杆)"self.advantage_label.config(text=advantage_text)# 类型描述lever_type = self.lever_type.get()descriptions = {"first": "第一类杠杆:支点在中间,可以是省力、费力或等臂杠杆","second": "第二类杠杆:阻力点在中间,一定是省力杠杆", "third": "第三类杠杆:动力点在中间,一定是费力杠杆"}self.type_description.config(text=descriptions[lever_type])except ValueError:self.moment_label.config(text="请输入有效的数值")self.balance_label.config(text="")self.advantage_label.config(text="")self.type_description.config(text="")def update_lever(self):"""更新杠杆显示"""target_angle = self.calculate_lever_angle()if not self.is_animating:self.lever_angle = target_angleself.draw_lever()self.update_info()def start_animation(self):"""开始动画"""self.is_animating = Trueself.animate()def stop_animation(self):"""停止动画"""self.is_animating = Falsedef animate(self):"""动画循环"""if self.is_animating:target_angle = self.calculate_lever_angle()angle_diff = target_angle - self.lever_angleif abs(angle_diff) > 0.001:self.lever_angle += angle_diff * self.animation_speedelse:self.lever_angle = target_angleself.draw_lever()self.root.after(50, self.animate)def reset_lever(self):"""重置杠杆"""self.stop_animation()self.lever_angle = 0self.reset_to_default()self.update_lever()def run(self):"""运行程序"""self.update_example_list()self.root.mainloop()# 运行程序
if __name__ == "__main__":simulator = LeverSimulator()simulator.run()
OK!