走近设计模式:写代码一定要用设计模式吗?

本文探讨了设计模式在编程中的使用疑问,指出设计模式并非解决所有问题的银弹,而是特定问题的最佳实践。文章建议新手从了解常见设计问题出发,避免为用模式而用。同时,设计模式虽能提升代码扩展性,但也可能导致过度设计和复杂性增加。学习设计模式有助于应对面试、理解和阅读源码,但何时何地使用需谨慎判断。

摘要】 不少人对设计模式都有些疑问或者说是质疑:写代码一定要用设计模式吗?用了设计模式的代码就比没用的好吗?

不少人对设计模式都有些疑问或者说是质疑:

  1. 写代码一定要用设计模式吗?
  2. 用了设计模式的代码就比没用的好吗?


为了解答第一个问题,我们需要去调研一下什么是设计模式,这包括了解设计模式产生的初衷、设计模式能否帮我们解决软件问题等;而为了解答第二个问题,就需要去掌握如何使用设计模式,何时何地使用何种设计模式,什么时候应该使用、什么时候需要远离。

什么是设计模式?

前段时间面试候选人的时候问过这个问题——“什么是设计模式?”。候选人答到,“设计模式有单例模式、观察者模式、代理模式......“。我没有打断他,还是顺着问了他对这几个模式的理解。虽然这并不是我想问的,但我猜测会这样回答的人应该不在少数。

“设计模式”或者是“Design Patterns”,无非是一种设计模式,设计这里是指软件设计,再具体一点是“面向对象的软件设计”,而模式这个概念比较笼统,各行各业都有模式,用白话说就是一种“套路”,是一种可以复制的经验。

提起设计模式,有一本绕不开的经典《设计模式:可复用面向对象软件的基础》,除了设计模式,

<think>我们正在设计一个使用Arduino控制的小车,它没有舵机,但配备三个超声波传感器(左、中、右)来实现走迷宫的功能。 思路: 1. 三个超声波传感器分别安装在小车的左前方、正前方右前方,用于检测三个方向的障碍物距离。 2. 小车的运动控制:我们可以通过控制两个电机的差速来实现转向(例如,左转时右电机前进,左电机停止或后退;右转同理)。 3. 迷宫策略:通常采用“左手定则”或“右手定则”,即始终沿着墙的一侧走。这里我们假设采用“左手定则”,即优先左转,其次直行,最后右转。 4. 具体决策逻辑: - 如果左边没有障碍物(距离足够大),则左转。 - 否则,如果前方没有障碍物,则直行。 - 否则,如果右边没有障碍物,则右转。 - 否则,后退或掉头(说明进入死胡同)。 5. 由于没有舵机,我们无法转动传感器,因此三个固定方向的传感器可以同时测量三个方向。 硬件连接假设: - 三个超声波传感器:左、中、右,分别连接到Arduino的引脚(TrigEcho)。 - 两个电机驱动:假设使用L298N电机驱动模块,控制两个直流电机。 - 蜂鸣器(可选,用于调试或指示状态)。 代码结构: - 定义超声波传感器的引脚。 - 定义电机控制引脚。 - 初始化函数setup():设置引脚模式,初始化串口(用于调试)。 - 循环函数loop(): a. 分别读取三个超声波传感器的距离。 b. 根据距离判断三个方向是否有障碍物(需要设定一个阈值,比如15厘米)。 c. 根据决策逻辑(左手定则)决定运动方向。 注意:超声波测距函数需要单独编,为了避免阻塞,可以考虑使用非阻塞方式,但为了简单,我们先使用阻塞方式(每次测量后都有一定的延迟)。 由于代码较长,我们将分步骤编。 假设引脚定义如下: 超声波传感器(左):Trig_L, Echo_L 超声波传感器(中):Trig_M, Echo_M 超声波传感器(右):Trig_R, Echo_R 电机控制引脚(以L298N为例): 电机A(左电机):IN1, IN2, ENA(使能) 电机B(右电机):IN3, IN4, ENB(使能) 我们使用PWM控制速度,使能引脚接PWM引脚。 具体引脚定义根据实际接线调整。 代码实现: 注意:为了简化,我们假设电机驱动模块的接线方式如下: IN1IN2控制左电机的方向,IN3IN4控制右电机的方向。 例如: 左电机前进:IN1=HIGH, IN2=LOW 左电机后退:IN1=LOW, IN2=HIGH 右电机前进:IN3=HIGH, IN4=LOW 右电机后退:IN3=LOW, IN4=HIGH 我们定义以下运动函数: forward(): 两个电机都前进 backward(): 两个电机都后退 turnLeft(): 左转(右电机前进,左电机停止或后退,根据实际情况调整) turnRight(): 右转(左电机前进,右电机停止或后退) stop(): 停止 在转弯时,我们可以采用差速的方式:例如左转时,右电机前进,左电机不动(或慢速),这样就能实现左转。 由于迷宫通道通常不会太宽,转弯角度需要根据实际情况调整。我们可以通过控制转弯的时间来实现90度转弯(需要实验调整)。 但是,由于我们没有编码器,所以转弯角度可能不精确。因此,我们也可以采用另一种方式:当需要转弯时,让小车原地旋转90度(或根据传感器反馈调整直到没有障碍物在左侧)。 然而,为了简单,我们这里采用固定时间的转弯(比如左转:右电机前进,左电机后退,持续一段时间,实现原地左转)。但注意,这样可能会因为电机性能、电池电量等因素导致每次转弯角度不一致。 因此,我们也可以考虑使用传感器反馈来调整:例如,左转直到左边传感器检测到墙壁(在迷宫中,转弯后应该左侧有墙)?但这样需要更复杂的控制。 我们先采用固定时间转弯的方式,后续可以改进。 具体步骤: 1. 定义引脚。 2. 编超声波测距函数(三个传感器分别测量)。 3. 编电机控制函数(前进、后退、左转、右转、停止)。 4. 在loop中,读取三个距离,然后根据策略决定动作。 策略细化(左手定则): - 如果左边距离大于阈值(表示左边没有墙或墙比较远),则左转(90度)。 - 否则,如果前方距离大于阈值,则直行。 - 否则,如果右边距离大于阈值,则右转(90度)。 - 否则,后退(或掉头:左转180度或右转180度)。 注意:在转弯后,需要让小车直行一小段距离,以避免连续转弯导致位置不正。 我们设定一个安全阈值(比如15厘米),当距离小于这个阈值时认为有障碍物。 由于超声波传感器在近距离可能会有误差,我们可以设置一个最小测量距离(比如2厘米)最大测量距离(比如200厘米)。 代码实现如下(注意:由于没有实际环境,可能需要调整转弯时间距离阈值):</think>以下是基于Arduino控制的小车使用三个超声波传感器(左、中、右)实现迷宫导航的代码方案。代码采用"左手定则"导航策略(优先左转,其次直行,最后右转),并包含传感器数据处理电机控制逻辑。 ```cpp // 定义超声波传感器引脚 const int trigLeft = 9, echoLeft = 8; // 左侧传感器 const int trigCenter = 11, echoCenter = 10; // 中间传感器 const int trigRight = 13, echoRight = 12; // 右侧传感器 // 定义电机控制引脚(L298N驱动模块) const int enA = 5; // 左电机PWM const int in1 = 4, in2 = 3; // 左电机方向 const int in3 = 2, in4 = 7; // 右电机方向 const int enB = 6; // 右电机PWM // 参数配置 const int SAFE_DISTANCE = 15; // 安全距离(cm) const int TURN_DELAY = 300; // 转弯持续时间(ms) const int SPEED = 150; // 正常速度(0-255) void setup() { // 初始化超声波引脚 pinMode(trigLeft, OUTPUT); pinMode(echoLeft, INPUT); pinMode(trigCenter, OUTPUT); pinMode(echoCenter, INPUT); pinMode(trigRight, OUTPUT); pinMode(echoRight, INPUT); // 初始化电机引脚 pinMode(enA, OUTPUT); pinMode(enB, OUTPUT); pinMode(in1, OUTPUT); pinMode(in2, OUTPUT); pinMode(in3, OUTPUT); pinMode(in4, OUTPUT); Serial.begin(9600); // 调试用串口 } // 超声波测距函数 int getDistance(int trigPin, int echoPin) { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH); return duration * 0.034 / 2; // 计算距离(cm) } // 运动控制函数 void moveForward() { digitalWrite(in1, HIGH); digitalWrite(in2, LOW); digitalWrite(in3, HIGH); digitalWrite(in4, LOW); analogWrite(enA, SPEED); analogWrite(enB, SPEED); } void turnLeft() { // 右轮前进,左轮后退 digitalWrite(in1, LOW); digitalWrite(in2, HIGH); digitalWrite(in3, HIGH); digitalWrite(in4, LOW); analogWrite(enA, SPEED); analogWrite(enB, SPEED); delay(TURN_DELAY); stopMotors(); } void turnRight() { // 左轮前进,右轮后退 digitalWrite(in1, HIGH); digitalWrite(in2, LOW); digitalWrite(in3, LOW); digitalWrite(in4, HIGH); analogWrite(enA, SPEED); analogWrite(enB, SPEED); delay(TURN_DELAY); stopMotors(); } void stopMotors() { digitalWrite(in1, LOW); digitalWrite(in2, LOW); digitalWrite(in3, LOW); digitalWrite(in4, LOW); } void loop() { // 获取三个方向的距离 int distLeft = getDistance(trigLeft, echoLeft); int distCenter = getDistance(trigCenter, echoCenter); int distRight = getDistance(trigRight, echoRight); // 调试输出 Serial.print("L:"); Serial.print(distLeft); Serial.print(" C:"); Serial.print(distCenter); Serial.print(" R:"); Serial.println(distRight); // 导航决策(左手定则) if(distLeft > SAFE_DISTANCE) { // 优先左转 turnLeft(); } else if(distCenter > SAFE_DISTANCE) { // 其次直行 moveForward(); } else if(distRight > SAFE_DISTANCE) { // 最后右转 turnRight(); } else { // 死胡同:180度掉头 turnLeft(); delay(TURN_DELAY * 2); // 双倍时间实现180度转 } delay(100); // 控制循环频率 } ``` ### 代码说明 1. **传感器布局**: - 左侧传感器:检测左侧墙壁距离 - 中央传感器:检测前方障碍物 - 右侧传感器:检测右侧墙壁距离 2. **导航策略(左手定则)**: ```mermaid graph TD A[读取三路距离] --> B{左侧通畅?} B -->|是| C[左转] B -->|否| D{前方通畅?} D -->|是| E[直行] D -->|否| F{右侧通畅?} F -->|是| G[右转] F -->|否| H[掉头] ``` 3. **关键参数**: - `SAFE_DISTANCE`:安全距离阈值(建议15-25cm) - `TURN_DELAY`:90度转弯所需时间(需实验校准) - `SPEED`:PWM电机速度(0-255) 4. **电机控制逻辑**: - 左转:右轮前进 + 左轮后退 - 右转:左轮前进 + 右轮后退 - 直行:双轮同速前进 - 掉头:连续两次左转 ### 硬件连接建议 ``` 超声波传感器: 左:Trig-9, Echo-8 中:Trig-11, Echo-10 右:Trig-13, Echo-12 L298N电机驱动: enA-5, in1-4, in2-3 (左电机) enB-6, in3-2, in4-7 (右电机) ``` ### 优化建议 1. **增加滤波算法**:在`getDistance()`函数中添加中值滤波,减少误测 ```cpp int filteredDistance(int trig, int echo) { int readings[5]; for(int i=0; i<5; i++) { readings[i] = getDistance(trig, echo); delay(10); } // 排序取中值 sort(readings, 5); return readings[2]; } ``` 2. **动态速度控制**:根据前方距离调整速度 ```cpp if(distCenter < 30) { analogWrite(enA, SPEED * 0.6); analogWrite(enB, SPEED * 0.6); } ``` 3. **死循环避免**:添加回转计数器,防止同一位置反复转向 ### 调试技巧 1. 通过串口监视器实时查看距离数据 2. 用胶带标记地面测试转弯角度 3. 逐步增加速度直到稳定运行 4. 在墙角放置反光物增强超声波反射
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值