Bicycle Powermeter ANT+/BLE

Hey Arduino Community!
I'm really interested in building my own Powermeter for my Bicycle.
To give you an example:

But I don't want to send the date to a second Arduino, I would like to send it to my Garmin Edge 530 device. Does anyone of you have experience on that topic and could give me an overview how complicated this project would be and if it's possible to manage this project with a low level of arduino experience?
looking forward to your Answers!
Regards,
Felix

How much research have you already done? For example, do you know how the Garmin device might accept external data?

1 Like

Without the code available, impossible to suggest communication changes.

Thanks for your answer!
Most of the Projects with arduino and Garmin use ANT+. The Garmin Edge is also able to connect with a Bluetooth sensor, so I wondered if it wouldn't be easier to connect it with BT to the Arduino. However, I found nothing in my reseaches that someone connected a Arduino with Bluetooth to the Garmin, so I don't know if that would work.

you mean the code for the example I gave?

Please post the code here using code tags. The code You are working on.
No helper likes archeology in tutorials, videos, projects etc.

cujomalainey/antplus-arduino: An Implementation of the ANT+ Network on top of ant-arduino (github.com)

1 Like

code for the transmitter

// ========================================================================================
// Programm zur Bestimmung des Neigungswinkels mittels Kalmanfilter und des MPU6050-Sensors
// ========================================================================================

#include <SPI.h>
#include "RF24.h"
#include "Wire.h"
#include "I2Cdev.h"      // I2Cdev and MPU6050 must be installed as libraries
#include "MPU6050.h"     // class default I2C address is 0x68 = AD0 low
#include <math.h>

MPU6050 accelgyro;

int16_t ax, ay, az;   // Beschleunigungswerte in x-,y- und z-Richtung des MPU6050-Sensors
int16_t gx, gy, gz;   // Winkelgeschwindigkeitswerte in x-,y- und z-Richtung des MPU6050-Sensors

float data[2];                    // per Funk übertragenes Datenarray für Leistung P, Umdrehungszeit tau etc.
int sensorPin = A0;               // select the input pin for the force measurement

float Winkel_neu, Winkel_alt;     // aktueller und alter Neigungswinkel
float gz_alt, gz_neu;             // aktuelle und alte Winkelgeschwindigkeit

float time_alt, time_neu;         // aktuelle und alte Zeit
float t_Umdrehung_Start;          // Startzeit einer Umdrehung
float t_Umdrehung_Ende;           // Endzeit einer Umdrehung
float t_Umdrehung;                // Zeit für eine vollständige Umdrehung
float v;                          // Mittlere Pedalgeschwindigkeit
float r;                          // Kurbellänge
int n;                            // Anzahl der Kraftmessungen während einer Umdrehung

float F;                          // Mittelwert der während einer Umdrehung wirkenden Kraft
float k;                          // Kalibrierfaktor bzgl. welcher Zahlenwert [0,1023] welcher Kraft in Newton entspricht 
int offset;                       // offset der Eingangsspannung noch ohne Belastung, also bei F = 0
float P;                          // mittlere Leistung P


// Funkmodul NRF24L01 mit Arduino-Pins verbinden:
// SCK -> 13 // MISO -> 12 // MOSI -> 11 // CSN -> 10  // CE -> 9
// SPI-Bus Pins 9 und 10
// ==============================================================

const uint64_t pipe = 0xE8E8F0F0E1LL;   // Adresse des Übertragungskanals des NRF24L01

RF24 radio(9,10);




// ======================
// ======== SETUP =======
// ======================

void setup()
   {
    radio.begin();
    radio.openWritingPipe(pipe);        // Sende-Kanal öffnen  
     
     
    // join I2C bus (I2Cdev library doesn't do this automatically)
    Wire.begin();

    // initialize serial communication
    Serial.begin(115200);

    // initialize device
    accelgyro.initialize();
    
    // =====================================================================================
    // read raw accel/gyro measurements from device
    // Ausgabewerte-Acc: Auflösung 2g:  16384/g    Auflösung 4g:  8192/g
    // Ausgabewerte-Gyro: Auflösung 250°/s: 131/°/s ; 500°/s: 65.5/°/s ; 2000°/s: 16.375/°/s
    // =====================================================================================
        
    //Sensor output scaling (2g,4g,8g,16g)
    accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_8);   // Sensor konkret auf 8g eingestellt
   
    //Sensor output scaling (250°/s,500°/s,2000°/s)
    accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_500);   // Sensor konkret auf 500°/s eingestellt
    

    // verify connection
    //Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
    
    time_alt = 0.0;
    Winkel_alt = 0.0;
    gz_alt = 0.0;
    r = 0.175;       // Kurbellänge in m
    k = 292.0;       // Kalibrierfaktor in Newton/Volt
    offset = 0.0;    // offset ohne Belastung
    
    for (int i = 0; i < 5; i++)
       {
        offset = offset + analogRead(sensorPin);   // Ermittlung der mittleren (5 Messungen) offset-Spannung noch ohne Belastung
       }
       
    offset = offset / 5.0;
    
    data[0] = 5000.0 * analogRead(sensorPin) / 1024.0;    // einmalige Übergabe des Spannungswerts in mV ohne Belastung!
        
    /*    
    Serial.print(data[0]);
    Serial.print("   ");
    Serial.println(data[1]);
    */
    
    radio.write(data, 8);       // ACHTUNG: Adresse (data) und Länge (pro float 4 byte, d.h. für 2 Zahlen 8 eintragen) der zu sendenden Daten!
    delay(2000); 
    
   }


// ==============================
// ======== HAUPTSCHLEIFE =======
// ==============================

void loop()
   {
    n = 0;  // Zählvariable auf 0 gesetzt
    F = 0;  // Kraftmittelwert wird auf 0 gesetzt
    
    t_Umdrehung_Start = micros();     // Ermittlung der Startzeit einer Umdrehung
     
    do
       {
        accelgyro.getRotation(&gx, &gy, &gz);                     // Einlesen der aktuellen Winkelgeschwindigkeiten
        // accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);    // Einlesen der aktuellen Beschleunigungen und Winkelgeschwindigkeiten
    
        gz_neu = -gz;   // neue Winkelgeschwindigkeit
    
    
        // Berechnung des neuen Winkel mittels altem Winkel und dem Mittelwert aus alter und neuer Winkelgeschwindigkeit:
        // ==============================================================================================================
    
        time_neu = micros();    // aktuelle Laufzeit des Programms in µs
    
        Winkel_neu = Winkel_alt + 0.5 * ((gz_alt + gz_neu) / 65.5) * ((time_neu - time_alt) / 1000000.0);
        
          
        if (Winkel_neu < 0)   // Neustart bei negativen Winkel
           {
            Winkel_neu = 0.0;
            t_Umdrehung_Start = micros();
            n = 0;  // Zählvariable auf 0 gesetzt
            F = 0;  // Kraftmittelwert wird auf 0 gesetzt
           }
    
        F = F + k * (5.0 * (analogRead(sensorPin) - offset) / 1023.0);  // Integration über alle während einer Umdrehung wirkenden Kräfte; Faktor k = Newton/Volt !
    
        /* 
        Serial.print(Winkel_neu,0);
        Serial.print("   ");
        Serial.println(F/n,1);
        */
        
        /*  
        data[0] = Winkel_neu;
        data[1] = F / n;
        */
        
        radio.write(data, 8);       // ACHTUNG: Adresse (data) und Länge (pro float 4 byte, d.h. für 2 Zahlen 8 eintragen) der zu sendenden Daten!
        
        
        // Werteübergabe
        // =============
    
        gz_alt = gz_neu;
        time_alt = time_neu;
        Winkel_alt = Winkel_neu;
        n = n + 1;               // Anzahl der Messungen um 1 erhöht
        
       }
    while (Winkel_neu < 360);    // Ausstieg aus der Schleife, wenn der Winkel > 360°, sprich bei einer vollen Umdrehung


    // ============================
    // == Vollständige Umdrehung ==    
    // ============================

    t_Umdrehung_Ende = micros();        // Ermittlung der Endzeit einer Umdrehung
    
    Winkel_alt = Winkel_alt - 360.0;    // Reduzierung des Winkels auf das Intervall [0,360]
    
    F = F / n;                          // Berechnung der mittleren Kraft während einer Umdrehung
    
    t_Umdrehung = (t_Umdrehung_Ende - t_Umdrehung_Start) / 1000000.0;    // Berechnung der Umlaufszeit in Sekunden
    
    v = 2.0 * r * 3.141592654 / t_Umdrehung;    // Berechnung der mittleren Pedalgeschwindigkeit;
    
    P = 2.0 * F * v;                            // Berechnung der mittleren Leistung P
    
    
    // =========================
    // Datenübertragung per Funk
    // =========================
    
    data[0] = P; 
    data[1] = t_Umdrehung;
    
    /*    
    Serial.print(data[0]);
    Serial.print("   ");
    Serial.println(data[1]);
    */
    
    radio.write(data, 8);       // ACHTUNG: Adresse (data) und Länge (pro float 4 byte, d.h. für 2 Zahlen 8 eintragen) der zu sendenden Daten!
         
   }

Fine. Thanks.
Identify the radio specific details in the code and comment them out.
Then add the needed BT corresponding pieces.
Note that You need to install the BT system. You can't just change radio lines of code into any lookalike BT code.
Get comfortable with the use and setup of BT.

Many beginners search for a project to copy, and they waist their time. There is always code, circuitry eyc. that need "hands on".

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.