Friday, August 12, 2022

The code

// this code was adapted from Drew Dibble original code to run on arduino due
//you´ll need a library called "soft_uart.h" ,elapsedmillis.h ,liquidcrystal.h ,and bignumbers.h installed ,search the web for it.
// this code uses the arduino due to talk to the main board Hoverboard using a 3.2v hall thumb throtlle
//instead of the gyro board.
// odometer version is from Angel Garcia de la Cruz and bignumber lcd from Sean Auffinger
// version 1.0 by Alvaro Fogassa on 23/05/2022
// !!! CAUTION !!! , do not attempt to load the sketch to arduino with the hoverboard turned on or it might damage your pc.
// the usb is not isolated and will burn your pc. make a guess how i´ve found that out. 

///// 9bit serial ///////////////////////////////////////

 #include "soft_uart.h" 
 using namespace soft_uart; 
 using namespace soft_uart::arduino_due;
 #define RX_PIN 10 // software serial port's reception pin azul 
 #define TX_PIN 11 // software serial port's transmision pin verde 
 #define SOFT_UART_BIT_RATE 26315
 #define RX_BUF_LENGTH 256 // software serial port's reception buffer length
 #define TX_BUF_LENGTH 256 // software serial port's transmision buffer length 
 uint32_t counter1=256;
 uint32_t counter2=1;
 uint32_t counter3=85;
 uint32_t counter4=0xFF;
 int sensorValue = 0; // value read from the pot
 int outputValue = 0; // value output to the PWM (analog out)
 const int analogInPin = A0; // Analog input pin that the potentiometer is attached to
 // declaration of software serial port object serial_tc4
 // which uses timer/counter channel TC4
 serial_tc4_declaration(RX_BUF_LENGTH,TX_BUF_LENGTH);
 //serial_tc1_declaration(RX_BUF_LENGTH,TX_BUF_LENGTH); 
 auto& serial_obj=serial_tc4; //
// serial_tc4_t& serial_obj=serial_tc4;
 
 //////////////// lcd update every 100ms //////////////////////////////////////////////
#include <elapsedMillis.h>

elapsedMillis timeElapsed; //declare global if you don't want it reset every time loop runs
 unsigned int interval = 100;
 
 ///////////////// lcd bignumbers ////////////////////////////////////////////// 
#include <LiquidCrystal.h>
#include <BigNumbers.h>
 const int lcdD7Pin = 52; // LCD D7 pin 14 
 const int lcdD6Pin = 50; // LCD D6 pin 13 
 const int lcdD5Pin = 48; // LCD D5 pin 12 
 const int lcdD4Pin = 46; // LCD D4 pin 11 
 const int lcdEPin = 44; // LCD E Pin 6 
 const int lcdRSPin = 42; // LCD RS pin 4
 LiquidCrystal lcd(lcdRSPin, lcdEPin, lcdD4Pin, lcdD5Pin, lcdD6Pin, lcdD7Pin); //  construct LCD object
 BigNumbers bigNum(&lcd); //construct BigNumbers object, passing to it the name of our LCD object 
 // Circumference of bicycle wheel in meters.
 float bicycleWheelCircumference = 2.104867;
 const int revolutionButton = 2; 
 boolean lastRevolutionButton = LOW;
 boolean currentRevolutionButton = LOW; 
 unsigned long lastRevolutionStartTime = 0; 
 unsigned long revolutionTime = 0; // This must be the biggest display mode number
 const int currentDisplayMode = 3;
 float currentDistanceK;
 int currentMaximumKPH; 
 int currentAverageKPH; 
 int currentKPH;
 float currentDistanceM; 
 int currentMaximumMPH; 
 int currentAverageMPH; 
 int currentMPH;
 unsigned long revolutionCount = 0;
 unsigned long currentTime = 0; 
 unsigned long currentMovingTime = 0; 
 unsigned long lastStoppedTime = 0;
 unsigned long stoppedTime = 0; 
 boolean tooSlow = LOW; 
 float stoped=0.00; // added to display zero when stoped
 float km = 0.00;
 float kph = 0.00; 
 int intHours;
 int intMinutes; 
 int intSeconds;
 long previousMillis = 0; // will store last time Lcd was updated 
 unsigned long milliSecondsInSecond = 1000;
 unsigned long milliSecondsInMinute = 60000;
 unsigned long milliSecondsInHour = 3600000;
 
 void setup()
 {
  // serial_obj initialization 
  serial_obj.begin(
    RX_PIN,
    TX_PIN,
    SOFT_UART_BIT_RATE,
    soft_uart::data_bit_codes::NINE_BITS,
    soft_uart::parity_codes::NO_PARITY,
    soft_uart::stop_bit_codes::ONE_STOP_BIT
    );
    
  pinMode(revolutionButton, INPUT_PULLUP); // Sets the hall switch to be an input 
  lcd.begin(16,2); // setup LCD rows and columns
  bigNum.begin(); // set up BigNumbers
  lcd.clear(); // clear display 
  }
  int sp=0;
  void loop()
  {
    //////////////////motor controll /////////////////////////////////////////
    //we measure 50 times adn make the mean average the acelerator hall sensor value
    long measure = 0; 
    for(int i = 0; i < 50; i++){
      int value = measure += analogRead(analogInPin);
      } 
      measure /= 50;
      // read the analog in mean value and map it to outputvalue: 
      outputValue = map(measure, 477, 630, -1500, 0); // maps the throttle to the output values,need to be calibrated.
      sp=outputValue; // makes the motor to turn only forward. 
      if (sp>=1)
      { sp=0; } 
       serial_obj.write(counter1)%(1<<static_cast<int>(soft_uart::data_bit_codes::NINE_BITS)); 
        serial_obj.write(sp&counter4)%(1<<static_cast<int>(soft_uart::data_bit_codes::NINE_BITS)); 
        serial_obj.write((sp >> 8) & counter4)%(1<<static_cast<int>(soft_uart::data_bit_codes::NINE_BITS));
        serial_obj.write( sp & counter4)%(1<<static_cast<int>(soft_uart::data_bit_codes::NINE_BITS)); 
       serial_obj.write((sp >> 8) & counter4)%(1<<static_cast<int>(soft_uart::data_bit_codes::NINE_BITS)); 
        serial_obj.write(counter3)%(1<<static_cast<int>(soft_uart::data_bit_codes::NINE_BITS));
        delayMicroseconds(200); 
        
        //////////////// odometro //////////////////////////////////////////
        // Get current millis 
        currentTime = millis();
        if (tooSlow == HIGH) { 
          if ((currentTime - lastStoppedTime) >= 1000)
          {
            stoppedTime = stoppedTime + 1000; 
            lastStoppedTime = currentTime;
            }
            }
            // read Hall sensor
           currentRevolutionButton = debounce(lastRevolutionButton, revolutionButton);
            //currentRevolutionButton = (lastRevolutionButton, revolutionButton);
            if (lastRevolutionButton == HIGH && currentRevolutionButton == LOW) 
            { // Increase wheel revolution count
              revolutionCount++;
              // Compute millis it took for this latest revolution 
              if (lastRevolutionStartTime > 0) 
              { 
                revolutionTime = currentTime - lastRevolutionStartTime;
                kph = (3600000 / revolutionTime) * bicycleWheelCircumference / 1000;//
                currentKPH = kph; 
               // currentMPH = currentKPH * 0.62137119;  
                if (currentMaximumKPH < currentKPH) // If current speed is new maximum speed for this lap then store it
                { 
                  currentMaximumKPH = currentKPH; 
                  //currentMaximumMPH = currentMaximumKPH * 0.62137119;
                  }
                  
                  } 
                  lastRevolutionStartTime = currentTime;
                  }
                  lastRevolutionButton = currentRevolutionButton; 
                  // Determine if wheel revolution has taken too long. If so, cyclist has stopped display "--" instead of current speed. 
                  if ((currentTime - lastRevolutionStartTime) >= 5000) 
                  { tooSlow = HIGH; }
                  
                  if ((currentTime - lastRevolutionStartTime) < 5000)
                  { tooSlow = LOW;}
                  
                  if (revolutionCount > 0) { // Calculate current distance
                    currentDistanceK = revolutionCount * (bicycleWheelCircumference / 1000); 
                    // currentDistanceM = currentDistanceK * 0.62137119;
                    currentMovingTime = currentTime - stoppedTime;
                    
                    // Calculate average speed
                    currentAverageKPH = currentDistanceK * 3600000 / currentMovingTime;//em millis 
                    
                   // currentAverageMPH = currentAverageKPH * 0.62137119;
                   }
                   
                    // Display information on LCD
                    if (timeElapsed > interval)
                    { 
                      
                       lcd.setCursor(8,0); 
                      lcd.print(currentDistanceK);
                      lcd.print(" km");
                      
                      if (tooSlow == LOW)
                      { 
                       
                        bigNum.displayLargeInt(currentKPH , 0, 2, false);
                      }
                      else if (tooSlow == HIGH){
                          bigNum.displayLargeInt(stoped, 0, 2, false);
                      }


                // Display Average KPH in bottom right
                            lcd.setCursor(8, 1);
                            lcd.print("avg"); 
                            lcd.setCursor(12, 1); 
                            if (currentAverageKPH < 10)
                            {
                              lcd.print(" ");
                            }
                           
                            lcd.print(currentAverageKPH);
                            
                            timeElapsed = 0; // reset the counter to 0 so the counting starts over.
                            
                                } 
                            }
                            /////////////// loop end //////////////////////////// 
                            
                            //A debouncing function that can be used for any button
                            boolean debounce(boolean last, int pin) {
                              boolean current = digitalRead(pin);
                              if (last != current) 
                              { delay(1); 
                              current = digitalRead(pin);
                              } 
                              return current; 
                              }
       

windows crash

After my pc crashed last week,and lossing some arduino codes including the bike controller code, i had to download the code from here just to realize that some parts of the code got clipped when posting, So it would not compile. I´had to rewrite the code .I apologize for it.

Sunday, April 17, 2022

Batteries

i´ve recently ordered 6 Litokala 18650 x 3000mha from the aliexpress store (litokala official store) but I was disapointed, one of 6 batteries was about 2.45v and two other with 3.2v only 3 batteries got here with 3.6v. But testing it with my homemade 6amp/h arduino discharger tester shows an average of 2820 mha on all batteries. As it´s a home made tester it´s not precise maybe 10% accurate but it repeats withing 0.040 mv. not shure if I´ll keep buying batteries from the same supplyer as it should be withing 3.6v as arrived.

Videos

Saturday, April 16, 2022

Throttle

If you got all the step right your hoverboard will turn both motors in the same direction using only one gyro board.At this point you can hold the gyro board to the bike´s handle bar and tilt it to accelerate or run backwards the way i did for short time to see if the bike was strong enough to keep me moving, but its DANGER in this way as the bike can suddenly accelerate when going over curbs or a steep obstacle. I was looking on how to use a potentiometer in place of the gyro board and found a blog created by Drew dibble there he explains how the serial comm between the gyro board and the main board works. I modifie Drew dibble original arduino code to work with a arduino due and voala, it works nice no problems so far. So, i made a panel that holds a arduino due with front led lights , it takes the signal from a s41 hall sensor 0 to 3.3v and converts this signal to a serial communication that the main hoverboard board expects. I´ve made my own thumb trottle from the bike´s front shifter using a s41 hall sensor and 2 very small scrap magnets. It´s not a linear throttle but who cares.I can not post the code here , there is no option on this blog to do it. I still have to implement a speedometer lcd etc... the only down side is that i need to turn the controller on and off twice every time i turn the bike on to get the thumb throttle to work but is not a problem as it works like a anti theft device.

Wiring

First step is to get both motors in the hoverboard to turn using a single gyro board, to do that just wire one gyro board to both gyro board input on the main hoverboard board. you will see that motors run oposit direction to each other when you tilt the gyro board. Next step is to make both motors to run in the same direction, to do that you will need to switch 2 of the 3 wires that comes from the hall sensor and 2 of 3 motor´s wires,dont mix motors wires with the hall sensor wires or black smoke will be released. there is only one combination that works correct play with the wiring till you find out the correct one, the motors will not run or speed up or work rough if it´s not the correct combination. do this while the motors still in the hoverboard.dont mix motors wires with the hall sensor wires or black smoke will be released.

Motor mods.

Motors are hold backto back by 4 m4 screws on the inside of the housing but the magnets needs to be aligned to each other to work as a single motor, i´ve do that by using a scrap magnet to identifie the corret position on each motor than made a mark on each motor and joined the two into one by the 4mm screws.again take your time on this step as the 2 motors needs to work in sinc to each other.

Motor support

I had some scrap steel so i designed the motor support around it, L shape steel just bend to fit and welded to the frame, it is a nightmare to get everything aligned thou. take your time on this step. this concludes the mechanical part of it.

Gear transmission

this is how i´ve made the bikes main gear transmission, it´s a 3 sprocket standard main gear had to buy 2 sets i´had to drill out the rivets that holds it in place and place a 9mm spacer between the 48 tooth gears otherwise the chains will rube each other.I´m using the small gear e 2 large ones.than i´had to enlarge the center hole of the small gear to fit a stardard 16 tooth freewheel and hold it by 3 screws.The 3 main gears is hold by 5 6mm allen screws. Next was to machine a freewheel threaded holder, you can use a rear wheel hub to make it, it´s about 16mm long with a blind hole thru it, the thing here is to keep the chain line the same as the stardard chain line.Next was to make a spline shaft to hold a bmx 14 tooth freewheel to the motor, again i´ve machined one but you can get a spline shaft at your local bike store and bolt it to the motor housing.I had to replace the bike´s down tube by a 2mm wall 40mm square tube , bike´s frame was flexing too much with the original down tube.

What is needed

Here is what you need: CAUTION!!! do not attempt to load arduino code with the hoverboard board turned on or it might damage your pc! guess how i found that out. a working hoverboard a old MTB bike. a throtlle controller 0- to 3.3v a arduino due or other arduino that works with 3.3v. tools and a welder, and a 3d printer if you want to print bat holder.

The code

// this code was adapted from Drew Dibble original code to run on arduino due //you´ll need a library called "soft_uart.h" ,elap...