Timekeeping

by Aristurtle in Circuits > Arduino

472 Views, 8 Favorites, 0 Comments

Timekeeping

ProofOfConcept.jpg

In Formula student competition you have to be as fast as possible to have a chance to compete with other teams. Knowing how fast your lap times are, is a competitive advantage. In Aristurtle, we managed to keep track of lap times in an automated and innovative way. The system in its simplest form, can be divided into a receiver and a transmitter. In the transmitter side an ultrasonic sensor is used for the detection of the car. The working principle of the sensor is based on longitudinal sound waves and the reflection phenomenon. Each time the sensor detects the car, the transmitter automatically sends that information wirelessly to the receiver. The lap time, the unknown of the equation, is being calculated on the receiver side. The receiver solves the equation by calculating the time between the messages he received.

Timekeeping Architecture

Architecture.png

The system was tested with success in all kinds of dynamic events that FSAE organizes. For example, for the acceleration event we came up with the following architecture.

Hardware

TX.jpg
RX componets.jpg
Final Design.jpg
PCBs.jpg

The transmitter subsystem consists of :

1 x Ultrasonic Sensor HC-SR05

1 x Arduino NANO

1 x nRF24L01 base module

1 x E01-ML01DP5 V6.5

Power Supply : 6700mAh power bank

The receiver subsystem consists of :

1 x nRF24L01 base module

1 x E01-ML01DP5 V6.5

1 x Arduino UNO

Power Supply : From PC through USB

Schematic Designs

RX Sc.png
TX Sc.png

How to Order PCBs From JLCPCB

Screenshot (328).png

Here, we would like to take this opportunity to express our gratitude towards JLCPCB for providing the PCBs and making this project a reality. You can order your own PCBs from JLCPCB by clicking here. First of all, you have to add a gerber file. Gerber file is a file that is exported from the software that you design the PCB. In our case that software is Altium Designer. The next step is to select all the characteristics you require for your PCB. After that, you will have to add the remaining files, such as the bom files and the pick and place files. Upload these files and you are ready to complete the order.

Timekeeping Interface

Screenshot (123).png

The serial data from the USB is being transferred automatically to an excel that is being updated in real time. To do that we used Data Streamer and you can find it here.

Proof of Concept

ProofOfConcept.jpg

We tested the system with the receiver on the left and the transmitter on the right. Note that this set up is suitable for keeping the time for the Skidpad Event. We also found that the maximum distance that these modules have is around 400m in line of sight (LoS) by sending 1 byte/s.

Receiver_Skidpad Code

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <stdio.h>
#include "printf.h"
#include <RF24Network.h>

// Power Amplifier available levels Levels : RF24_PA_MIN (-18dBm), RF24_PA_LOW(-12dBm), RF24_PA_HIGH(-6dBm) AND RF24_PA_MAX(0dBm)
#define PA_LEVEL RF24_PA_MAX // FIND 100 uF between VCC and GND
// Available Data Rates : RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps . Choosing 250kbs we get the longest range.
#define DataRate RF24_250KBPS

// Create a RF24 object
RF24 radio(7, 8);  // CE, CSN
RF24Network network(radio);
const uint16_t this_node = 00 ;

// Timekeeping with millis()
unsigned long StartTime, CurrentTime, ElapsedTime = 0   ;

uint8_t data ;
int counter, lap, j = 0;
// Counter is a variable which gives me the ability to seperate the messages so I can measure the elapsed time between them.

void setup()
{
  
// --- Serial communication Start ---

  SPI.begin();
  Serial.begin(9600);
 
  
// --- Serial communication End ---

// --- NRF Configuration Start ---
  
  radio.begin();
  network.begin(90, this_node);  // (channel, node address)
  radio.enableDynamicPayloads();
  
  radio.setDataRate(DataRate);
  radio.setPALevel(PA_LEVEL);
  // radio.setPayloadSize();
  
  radio.setAutoAck(true); // Checksum Logic...In the end of each packet there is the CRC number (1-2 byte). Due to the fact that the receiver knows 
                          // how to calculate the CRC, he can inform the sender if the message was correct or not.
                          // If the CRC is correct, receiver send an ACK message to the sender, and basically tells him to continue to send
                          // the next packet of data. If the receiver does not send the ACK message, the sender must send the packet again.
  
  
  radio.enableDynamicPayloads();    // Must have for multi pipe receiving
  
  printf_begin(); 
  radio.printDetails(); // don't printDetails in excel...It works properly only in Serial Monitor.
 
  radio.startListening();           // Put this module in receiver mode.
  
  
// --- NRF Configuration End ---

}

void loop()
{
  network.update();
  while (network.available()) 
  {
    RF24NetworkHeader header;
    network.read(header, &data, sizeof(data)); // Read the incoming data
    counter++ ;
    if(counter == 1)
    {
      if(j == 0)
      {
         StartTime = starttime();
         lap++;
      }
      if (j > 0)
      {
        ElapsedTime = elapsedtime();
        Serial.print(lap);
        Serial.print(",");
        Serial.println(ElapsedTime);
        lap++;
      }
      j = 1 ;
    }
    if(counter == 2)
    {
      // Serial.print("First Lap Time: ");
      ElapsedTime = elapsedtime();
      // The following prints are in this way in order to read the data from excel ( with Data Streamer )
      Serial.print(lap);
      Serial.print(",");
      Serial.println(ElapsedTime);
      lap++;
      counter = 0 ;
    }
  }
}

unsigned long starttime()
{
  return millis();
}

unsigned long elapsedtime()
{
  CurrentTime = millis();
  ElapsedTime = CurrentTime - StartTime ; 
  StartTime = CurrentTime ;
  return ElapsedTime ;
}

Transmitter Code

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <stdio.h>  // It doesn't work the printf without this!!!
#include "printf.h"
#include <NewPing.h>
#include <RF24Network.h>


// Power Amplifier available levels Levels : RF24_PA_MIN (-18dBm), RF24_PA_LOW(-12dBm), RF24_PA_HIGH(-6dBm) AND RF24_PA_MAX(0dBm)
#define PA_LEVEL RF24_PA_MAX
// Available Data Rates : RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps . Choosing 250kbs we get the longest range.
#define DataRate RF24_250KBPS
#define CE_Pin 9
#define CSN_Pin 8

// Configuration of Ultrasonic sensor :
#define PinToEcho 5 // Attach D5 of Arduino Nano to echo pin of Ultrasonic sensor
#define PinToTrig 4 // Attach D4 of Arduino Nano to trig pin of Ultrasonic sensor
#define MAX_Distance 250
NewPing ultrasonic(PinToTrig, PinToEcho, MAX_Distance);
int distance = 0 ; // for Serial print purposes


// Variable that indicates if the car has passed or not
uint8_t passed = 0 ;

// create an RF24 object
RF24 radio(CE_Pin, CSN_Pin);
RF24Network network(radio) ;
const uint16_t this_node = 01 ;    // Address of our node in Octal format.
const uint16_t master00  = 00 ;    // Address of the other node in Octal format

// LED
#define RES1 1 // For increasing power consumption in order the powerbank not to get into sleep mode.
#define RES2 3 //

void setup()
{
  
  SPI.begin();
  Serial.begin(115200);
  // --- NRF Configuration Start ---
  
  radio.begin();
  network.begin(90, this_node);
  
  radio.setDataRate(DataRate); 
  radio.setPALevel(PA_LEVEL);
  radio.enableDynamicPayloads();
  
  printf_begin();
  radio.printDetails();
  
  radio.stopListening();
  
  // --- NRF Configuration End ---
  pinMode(RES1,OUTPUT);
  pinMode(RES2,OUTPUT);
}


void loop()
{
  digitalWrite(RES1, HIGH);
  digitalWrite(RES2, HIGH);
  network.update();
  passed = checkIfPassed();
  if(passed)
  {
     RF24NetworkHeader header1(master00); // send to master node. 
     network.write(header1, &passed, sizeof(passed));
     delay(2000);
  }  
}
uint8_t checkIfPassed()
{
  passed = 0 ;
  unsigned int uS = ultrasonic.ping();  // Send ping, get ping time in microseconds (uS).
  distance = ultrasonic.convert_cm(uS);
  
  if (distance > 1 && distance < 200)
  {
    Serial.print("Distance: ");
    Serial.print(distance);    // Convert ping time to distance and print result (0 = outside set distance range, no ping echo)
    Serial.print(" cm , passed: ");
    passed = 1 ;
    Serial.println(passed);
  }

  return passed ;
}