Bajdi electronics

Hobby electronics website

Browse: Page 8

2.2 inch TFT display

By Bajdi on November 11, 2013

TFT 320x240

TFT 320×240

Bought a TFT display from Electrodragon. Electrodragon sells 2 versions, a 1.8″ and a 2.2″ version. I got the 2.2 inch version, it costs only 7.2$. It’s a colour (QVGA) display with 240×320 pixels. The display uses an ILI9341 driver chip. I found the datasheet of the ILI9341 here. The chip works at 3.3V, so I used one of my own boards with an ATmega328 running at 3.3V to test the display. On the back of the display there is also an SD card reader.
The display can be used with an Arduino, I’ve found 2 Arduino libraries that support this display.
I first tried out the library provided by Adafruit, you can download it on Github. This library uses hardware SPI to communicate with the driver chip. SPI pins for an Arduino Duemilanove/Nano/Uno are 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). The driver chip needs another 2 pins, D/C and a reset pin (RST).
Back view of the display showing the connection pins:

TFT 320x240

TFT 320×240

I connected the display to an Atmega328 and uploaded the “graphicstest” example sketch.

I also found another library that supports this display, the UTFT library. This library supports a number of 8bit, 16bit and serial graphic displays including the ILI9341 driver chip. You can find the library and more information about it here. This library is a little bit more difficult to make it work but it comes with a manual that explains most things. This library does not use the same pins as the Adafruit library. I couldn’t figure out how to connect the display to my ATmega328. So I emailed the programmer of the library and I received a prompt reply how to connect my new display.
These are the connections I made:
DO (MISO) -> Not used by UTFT
SCK -> pin 8
SDI (MOSI) -> pin 9
D/C -> pin 10
RESET -> pin 11
CS -> pin 12
In the sketch you then need to use this constructor to define the type of display and the pins:
UTFT myGLCD(TFT01_22SP,9,8,12,11,10);
I then uploaded the example sketch and it worked, see next video:

I then successfully wrote a simple sketch to display a jpg on the display. The library comes with a tool to convert images files to .c files. That way you can store the image in progmem and show it on the display. But be warned it’s easy to fill the complete memory of an ATmega328 with one image file.

Posted in Arduino, Buying parts | Tagged TFT | 9 Responses

Adding encoders to those cheap yellow motors

By Bajdi on November 7, 2013

Dagu encoder kit

Dagu encoder kit

My little Ebay bot is powered by 2 cheap DC geared motors. These yellow geared DC motors are very popular. Lots of cheap robot kits use them. I bought mine on Ebay and used double sided tape to stick them to the chassis of the robot. I had one annoying problem with the cheapo motors. One was faster then the other. It took me some time to find the right PWM settings so they would run at approximately the same speed so the robot would drive in a straight line.
A better solution to this problem is to fit encoders to the motors. So I bought a Dagu simple encoder kit and fitted it to my Ebay bot. I attached the magnetic disc to the axle that drives the wheels. This is not ideal though. For better resolution you should try and mount the encoders to the motor axle. But the motor axle of my motors is unfortunately not long enough.

Motor encoder

Motor encoder

There is a nice guide on how to use these encoders on Lets Make Robots. So I decided to try out the example code with my robot. And it didn’t really work… The example code was written for encoders that were fitted to the motor axle, these means you have a very high resolution. My encoders are fitted to the output axle of the gearbox so the encoders have a much lower resolution. The difference between a high and a low resolution is the number of pulses you get from the encoders. With my setup the encoders only give a pulse once every xx milliseconds when running fast and xxx milliseconds when running really slow. I did get the encoders to work after changing some of the code.
The code measures the time between 2 encoder pulses using interrupts. The speed of the motors is determined by a predefined time. This parameter is the time between 2 encoder pulses we want the motors to run. Shorter time means faster speed and longer time is slower. Because of the low resolution of my setup the example code would run so fast that the motors would just stop because so few pulses are measured. So I had to slow things down. I started by replacing the micros function with millis. Then I wrote some code that measures the time when the last pulse was detected. The code constantly adjusts the PWM of each motor. If the time since the last pulse is longer then what we want the PWM value is ramped up. If its shorter the PWM is lowered.
Here is my test sketch:

// http://www.bajdi.com
// Encoder test sketch
// Dagu simple encoder kit attached to yellow geared DC motors

// Motor controller pins:
const int EN1 = 3;        //enable motor 1 = pin 1 of L293D
const int direction1 = 13; //direction motor 1 = pin 2 of L293D
const int EN2 = 14;        //enable motor 2 = pin 9 of L293D
const int direction2 = 15; //direction motor 2 = pin 15 of L293D

// Motor speed
byte speedLeft = 160;        // start speed for left motor
byte speedRight = 160;      //  start speed for right motor

// Encoders
const int lEncoder = 10;    // interrupt 0                                  
const int rEncoder = 11;    // interrupt 1
int motorTime = 120;                     // width of pulse in mS we want the motor to run (120 is pretty slow)
volatile unsigned long lpulse = 121;      // width of left encoder pulses in mS
volatile unsigned long rpulse = 121;      // width of right encoder pulses in mS
volatile unsigned long ltime;             // remembers time of left  encoders last state change in mS
volatile unsigned long rtime;             // remembers time of right encoders last state change in mS

#define runEvery(t) for (static typeof(t) _lasttime;(typeof(t))((typeof(t))millis() - _lasttime) > (t);_lasttime += (t))


void setup() {
  Serial.begin(9600); //to use the serial monitor  
  pinMode(EN1, OUTPUT); 
  pinMode(direction1, OUTPUT);
  pinMode(EN2, OUTPUT);
  pinMode(direction2, OUTPUT);
  analogWrite(EN1, 0);
  analogWrite(EN2, 0);
  digitalWrite(lEncoder,1);                               // enable pullup resistor for left  encoder sensor
  digitalWrite(rEncoder,1);                               // enable pullup resistor for right encoder sensor
  attachInterrupt(0,Lencoder,CHANGE);                     // trigger left  encoder ISR on state change
  attachInterrupt(1,Rencoder,CHANGE);                     // trigger right encoder ISR on state change
}

void loop() {

  runEvery(500)
  {
    Serial.print("lpulse = ");
    Serial.println(lpulse);
    Serial.print("rpulse = ");
    Serial.println(rpulse);
    Serial.print("speedLeft = ");
    Serial.println(speedLeft);
    Serial.print("speedRight = ");
    Serial.println(speedRight);
  }

  runEvery(5){                            // Run every 5ms, to fast would stop the motors
    int lastPulseL = millis() - ltime;     // Check how much time has passed since last pulse

   int lastPulseR = millis() - rtime;


    if (lastPulseL > motorTime && speedLeft < 255)    // If the pulse is longer then the time we want speed up motor
    {
      speedLeft = speedLeft+1;
    }
    if (lastPulseL < motorTime && speedLeft > 0)      // // If the pulse is shorter then the time we want slow down motor
    {
      speedLeft = speedLeft-1;
    }

    if (lastPulseR > motorTime && speedRight < 255)
    {
      speedRight = speedRight+1;
    }
    if (lastPulseR < motorTime && speedRight > 0)
    {
      speedRight = speedRight-1;
    }
  }
  forward();
  //backward();
  //left();
  //right();
  
}

void forward()
{
  digitalWrite(direction1, HIGH);
  digitalWrite(direction2, HIGH);  
  analogWrite(EN1, speedLeft);
  analogWrite(EN2, speedRight);

}

void stop()
{
  digitalWrite(direction1, LOW);  
  digitalWrite(direction2, LOW);  
  analogWrite(EN1, 0);
  analogWrite(EN2, 0);

}

void backward()
{
  digitalWrite(direction1, LOW); 
  digitalWrite(direction2, LOW);  
  analogWrite(EN1, speedLeft);
  analogWrite(EN2, speedRight);

}

void left()
{
  digitalWrite(direction1, LOW);
  digitalWrite(direction2, HIGH);  
  analogWrite(EN1, speedLeft);
  analogWrite(EN2, speedRight);

}

void right()
{
  digitalWrite(direction1, HIGH);
  digitalWrite(direction2, LOW);  
  analogWrite(EN1, speedLeft);
  analogWrite(EN2, speedRight);

}


//======================================================= ISR for left encoder =======================================================
void Lencoder()
{
  lpulse=millis()-ltime;                               // time between last state change and this state change
  ltime=millis();  // update ltime with time of most recent state change
}

//======================================================= ISR for right encoder ======================================================
void Rencoder()
{
  rpulse=millis()-rtime;                               // time between last state change and this state change
  rtime=millis();  // update ltime with time of most recent state change
}

Posted in Arduino sketches | Tagged encoder, pwm | 7 Responses

Building a self balancing bot

By Bajdi on October 30, 2013

Self balancing bot

Self balancing bot

I bought most of the parts to built a self balancing bot many months ago. This time I didn’t use cheap Chinese stuff. I actually bought Pololu parts from a local shop. Pololu has a nice range of motors and motor controllers. I wanted to keep the bot small so I used the micro metal gear motors with 2 matching 60mm wheels. I did go for the most powerful version of the micro metal gear motors. To control the motors I got a DRV8833 break out board.

Pololu motors and wheels

Pololu motors and wheels

For the electronics I used one of my own PCB creations, a Bajduino of course 🙂 It’s just a small (50x50mm) break out board for an ATmega328. I’m running the ATmega @ 16MHz and 3.3V. It’s out of spec according to the datasheet but it works… I also needed an IMU of course. I found a MP6050 sensor in my parts box. The MPU6050 combines a 3 DOF gyro and 3 DOF accelerometer in a small package, ideal for a self balancing bot.

The chassis is made from a sheet of polystyrene, I made 3 small plates out of a big sheet. Polystyrene is very easy to cut up with a sharp knife. Very handy to quickly make a custom robot chassis. I then drilled holes in the plates to fit the motors and electronics. To connect the 3 chassis plates I used brass spacers. I mounted the MPU6050 sensor to the bottom of the lowest chassis plate.

Self balancing bot

Self balancing bot

I did have some trouble with the little motors. During my initial tests I noticed that the MPU6050 sensor would stop working when driving the motors. I hooked up my oscilloscope to the 3.3V that powers the sensor and saw that the regulator on my board was oscillating.

LM1117 oscillating

LM1117 oscillating

Brushed DC motors are noisy things so I soldered the biggest (0,22µF) ceramic capacitors I had on hand to each motor. This did the trick and the regulator now gives a nice stable 3.3V.

The hard part in building a self balancing bot is coding it. Luckily there are some smart people that have shared their code and ideas about self balancers. So I just borrowed a lot of code I found online and turned it in to something that makes my bot balance.

First thing I needed was code to get the data from the MPU6050 sensor. You need some kind of filter to get good results. There are different ways of doing this. The guys from TKJElectronics have shared the necessary code to get the data from the MPU6050 sensor. They have also made a library for a Kalman filter. Their code can be downloaded on Github.

Next step was coding a PID algorithm. I have no experience with this and tried lots of different things. Including using the Arduino PID library. I could never get decent results with it so I gave up pretty fast. I then got some nice PID code from someone on letsmakerobots (thanks Protowrxs). This code worked a lot better but I could not find the right PID parameters. I then had a good look at this excellent guide to make a self balancing bot and rewrote my sketch. The following video shows my latest code:

This is the sketch I’m using (you need the library from TKJElectronics to compile this code):

// http://www.bajdi.com
// Self balancing bot:
// µController = ATmega328
// 2 Pololu micro metal gear motors with 60mm wheels + DRV8833 motor controller
// 6DOF MPU6050 sensor 

#include <Wire.h>
#include "Kalman.h" // Source: https://github.com/TKJElectronics/KalmanFilter

Kalman kalmanX; // Create the Kalman instance

/* IMU Data */
int16_t accX, accY, accZ;
int16_t tempRaw;
int16_t gyroX, gyroY, gyroZ;

float accXangle;//, accYangle; // Angle calculate using the accelerometer
float gyroXangle;//, gyroYangle; // Angle calculate using the gyro
float kalAngleX;//, kalAngleY; // Calculate the angle using a Kalman filter

unsigned long timer;
uint8_t i2cData[14]; // Buffer for I2C data
float CurrentAngle;

// Motor controller pins
const int AIN1 = 3;  // (pwm) pin 3 connected to pin AIN1 
const int AIN2 = 9;  // (pwm) pin 9 connected to pin AIN2 
const int BIN1 = 10; // (pwm) pin 10 connected to pin BIN1  
const int BIN2 = 11;  // (pwm) pin 11 connected to pin BIN2 

int speed;

// PID
const float Kp = 4; 
const float Ki = 1;
const float Kd = 1;
float pTerm, iTerm, dTerm, integrated_error, last_error, error;
const float K = 1.9*1.12;
#define   GUARD_GAIN   10.0

#define runEvery(t) for (static typeof(t) _lasttime;(typeof(t))((typeof(t))millis() - _lasttime) > (t);_lasttime += (t))


void setup() {  
  pinMode(AIN1, OUTPUT); // set pins to output
  pinMode(AIN2, OUTPUT);
  pinMode(BIN1, OUTPUT);
  pinMode(BIN2, OUTPUT);
  Serial.begin(57600);
  Wire.begin();
  i2cData[0] = 7; // Set the sample rate to 1000Hz - 8kHz/(7+1) = 1000Hz
  i2cData[1] = 0x00; // Disable FSYNC and set 260 Hz Acc filtering, 256 Hz Gyro filtering, 8 KHz sampling
  i2cData[2] = 0x00; // Set Gyro Full Scale Range to ±250deg/s
  i2cData[3] = 0x00; // Set Accelerometer Full Scale Range to ±2g
  while(i2cWrite(0x19,i2cData,4,false)); // Write to all four registers at once
  while(i2cWrite(0x6B,0x01,true)); // PLL with X axis gyroscope reference and disable sleep mode 

    while(i2cRead(0x75,i2cData,1));
  if(i2cData[0] != 0x68) { // Read "WHO_AM_I" register
    Serial.print(F("Error reading sensor"));
    while(1);
  }

  delay(100); // Wait for sensor to stabilize

  /* Set kalman and gyro starting angle */
  while(i2cRead(0x3B,i2cData,6));
  accX = ((i2cData[0] << 8) | i2cData[1]);
  accY = ((i2cData[2] << 8) | i2cData[3]);
  accZ = ((i2cData[4] << 8) | i2cData[5]);
  accXangle = (atan2(accY,accZ)+PI)*RAD_TO_DEG;

  kalmanX.setAngle(accXangle); // Set starting angle
  gyroXangle = accXangle;
  timer = micros();
}

void loop() {
  runEvery(25)  // run code @ 40 Hz
  {
    dof();
    if (CurrentAngle <= 180.2 && CurrentAngle >= 179.8)
    {
      stop();
    }
    else{
    if (CurrentAngle < 230 && CurrentAngle > 130)
    {
    Pid();
    Motors();
    }
    else
    {
      stop();
    }
  }
  }
}

void Motors(){
  if (speed > 0)
  { 
    //forward 
    analogWrite(AIN1, speed);
    analogWrite(AIN2, 0);
    analogWrite(BIN1, speed);
    analogWrite(BIN2, 0);
  }
  else
  { 
    // backward
    speed = map(speed,0,-255,0,255);
    analogWrite(AIN1, 0);
    analogWrite(AIN2, speed);
    analogWrite(BIN1, 0);
    analogWrite(BIN2, speed);
  }
}

void stop()
{
  analogWrite(AIN1, 0);
  analogWrite(AIN2, 0);
  analogWrite(BIN1, 0);
  analogWrite(BIN2, 0);
}

void Pid(){
  error = 180 - CurrentAngle;  // 180 = level
  pTerm = Kp * error;
  integrated_error += error;
  iTerm = Ki * constrain(integrated_error, -GUARD_GAIN, GUARD_GAIN);
  dTerm = Kd * (error - last_error);
  last_error = error;
  speed = constrain(K*(pTerm + iTerm + dTerm), -255, 255);
}

void dof()
{
  while(i2cRead(0x3B,i2cData,14));
  accX = ((i2cData[0] << 8) | i2cData[1]);
  accY = ((i2cData[2] << 8) | i2cData[3]);
  accZ = ((i2cData[4] << 8) | i2cData[5]);
  tempRaw = ((i2cData[6] << 8) | i2cData[7]);  
  gyroX = ((i2cData[8] << 8) | i2cData[9]);
  gyroY = ((i2cData[10] << 8) | i2cData[11]);
  gyroZ = ((i2cData[12] << 8) | i2cData[13]);
  accXangle = (atan2(accY,accZ)+PI)*RAD_TO_DEG;
  double gyroXrate = (double)gyroX/131.0;
  CurrentAngle = kalmanX.getAngle(accXangle, gyroXrate, (double)(micros()-timer)/1000000);
  timer = micros();
}

I spent hours trying to find the right PID parameters but the bot still does not balance like it should… I tried lots of things, to no avail. I changed the height of the bot. Moved the battery from the top to the bottom… I’m giving up for the moment. I might take another shot at it at a later date.

Posted in Arduino sketches, Self balancing bot | Tagged MPU6050, Pololu, robot | 56 Responses

« PreviousNext »

Recent Posts

  • 3D Printer extruders
  • Mearm forked
  • Arduino time lapse – camera pan device
  • Bought a 199$* Prusa I3 3D printer
  • Simple DIY lab power supply
  • Bajduino
    • Bajduino 1284
    • Bajduino 328
  • Stepper robot arm

Recent Comments

  1. 200+ Arduino Projects List For Final Year Students - He Loves Math on Obstacle avoiding robot made from cheap parts
  2. MP3 Alarm Clock: Crafting Customized wake-Up tunes with Arduino on Arduino MP3 alarm clock
  3. Bas on L9110 H-bridge module
  4. Victor on L9110 H-bridge module
  5. WAQAR AHMED on Dimming led with IR remote control

Archives

  • June 2016
  • August 2015
  • May 2015
  • January 2015
  • December 2014
  • November 2014
  • May 2014
  • April 2014
  • March 2014
  • February 2014
  • January 2014
  • December 2013
  • November 2013
  • October 2013
  • September 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
  • January 2013
  • December 2012
  • November 2012
  • October 2012
  • September 2012
  • August 2012
  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011

Categories

  • 3D printing
  • Arduino
  • Arduino sketches
  • Bajdupod 996R
  • Bajdupod 9G
  • Bob the biped
  • Buying parts
  • Dagu Rover 5
  • Dagu service droid
  • Gentoo
  • Insectbot
  • Line following robot
  • Raspberry Pi
  • Self balancing bot
  • Bajduino
    • Bajduino 1284
    • Bajduino 328
  • Stepper robot arm

Copyright © 2026 Bajdi electronics.

Powered by WordPress and Hybrid by Bajdi.