人工智能综合实验箱是当前高校和培训机构开展人工智能相关课程教学的重要工具。它通过集成硬件平台、软件环境和实验案例,为学生提供了一个从理论到实践的完整学习路径。这类实验箱通常支持《人工智能数据服务》《机器视觉》《机器学习》《深度学习》《数字图像处理》《语音识别与应用》《智能传感器技术与应用》《ROS系统》等核心课程,覆盖了人工智能领域的主要技术方向。
对于初学者来说,面对如此广泛的技术栈,最大的挑战是如何将分散的知识点串联起来,形成系统的工程能力。实验箱的价值不仅在于提供现成的硬件接口和软件包,更重要的是它构建了一个标准化的实验环境,让学生能够专注于算法原理和实现细节,而不必在环境配置和基础框架上耗费过多时间。
1. 理解实验箱的整体架构与课程映射关系
人工智能综合实验箱的设计目标是为多门课程提供统一的实验平台。这意味着它的硬件接口和软件架构必须足够灵活,能够支持从数据采集到智能决策的完整流程。
1.1 硬件组成与对应课程模块
典型的实验箱包含以下硬件组件,每个组件对应特定的课程实验:
- 多模态传感器阵列:包括摄像头、麦克风、温湿度传感器、距离传感器等,对应《智能传感器技术与应用》课程的数据采集实验。
- 计算核心:通常是嵌入式AI开发板(如Jetson Nano、RK3588等)或PC级主板,提供足够的算力运行机器学习模型。
- 执行机构:如机械臂、舵机、电机等,用于《ROS系统》课程中的机器人控制实验。
- 通信模块:Wi-Fi、蓝牙、4G/5G模块,支持分布式系统和物联网应用开发。
- 扩展接口:GPIO、I2C、SPI、USB等标准接口,方便连接自定义传感器和执行器。
这些硬件组件通过统一的电源管理和机械结构集成在箱体中,学生可以通过标准接口快速搭建实验环境。
1.2 软件栈的分层设计
实验箱的软件环境通常采用分层架构,确保不同课程实验之间的隔离性和复用性:
应用层:课程专用实验案例(目标检测、语音识别、路径规划等) 算法层:机器学习框架(PyTorch、TensorFlow)、视觉库(OpenCV)、语音库 中间件层:ROS(机器人操作系统)、消息队列、服务发现 操作系统层:Ubuntu/Linux + 硬件驱动这种分层设计让学生能够根据课程需求选择合适的技术栈,同时保持底层环境的一致性。
1.3 课程内容与实验箱能力的对应关系
| 课程名称 | 核心实验内容 | 实验箱支持功能 | 技术栈 |
|---|---|---|---|
| 人工智能数据服务 | 数据采集、清洗、标注、存储 | 传感器数据采集、数据标注工具 | Python、SQL、Pandas |
| 机器视觉 | 图像处理、特征提取、目标检测 | 摄像头模块、OpenCV、深度学习模型 | OpenCV、YOLO、CNN |
| 机器学习 | 分类、回归、聚类算法实践 | CPU/GPU算力、Jupyter环境 | Scikit-learn、XGBoost |
| 深度学习 | 神经网络构建、训练、部署 | GPU加速、模型转换工具 | PyTorch、TensorFlow |
| 数字图像处理 | 滤波、变换、形态学操作 | 实时图像处理接口 | OpenCV、NumPy |
| 语音识别与应用 | 语音信号处理、ASR模型 | 麦克风阵列、语音SDK | PyAudio、SpeechRecognition |
| 智能传感器技术与应用 | 传感器数据采集与融合 | 多类型传感器接口 | Arduino、Raspberry Pi |
| ROS系统 | 机器人建模、仿真、控制 | 执行机构、ROS包管理 | ROS、Gazebo、MoveIt |
2. 实验环境准备与基础配置
在开始具体课程实验前,需要完成实验箱的基础环境配置。这个过程虽然繁琐,但理解每个配置步骤的目的对后续实验至关重要。
2.1 系统初始化与依赖安装
实验箱通常预装了定制化的Linux系统,但首次使用仍需进行基础配置:
# 更新系统包管理器 sudo apt update sudo apt upgrade -y # 安装基础开发工具 sudo apt install -y build-essential cmake git wget curl # 安装Python环境(如果实验箱使用Python作为主要开发语言) sudo apt install -y python3 python3-pip python3-venv python3 -m pip install --upgrade pip # 创建虚拟环境用于隔离不同课程的依赖 python3 -m venv ~/ai_lab source ~/ai_lab/bin/activate注意:使用虚拟环境可以避免不同课程项目之间的依赖冲突。建议为每门课程创建独立的虚拟环境。
2.2 核心开发框架安装
人工智能实验箱的核心价值在于集成了主流AI框架,避免学生耗费大量时间在环境配置上:
# 在激活的虚拟环境中安装核心AI框架 pip install torch torchvision torchaudio pip install tensorflow pip install opencv-python pip install scikit-learn pandas matplotlib jupyter # 安装ROS(如果实验箱支持机器人课程) # 具体安装命令取决于ROS版本和Linux发行版 sudo apt install -y ros-noetic-desktop-full echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc source ~/.bashrc2.3 硬件驱动与权限配置
实验箱的硬件组件需要正确的驱动和用户权限才能正常访问:
# 添加用户到dialout组(串口设备访问权限) sudo usermod -a -G dialout $USER # 配置摄像头访问权限 sudo usermod -a -G video $USER # 安装特定硬件驱动(根据实验箱具体型号) # 例如:Jetson Nano的CUDA驱动、Intel RealSense的SDK等配置完成后需要重新登录或重启系统使权限生效。
2.4 验证环境完整性
通过简单的测试脚本验证关键组件是否正常工作:
#!/usr/bin/env python3 """ 实验箱环境验证脚本 检查主要硬件和软件组件是否就绪 """ import sys import cv2 import torch import tensorflow as tf import numpy as np def check_opencv(): """验证OpenCV安装和摄像头访问""" print("检查OpenCV版本:", cv2.__version__) cap = cv2.VideoCapture(0) if cap.isOpened(): ret, frame = cap.read() if ret: print("✓ 摄像头访问正常") else: print("✗ 摄像头读取失败") cap.release() else: print("✗ 摄像头无法打开") def check_pytorch(): """验证PyTorch和GPU支持""" print("检查PyTorch版本:", torch.__version__) if torch.cuda.is_available(): print("✓ CUDA可用,GPU设备:", torch.cuda.get_device_name(0)) else: print("⚠ 使用CPU模式") def check_tensorflow(): """验证TensorFlow安装""" print("检查TensorFlow版本:", tf.__version__) print("✓ TensorFlow导入正常") if __name__ == "__main__": check_opencv() check_pytorch() check_tensorflow()运行此脚本应该能确认基础环境配置正确,为后续课程实验打下基础。
3. 典型课程实验案例详解
下面以《机器视觉》和《机器学习》两门课程为例,展示如何在实验箱上开展完整的实验项目。
3.1 《机器视觉》课程实验:实时目标检测系统
这个实验综合了图像采集、预处理、深度学习模型推理和结果显示等多个环节。
3.1.1 实验目标与流程设计
实验目标:使用YOLOv5模型实现实时目标检测,并在实验箱的显示屏上显示检测结果。
实验流程:
- 初始化摄像头并设置采集参数
- 加载预训练的YOLOv5模型
- 循环读取视频帧并进行推理
- 解析检测结果并在图像上绘制边界框
- 显示处理后的图像并计算帧率
3.1.2 核心代码实现
import cv2 import torch import numpy as np from pathlib import Path import time class RealTimeObjectDetection: def __init__(self, model_path='yolov5s.pt', conf_threshold=0.5): """初始化检测器""" # 加载YOLOv5模型(实验箱应预装或提供下载路径) self.model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True) self.model.conf = conf_threshold # 置信度阈值 self.classes = self.model.names # 类别名称映射 # 初始化摄像头(实验箱的摄像头设备号通常是0) self.cap = cv2.VideoCapture(0) self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # 性能统计 self.frame_count = 0 self.fps = 0 self.start_time = time.time() def process_frame(self, frame): """处理单帧图像""" # 转换颜色空间(OpenCV使用BGR,YOLO需要RGB) rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 推理 results = self.model(rgb_frame) # 解析结果 detections = results.xyxy[0].cpu().numpy() # 在图像上绘制检测结果 for detection in detections: x1, y1, x2, y2, conf, cls = detection label = f"{self.classes[int(cls)]} {conf:.2f}" # 绘制边界框和标签 cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.putText(frame, label, (int(x1), int(y1)-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) return frame def calculate_fps(self): """计算并显示帧率""" self.frame_count += 1 if self.frame_count >= 30: end_time = time.time() self.fps = self.frame_count / (end_time - self.start_time) self.frame_count = 0 self.start_time = end_time return self.fps def run(self): """主循环""" print("启动实时目标检测...按'q'退出") while True: ret, frame = self.cap.read() if not ret: print("无法读取摄像头帧") break # 处理帧 processed_frame = self.process_frame(frame) # 计算并显示FPS fps = self.calculate_fps() cv2.putText(processed_frame, f"FPS: {fps:.1f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) # 显示结果 cv2.imshow('Real-time Object Detection', processed_frame) # 退出条件 if cv2.waitKey(1) & 0xFF == ord('q'): break # 清理资源 self.cap.release() cv2.destroyAllWindows() if __name__ == "__main__": detector = RealTimeObjectDetection() detector.run()3.1.3 实验要点与常见问题
关键配置参数:
conf_threshold:置信度阈值,影响检测的严格程度- 图像分辨率:平衡处理速度和质量
- 模型选择:YOLOv5s(小模型)适合实时应用,YOLOv5x(大模型)精度更高但速度慢
常见问题排查:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 摄像头无法打开 | 设备号错误或权限不足 | 检查/dev/video*设备,确认用户有video组权限 |
| 模型加载失败 | 网络问题或路径错误 | 手动下载模型文件或检查网络连接 |
| 帧率过低 | 模型太大或分辨率过高 | 换用更小的模型或降低分辨率 |
| 检测结果不准确 | 置信度阈值设置不当 | 调整conf_threshold参数 |
3.2 《机器学习》课程实验:基于传感器数据的分类模型
这个实验使用实验箱的多种传感器采集数据,构建一个完整的机器学习流水线。
3.2.1 数据采集与特征工程
实验箱通常配备温湿度、光照、运动等多种传感器,可以模拟智能家居的环境监测场景。
import pandas as pd import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report import json import time class SensorDataClassifier: def __init__(self): self.model = None self.feature_names = ['temperature', 'humidity', 'light', 'motion'] self.target_names = ['normal', 'abnormal'] def collect_training_data(self, duration=300): """采集训练数据(模拟实际传感器数据采集)""" print(f"开始采集数据,持续时间:{duration}秒") data = [] labels = [] for i in range(duration): # 模拟传感器读数(实际项目中从硬件接口读取) temperature = np.random.normal(25, 2) # 温度,均值25℃,标准差2 humidity = np.random.normal(50, 5) # 湿度,均值50%,标准差5 light = np.random.normal(500, 100) # 光照,均值500lux,标准差100 motion = np.random.randint(0, 2) # 运动检测,0或1 # 模拟异常情况(每10个样本中有1个异常) if i % 10 == 0: # 异常模式:温度异常高、湿度异常低 temperature += 10 humidity -= 20 label = 'abnormal' else: label = 'normal' data.append([temperature, humidity, light, motion]) labels.append(label) time.sleep(1) # 模拟1秒采样间隔 df = pd.DataFrame(data, columns=self.feature_names) df['label'] = labels # 保存数据集 df.to_csv('sensor_training_data.csv', index=False) print(f"数据采集完成,共{len(df)}条样本") return df def preprocess_data(self, df): """数据预处理""" # 将标签转换为数值 df['label_encoded'] = df['label'].map({'normal': 0, 'abnormal': 1}) # 划分特征和标签 X = df[self.feature_names] y = df['label_encoded'] return X, y def train_model(self, X, y): """训练随机森林分类器""" # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) # 创建并训练模型 self.model = RandomForestClassifier( n_estimators=100, max_depth=10, random_state=42 ) self.model.fit(X_train, y_train) # 评估模型 y_pred = self.model.predict(X_test) print("模型评估结果:") print(classification_report(y_test, y_pred, target_names=self.target_names)) return self.model def predict_real_time(self): """实时预测(模拟实际应用场景)""" if self.model is None: print("请先训练模型") return print("开始实时预测...按Ctrl+C停止") try: while True: # 模拟实时传感器数据 new_data = np.array([[ np.random.normal(25, 2), np.random.normal(50, 5), np.random.normal(500, 100), np.random.randint(0, 2) ]]) prediction = self.model.predict(new_data)[0] probability = self.model.predict_proba(new_data)[0] status = self.target_names[prediction] confidence = probability[prediction] print(f"预测结果: {status} (置信度: {confidence:.3f})") time.sleep(2) except KeyboardInterrupt: print("预测停止") # 使用示例 if __name__ == "__main__": classifier = SensorDataClassifier() # 1. 采集数据 df = classifier.collect_training_data(duration=60) # 1分钟数据用于演示 # 2. 预处理数据 X, y = classifier.preprocess_data(df) # 3. 训练模型 model = classifier.train_model(X, y) # 4. 实时预测演示 classifier.predict_real_time()3.2.2 模型优化与评估
在实验箱环境中,还需要考虑模型的实际部署要求:
import joblib from sklearn.model_selection import cross_val_score def optimize_and_save_model(classifier, X, y): """模型优化与持久化""" # 交叉验证评估 scores = cross_val_score(classifier.model, X, y, cv=5) print(f"交叉验证准确率: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})") # 特征重要性分析 feature_importance = pd.DataFrame({ 'feature': classifier.feature_names, 'importance': classifier.model.feature_importances_ }).sort_values('importance', ascending=False) print("\n特征重要性排序:") print(feature_importance) # 保存模型(用于后续课程或项目) joblib.dump(classifier.model, 'sensor_classifier_model.pkl') print("模型已保存为 'sensor_classifier_model.pkl'") # 保存特征名称(用于后续预测时的一致性) with open('feature_names.json', 'w') as f: json.dump(classifier.feature_names, f)4. 多课程融合的综合项目实践
人工智能综合实验箱的真正价值在于支持跨课程的综合项目。下面以"智能家居监控系统"为例,展示如何将多门课程知识整合应用。
4.1 项目架构设计
系统组件:
- 数据采集层:传感器数据(温湿度、光照、运动)
- 视觉感知层:摄像头实时监控
- 决策分析层:异常检测与报警逻辑
- 控制执行层:灯光、报警器控制
- 人机交互层:Web界面或移动端应用
技术栈整合:
- 《智能传感器技术与应用》:数据采集与预处理
- 《机器视觉》:人脸识别、运动检测
- 《机器学习》:异常模式识别
- 《深度学习》:复杂场景理解
- 《ROS系统》:设备控制与消息传递
4.2 核心实现代码框架
#!/usr/bin/env python3 """ 智能家居监控系统 - 多课程融合示例 演示如何整合传感器数据、计算机视觉和机器学习决策 """ import threading import time import json from datetime import datetime class SmartHomeMonitor: def __init__(self): self.sensor_data = {} self.camera_status = False self.alarm_status = False self.anomaly_detector = None self.face_recognizer = None # 初始化各模块 self.setup_sensors() self.setup_camera() self.setup_decision_engine() def setup_sensors(self): """初始化传感器模块""" print("初始化传感器...") # 这里集成《智能传感器技术与应用》课程内容 # 实际实现需要根据实验箱具体硬件调整 def setup_camera(self): """初始化视觉模块""" print("初始化摄像头...") # 这里集成《机器视觉》和《深度学习》课程内容 # 包括人脸识别、运动检测等功能 def setup_decision_engine(self): """初始化决策引擎""" print("初始化决策引擎...") # 这里集成《机器学习》课程内容 # 包括异常检测、模式识别等算法 def sensor_data_collection(self): """传感器数据采集线程""" while True: # 模拟多传感器数据采集 self.sensor_data = { 'timestamp': datetime.now().isoformat(), 'temperature': np.random.normal(25, 1), 'humidity': np.random.normal(50, 2), 'light': np.random.normal(300, 50), 'motion': np.random.choice([0, 1], p=[0.9, 0.1]) } # 保存到数据库或文件(实际项目) time.sleep(2) # 2秒采集间隔 def video_analysis(self): """视频分析线程""" while True: if self.camera_status: # 执行人脸识别、运动检测等 # 这里调用OpenCV和深度学习模型 pass time.sleep(0.1) # 10Hz分析频率 def decision_making(self): """决策引擎线程""" while True: # 综合分析传感器数据和视觉分析结果 if self.detect_anomaly(): self.trigger_alarm() time.sleep(1) # 1秒决策间隔 def detect_anomaly(self): """异常检测逻辑""" # 综合多种算法进行异常判断 temperature_anomaly = self.sensor_data.get('temperature', 25) > 30 motion_anomaly = self.sensor_data.get('motion', 0) == 1 return temperature_anomaly or motion_anomaly def trigger_alarm(self): """触发报警""" if not self.alarm_status: print(f"[警报] {datetime.now()} 检测到异常情况!") self.alarm_status = True # 这里可以集成《ROS系统》课程内容 # 控制实际报警设备 def start_monitoring(self): """启动监控系统""" print("启动智能家居监控系统...") # 创建并启动各功能线程 sensor_thread = threading.Thread(target=self.sensor_data_collection) video_thread = threading.Thread(target=self.video_analysis) decision_thread = threading.Thread(target=self.decision_making) sensor_thread.daemon = True video_thread.daemon = True decision_thread.daemon = True sensor_thread.start() video_thread.start() decision_thread.start() # 主线程保持运行 try: while True: time.sleep(1) except KeyboardInterrupt: print("监控系统停止") if __name__ == "__main__": monitor = SmartHomeMonitor() monitor.start_monitoring()4.3 项目扩展方向
这个基础框架可以扩展到更多实际应用场景:
- 能源管理优化:基于历史数据预测能耗,自动调节设备
- 安全监控增强:结合声音分析实现多模态异常检测
- 健康关怀应用:监测老年人日常活动模式,发现异常行为
- 环境自适应:根据室外天气和室内环境自动调节空调、照明
5. 实验箱使用中的常见问题与解决方案
在实际教学过程中,学生使用实验箱时经常会遇到各种技术问题。下面整理了一些典型问题及其解决方法。
5.1 环境配置问题
问题1:Python包版本冲突
现象:不同课程需要的包版本不一致,导致环境混乱。
解决方案:
# 为每门课程创建独立的虚拟环境 python -m venv ~/courses/machine_learning python -m venv ~/courses/computer_vision # 使用requirements.txt管理依赖 # machine_learning/requirements.txt scikit-learn==1.0.2 pandas==1.3.5 # computer_vision/requirements.txt opencv-python==4.5.5.64 torch==1.10.0问题2:硬件设备权限不足
现象:无法访问摄像头、串口等设备。
解决方案:
# 永久解决方案:将用户添加到相应组 sudo usermod -a -G video $USER # 摄像头 sudo usermod -a -G dialout $USER # 串口 # 临时解决方案:更改设备权限 sudo chmod 666 /dev/video05.2 性能优化问题
问题3:模型推理速度慢
现象:实时应用帧率过低,影响用户体验。
优化策略:
- 使用更小的模型(如YOLOv5s而不是YOLOv5x)
- 降低输入图像分辨率
- 启用GPU加速(如果硬件支持)
- 使用模型量化技术
# 启用GPU加速示例 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = model.to(device) # 使用半精度浮点数加速推理 model.half()问题4:内存不足
现象:训练大模型时出现内存错误。
解决方案:
- 减小批量大小(batch size)
- 使用数据生成器而不是一次性加载所有数据
- 及时清理不需要的变量
import gc # 训练循环中及时清理 for batch in dataloader: # 前向传播、反向传播... loss.backward() optimizer.step() # 清理 del batch, loss gc.collect()5.3 工程实践问题
问题5:代码可维护性差
现象:实验代码混乱,难以复用和扩展。
最佳实践:
- 使用面向对象编程封装功能模块
- 遵循PEP 8代码规范
- 编写清晰的文档字符串
- 使用配置文件管理参数
class ExperimentBase: """实验基类,提供通用功能""" def __init__(self, config_file): self.load_config(config_file) self.setup_environment() def load_config(self, config_file): """加载配置文件""" with open(config_file, 'r') as f: self.config = json.load(f) def setup_environment(self): """设置实验环境""" # 通用环境设置代码 pass def run(self): """运行实验(子类必须实现)""" raise NotImplementedError class ObjectDetectionExperiment(ExperimentBase): """目标检测实验""" def run(self): """实现具体的实验逻辑""" # 实验具体实现 pass问题6:实验结果不可复现
现象:相同代码每次运行结果不同。
解决方案:
- 设置随机种子
- 记录实验配置和环境信息
- 使用版本控制管理代码和数据
import random import numpy as np import torch def set_random_seed(seed=42): """设置随机种子确保结果可复现""" random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic = True6. 从实验箱到真实项目的过渡建议
实验箱提供了标准化的学习环境,但真实项目往往面临更多挑战。以下是帮助学生从实验环境过渡到工程实践的建议。
6.1 工程化思维培养
版本控制习惯:
- 从第一个实验开始就使用Git管理代码
- 编写有意义的提交信息
- 使用分支管理不同实验版本
文档化实践:
- 为每个实验编写README说明
- 记录实验假设、参数设置和结果分析
- 建立个人知识库积累经验
自动化脚本:
- 编写脚本自动化环境配置过程
- 使用Makefile或Shell脚本管理常用命令
- 实现一键式的实验复现流程
6.2 性能与资源意识
资源监控:
# 监控GPU使用情况 nvidia-smi # 监控内存使用 htop # 监控磁盘空间 df -h性能分析工具:
import cProfile import pstats def profile_function(func, *args, **kwargs): """函数性能分析工具""" profiler = cProfile.Profile() profiler.enable() result = func(*args, **kwargs) profiler.disable() stats = pstats.Stats(profiler) stats.sort_stats('cumulative') stats.print_stats(10) return result6.3 安全与可靠性考虑
错误处理机制:
class RobustSensorReader: """健壮的传感器读取类""" def read_sensor_with_retry(self, max_retries=3): """带重试机制的传感器读取""" for attempt in range(max_retries): try: data = self._read_sensor() return data except SensorError as e: print(f"传感器读取失败(尝试 {attempt+1}/{max_retries}): {e}") if attempt == max_retries - 1: raise # 最后一次尝试失败后抛出异常 time.sleep(1) # 等待后重试 def _read_sensor(self): """实际的传感器读取逻辑""" # 实现细节 pass日志记录系统:
import logging def setup_logging(): """设置日志系统""" logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('experiment.log'), logging.StreamHandler() ] ) # 在代码中使用 logger = logging.getLogger(__name__) logger.info("实验开始")人工智能综合实验箱作为教学工具,其真正价值在于为学生提供一个从理论到实践的完整学习路径。通过系统性地完成各课程实验,学生不仅能够掌握具体的技术技能,更重要的是培养解决实际问题的工程能力。这种能力在从学习环境向真实项目过渡时将发挥关键作用。
实验箱的设计应该平衡标准化与灵活性,既提供足够的基础设施减少环境配置的负担,又保留足够的自定义空间鼓励学生探索创新。教师在使用实验箱进行教学时,应该注重培养学生的问题分析能力、系统设计思维和工程实践习惯,而不仅仅是完成实验步骤。