RC Controller

Learn how to control your Stackr robot using an RC (Radio Control) transmitter. This code enables remote control of the robot's movement through PWM signals from an RC receiver.

Controlling the Stackr with an RC Controller

This code demonstrates how to read signals from an RC controller and translate them into motor commands for differential drive control. The robot can move forward, backward, turn left, turn right, and perform combinations of these movements based on the RC controller inputs.

Stackr_RC_Control.ino
#include <SparkFun_TB6612.h>

const int fwdDirectionA = 1;
const int fwdDirectionB = 1;

unsigned long hori_pulse = 0;
unsigned long vert_pulse = 0;

// Pins for all inputs, keep in mind the PWM defines must be on PWM pins
#define AIN1 D5
#define BIN1 D6
#define AIN2 D4
#define BIN2 D7
#define PWMA D3
#define PWMB D8
#define STBY D9

#define CH1_LR A0 //Channel1
#define CH2_FWD A1 //Channel2

//Initializing Motors
Motor motor1 = Motor(AIN1, AIN2, PWMA, fwdDirectionA, STBY);
Motor motor2 = Motor(BIN1, BIN2, PWMB, fwdDirectionB, STBY);

void setup()
{
  //Set pins as input
  pinMode(CH1_LR, INPUT_PULLUP);
  pinMode(CH2_FWD, INPUT_PULLUP);
  motor1.brake();
  motor2.brake();
}

void loop()
{
  //Reads signal from RC controller, specifically when the signal is high
  hori_pulse = pulseIn(CH1_LR,HIGH);
  vert_pulse = pulseIn(CH2_FWD,HIGH);

  //Check if signal received is within proper range, then convert to a readable speed
  if(hori_pulse >= 999 && hori_pulse <= 2000 && vert_pulse >= 999 && vert_pulse <= 2000){
    int speed = map(vert_pulse,999,2000,-255,255);
    int direction = map(hori_pulse,999,2000,-255,255);

    // Set exact speed for each motor, accounting for direction
    int left_speed  = constrain(speed + direction, -255, 255);
    int right_speed = constrain(speed - direction, -255, 255);
    motor1.drive(right_speed);
    motor2.drive(left_speed);
  }

}

Code Breakdown

Library Inclusion: The SparkFun_TB6612 library provides DC motor control functionality for the TB6612FNG motor driver on ESP32-based boards.

#include <SparkFun_TB6612.h>

Forward Direction Constants: These constants define the default forward direction for each motor. A value of 1 indicates the normal forward direction, while -1 would reverse it.

const int fwdDirectionA = 1;
const int fwdDirectionB = 1;

Pulse Variables: These variables store the pulse width duration read from the RC controller channels. The pulse width indicates the position of the RC controller sticks.

unsigned long hori_pulse = 0;
unsigned long vert_pulse = 0;

Motor Control Pin Definitions: The code defines pins for the motor controller. AIN1/AIN2 and BIN1/BIN2 control direction, PWMA/PWMB control speed via PWM, and STBY is the standby enable pin.

#define AIN1 D5
#define BIN1 D6
#define AIN2 D4
#define BIN2 D7
#define PWMA D3
#define PWMB D8
#define STBY D9

RC Channel Pin Definitions: CH1_LR reads horizontal (left-right) control from Channel 1, and CH2_FWD reads vertical (forward-backward) control from Channel 2 of the RC receiver.

#define CH1_LR A0 //Channel1
#define CH2_FWD A1 //Channel2

Motor Initialization: Two Motor objects are created to control the left and right motors. Each motor is initialized with its control pins and forward direction configuration.

Motor motor1 = Motor(AIN1, AIN2, PWMA, fwdDirectionA, STBY);
Motor motor2 = Motor(BIN1, BIN2, PWMB, fwdDirectionB, STBY);

Setup Function: The setup function configures the RC channel pins as inputs with pull-up resistors, and initially applies brakes to both motors to ensure the robot starts in a stopped state.

void setup()
{
  //Set pins as input
  pinMode(CH1_LR, INPUT_PULLUP);
  pinMode(CH2_FWD, INPUT_PULLUP);
  motor1.brake();
  motor2.brake();
}

Reading RC Signals: The pulseIn() function reads the pulse width in microseconds when the signal goes HIGH. This value represents the RC controller stick position, typically ranging from 1000μs (full left/down) to 2000μs (full right/up) with 1500μs as center.

hori_pulse = pulseIn(CH1_LR,HIGH);
vert_pulse = pulseIn(CH2_FWD,HIGH);

Signal Validation and Mapping: The code validates that the received pulse widths are within the expected range (999-2000 microseconds). Then it maps these values to motor speed ranges (-255 to 255), where positive values drive forward and negative values drive backward.

if(hori_pulse >= 999 && hori_pulse <= 2000 && vert_pulse >= 999 && vert_pulse <= 2000){
    int speed = map(vert_pulse,999,2000,-255,255);
    int direction = map(hori_pulse,999,2000,-255,255);
}

Differential Drive Calculation: The code implements differential drive (tank drive) by combining speed and direction. Adding direction to speed creates the left motor speed, while subtracting direction creates the right motor speed. This allows the robot to turn while moving forward or backward.

int left_speed  = constrain(speed + direction, -255, 255);
int right_speed = constrain(speed - direction, -255, 255);

Motor Control: Finally, the calculated speeds are applied to each motor. The constrain() function ensures the speed values stay within the valid range (-255 to 255) to prevent any potential issues.

motor1.drive(right_speed);
motor2.drive(left_speed);

Library Installation

To use the code examples above, you'll need to install the SparkFun_TB6612 library in your Arduino IDE. Here are the resources and steps to get started:

Installation Method

Manual Installation

  • Download the library from the SparkFun GitHub repository
  • Extract the ZIP file
  • Copy the library folder to your Arduino libraries directory
  • Restart Arduino IDE

External Resources