Pages

Wednesday 11 June 2014

Practice - Remotely controlling a car with Arduino by using Xbee

About

In this post we explain the process as usual. However, if you prefer it, you can download our class presentation slides by clicking on the dropbox link below:

Description

This time we are going to show you our final project for the Wireless Sensor Networks course, which consists in a remote controlled car built with an Arduino.

Communication between the remote control and the car is going to be supported with XBee's. As usual, here is the list of the needed material to the final build:
  • Hookup wires
  • 1x Arduino Uno
  • 2x XBee (with XBee explorer)
  • 2x BC547 Transistor 
  • 2x 1N4007 Diodes
  • 2x 1KOhm Resistors
  • 3x 10KOhm Resistors
  • 3x Push Buttons
  • 6x 1,5V Batteries (2x AAA + 4 x AA)
  • 2x  Battery Holders (one with capcacity 2 and the other with cap. 4)
  • 2x Motors
  • 3x Wheels  (one for support)
  • ... 
Before showing the circuit and the code used, we want to explain you some features about the electronics that we have applied on the design, which will roughly give you the needed knowledge:

Voltage batteries

When using circuits with different voltages, you have to connect their grounds together to provide a common ground. In our case, we have used 3V(2x 1,5V) and 6V (4x 1,5V) batteries for feeding one XBee and the motors, respectively.

Transistor

A transistor is an electronic device that can be used on circuits for amplifying or switching purposes. The transistor that we have used (of type Negative-Positive-Negative, NPN) is bipolar junction type and has three terminals (base, collector and emitter), which currents and voltages depend on the others, i.e. current on the base terminal controls the current on collector and emitter.

In our case, we have used transistors as switches, changing their state from OFF to ON as desired, in order to have control on the power supply. This can be done because transistors do not let the current path unless a saturation voltage on the Collector pin is reached.

Figure : NPN Transistor Scheme [1]
When maximum Collector current flows the transistor is said to be Saturated. The value of the Base resistor determines how much input voltage is required and corresponding Base current to switch the transistor fully “ON”. In our case, we had to implement a voltage divisor in order to get an input base intensity low enough to make the transistor act as a digital switch.

Figure : BC547 Transistor [2]

Diode

Diode is a polarized component which can go only one way in the circuit (it let the current path just in one direction) and it has a stripe on one end. That end is the negative end, or cathode, of the diode. The other end is the positive end, or anode. The anode of the diode is connected to the ground of the motor and the cathode of the diode to the power of the motor.

This may seem backward, and in fact, it is. The diode will help prevent any back-voltage generated by the motor from going back into the circuit. Back voltage will flow in the opposite direction of the voltage supply (must be avoided). The diodes we have used are Diodes 1N4007.

Figure: Diode 1N4007

Assembly of the pieces

To mount the car we used the breadboard as the support of all the materials (e.g. XBee Explorer, hookup wires, batteries, motors). We needed some way to stick all these materials; therefore we used some adhesive tape along with mini-boards of cork so that motors and batteries could be well fixed to the breadboard.

Figure: Car ready to be build (left circuit is the controller)
Figure: Put the motors over the first cork layer and stick them with adhesive tape (I)
Figure: Put the motors over the first cork layer and stick them with adhesive tape (II)

Figure: Cork layer used to mount the car
Figure: Stick the batteries to the last cork layer (there are 3 layers)

Figure: Final circuit (without battery feeding the XBee)

Figure: Final circuit (with battery feeding the XBee)
Moreover, we had problems with motors and wheels since the axis of the motors was not wide enough to be put in the wheel. To solve this we used some elastic weave put along the motor axis and then we put some adhesive tape over it. This made enough space for the wheel to fit well in the axis. Another possibility, which could work better, consists in adding blu-tack in the joint between the wheel and the axis. In any case, try to get a wheel that fits perfectly the motor axis to avoid these shoddy works.

Figure: Motor axis covered by elastic weave to fit into the wheel hole

Respect to the motors, it was necessary to weld them to hookup wires since it was not done. The motors we used are the ones at [3].

Figure: Welding the hookup wires to the motor (I)

Figure: Welding the hookup wires to the motor

There is also a support wheel which is not actioned by a motor. We also stuck to the last cork layer using blu-tack. It made that the height of the breadboard increased and it made not work completely well; ideally, it would have been put such that the height of the breadboard was completely straight.

Figure: Support wheel stuck with blu-tack

Finally, after adding all these components we have the final result:

Figure: Final car with the remote control to drive it

Circuits

Figure: Controller circuit
Figure: Car circuit


Code


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
 * This code is used to control the remote car by sending
 * messages through an XBee.
 */

// Pins of the Arduino to which the switches to move the car are connected
const int LEFT_PIN = 2;
const int FORW_PIN = 3;
const int RIGHT_PIN = 4;

// Pins to which we will transmit the information we want to send to the XBee
const int D1_PIN = 8; // corresponds to right wheel
const int D2_PIN = 9; // corresponds to left wheel

// Keeps track of the desired remote on/off state (left, right, forward)
int lRI = false; 
int rRI = false;
int fRI = false;

// Keeps track of the previous remote on/off state
int last_lRI= false;
int last_rRI = false;
int last_fRI = false;

// records last time the remote was re-set to keep it in sync
unsigned long lastSent = 0;

void setup()
{  
  // declare the switch (directions) pins as inputs   
  pinMode(LEFT_PIN, INPUT);
  pinMode(FORW_PIN, INPUT);
  pinMode(RIGHT_PIN, INPUT);
  Serial.begin(9600);
}

void loop()
{
  setRemoteIndicators();
  sendInformation();
}

// Read the value of the switches
//   digitalRead() checks to see if there is voltage on the pin or not  
void setRemoteIndicators()
{
  if (digitalRead(LEFT_PIN) == HIGH) // move left
  {
    lRI = true;
    rRI = false;
    fRI = false;
  } 
  else if (digitalRead(FORW_PIN) == HIGH) // move forward
  {
    lRI = false;
    rRI = false;
    fRI = true;
  }
  else if (digitalRead(RIGHT_PIN) == HIGH) // move right
  {
    lRI = false;
    rRI = true;
    fRI = false;
  }
  else // do not move
  {
    lRI = false;
    rRI = false;
    fRI = false;
  }
}

void sendInformation()
{
  // set the indicators immediately when there's a state change
  if (lRI != last_lRI)
  {
    if (!lRI) setRemoteState(0x4,'1');
    if (lRI) setRemoteState(0x5,'1');
    last_lRI = lRI;
  }
  delay(10);
  
  if (rRI != last_rRI)
  {
    if (!rRI) setRemoteState(0x4,'2');
    if (rRI) setRemoteState(0x5,'2');
    last_rRI = rRI;
  }
  delay(10);
  
  if (fRI != last_fRI)
  {
    if (!fRI)
    {
      setRemoteState(0x4,'1');
      setRemoteState(0x4,'2');
    }
    if (fRI)
    {
      setRemoteState(0x5,'1');
      setRemoteState(0x5,'2');
    }
    last_fRI = fRI;
  }

  // re-set the indicator occasionally in case it's out of sync
  if (millis() - lastSent > 10000 )
  {
    if (!lRI) setRemoteState(0x4,'1');
    if (lRI) setRemoteState(0x5,'1');
    delay(10);
    
    if (!rRI) setRemoteState(0x4,'2');
    if (rRI) setRemoteState(0x5,'2');
    lastSent = millis();
  }
}

// Send msg through the xbee (note that the frame has to be formed)
void setRemoteState(int value, char pinNum)
{
  Serial.write(0x7e);//Start byte
  Serial.write((byte)0x0);//Length
  Serial.write(0x10);//Length High
  Serial.write(0x17);//AT Command Request
  Serial.write((byte)0x0);//Frame ID
  Serial.write((byte)0x0);//Serial Number of Destination
  Serial.write((byte)0x0);
  Serial.write((byte)0x0);
  Serial.write((byte)0x0);
  Serial.write((byte)0x0);
  Serial.write((byte)0x0);
  Serial.write(0xFF);
  Serial.write(0xFF);//End of Serial Number of Destinition

  // 16 bit of recipient or 0xFFFE if unknown
  Serial.write(0xFF);
  Serial.write(0xFE);
  Serial.write(0x02);//Apply changes immediately

  //Command name in ASCII characters
  Serial.write('D');
  Serial.write(pinNum);

  //command data in as many bytes after length bytes
  Serial.write(value);

  //checksum is all bytes after length bytes
  long sum = 0x17 + 0xFF+ 0xFF + 0xFF + 0xFE + 0x02 + 'D' + pinNum + value;
  Serial.write (0xFF - ( sum & 0xFF) );
  delay(10); // avoiding overwhelming
} 

Video

References

[1] www.electronics-tutorials.ws/transistor/tran_2.html
[2] www.bhashatech.com/transistors/48-npn-bc547.html
[3] http://www.bricogeek.com/shop/motores/220-motor-micro-metal-dc-con-reductora-298-1.html

No comments:

Post a Comment