Funpack - S3-5 - Arduino UNO R4 - 模拟赛车挡位指示(RacingGear)
该项目使用了Arduino UNO R4,实现了模拟赛车挡位指示(RacingGear)的设计,它的主要功能为:实时显示模拟赛车游戏中的挡位,便于车手更好的驾驶赛车。
标签
Arduino
Funpack活动
嵌入式
LED矩阵
模拟赛车
arilink
更新2025-01-13
34

项目背景

首先由衷的祝愿电子森林发展的越来越好,自从参与Funpack项目以来,接触了越来越多的开发板,也拓宽了很多知识面,所以无需犹豫,果断参与第四期。

本项目即是实现一个赛车模拟器的配套外设,用于玩家在使用赛车模拟器的时候,可以像驾驶真实汽车一样,直观的获取到比赛中最重要的时速、转速、挡位等信息,以达到更好的成绩,Adruino UNO R4 WIFI(以下简称Arduino)有一个12x8 的LED矩阵,用作赛车模拟器的挡位指示非常合适。

项目详情

项目使用ESP32作为联网模块,将Arduino连接到局域网后,与上位机建立通讯,上位机实时获取游戏里赛车的遥测数据并通过局域网发送给Arduino,Arduino驱动LED矩阵显示挡位信息。项目架构如下:

IMG-Funpack 4 - Arduino - RacingGear-20241202213641.png设计思路

  1. 上位机通过UDP与游戏建立通讯,获取到游戏中赛车的实时遥测数据。
  2. 上位机和Arduino之间建立UDP通讯,将遥测数据下发到Arduino
  3. Arduino有挂载ESP32的WIFI模组,可以与上位机在局域网内建立通讯。
  4. Arduino有8x12的LED矩阵,可以用来自由定制要显示的数字或字母等信息

硬件介绍

Pin Out信息

Pasted image 20241206142626.png

系统框图

Pasted image 20241206142427.png

LED矩阵Map

Pasted image 20241206142532.png

软件流程

Pasted image 20241203173220.png

如上图所示,Arduino在上电后,通过配置的WIFI SSID和PassWord连接到局域网,确定网络连接成功后,开启UDP与上位机建立通讯,当收到上位机下发的数据后,使用结构体解析出需要的Gear挡位信息,并更新LED矩阵的内容显示。

开发过程

Ardruino官方提供了非常丰富的资料,跟随官方文档和示例,能够很快速的完成本次项目的开发
https://docs.arduino.cc/tutorials/uno-r4-wifi/wifi-examples/

显示内容准备

const uint32_t gear_0[] = {
  0xf009009,
  0x900900,
  0x900f0000
};
const uint32_t gear_1[] = {
  0xc014004,
  0x400400,
  0x401f0000
};
const uint32_t gear_2[] = {
  0xf001001,
  0xf00800,
  0x800f0000
};

//......其余0-8的显示内容省略

UDP通讯

#include "Arduino_LED_Matrix.h"   // Include the LED_Matrix library
#include "frames.h"               // Include a header file containing some custom icons
#include <WiFiS3.h>
#include <string.h>
#define SECRET_SSID "Arilink"
#define SECRET_PASS "********"


int status = WL_IDLE_STATUS;
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key index number (needed only for WEP)


unsigned int localPort = 2390;      // local port to listen on


char packetBuffer[256]; //buffer to hold incoming packet
uint8_t recvBuffer[4];
char  ReplyBuffer[] = "acknowledged\n";       // a string to send back


WiFiUDP Udp;
ArduinoLEDMatrix matrix;          // Create an instance of the ArduinoLEDMatrix class


#pragma pack(push) // 将当前对齐方式推入堆栈
#pragma pack(1)   // 设置一字节对齐
 
typedef struct  {
    int8_t    gear;
    uint8_t   reserved;
    uint16_t  led_num;
    uint16_t  speed;
    uint16_t  rpm;
}CarStatus;
 
#pragma pack(pop)  // 将对齐方式设置回之前的值


void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }


  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }


  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);


    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to WiFi");
  printWifiStatus();


  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  Udp.begin(localPort);
  matrix.begin();                 // Initialize the LED matrix
}

遥测数据解析

void loop() {
  // Load and display the "chip" frame on the LED matrix
  // for(int i = -1; i < 9; i++)
  // {
  //   update_gear_ind(i);
  //   delay(500);  // Pause for 500 milliseconds (half a second)
  // }
  // // Turn off the display
  // matrix.clear();
  // delay(1000);

  // // Print the current value of millis() to the serial monitor
  // Serial.println(millis());
    // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {
   // Serial.print("Received packet of size ");
   // Serial.println(packetSize);
    //Serial.print("From ");
   // IPAddress remoteIp = Udp.remoteIP();
   // Serial.print(remoteIp);
   // Serial.print(", port ");
   // Serial.println(Udp.remotePort());
    // read the packet into packetBuffer
    int len = Udp.read(recvBuffer, 8);
    // if (len > 0) {
    //   packetBuffer[len] = 0;
    // }
    CarStatus *curCarStatus = (CarStatus*)recvBuffer;
    char logBuffer[50];
    //snprintf(logBuffer,sizeof(logBuffer),"Speed:%d Gear:%d RPM:%d",curCarStatus->speed,curCarStatus->gear,curCarStatus->rpm);
    if((curCarStatus->speed)!=0)
    {
      update_gear_ind(curCarStatus->gear);
    }
    Udp.endPacket();
  }
}

挡位信息更新

void update_gear_ind(int gear)
{
  switch(gear)
  {
    case 0:
      matrix.loadFrame(gear_0);
    break;
    case 1:
      matrix.loadFrame(gear_1);
    break;
    case 2:
      matrix.loadFrame(gear_2);
    break;
    case 3:
      matrix.loadFrame(gear_3);
    break;
    case 4:
      matrix.loadFrame(gear_4);
    break;
    case 5:
      matrix.loadFrame(gear_5);
    break;
    case 6:
      matrix.loadFrame(gear_6);
    break;
    case 7:
      matrix.loadFrame(gear_7);
    break;
    case 8:
      matrix.loadFrame(gear_8);
    break;
    case -1:
      matrix.loadFrame(gear_r);
    break;
    default:
      matrix.loadFrame(gear_0);
    break;
  }
}
//........

项目展示

项目演示视频已上传到B站,链接如下:

演示视频


附件下载
RacingGear.rar
RacingGear源代码
团队介绍
self
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号