December 9, 2018

14. Radio-controlled Robot

The new challenges


We consider our tank-robot project as a very successful one - our creature can be nicely controlled remotely over Wi-Fi, or navigate around in the autonomous mode avoiding dangers and collisions. Still, there are questions which we could not answer:
  • Remote control over the Wi-Fi lags even if you connect your agents directly. Is there any better way to control the robot? Can the Radio Controlling system be the answer?
  • Do you really need to purchase expensive factory-made chassis, or there is some better way?
  • Could LCD displays be useful for a small robot?
  • Is it hard to use Li-Ion battery in the project?
To answer these questions - we decided to build a new robot, which will be a lightweight peer for our tank.

Radio-Controlled Robot



Used components

Erector construction set parts
Custom chassis made from the remains of the old erector construction set (including wheels)
Arduino Nano-like microcontroller with the expansion shield
Arduino Nano-like microcontroller with the expansion shield
DC Motor 100 RPM, 6 V
DC Motor 100 RPM, 6 V, 2 pcs
Motor mounting bracket
Motor mounting bracket, 2 pcs.
Wheel mounting coupler
Wheel mounting coupler, 4 mm., 2 pcs.
DC Motor driver with the power conversion function
DC Motor driver with the power conversion function
LCD screen 128x64, I2C
LCD screen 128x64, I2C
LCD screen text 1602, I2C
LCD screen text 1602, I2C
RC System, 6-channel
RC System, 6-channel
Li-Ion cell 18650
Li-Ion cell 18650, 2 pcs.
Li-Ion battery charging controller 2S
Li-Ion battery charging controller 2S
T-Plug connector
T-Plug connector
Universal charger
Universal charger

Chassis


The chassis was successfully built from the parts of old erector construction set (including wheels). Still, we had to buy separately motor mounting brackets.

Chassis with the motor mounting brackets


We use regular DC motors, with the built-in reduction gears.

Chassis with the motor mounted


Main parameters you should pay attention to while selecting motors for your projects are working voltage and max RPM the motor can produce.

From the very beginning, we were planning to use 2S Li-Ion 18650 battery (see below), so working voltage around 6-7 volts is a perfect choice.

With the RPM - we missed a bit. 100 RPM appeared to be slow. We recommend to stick to 200 RPM - you still get quite good torque, and twice wider speed range (you can limit it programmatically later if needed).

As a nice bonus, our motors have Hall sensors which count the real RPM of the wheels (also known as encoders). Thus you can detect if your robot stuck in front of some obstacle, or calculate the running distances more precisely. In this project, we do not use these sensors as for now.

Motor connector


The wheels are connected directly to the motor shafts using wheel mounting couplers purchased separately. Pay attention to choosing proper inner diameter - it must fit tightly the motor shaft, In our case, it was 4 mm.

Wheels with the couplers

Chassis with the motors and wheels - 1

Chassis with the motors and wheels - 2


Finally - we've got a nice and reliable two-wheeled chassis to lay as a foundation of the robot.

The Electronic Components

 

Schematics


Electrical schematic

The electrical schematic shows the minimal set of the components, sufficient for the robot to be able to move and react to the commands from the RC receiver. LCD screens are optional - we included them only to make the robot nicer and easier to understand (the robot can show debug information on the screens if needed).

Microcontroller

The size of the chassis allows using any board from the Arduino family, but we happen to have a spare Arduino Nano which fit the project perfectly well. To make the wires connection easier, we also use the expansion board.

Arduino Nano on the expansion shield


Power source

The power source was built using two Li-Ion 18650 elements (like those) connected in series. We explained in a separate post in more details the main battery-building ideas (Power for the Robot).

Battery parts

Battery assembled



The battery is managed by the 2S battery controller - this is the board which protects the battery from overcharge and too deep discharge.

To charge Li-Ion batteries we use Eachine WT50 charger. Out of all other options - this charger looks the most user-friendly, covering all our use cases. Cables supplied allow connecting to the batteries by the T-shaped plug, so we installed corresponding sockets on a battery.

A simple two-position switch connects the positive battery line either to the first or to the second T-plug. Having one connected to the robot's circuits, and the other to be used for charging, you can choose if the battery sends power to the robot or receives the current from the charger.

Motor Driver

As a motor driver, we use the L298N-based board.
Motor driver board

This board has a specific useful feature - the power conversion circuit. It extracts 5 V from the input voltage used for the motors (7-35 V) and not only use it to power own chips but can also provide a reliable 5 V power to the whole robot.

Please check here for more details on how to operate this board. Key points:
  • Battery power should be connected to the +12 V input socket on a board. Don't be misled by the socket label - actually, any voltages in the range 7-35 V are fine. Just keep in mind that this voltage is going to be applied to your motors, so make sure they will be fine with this.
  • Place the jumper next to the +12 V input socket - this will engage the power conversion circuit
  • Connect the robot +5 V power line to the +5 V socket on the motor drive board, if that is the way you'd like power your robot. We connected Arduino Nano directly to the battery power using the Vin line instead, leaving the motor driver 5 V for internal use only.
  • Connect the motors to the corresponding sockets OUT1-4
  • Remove jumpers from ENA and ENB pins. Thus you can control the motors speed connecting them to the PWM pins of the Arduino Nano. Having these lines connected to the +5 V means motors will always run at the maximum speed.
  • Connect pins IN1-4 to any pins at the microcontroller board. Setting different voltage combinations there, you can control the motors rotation direction.

To simplify the robot's firmware source code, we separated all motors-specific handling in a standalone simple class (module).

As a starting step - create an instance of the motor controller class, providing the ID's of the Arduino pins, you connected to the motor driver controlling lines:

const uint8_t ENA = 10;
const uint8_t IN1 = 9;
const uint8_t IN2 = 8;
const uint8_t IN3 = 7;
const uint8_t IN4 = 6;
const uint8_t ENB = 5;
MotorL298NController motorController(ENA, IN1, IN2, ENB, IN3, IN4);

Then - in any place of your code just call the go() method of the object created, specifying the desired motors speed as a parameter. The speed can be in the range from -255 (full reverse) to +255 (full ahead). Specifying a single parameter you will run both motors at the same speed. Specifying two parameters you can choose the speed for each motor separately.

motorController.go(255); // both motors - full ahead
motorController.go(255,100); // turning right smoothly

Please keep in mind - motors cannot be started at the speeds too close to zero. In our case - they do not react to any speeds in the range from -30 to +30. In this range they also produce an annoying squeak. So, find the working range for your motors and make sure you are not trying to operate them at too slow speeds. Below you will see how we did this in our code.

Radio Control System


The Basic Principles




Robot & RC system

The RC system consists of two parts - the RC transmitter and the RC receiver. Using the radio signals, a transmitter sends to the receiver information about the state of its joysticks and buttons. The receiver decodes this information and relays it to the motors or other mechanisms of the model (or the robot).

Modern RC systems can also transfer information back from the model to the RC transmitter (for example, this can be information about the battery charge level, motors temperature). This telemetry can be shown right on the transmitter's LCD screen.

The first versions of the RC receivers were built with the intention to connect them directly to the servos, which are operated by the PWM signals (see the previous post for more information on PWM). The further you push a joystick lever on a transmitter, the more intense PWM signal is sent, the further servo's arm deviates from the starting point. For such a simple case - you don't even need to solder anything. The servo connector can be plugged directly to the receiver socket (assuming the receiver +5 V can supply enough power for the servo).

RC system working principle
Having 6 channels means you can connect 6 servos (or other mechanisms) in this simple PWM mode.

The next level was reached by introducing the PPM (Pulse Position Modulation) protocol. Sometimes it is also referred to as CPPM or PPMSUM. The idea is to use a single channel to transmit information about the state of more than one (up to 12) controls. First, the transmitter sends the position of the first switch, then - the second, and so on. Unfortunately, you can't send such signal directly to the servos - it should be decoded first using a special module.

A family of the Serial RX protocols is even more complicated. In contrast to the previous protocols, it is purely digital. Information is transmitted as a sequence of "ones" and "zeroes", encoding the data in the format like the following: "Channel 1: 1234; Channel 2: 5512; Channel 3…". This is a real break-through which opens almost limitless possibilities. A major problem with these protocols - each manufacturer has its own version, incompatible with others (S.Bus, i-Bus, XBus, Graupner Hott).

See here for more information about the RC systems. The simplest PWM mode use in the Arduino projects is nicely explained in the SparkFun tutorial.

We use a FlySky 6-channel RC system. It is quite inexpensive and easy to operate, and still provide a good set of features. Even though we employed just two radio channels out of six, and used them in the very basic PWM mode, don't hesitate to get a feature-rich set if the price difference is not big. For sure you will be adding more and more features to your project, so having some spare capacity can be a good idea.

Connecting the Receiver


RC receiver smoothly integrates into the Arduino projects. It can be powered by the Arduino +5 V / GND lines. Connect the RC channel output directly to any Arduino pin. You will spend much more time setting up the transmitter - don't forget to switch the channels to the PWM mode.

The receiver can be mounted on a chassis any way you like. There are only specific recommendations on how to mount the external antenna:
  1. Prevent antenna from touching any metallic parts of the robot.
  2. If your antenna has two wires - try to set them perpendicularly - this will improve the link reliability.

Reading Programmatically the RC Commands


In the firmware code follow these steps to read the RC commands from the receiver:
  1. Make sure the Arduino pins connected to the receiver are set to the INPUT mode:
    pinMode(RC_CH_TURN, INPUT);
    pinMode(RC_CH_THROTTLE, INPUT);
  2.  Since the receiver sends to Arduino a regular PWM signal - we can decode it by calculating the pulse duration
    long chThrottle = pulseIn(RC_CH_THROTTLE, HIGH, 30000);
    long chTurn = pulseIn(RC_CH_TURN, HIGH, 30000);
    In our case, we had to specify 30000 as a third parameter. A smaller number did not yield correct readings. Maybe this is a specific feature of the Arduino Nano.
  3. Pulse durations below 900, mean that the channel is not active. Maybe the receiver does not have a connection to the transmitter at all. In such case, it is better to shut off the motors and do nothing.
  4. We also ignore the pulse duration between 900 and 1000. Just to reliably fix the robot at the zero point and avoid unexpected motors launch due to the accidental radio noise.
  5. We take into account only values between 1000 and 2000 and proportionally scale it to the motor speed range (between 30 and 255). Do you still remember why 30?
    speedL = map(chThrottle, 1000, 2000, 30, 255);
  6. Next - you can apply a simple logic to determine the turning speed and send a final command to the motors.
Pay attention - pulse durations and the motors working speed range can be different for your hardware. Be ready to experiment with these numbers a bit to find the best fit.

Optional LCD screens

 

Front Graphical 128x64 Screen


To make more fun interacting with the robot we added two screens.

The front screen is graphical single-color LCD one with the resolution 128x64. We use it to show smiles and emotions. This screen is connected by the I2C bus, so it uses just two wires to transmit commands from the Arduino.

For the programmer, all the low-level details are covered by the library U8g2, which can be activated right in the Arduino development environment. We paint a happy smile, which stays on the robot's face for all time it is online:

U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0);
…
u8g2.begin();
u8g2.firstPage();
do {
    u8g2.drawLine(41, 8, 45, 32);
    u8g2.drawLine(83, 8, 87, 32);
    u8g2.drawEllipse(65, 43, 29, 8,
            U8G2_DRAW_LOWER_LEFT | U8G2_DRAW_LOWER_RIGHT);
    u8g2.drawLine(73, 51, 78, 55);
    u8g2.drawLine(61, 51, 66, 55);
    u8g2.drawLine(67, 51, 72, 57);
    u8g2.drawEllipse(72, 55, 6, 8,
            U8G2_DRAW_LOWER_LEFT | U8G2_DRAW_LOWER_RIGHT);
} while (u8g2.nextPage());

A happy smile on a graphical screen

Try changing the smile to frustrated when the robot can't establish a connection with the remote radio controller.

Back-facing text screen 1602


At the robot's back, we placed a text screen, where we show additional information about the robot status.

Debug messages on the text screen


Numbers 1602 in the screen name mean it has 2 rows and is 16 characters wide.

This screen also uses the I2C bus, so it shares the same two signal lines as the front screen.

We use LiquidCrystal-I2C library to work with this screen. Here some samples from our code:

// I2C address = 0x27, 16 chars, 2 rows
LiquidCrystal_I2C backLCD = LiquidCrystal_I2C(0x27, 16, 2);// initialization
backLCD.init();
// turn off the auto-scroll
backLCD.noAutoscroll();
// turn on the backlight
backLCD.backlight();
// print some text
backLCD.print("Initializing...");

The only not quite obvious step is guessing the I2C address used by the precise board you have. Normally boards are set to some default addresses which are also used in the Arduino IDE examples. But if your I2C board does not work for an unknown reason - maybe the wrong address is the case. Use I2C Scanner sketch to detect the real addresses, having your board connected.

A good piece of information about I2C is provided in Nick Gammon's Forum. If you prefer video - refer to Jeremy Blum's video blog.

No comments:

Post a Comment