【花雕学编程】Arduino OLED 之模拟雷达扫描效果

在这里插入图片描述
《Arduino 手册(思路与案例)》栏目介绍:
在电子制作与智能控制的应用领域:广泛涉及了Arduino BLDC、Arduino CNC、Arduino ESP32 SPP、Arduino FreeRTOS、Arduino FOC、Arduino GRBL、Arduino HTTP、Arduino HUB75、Arduino IoT Cloud、Arduino JSON、Arduino LCD、Arduino OLED、Arduino LVGL、Arduino PID 及 Arduino TFT 等方面的相关拓展思路和众多参考案例。本专栏目前博客近2300篇。
https://blog.csdn.net/weixin_41659040/category_12422453.html

Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用Arduino IDE(集成开发环境)来编写、编译和上传代码到Arduino板上。Arduino还有一个丰富的库和社区,你可以利用它们来扩展Arduino的功能和学习Arduino的知识。

Arduino的特点是:
1、开放源码:Arduino的硬件和软件都是开放源码的,你可以自由地修改、复制和分享它们。
2、易用:Arduino的硬件和软件都是为初学者和非专业人士设计的,你可以轻松地上手和使用它们。
3、便宜:Arduino的硬件和软件都是非常经济的,你可以用很低的成本来实现你的想法。
4、多样:Arduino有多种型号和版本,你可以根据你的需要和喜好来选择合适的Arduino板。
5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。

在这里插入图片描述

概念概述
Arduino OLED 指的是将 Arduino 开发平台与 OLED(有机发光二极管)显示屏相结合的应用组合。Arduino 是开源电子原型平台,具备灵活的硬件扩展性和简单易上手的编程环境;OLED 显示屏则以其自发光、高对比度、宽视角、响应速度快等优势,为信息展示提供了优质的视觉体验。二者结合能实现各类数据显示、图形绘制及交互界面展示等功能,在电子制作、物联网、机器人等诸多领域广泛应用。
详细解释

Arduino 相关特性
硬件特性
开源设计:Arduino 的硬件设计方案完全公开,用户能够获取其原理图、PCB 版图等详细资料。这不仅降低了开发成本,还方便开发者根据自身需求对硬件进行修改和扩展,例如制作自定义外形或功能的开发板。
丰富接口资源:Arduino 开发板配备了多种类型的接口。数字输入输出引脚可用于连接开关、继电器、LED 等设备,实现数字信号的读取和输出控制;模拟输入引脚能够采集如温度传感器、光照传感器输出的连续模拟信号,经内部 ADC(模拟 - 数字转换器)转换为数字值供程序处理。
多种供电方式:支持 USB 供电、外接电源适配器供电以及电池供电等多种方式。使用 USB 供电时,可方便地与计算机连接进行程序上传和调试;外接电源适配器则能提供稳定的电源,适用于长时间运行的项目;电池供电赋予了 Arduino 设备便携性,可应用于移动监测等场景。
软件特性
简易编程环境:Arduino 使用基于 C/C++ 的编程语言,其语法简洁易懂。Arduino IDE 是专门为其开发的集成开发环境,具有跨平台性,可在 Windows、Mac OS、Linux 等操作系统上运行。IDE 提供了直观的代码编辑界面、便捷的编译和上传功能,还内置了大量示例代码,帮助初学者快速入门。
庞大的库资源:Arduino 社区拥有丰富的开源库,涵盖了传感器驱动、通信协议、图形绘制等各个领域。例如,Wire 库用于 I2C 通信,SPI 库用于 SPI 通信,开发者可以直接调用这些库,无需从头编写底层代码,大大提高了开发效率。
OLED 显示屏特性
显示原理
OLED 基于有机材料的电致发光特性工作。当在有机材料层两端施加电压时,电子从阴极注入,空穴从阳极注入,二者在有机材料中相遇并复合,释放出能量以光的形式呈现,从而实现发光显示。由于每个像素都能独立发光,OLED 显示屏无需背光源。
性能优势
自发光与高对比度:自发光特性使得 OLED 能够实现真正的黑色显示,因为不发光的像素完全不产生光线。这使得其对比度极高,图像的亮部更亮,暗部更暗,色彩表现更加生动逼真。
宽视角:OLED 的视角非常宽广,通常可达 170° 以上。从不同角度观看显示屏,画面的颜色和亮度变化极小,能为用户提供一致的视觉体验,适用于各种需要多角度观察的应用场景。
快速响应时间:OLED 的响应时间极短,一般在几微秒到几十微秒之间。相比传统的液晶显示屏,OLED 在显示动态画面时不会出现拖影现象,能够清晰、流畅地展示快速变化的图像,如动画、视频等。
轻薄与低功耗:由于无需背光源,OLED 显示屏的结构更加简单,厚度更薄,重量更轻。同时,其在显示黑色画面时几乎不消耗电能,只有发光的像素才会消耗功率,因此在显示深色画面较多的场景下,功耗显著降低。
Arduino 与 OLED 的连接和通信
通信接口类型
SPI(Serial Peripheral Interface):SPI 是一种高速的全双工串行通信协议,Arduino 通过 SPI 接口与 OLED 显示屏连接时,通常需要使用时钟线(SCK)、主输出从输入线(MOSI)、主输入从输出线(MISO)和片选线(SS)。SPI 通信速度快,适合需要快速传输大量数据的应用场景,如显示高分辨率的图像或视频流。
I2C(Inter - Integrated Circuit):I2C 是一种串行通信协议,使用两根线进行通信,即时钟线(SCL)和数据线(SDA)。I2C 接口简单,占用 Arduino 的引脚资源少,并且支持多个设备挂载在同一总线上,通过不同的设备地址进行区分。在一些对引脚资源要求较高的项目中,I2C 接口更为适用。
通信流程
初始化:在 Arduino 代码中,首先需要初始化所选的通信接口(SPI 或 I2C),并设置相关的通信参数,如时钟频率、设备地址等。
发送数据:Arduino 根据需要显示的内容,将数据按照 OLED 显示屏的通信协议进行编码,然后通过通信接口发送给 OLED 显示屏。数据可以是字符、数字、图形等信息。
显示更新:OLED 显示屏接收到数据后,对其进行解码和处理,将相应的内容显示在屏幕上。为了实现动态显示效果,Arduino 可以定期更新发送的数据,使 OLED 显示屏不断刷新显示内容。

应用场景
数据监测与显示:在环境监测系统中,Arduino 连接各种传感器(如温度传感器、湿度传感器、空气质量传感器等)采集环境数据,然后将数据通过通信接口传输到 OLED 显示屏上进行实时显示。用户可以直观地了解环境参数的变化情况。
智能家居控制:在智能家居系统中,Arduino 作为控制核心,连接各种家电设备和传感器。OLED 显示屏可以显示家电设备的状态(如开关状态、温度设置等),并提供操作菜单,用户可以通过触摸按键或其他输入设备在 OLED 显示屏上进行操作,实现对家电设备的远程控制。
机器人交互界面:在机器人项目中,OLED 显示屏可以作为机器人的交互界面,显示机器人的工作状态、任务进度、传感器数据等信息。同时,还可以显示一些动画或图标,增强机器人的人机交互体验。
手持设备与可穿戴设备:由于 OLED 显示屏的轻薄和低功耗特性,与 Arduino 结合可用于开发手持设备和可穿戴设备。例如,制作一个便携式的健康监测设备,通过 Arduino 连接心率传感器、计步器等,将监测数据显示在 OLED 显示屏上,方便用户随时查看自己的健康状况。

在这里插入图片描述

在Arduino项目中,OLED之模拟雷达扫描效果(Simulating Radar Scanning Effect on OLED) 是一种非常有趣且直观的视觉展示方式。通过模拟雷达波形的动态扫描,可以为用户提供实时的环境感知信息或增强用户体验。以下是关于这一技术的主要特点、应用场景以及需要注意的事项的专业解析。

主要特点

  1. 视觉吸引力
    动态扫描效果:模拟真实的雷达扫描过程,通过循环绘制弧线或扇形区域来模仿雷达波的扩散,吸引用户的注意力。
    直观反馈:能够以图形化的方式展示周围环境的状态变化,如障碍物的位置、距离等信息,使用户能够快速理解当前环境状况。
  2. 资源效率
    尽管涉及动态绘图操作,但通过优化算法和合理的刷新策略,可以在Arduino等资源受限的平台上实现流畅的显示效果。
    使用简单的几何形状(如圆弧、直线)进行绘制,减少对处理器性能的要求。
  3. 可定制性强
    可以根据具体需求调整扫描角度、速度、颜色等参数,提供个性化的用户体验。
    支持多种显示模式(如单色或灰度),适应不同的应用场合。
  4. 互动性高
    结合传感器数据(如超声波传感器、红外传感器),可以将实际检测到的信息映射到雷达界面上,增加互动性和实用性。
    提供即时反馈机制,帮助用户更好地理解和响应设备输出的信息。

应用场景

  1. 机器人导航与避障
    在自主移动机器人中,用于实时展示前方障碍物的位置和距离,辅助路径规划和避障决策。
    示例:扫地机器人上使用雷达扫描界面展示房间布局,标记出家具和其他障碍物的位置。
  2. 安防监控系统
    在智能家居或工业环境中,用于展示运动检测结果或入侵警报,帮助用户及时发现异常情况。
    示例:家庭安防摄像头系统中,通过雷达界面显示人员活动区域,提醒用户注意潜在的安全威胁。
  3. 教育与培训工具
    制作基于Arduino的学习装置,帮助学生理解编程概念或电子元件的工作原理,并通过雷达界面生动地展示实验结果。
    示例:物理实验仪器上的显示屏模拟声纳探测过程,让学生更直观地了解回声定位原理。
  4. 娱乐与游戏
    在互动游戏中,使用雷达界面作为玩家视角的一部分,增加游戏的真实感和沉浸感。
    示例:飞行模拟器游戏中,雷达界面显示敌机位置和导弹轨迹,提升玩家的游戏体验。

注意事项

  1. 算法优化
    雷达扫描涉及大量的重复绘图操作,需确保算法高效,避免不必要的计算开销。
    考虑采用增量更新的方法,仅重绘发生变化的部分,减少全屏刷新带来的性能损耗。
  2. 屏幕刷新频率
    控制好每次刷新的时间间隔,既要保证动画流畅,又要避免过高的刷新率导致处理器负担过重。
    建议初始设定一个适中的刷新频率(如每秒20帧),然后根据实际效果进行微调。
  3. 内存管理
    动态绘图过程中可能会占用较多的内存,尤其是在处理复杂的图形或较大的屏幕分辨率时。
    对于频繁更新的数据,考虑使用局部变量而非全局变量,减少内存泄漏的风险。
  4. 硬件兼容性
    根据所使用的传感器类型(如超声波、红外、激光雷达等),调整数据采集和处理逻辑,确保准确反映实际环境信息。
    测试不同传感器与OLED屏幕的组合效果,选择最适合的硬件配置方案。

在这里插入图片描述
1、基于Processing的雷达扫描效果模拟

int offset = 10;
float x, y;
float r = 300;
float a = 0;
float pi = 3.141592697932;

void setup() {
  size(600, 600);
  background(0);
}

void draw() {
  background(0);
  x = r * cos(a);
  y = r * sin(a);

  // 绘制扫描线
  fill(0, 180, 0);
  line(width / 2, height / 2, width / 2 + x, height / 2 + y);

  // 绘制坐标轴
  fill(0, 110, 0, 50);
  for (int i = 0; i < 4; i++) {
    line(width / 2, height / 2, width / 2 + r * cos(i * pi / 2), height / 2 + r * sin(i * pi / 2));
  }

  // 绘制同心圆
  stroke(0, 110, 0);
  for (int j = 1; j < 7; j++) {
    ellipse(width / 2, height / 2, 2 * 50 * j, 2 * 50 * j);
  }

  // 刻度标识距离
  fill(160, 250, 160);
  for (int ii = 0; ii < 4; ii++) {
    for (int t = 0; t < 6; t++) {
      text(t * 50, width / 2 + t * 50 * cos(ii * pi / 2), height / 2 + t * 50 * sin(ii * pi / 2));
    }
  }

  fill(0, 180, 0);
  text("Angle:" + (a / pi) * 180, 480, 580);

  // 扫描角度变化
  a = a + 0.0124;
}

要点解读
动态扫描线:使用cos和sin函数计算扫描线的端点坐标,通过不断更新角度a实现扫描线的动态旋转。
图形绘制:利用Processing的绘图功能,绘制同心圆、坐标轴和刻度,模拟雷达表盘。
适用场景:主要用于教学演示或简单的视觉效果展示,适合初学者学习雷达扫描的基本原理。

2、Arduino与Processing结合的雷达扫描系统

#include <Servo.h>

Servo servo; // 创建舵机对象
const int trigPin = 9;  // 超声波模块的Trig引脚连接到Arduino的D9
const int echoPin = 10; // 超声波模块的Echo引脚连接到Arduino的D10
int pos = 0;            // 舵机的当前位置

void setup() {
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  servo.attach(8); // 将舵机连接到Arduino的D8引脚
}

void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // 从0°到180°旋转
    servo.write(pos); // 控制舵机旋转到指定位置
    delay(15);        // 等待舵机到达位置
    long duration = ping();
    float distance = duration * 0.0343 / 2;
    Serial.print(pos); // 发送角度
    Serial.print(",");
    Serial.println(distance); // 发送距离
  }

  for (pos = 180; pos >= 0; pos -= 1) { // 从180°到0°旋转
    servo.write(pos);
    delay(15);
    long duration = ping();
    float distance = duration * 0.0343 / 2;
    Serial.print(pos); // 发送角度
    Serial.print(",");
    Serial.println(distance); // 发送距离
  }
}

long ping() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  return pulseIn(echoPin, HIGH);
}

Processing代码

import processing.serial.*;
Serial myPort;
String data;
int angle, distance;

void setup() {
  size(600, 600);
  myPort = new Serial(this, "COM4", 9600); // 根据实际串口号修改
}

void draw() {
  background(0);
  if (myPort.available() > 0) {
    data = myPort.readStringUntil('\n');
    if (data != null) {
      String[] values = split(data, ',');
      angle = int(values[0]);
      distance = int(values[1]);
    }
  }
  // 绘制雷达扫描效果
  drawRadar(angle, distance);
}

void drawRadar(int angle, int distance) {
  translate(width / 2, height / 2);
  rotate(radians(angle));
  stroke(255, 0, 0);
  line(0, 0, 0, -distance * 2); // 根据距离绘制目标点
}

要点解读
硬件结合:通过舵机控制超声波传感器的旋转,Arduino采集角度和距离数据,并通过串口发送给Processing。
数据处理:Processing接收串口数据,解析角度和距离,并在屏幕上绘制雷达扫描效果。
适用场景:适用于需要实时显示雷达扫描数据的场景,如小型机器人避障系统的可视化。

在这里插入图片描述
3、基础雷达扫描动画(动态旋转线 + 渐隐尾迹)​​

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define RADAR_CENTER_X 64
#define RADAR_CENTER_Y 32
#define MAX_RADIUS 30

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float scanAngle = 0;  // 当前扫描角度(弧度)
unsigned long lastScanTime = 0;

void drawRadar() {
  display.clearDisplay();
  
  // 1. 绘制雷达固定元素
  display.drawCircle(RADAR_CENTER_X, RADAR_CENTER_Y, MAX_RADIUS, SSD1306_WHITE);  // 外圈
  display.drawCircle(RADAR_CENTER_X, RADAR_CENTER_Y, MAX_RADIUS/2, SSD1306_WHITE); // 内圈
  
  // 2. 计算扫描线终点坐标(极坐标转直角坐标)
  int scanEndX = RADAR_CENTER_X + MAX_RADIUS * cos(scanAngle);
  int scanEndY = RADAR_CENTER_Y + MAX_RADIUS * sin(scanAngle);
  
  // 3. 绘制扫描线
  display.drawLine(RADAR_CENTER_X, RADAR_CENTER_Y, scanEndX, scanEndY, SSD1306_WHITE);
  
  // 4. 绘制渐隐尾迹(保留最近3帧的扫描线)
  for (int i = 1; i <= 3; i++) {
    float prevAngle = scanAngle - i * 0.2;
    int prevEndX = RADAR_CENTER_X + MAX_RADIUS * cos(prevAngle);
    int prevEndY = RADAR_CENTER_Y + MAX_RADIUS * sin(prevAngle);
    display.drawLine(RADAR_CENTER_X, RADAR_CENTER_Y, prevEndX, prevEndY, SSD1306_WHITE);
  }
  
  display.display();
}

void setup() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.setTextColor(SSD1306_WHITE);
}

void loop() {
  if (millis() - lastScanTime > 30) {  // 控制扫描速度(30ms/帧)
    lastScanTime = millis();
    scanAngle += 0.1;  // 角度增量
    if (scanAngle > 2 * PI) scanAngle = 0;  // 重置扫描
    drawRadar();
  }
}

​​要点解读​​
​​极坐标转换​​
使用 cos() 和 sin() 计算扫描线终点坐标,实现旋转效果。
​​尾迹模拟​​
通过绘制前几帧的扫描线(prevAngle)模拟雷达余辉。
​​性能优化​​
固定帧间隔(30ms)保证动画流畅性,避免 delay() 阻塞。

4、目标检测雷达(超声波模拟 + 动态标记)​​

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define RADAR_CENTER_X 64
#define RADAR_CENTER_Y 32
#define MAX_RADIUS 30

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float scanAngle = 0;
struct Target {
  float angle;
  float distance;
  unsigned long detectedTime;
};
Target targets[5];  // 存储最多5个目标

void simulateTargetDetection() {
  // 随机生成目标(实际项目替换为超声波/红外传感器数据)
  if (random(100) > 95) {  // 5%概率生成新目标
    for (int i = 0; i < 5; i++) {
      if (targets[i].distance == 0) {  // 寻找空位
        targets[i] = {
          .angle = random(360) * PI / 180.0,  // 随机角度
          .distance = random(10, MAX_RADIUS), // 随机距离
          .detectedTime = millis()
        };
        break;
      }
    }
  }
}

void drawTargets() {
  for (int i = 0; i < 5; i++) {
    if (targets[i].distance > 0) {
      // 计算目标坐标
      int x = RADAR_CENTER_X + targets[i].distance * cos(targets[i].angle);
      int y = RADAR_CENTER_Y + targets[i].distance * sin(targets[i].angle);
      
      // 绘制目标(带淡出效果)
      if (millis() - targets[i].detectedTime < 2000) {  // 2秒后消失
        display.fillCircle(x, y, 2, SSD1306_WHITE);
      } else {
        targets[i].distance = 0;  // 清除过期目标
      }
    }
  }
}

void loop() {
  if (millis() - lastScanTime > 30) {
    lastScanTime = millis();
    scanAngle += 0.1;
    if (scanAngle > 2 * PI) scanAngle = 0;
    
    simulateTargetDetection();  // 模拟目标检测
    display.clearDisplay();
    drawRadarBase();  // 绘制雷达基础图形(同案例1)
    drawTargets();    // 绘制目标
    display.display();
  }
}

​​要点解读​​
​​目标数据结构​​
使用 Target 结构体存储目标的极坐标(角度+距离)和存活时间。
​​传感器集成​​
simulateTargetDetection() 可替换为真实传感器逻辑(如超声波测距)。
​​动态标记​​
目标显示2秒后自动消失(通过 millis() 计时),模拟真实雷达刷新。

5、交互式雷达(旋钮控制 + 距离标尺)​​

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Encoder.h>  // 用于旋钮控制

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define ENCODER_A 2
#define ENCODER_B 3

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Encoder myEncoder(ENCODER_A, ENCODER_B);

int maxDetectionRange = 50;  // 可调探测范围(通过旋钮)

void drawRangeScale() {
  display.setTextSize(1);
  display.setCursor(10, 10);
  display.print("Range: ");
  display.print(maxDetectionRange);
  display.print("m");
  
  // 绘制距离刻度
  for (int r = 10; r <= maxDetectionRange; r += 10) {
    int pixelRadius = map(r, 0, maxDetectionRange, 0, MAX_RADIUS);
    display.drawCircle(RADAR_CENTER_X, RADAR_CENTER_Y, pixelRadius, SSD1306_WHITE);
  }
}

void loop() {
  // 旋钮控制探测范围
  int encoderChange = myEncoder.read() / 4;  // 降低灵敏度
  if (encoderChange != 0) {
    maxDetectionRange = constrain(maxDetectionRange + encoderChange, 10, 100);
    myEncoder.write(0);
  }
  
  if (millis() - lastScanTime > 30) {
    lastScanTime = millis();
    scanAngle += 0.1;
    display.clearDisplay();
    drawRangeScale();  // 绘制可调标尺
    drawRadarBase();   // 同案例1
    display.display();
  }
}

​​要点解读​​
​​交互控制​​
使用旋转编码器(Encoder 库)动态调整探测范围。
​​动态标尺​​
drawRangeScale() 根据 maxDetectionRange 实时更新距离刻度。
​​约束处理​​
constrain() 限制范围在10-100米,避免数值溢出。

注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驴友花雕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值