Learn. Create. Enjoy.
Learn how to assemble the Cannon add-on for Stackr and control it with an RC transmitter and receiver—required for this project. You will drive Stackr with the left stick and fire the cannon with a button on channel 6.
The easiest way to assemble the Cannon is by following the instructions in the video below.
An RC controller is required. This sketch reads channels from your RC receiver: channels 1 and 2 drive Stackr with differential steering (same as the RC control tutorial), and channel 6 fires the cannon by moving the rack-and-pinion servo on D10.
#include <SparkFun_TB6612.h>
#include <ESP32Servo.h>
#define AIN1 D5
#define BIN1 D6
#define AIN2 D4
#define BIN2 D7
#define PWMA D3
#define PWMB D8
#define STBY D2
#define CH1_LR A0
#define CH2_FWD A1
#define CH6_BTTN A7
Servo servo1;
const int fwdDirectionA = 1;
const int fwdDirectionB = 1;
Motor motor1 = Motor(AIN1, AIN2, PWMA, fwdDirectionA, STBY);
Motor motor2 = Motor(BIN1, BIN2, PWMB, fwdDirectionB, STBY);
long hori_pulse = 0;
long vert_pulse = 0;
long bttn_pulse = 0;
boolean valueCheck(long signal_length) {
if (signal_length >= 999 && signal_length <= 2000) {
return true;
} else {
return false;
}
}
void setup()
{
Serial.begin(115200);
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
servo1.setPeriodHertz(50);
servo1.attach(D10);
servo1.write(90);
pinMode(CH1_LR, INPUT_PULLUP);
pinMode(CH2_FWD, INPUT_PULLUP);
pinMode(CH6_BTTN, INPUT_PULLUP);
motor1.brake();
motor2.brake();
}
void loop()
{
hori_pulse = pulseIn(CH1_LR, HIGH);
vert_pulse = pulseIn(CH2_FWD, HIGH);
bttn_pulse = pulseIn(CH6_BTTN, HIGH);
if (valueCheck(hori_pulse) && valueCheck(vert_pulse)) {
int speed = map(vert_pulse, 999, 2000, -255, 255);
int direction = map(hori_pulse, 999, 2000, -255, 255);
int left_speed = constrain(speed + direction, -255, 255);
int right_speed = constrain(speed - direction, -255, 255);
motor1.drive(right_speed);
motor2.drive(left_speed);
}
if (valueCheck(bttn_pulse)) {
if (bttn_pulse >= 1500) {
servo1.write(0);
} else {
servo1.write(90);
}
}
}
RC required: Connect an RC receiver to the Stackr board. Without valid pulse signals on the RC channels, drive and fire commands will not run as intended.
Libraries and setup: SparkFun_TB6612 controls the drive motors; ESP32Servo runs the cannon servo on D10, centered at 90° at startup.
servo1.attach(D10);
servo1.write(90);valueCheck: RC pulses must be between 999 and 2000 microseconds—typical for a hobby receiver—before they are used.
Differential drive: Channel 2 (forward/back) sets base speed; channel 1 (left/right) adds steering. Each motor gets a combined speed, clamped to ±255.
int speed = map(vert_pulse, 999, 2000, -255, 255);
int direction = map(hori_pulse, 999, 2000, -255, 255);
int left_speed = constrain(speed + direction, -255, 255);
int right_speed = constrain(speed - direction, -255, 255);Firing the cannon: Channel 6 is read each loop. When the pulse is valid, a high reading (≥ 1500 µs) moves the servo to 0° to actuate the rack and pinion; a low reading returns it to 90° (ready position).
if (valueCheck(bttn_pulse)) {
if (bttn_pulse >= 1500) {
servo1.write(0);
} else {
servo1.write(90);
}
}Install SparkFun TB6612 and ESP32Servo from the Arduino Library Manager. You also need an RC transmitter and receiver wired to the channels shown in the sketch.