Project showcase
Exercise Bike - as a Gaming Device for PC

Exercise Bike - as a Gaming Device for PC

Alteration of the exercise bike for games on the PC, in car simulators and others.

  • 997 views
  • 0 comments
  • 2 respects

Components and supplies

About this project

Bike pedaling boring lesson. In order to make the process more interesting, I decided to connect it to a PC for the ability to play various computer games simulators. We pedal and drive for example a truck.

Speed ​​depends on the speed of the pedals. For braking it is necessary to pedal back. To determine the speed and direction of rotation of the pedals, 2 Hall sensors are used.

18 pairs of niode magnets are glued on the cadence disc. The project is assembled on two Arduino Micro and Arduino Nano boards.

Arduino Micro programmed as a dual-axis joystick with 15 buttons. Arduino Nano used as a port expander. Communication is via the SPI bus. Installation is made on a breadboard for soldering.

The speed of pedaling and the maximum steering angle are carried out using potentiometers.

Code

Leonardo_final2.inoArduino
#include <SPI.h>
#include <Wire.h>
#include "spi_master.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Joystick.h>

Adafruit_SSD1306 display(128, 32, &Wire, -1);


Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
                   15, 0,                  // Button Count, Hat Switch Count
                   true, true, false,     // X and Y, but no Z Axis
                   false, false, false,   // No Rx, Ry, or Rz
                   false, false,           // No rudder or throttle
                   false, false, false);  // No accelerator, brake, or steering


int16_t X = 0;          //   
int16_t XL = 0;         //    
int16_t XR = 0;         //    
int16_t XF = 0;         //   X  ()
int16_t XLm = 490;      //    
int16_t XRm = 500;      //    
int16_t wheelAngle = 0; //   

int8_t Y = 0;

//    , , 
uint8_t hours = 0;
uint8_t minutes = 0;
uint8_t seconds = 0;
//    long   
long previousMillis = 0;        //     
long interval = 1000;           //   /  (1 )
long lastTime = 0;

void setup (void)
{
  mater_init();
  // 
  Serial.begin (9600);
  Serial.println ();
  //  
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  //   (  -  )
  pinMode(13, OUTPUT);

  master_arr [0] = 0; // n/a
  master_arr [1] = 0; // n/a
  master_arr [2] = 0; // n/a

  //    ( )
  Joystick.begin(false);
  Joystick.setYAxisRange(-64, 64);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}


void loop (void)
{
  refreshSPI ();

  unsigned long currentMillis = millis();

  //     ,   
  if (currentMillis - previousMillis > interval) {
    //    
    previousMillis = currentMillis;

    //...  lastTime      +1
    lastTime = millis();
    seconds++;
    //      60,        +1...
    if (seconds >= 60) {
      seconds = 0;
      minutes++;
    }
    // ...   ...
    if (minutes >= 60) {
      minutes = 0;
      hours++;
    }
    // ...       
    if (hours >= 24) {
      hours = 0;
    }
  }

  // 
  if (!digitalRead(7)&&!digitalRead(4)) {
  seconds = 0;
  minutes = 0;
  hours = 0;  
  }


  // /
  digitalWrite(13, bitRead(slave_arr [1], 7));

  wheelAngle = map(analogRead(A5), 2, 1020, 90, 20);
  wheelAngle = wheelAngle * 10;

  Joystick.setXAxisRange(-wheelAngle / 2, wheelAngle / 2);

  X =  map(analogRead(A0), 0, 1023, 1023, 0);

  XL = map(analogRead(A1), 470, 720, 0, 350);
  if (XL < 0) XL = 0;
  if (XL > 350) XL = 350;

  XR = map(analogRead(A2), 580, 340, 0, 350);
  if (XR < 0) XR = 0;
  if (XR > 350) XR = 350;

  if (X >= XLm && X <= XRm) {
    //  
    XF = 0;
  } else if (X > XRm) {
    //  
    int16_t x = X - XRm;
    if (x > 300)x = 300;
    XF = x / 3;
  } else if (X < XLm) {
    //  
    int16_t x = X - XLm;
    if (x < -292) x = -300;
    XF = x / 3;
  }

  XF = XF + XR - XL;

  Y = slave_arr [0];

  //    
  if (!digitalRead(10)) Joystick.pressButton (0); else Joystick.releaseButton (0);    // rudder BT1
  if (!digitalRead(11)) Joystick.pressButton (1); else Joystick.releaseButton (1);    // rudder BT2
  if (!digitalRead(9))  Joystick.pressButton (2); else Joystick.releaseButton (2);    // rudder BT3
  if (!digitalRead(8))  Joystick.pressButton (3); else Joystick.releaseButton (3);    // rudder BT4
  if (!digitalRead(7))  Joystick.pressButton (4); else Joystick.releaseButton (4);    // rudder BT5
  if (!digitalRead(5))  Joystick.pressButton (5); else Joystick.releaseButton (5);    // rudder BT6
  if (!digitalRead(6))  Joystick.pressButton (6); else Joystick.releaseButton (6);    // rudder BT7
  if (!digitalRead(4))  Joystick.pressButton (7); else Joystick.releaseButton (7);    // rudder BT8

  if (bitRead(slave_arr [1], 0)) Joystick.pressButton (8); else Joystick.releaseButton (8);   // rudder BT9
  if (bitRead(slave_arr [1], 1)) Joystick.pressButton (9); else Joystick.releaseButton (9);   // rudder BT10
  if (bitRead(slave_arr [1], 2)) Joystick.pressButton (10); else Joystick.releaseButton (10); // rudder BT11
  if (bitRead(slave_arr [1], 3)) Joystick.pressButton (11); else Joystick.releaseButton (11); // rudder BT12
  if (bitRead(slave_arr [1], 4)) Joystick.pressButton (12); else Joystick.releaseButton (12); // rudder BT13
  if (bitRead(slave_arr [1], 5)) Joystick.pressButton (13); else Joystick.releaseButton (13); // rudder BT14
  if (bitRead(slave_arr [1], 6)) Joystick.pressButton (14); else Joystick.releaseButton (14); // rudder BT15

  Joystick.setXAxis(XF);
  Joystick.setYAxis(Y);


  Serial.println(XL);
  //Serial.print('=');
  //Serial.println(XF);


  //    
  display.clearDisplay();
  display.setTextSize(2);                     // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0, 0);                    // Start at top-left corner
  display.print(XF);
  display.setCursor(64, 0);                   // Start at top-left corner
  display.print(Y);

  if (!digitalRead(13)) {
    //     -   
    //    X
    display.setTextSize(1);
    display.setCursor(0, 16);
    display.print (wheelAngle);
    //    Y
    display.setCursor(64, 16);
    //   
    display.print(slave_arr [2]);
    //   
    display.setCursor(64, 24);
    display.print(slave_arr [3]);
  } else {
    //  -     
    display.setTextSize(2);
    display.setCursor(0, 16);

    if (hours < 10) display.print(0);
    display.print(hours);
    display.print(':');

    if (minutes < 10) display.print(0);
    display.print(minutes);
    display.print(':');

    if (seconds < 10) display.print(0);
    display.print(seconds);
  }

  display.display();

  //   
  Joystick.sendState();
}
spi_master.hArduino
// Arduino UNO, NANO, Leonardo
//    SPI  
// 13 - SCK, 12 - MISO, 11 - MOSI, 10 - SS
// SCK, MI, MO, SS  Leonardo
//     
//      
//      

//    
uint8_t master_arr [4];
//     
uint8_t slave_arr  [4];

void mater_init(){
  digitalWrite(SS, HIGH);  // ensure SS stays high for now
  SPI.begin ();
  //   
  SPI.setClockDivider(SPI_CLOCK_DIV8);
}

void refreshSPI ()          //     
{
  digitalWrite(SS, LOW);    // enable Slave Select
  //  ""      slave_arr[]
  SPI.transfer (0xFF);
  //       
  delayMicroseconds (20);
  //   master_arr[]
  for (uint8_t i = 0; i < sizeof(master_arr); i++) {  
  slave_arr[i] = SPI.transfer(master_arr[i]);
  //       
  delayMicroseconds (20);     
  }    
  digitalWrite(SS, HIGH);   // disable Slave Select
} // end of refreshSPI
Nano_final2.inoArduino
#include "spi_slave.h"

volatile uint8_t filter = 0;           //  
volatile uint32_t fDisk18 = 0;         //  /18
volatile uint32_t bDisk18 = 0;         //   /18
volatile uint32_t OLDfDisk18 = 0;      //   /18
volatile uint32_t OLDbDisk18 = 0;      //    /18
volatile uint32_t startTime = 0;       //  
volatile uint32_t endTime = 0;         //  1/18 
boolean buttonWasUp = true;            // BTSet     ?

void setup (void)
{
  slave_init();                          //  SPI  SLAVE
  pinMode (2, INPUT_PULLUP);             // yellow hall
  pinMode (3, INPUT_PULLUP);             // green  hall
  pinMode (4, OUTPUT);                   // yellow LED !!!
  pinMode (5, OUTPUT);                   // green  LED !!!
  //      D
  bitSet(PCICR, 2);
  //     2  3
  bitSet(PCMSK2, 2);
  bitSet(PCMSK2, 3);
  slave_arr [0] = 0;                     //  / int8_t
  slave_arr [1] = 0;                     // 
  slave_arr [2] = 255;                   //   
  slave_arr [3] = 0;                     //       Y
  pinMode (14, INPUT_PULLUP); // BT9
  pinMode (15, INPUT_PULLUP); // BT10
  pinMode (16, INPUT_PULLUP); // BT11
  pinMode (17, INPUT_PULLUP); // BT12
  pinMode (9, INPUT_PULLUP);  // BT13
  pinMode (8, INPUT_PULLUP);  // BT14
  pinMode (7, INPUT_PULLUP);  // BT15
  pinMode (6, INPUT_PULLUP);  // BTSet
}


ISR (PCINT2_vect) {                       //      D0..D7

  //     
  if (!bitRead(slave_arr [1], 7)) {
    bitWrite(PORTD, 4, bitRead(PIND, 2));
    bitWrite(PORTD, 5, bitRead(PIND, 3));
  }

  filter = filter << 1;
  bitWrite(filter, 0, bitRead(PIND, 2));
  filter = filter << 1;
  bitWrite(filter, 0, bitRead(PIND, 3));

  //    2,3 B10110100
  if (filter == B10110100) {
    //   
    OLDfDisk18 = fDisk18;
    //    
    fDisk18++;
    endTime =  millis() - startTime;
    startTime = millis();
  }

  //    2,3 B10000111
  if (filter == B10000111) {
    //   
    OLDbDisk18 = bDisk18;
    //    
    bDisk18++;
    endTime =  millis() - startTime;
    startTime = millis();
  }

  //    
  if (endTime>255) endTime = 255;

}

void loop (void)
{
  if (digitalRead (SS) == HIGH) countSPIb = -1;  //    

  //   0  / 1 
  boolean buttonIsUp = digitalRead(6);
  //      (&&)   ...
  if (buttonWasUp && !buttonIsUp) {
    delay(10);
    //   
    buttonIsUp = digitalRead(6);
    if (!buttonIsUp) {  //     ...
      // ... ! 0  / 1 
      bitWrite(slave_arr [1], 7, !bitRead(slave_arr [1], 7));
    }
  }
  //       
  buttonWasUp = buttonIsUp;

  //   
  bitWrite(slave_arr [1], 0, !digitalRead(14)); // BT9
  bitWrite(slave_arr [1], 1, !digitalRead(15)); // BT10
  bitWrite(slave_arr [1], 2, !digitalRead(16)); // BT11
  bitWrite(slave_arr [1], 3, !digitalRead(17)); // BT12
  bitWrite(slave_arr [1], 4, !digitalRead(9));  // BT13
  bitWrite(slave_arr [1], 5, !digitalRead(8));  // BT14
  bitWrite(slave_arr [1], 6, !digitalRead(7));  // BT15

  //     
  slave_arr [3] = map(analogRead(A7),0,1023,1,254);

  //    
  if (millis() - startTime > 255) {
    slave_arr[0] = 0;
    endTime = 255;
  }


  if (OLDfDisk18 != fDisk18) {  //   
    OLDfDisk18 = fDisk18;       //  
    if (endTime < slave_arr [3]) slave_arr [0] = 64;
    else slave_arr [0] = map(endTime, 255, slave_arr [3], 0, 64);
  }

  if (OLDbDisk18 != bDisk18) {   //   
    OLDbDisk18 = bDisk18;        //     
    if (endTime < slave_arr [3]) slave_arr [0] = -64;
    else slave_arr [0] = map(endTime, 255, slave_arr [3], 0, -64);
  }

  //    
  slave_arr [2] = endTime;
}

// 
// Serial.begin(9600);
//long previousMillis = 0;               //   
//long interval = 100;                   //  
/*
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    //    
    previousMillis = currentMillis;
    int8_t testik = slave_arr [0];
    Serial.println(slave_arr [3]);
  }
*/
Untitled fileArduino
//          ATmega328P 
// Arduino UNO, NANO
//    SPI  
// 13 - SCK, 12 - MISO, 11 - MOSI, 10 - SS

//     
//      
//      

//     
volatile uint8_t master_arr [4];
//     
volatile uint8_t slave_arr  [4];
//   
volatile int16_t countSPIb = -1;

void slave_init(){
  //  SPI  SLAVE
  DDRB|=(1<<PB4);                        //   MISO  
  SPCR |= (1 << SPIE)|(1 << SPE);        //     SPI  SLAVE
}

ISR (SPI_STC_vect)                       //  SPI -  
{
  if (countSPIb < 0) {                   //  ""
    countSPIb++;                         //  
    SPDR = slave_arr [countSPIb];        //     
    return;                              //   
  }

  master_arr [countSPIb] = SPDR;         //    
  countSPIb++;                           //  
  SPDR = slave_arr [countSPIb];          //    (+1 )

  if (countSPIb >= sizeof(master_arr)) { //   
    countSPIb = -1;                      //      
  }
}                                        //  SPI -  
spi_slave.hArduino
//          ATmega328P 
// Arduino UNO, NANO
//    SPI  
// 13 - SCK, 12 - MISO, 11 - MOSI, 10 - SS

//     
//      
//      

//     
volatile uint8_t master_arr [4];
//     
volatile uint8_t slave_arr  [4];
//   
volatile int16_t countSPIb = -1;

void slave_init(){
  //  SPI  SLAVE
  DDRB|=(1<<PB4);                        //   MISO  
  SPCR |= (1 << SPIE)|(1 << SPE);        //     SPI  SLAVE
}

ISR (SPI_STC_vect)                       //  SPI -  
{
  if (countSPIb < 0) {                   //  ""
    countSPIb++;                         //  
    SPDR = slave_arr [countSPIb];        //     
    return;                              //   
  }

  master_arr [countSPIb] = SPDR;         //    
  countSPIb++;                           //  
  SPDR = slave_arr [countSPIb];          //    (+1 )

  if (countSPIb >= sizeof(master_arr)) { //   
    countSPIb = -1;                      //      
  }
}                                        //  SPI -  

Comments

Similar projects you might like

Handheld Gaming Console | Arduboy Clone

Project tutorial by Neeraj Rane

  • 5,156 views
  • 4 comments
  • 21 respects

Simple Wireless Keyboard for PC

Project showcase by Gyro1

  • 14,394 views
  • 8 comments
  • 73 respects

Pen Stand: Gaming Enabled

Project tutorial by AdiK

  • 4,956 views
  • 0 comments
  • 20 respects

Gesture Based Wireless Gaming Console

Project tutorial by Team Xolcano Technologies

  • 2,830 views
  • 0 comments
  • 4 respects

Super Diet Racing Game Bike

Project in progress by luxlike

  • 2,659 views
  • 0 comments
  • 10 respects

GoPro Voice Control Panorama Device

Project showcase by Jeremy S. Cook

  • 1,100 views
  • 1 comment
  • 4 respects
Add projectSign up / Login