From design to manufacturing, we support every stage, including software development, hardware, and CAD design. Our expertise spans scalable IoT solutions, embedded software & microcontroller programming, networks & servers, smart device integration, production automation, hardware-software integration, mobile app development and web services. Whether you need custom IoT systems, connected devices, or specialized development services, we bring your ideas to life!
Leobot Electronics South Africa - Electronic Component Supplier & Development Service Provider
Leobot Electronics Online Shop
These tutorials & guides are intended to help beginners in the field of electronics get started or provide some insight into a specific component.
The information in these guides will be updated as often as possible!
A guide to construct your own Arduino-based 2 Wheel-Drive Robot
This is an absolute beginner’s guide on how to get started designing, building and coding a robot from scratch. The basic components to construct a robot is available at Leobot Electronics of course but you are free to obtain the modules at your electronic shop of choice.
The first consideration is Purpose – What is the objective of the robot or device. It is easy to get imaginative with what purposes a robot can serve but it just as important to realise that each and every motion & action has to be practically implementable. Some things may not be practical simply because the cost involved to obtain the precision required may outweigh the benefits of having the robot in the first place. Robotic arms are good example of components that can accomplish a wide variety of task yet have an extremely high entry-level cost to obtain a descent & capable robot arm or hand.
Hence the second consideration is Practical- Is every individual sub-task that forms part of the objective accomplishable? Often you will find that there are alternative approaches available when you run into problems relating to practicality but there will always be a trade-off to compromise. When starting out designing robots, keep it small and simple.
Finally, you have to consider what budget you have available and what your return will yield if the goal is accomplished. For amateur and educational purposes, the expected return may be non-existent other than gaining the experience required, in which case you may not need to work with the most expensive high-tech equipment but simply need to test the concept of working with the principles involved and can use a cheaper module instead. Consider the scenario of building your own CNC or 3D printer: The important part is to understand all the constraints involved and, this can be tested by building the smaller-scale prototype. Instead of building a room-sized 3D printer for your first project, rather build compact desktop-size version instead because you will gain most of the same experience & knowledge but if you do break a motor, gear, pulley or other component, it won’t make an impact on your budget. When scaling up a project physically, many new challenges will come into play that may not directly relate to your task at all.
Let us take on a simple project of building a RC car. The only reason this does not formally qualify as a ‘robot’ is because it not fully automated; the logic will be in the brain of the human and not the machine.
Objective: We want our car to be able to drive on-demand, controlled by remote control.
All wheeled robot cars have the following components in common:
Robots generally use DC motors due to DC motors being able to obtain the highest speed compared to a stepper motor. If you need very precise motion at the expense of speed then you would use a stepper motor. With a stepper motor it is much easier to turn a specific number of degrees while a DC motor will attempt to spin as fast as possible depending on how much power it is given. My robot chassis being used for this project already contains 2 DC motors included that I will use but any DC motor can be used that fits the scope of the project.
First before we start constructing the robot in earnest we first need to make sure we understand all the aspects that we intend to use. It is easier to test modules & sensors in a standalone environment that to test them when already integrated in the rest of the project.
Thus, there are 2 aspects that we would want to gain clarity on before we construct the robot:
So first, lets see how can we control the speed and direction of a DC motor with an Arduino.
The direction of a DC motor is determined by the polarity of the power source attached. Switch the connections around and the polarity will change and thus the direction will change.
The speed of a DC motor is determined by the voltage applied to the motor. The high the voltage, the faster the motor will turn.
Consider trying to change the direction of a DC motor using only an Arduino: You would need to somehow change the polarity of the motor connections yet the Arduino can only provide an output voltage that is positive is polarity. Thus, an H-Bridge module comes into play. The H-Bridge will allow you to change the polarity of the connections to the motor by changing the state of the H-Bridge directly from an Arduino. This means, the Arduino will communicate with the H-Bridge, which in turn will actually drive the motor in the required direction. This solves the polarity issue.
Next, to correctly set the speed of a DC motor a trick is used, namely Pulse Width Modulation (PWM). First lets consider how a DC motor rotates at a specific speed. The higher the voltage the faster the motor spins and the lower the applied voltage the slower it turns. It may seem simple enough but if you consider the fact that by providing a lower voltage, lesss current/ampere will flow through the motor and the total power/wattage, determined by Voltage*Ampere, would also decrease. Thus, the lower the applied voltage, the slower the motor but also the less power (torque) it has! Therefore, you do not simply want to change the voltage directly, and this is where Pulse Width Modulation does the trick. PWM means that instead of sending a constant voltage to the motor, we instead send pulses to the motor. The pulse peak will be the maximum voltage that we can provide, and the troth will be 0V. Essentially, the motor will react to the average voltage being applied to it, while at every instant that voltage is applied it is applied at maximum power, thereby providing high-torque but at a reduced RPM speed. With PWM we can make the motor turn extremely slow but still have the same torque as would have been available at maximum speed.
There is a good explanation on how to use the L298N with an Arduino to set the speed using PWM and change directions available here https://www.instructables.com/id/Control-DC-and-stepper-motors-with-L298N-Dual-Moto/
Next is understanding the IR remote control interface.
Our universal IR receiver has a filter to receive only Infrared light and can really be used with any IR transmitter as all IR light signals will be detected by the IR receiver. A basic IR remote will send 8 hexadecimal digits, encoded in binary as IR light. Our IR receiver simply needs to decode this message and react on it. To make life simple, there is a great IR library available that will take care of actually receiving & decoding messages so that you can simply read the result as a set of hexadecimal values. The IR library is available here https://www.arduinolibraries.info/libraries/i-rremote
To know what messages are actually being sent by a specific IR remote control we simply load the basic IR sketch to dump any signals it receives to the serial port for us to visually inspect. By systematically pressing every key on the remote and saving the value that is received we can easily match signals received with physical buttons on the remote, and then react appropriately as required for that specific button.
Next up it is time to code the logic of the robot to act as traditional RC Car by responding to only 4 commands, namely Forward, Backward, Left and Right and, use this information to drive the 2 motors.
By pressing Up or Down we will move Forward and Backward respectively. Instead of making this complicated by adding variable acceleration to the robot we will simply crank up the power to both motors to the max. The downside of this is that there will be a big jump in current being drawn from the power source as the motors attempt to instantaneously reach the required speed. To avoid this surge in current usage a gradual climb to the required speed would be preferred. If your Arduino seems to reset at random times when just starting to move forward or backward then you are most likely drawing more current from your battery or power supply than it can provide and definitely need to use a gradual climb instead.
Because we do not want the robot to stutter around between waiting for signals from the remote control, we will give it a countdown time to keep on reacting to the last command given until the timer runs down to 0 or a new command is received.
Here is the full source code for a simple IR Remote Controlled Robot (RC Car). You may want to change the commands being responded to depending on your IR remote being used (as described above).
#include <IRremote.h> // THESE ARE THE MOTOR PINS // Motor One int enA = 10; int in1 = 9; int in2 = 8; // Motor Two int enB = 5; int in3 = 7; int in4 = 6; // Remote Control IR Receiver Pin int RECV_PIN = 11; int count=0; bool state= 1; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { Serial.begin(9600); // In case the interrupt driver crashes on setup, give a clue // to the user what's going on. //Serial.println("Enabling IRin"); irrecv.enableIRIn(); // Start the receiver // Serial.println("Enabled IRin"); pinMode(enA, OUTPUT); pinMode(enB, OUTPUT); pinMode(in1, OUTPUT); pinMode(in2, OUTPUT); pinMode(in3, OUTPUT); pinMode(in4, OUTPUT); pinMode(loutpin, OUTPUT); } enum EnumDirection { Stop, Up, Down, Left, Right }; EnumDirection currentDirection; int timeDown=0; int timerMax=100; void loop() { bool HasNewVal=false; EnumDirection nextDirection= currentDirection; count++; if(count>=1) { count=0; } if (irrecv.decode(&results)) { //Serial.println(results.value, HEX); irrecv.resume(); // Receive the next value if(results.value==0xFF18E7) { HasNewVal=true; nextDirection= EnumDirection::Up; // Serial.println("up"); } if(results.value==0xFF4AB5) { HasNewVal=true; nextDirection= EnumDirection::Down; // Serial.println("down"); } if(results.value==0xFF10EF) { HasNewVal=true; nextDirection= EnumDirection::Left; // Serial.println("left"); } if(results.value==0xFF5AA5) { HasNewVal=true; nextDirection= EnumDirection::Right; // Serial.println("right"); } if(results.value==0xFFFFFFFF) { HasNewVal=true; // Serial.println("redo last"); } if(results.value==0xFF38C7) { HasNewVal=true; nextDirection= EnumDirection::Stop; // Serial.println("stop"); } } if(HasNewVal) { currentDirection=nextDirection; timeDown=timerMax; } if(timeDown>0) { timeDown--; } if(timeDown>0) { //drive if(nextDirection== EnumDirection::Stop) { StopAll(); } if(nextDirection== EnumDirection::Up) { DriveForward(); } if(nextDirection== EnumDirection::Down) { DriveBackward(); } if(nextDirection== EnumDirection::Left) { DriveLeft(); } if(nextDirection== EnumDirection::Right) { DriveRight(); } } if(timeDown==0) { //turn off StopAll(); } delay(100); } byte speedx=200; void DriveForward() { // turn on motor A digitalWrite(in1, LOW); digitalWrite(in2, HIGH); // set speed to x out of possible range 0~255 analogWrite(enA, speedx); // turn on motor B digitalWrite(in3, LOW); digitalWrite(in4, HIGH); // set speed to x out of possible range 0~255 analogWrite(enB, speedx); } void DriveRight() { // turn on motor A digitalWrite(in1, LOW); digitalWrite(in2, HIGH); // set speed to x out of possible range 0~255 analogWrite(enA, speedx); // turn on motor B digitalWrite(in3, LOW); digitalWrite(in4, HIGH); // set speed to x out of possible range 0~25 5 analogWrite(enB, (byte)speedx/10); } void DriveLeft() { // turn on motor A digitalWrite(in1, LOW); digitalWrite(in2, HIGH); // set speed to x out of possible range 0~255 analogWrite(enA, (byte)speedx/10); // turn on motor B digitalWrite(in3, LOW); digitalWrite(in4, HIGH); // set speed to x out of possible range 0~25 5 analogWrite(enB, speedx); } void DriveBackward() { // turn on motor A digitalWrite(in1, HIGH); digitalWrite(in2, LOW); // set speed to 200 out of possible range 0~255 analogWrite(enA, speedx); // turn on motor B digitalWrite(in3, HIGH); digitalWrite(in4, LOW); // set speed to 200 out of possible range 0~25 5 analogWrite(enB, speedx); } void StopAll() { digitalWrite(in1, LOW); digitalWrite(in2, LOW); digitalWrite(in3, LOW); digitalWrite(in4, LOW); }
#include <IRremote.h>
// THESE ARE THE MOTOR PINS
// Motor One
int enA = 10;
int in1 = 9;
int in2 = 8;
// Motor Two
int enB = 5;
int in3 = 7;
int in4 = 6;
// Remote Control IR Receiver Pin
int RECV_PIN = 11;
int count=0;
bool state= 1;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
// In case the interrupt driver crashes on setup, give a clue
// to the user what's going on.
//Serial.println("Enabling IRin");
irrecv.enableIRIn(); // Start the receiver
// Serial.println("Enabled IRin");
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
pinMode(loutpin, OUTPUT);
}
enum EnumDirection
Stop,
Up,
Down,
Left,
Right
};
EnumDirection currentDirection;
int timeDown=0;
int timerMax=100;
void loop() {
bool HasNewVal=false;
EnumDirection nextDirection= currentDirection;
count++;
if(count>=1)
count=0;
if (irrecv.decode(&results)) {
//Serial.println(results.value, HEX);
irrecv.resume(); // Receive the next value
if(results.value==0xFF18E7)
HasNewVal=true;
nextDirection= EnumDirection::Up;
// Serial.println("up");
if(results.value==0xFF4AB5)
nextDirection= EnumDirection::Down;
// Serial.println("down");
if(results.value==0xFF10EF)
nextDirection= EnumDirection::Left;
// Serial.println("left");
if(results.value==0xFF5AA5)
nextDirection= EnumDirection::Right;
// Serial.println("right");
if(results.value==0xFFFFFFFF)
// Serial.println("redo last");
if(results.value==0xFF38C7)
nextDirection= EnumDirection::Stop;
// Serial.println("stop");
if(HasNewVal)
currentDirection=nextDirection;
timeDown=timerMax;
if(timeDown>0)
timeDown--;
//drive
if(nextDirection== EnumDirection::Stop)
StopAll();
if(nextDirection== EnumDirection::Up)
DriveForward();
if(nextDirection== EnumDirection::Down)
DriveBackward();
if(nextDirection== EnumDirection::Left)
DriveLeft();
if(nextDirection== EnumDirection::Right)
DriveRight();
if(timeDown==0)
//turn off
delay(100);
byte speedx=200;
void DriveForward()
// turn on motor A
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
// set speed to x out of possible range 0~255
analogWrite(enA, speedx);
// turn on motor B
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
analogWrite(enB, speedx);
void DriveRight()
// set speed to x out of possible range 0~25 5
analogWrite(enB, (byte)speedx/10);
void DriveLeft()
analogWrite(enA, (byte)speedx/10);
void DriveBackward()
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
// set speed to 200 out of possible range 0~255
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
// set speed to 200 out of possible range 0~25 5
void StopAll()
18650 Lithium Battery Charging Module (5V Micro USB 1A)
R25.80
2-Chanel Logic Level Converter (LLC/IIC I2C) Bi-Directional Module 5V to 3.3V (DIY Soldering Needed)
4 Channel LLC I2C/IIC Logic Level Converter Bi-Directional Module 5V to 3.3V (DIY Soldering Needed)
R15.48
4 Channel Remote (315Mhz) + Receiver Module (315Mhz)
R58.05
4.0 Bluetooth Module (CC2540/CC2541 HM-10)
R189.00
5A Single-Phase Micro Current Transformer Module (AC Active Output, ZMCT103C)
R86.00
5mm RGB LED Module (KY-016 FZ0455)
R23.01
5V 1A Ultra-small Li-ion Lithium Battery Charger Module (DD08CRMB)
R90.72
Capacitive Touch Switch Button Self-Lock Module (11.5mm x 8mm)
R22.14
CH340G USB to Serial module (5V, 3.3V)
R51.60
DC 400W 15A Constant Current Power Supply & Step-Up Boost Converter (8.5V-50V to 10V-60V range)
R264.60
DC-DC 3.5V-30V To 4V-40V Step Up Power Supply Module LM2587 (80W Adjustable 5A Boost Converter Voltage Regulator)
R151.20
DS1302 RTC Real Time Clock Module
R34.40
DS1307 RTC Real Time Clock Module
DS3231 AT24C32 Precision Real Time Clock (RTC) Module
ESP01 Serial WiFi Power Regulator Adapter (ESP8266 compatible)
HC-SR04 Ultrasonic Distance Measuring Sensor Module
High Precision Laser Distance Range Finder Module (3.3V-5V, TTL)
R1769.04
IR Infrared Receiver Module
R43.00
LilyPad 328 Main Board (ATmega328P 16M)
R353.43
LM7805 5V Voltage Regulator Module
MAX3232 Mini RS232 to TTL Converter (3-5V)
R39.20
MICRO USB-B POWER SWITCH MODULE
R24.45
MOSFET Relay Module (0-24V Mosfet IRF520)
NE555 Adjustable Pulse Frequency Generator Module
Passive Buzzer Module
RFID Proximity Card Kit (RFID Reader/Writer Module + RFID Keyring Tag + RFID Card)
RS232 Serial Port Module (MAX3232CSE)
R89.00
Serial Micro-SD Card Module
R50.96
Serial SD Card Module
Serial Wifi Transceiver Module (Arduino)
Single Row 40 Pin Male 2.54 Breakable Pin Header Connector Strip
R4.06
SX1308 DC-DC Adjustable Step Up Power Booster Module (2-24V to 2-28V 1.2MHz 2A)
TCS3200 Color Recognition/Detector Module
R340.20
TLP281 4-Channel Opto-isolator
R68.80
Transparent Arduino Uno Enclosure Box
TTL to RS485 Converter Module (Arduino)
R29.80
TTP223 Capacitive Touch Sensor Module
R29.89
Universal LiPo Charger (4.2V/7.4V 2A)
USB - TTL SERIAL USART MODULE (PL2303/YP-01)