Wireless RC Robot with Arduino and XBees
2019-03-26 | By SparkFun Electronics
License: See Original Project Programmers Wireless Arduino XBee
Courtesy of SparkFun
Introduction
In this tutorial, we will expand on the SIK for RedBot to control a robot wirelessly with XBee radios! We'll explore a different microcontroller and wirelessly control the RedBot at a distance. Beware, we'll need to solder the wireless controller together.
Required Materials
To follow along with this tutorial, you will need the following materials. You may not need everything though depending on what you have. Add it to your cart, read through the guide, and adjust the cart as necessary.
Wireless RC Robot with Arduino and XBees Wish List SparkFun Wish List
(2) XBee 3 Module - PCB Antenna
SparkFun Inventor's Kit for RedBot
SparkFun Wireless Joystick Kit
(4) Panasonic Alkaline Battery - AA
SparkFun XBee Explorer USB
SparkFun Cerberus USB Cable - 6ft
Lithium Ion Battery - 850mAh
Heads up! This tutorial uses the RedBot mainboard programmed with Arduino and shadow chassis. Depending on your setup, you can choose different motor drivers for your motor and chassis.
Wild Thumper 6WD Chassis - Black (34:1 gear ratio)
Circular Robotics Chassis Kit (Three-Layer)
Actobotics Kit - ActoBitty 2
Multi-Chassis - Tank Version
Tools
You will need a soldering iron, solder, and general soldering accessories. If you have not soldered before, we suggest looking at the tool kits. You will also need a wire stripper and some wire depending on the XBees that you are using.
Suggested Reading
If you aren’t familiar with the following concepts, we recommend checking out these tutorials before continuing.
How to Solder: Through-Hole Soldering: This tutorial covers everything you need to know about through-hole soldering.
Working with Wire: How to strip, crimp, and work with wire.
Assembly Guide for RedBot with Shadow Chassis: Assembly Guide for the RedBot Kit. This tutorial includes extra parts to follow to go along with the RedBot Inventor's Kit tutorial.
Exploring XBees and XCTU: How to set up an XBee using your computer, the X-CTU software, and an XBee Explorer interface board.
Experiment Guide for RedBot with Shadow Chassis: This Experiment Guide offers nine experiments to get you started with the SparkFun RedBot. This guide is designed for those who are familiar with our SparkFun Inventor's Kit and want to take their robotics knowledge to the next level.
Wireless Joystick Hookup Guide: A hookup guide for the SparkFun Wireless Joystick Kit.
Hardware Hookup
Assembled Shadow Chassis
We'll assume that you have a fully assembled robot with the Shadow Chassis.
Assembly Guide for RedBot with Shadow Chassis
Assembly Guide for the RedBot Kit. This tutorial includes extra parts to follow to go along with the RedBot Inventor's Kit tutorial.
Motor and Power Switches
Make sure to flip the MOTOR and POWER switches to the RUN and ON positions respectively.
Motor Wires
To be consistent with the hookup used with the assembly and experiment guide, make sure that the motor wires match the table and image below.
Left Motor:
Right Motor:
Software Serial Switch
To avoid bricking the XBee on the RedBot or uploading, it is recommended to utilize the software serial port. Make sure to flip the switch to the "XBEE SW SERIAL" side.
Assembled Wireless Joystick
We'll also assume that you have a wireless joystick assembled together. Check out the Hardware Hookup section in the Wireless Joystick Hookup Guide for more information. Note that you will need to solder the components together as opposed to the solderless RedBot Kit.
Wireless Joystick Hookup Guide
A hookup guide for the SparkFun Wireless Joystick Kit.
The example code used in this tutorial works for both the dual joystick and single joystick.
Jumper Wire for XBee 3's
The following code works with a XBee Series 1 set to transparent mode. If you are using an XBee Series 3, you may need to add a jumper between the XBee Series 3's reset pin and A5 for the Wireless Joystick. Simply cut and strip a piece of wire to add between reset pin on the XBee's female socket and A5.
Solder Pin for XBee Series 3
Once the wire is soldered, it should look similar to the image below.
Jumper wire between A5 and RESET pin on the XBee Series 3
Configuring XBees
To configure the XBees, we will be using the XBee Series 1 firmware. It is recommended to configure each XBee using the XBee Explorer USB.
If you have not already, check out the Starting with XCTU section under Exploring XBees and XCTU to configure your XBees.
How to set up an XBee using your computer, the X-CTU software, and an XBee Explorer interface board.
Point-to-Point Configuration
For simplicity, we will be sending commands with the XBees in transparent mode set for a point-to-point configuration. Make sure to configure each XBee with a unique MY address if there are more than two XBees in your CH and PAN ID. You will then need to adjust the DL address for each respective XBee.
Point-to-Multipoint (i.e. Broadcast Mode)
Tip: Controlling more than one robot? To control multiple XBees as a point-to-multipoint configuration, simply configure the transmitting XBee attached to the wireless joystick to broadcasting mode by setting DL = FFFF. Just make sure to configure your XBees with unique addresses.
Setting Up Arduino
Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE.
Wireless Controller
SAMD21 Drivers
The wireless joystick has a built-in CDC. Depending on your operating system, you may need to install the drivers. Make sure to check out the section on drivers as explained in the SAMD21 Mini/Dev Breakout Hookup Guide.
Board SAMD21 Add-Ons
There are a few board add-ons to install. If you have not already, make sure to install the Arduino SAMD boards and the SparkFun board definitions as explained in the SAMD21 Mini/Dev Breakout Hookup Guide. These are the same add-ons used for the wireless joystick.
RedBot Mainboard
FTDI Drivers
Remember, to program your robot right from your browser, you will first need to install some FTDI drivers. Follow the steps in How to Install FTDI Drivers to do so. This is also explained in the RedBot Guides.
How to install drivers for the FTDI Basic on Windows, Mac OS X, and Linux.
Arduino Library
Note: If you have not previously installed an Arduino library, please check out our installation guide.
Make sure to install the RedBot library as explained in the RedBot Library Quick Reference. You'll also find the quick overview of the RedBot Library, classes, methods, and variables.
Experiment 1: Sending and Receiving a Signal
Introduction
There are a few methods of transmitting data between two Arduinos and a pair of XBees. You can send a serial character in transparent mode, packet in API mode, or control with an I/O pin. For simplicity, we will sending a character in transparent mode.
Parts Needed
You will need the following parts from the required materials:
2x XBees (Configured to Series 1 Firmware)
1x Cerberus Cable (or 1x micro-B USB and 1x mini-B USB Cable)
1x Assembled Shadow Chassis w/ RedBot Mainboard
4x AA Batteries
1x Assembled Wireless Joystick
1x LiPo Battery
1.1: Sending
For this part of the experiment, we are going to send a character from the controller to the RedBot on the same channel.
Hardware Hookup
If you have not already, insert the XBee and battery into the controller. Then connect the controller to your computer via USB cable.
Open the Sketch
Copy and paste the following code into the Arduino IDE. Select the SAMD21 DEV Breakout as the board, select the COM port that it enumerated on, flip the Wireless Joystick's switch to the ON position, and hit upload.
/* 1_1_XBee_Transmit_Basic_SAMD21.ino XBee Transmit Basic SAMD21 Example Written by: Ho Yun Bobby Chan Date: 2/15/19 SparkFun Electronics license: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) Do whatever you'd like with this code, use it for any purpose. Please attribute and keep this license. This is example code for the Wireless Joystick with SAMD21. Any character entered through the Serial Monitor will be sent to the hardware UART pins. Assuming that you have a pair of XBees Series 1 modules (or Series 3 modules configured with 802.15.4 protocol) on the same channel, a character will be transmitted wirelessly between the XBees. The receiving XBee will then pass the character to the an ATmega328P microcontroller to eventually control a robot. Note: You may need to connect A5 to the XBee Series 3's reset pin on the Wireless Joystick for certain XBee Series 3 modules. For more details, check out the xbee3_RESET() function. */ char c_data;//send values through the serial monitor for debugging //LED to check if the LED is initialized. const int status_LED = 13; //needed for certain XBee Series 3 modules #define xbee_reset A5 void setup() { SerialUSB.begin(9600);// Initialize Serial Monitor for DEBUGGING //Uncomment this if you want to wait until the serial monitor is open. //while (!SerialUSB); //Wait for Serial Monitor to Open SerialUSB.println("Wireless Joystick Controller Initializing"); Serial1.begin(9600); // Start serial communication with XBee at 9600 baud xbee3_RESET();//in case XBee3 has issues initializing, hardware reset //Status LED to see if the Controller is initializing pinMode(status_LED, OUTPUT); for (int i = 0; i < 3; i++) { digitalWrite(status_LED, HIGH);//set Status LED on delay(50); digitalWrite(status_LED, LOW); //set Status LED off delay(50); } SerialUSB.println("Wireless Joystick Controller's XBee Ready to Communicate"); delay(10); }//end setup void loop() { //send commands via serial monitor for testing here if (SerialUSB.available()) { c_data = SerialUSB.read();//take character from serial monitor and store in variable Serial1.print(c_data);//send to XBee //echo back what was sent to serial monitor SerialUSB.println("Sending Character Here, "); SerialUSB.println(c_data); digitalWrite(status_LED, HIGH); //turn ON Status LED } delay(100);//add short delay for LED for feedback, this can be commented out if it is affecting performance digitalWrite(status_LED, LOW); //turn OFF Status LED }//end loop void xbee3_RESET() { //HARDWARE RESET /* - XBee Series 3 Hardware Reference Manual - Pg 31 Power Supply Design recommends decoupling capacitor between Vcc and GND. Tested with 10uF capacitor and without. This was not necessary. - Pg 60 Brown Out Detection. This is REQUIRED. Add a jumper between the XBee's Reset and A5 https://www.digi.com/resources/documentation/digidocs/pdfs/90001543.pdf - Power cycle XBee Series 3 by grounding RESET Pin to avoid dicontinuities in ramp up and brown out detection https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2017/06/14/rmu_e203_avdd_ramp-j176 - Minimum Time to Force Reset: - EFM32 devices = 50ns; EFM32PG/JG: Pearl and Jade Gecko =100ns https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2016/07/22/minimum_reset_holdt-PglD */ pinMode(xbee_reset, OUTPUT); digitalWrite(xbee_reset, HIGH); delayMicroseconds(1); digitalWrite(xbee_reset, LOW); delayMicroseconds(1); digitalWrite(xbee_reset, HIGH); /* //SOFTWARE RESET //Software reset does not work with XBee Series 3... Needs a hardware reset delay(500);//wait until XBee Series 3 to start up after hardware reset Serial1.write("+++"); //Enter Command Mode delay(500);//short delay as the XBee gets into command mode Serial1.write("ATFR");//AT command for software reset Serial1.write("\r");//carriage return Serial1.write("\n");//new line */ }
Code to Note
The code sets up a variable to keep track of the character being sent, an LED for indicator on pin 13 when we are sending a character, and a pin to reset the XBee. Since the controller uses the SAMD21, we will initialize the serial monitor for debugging using SerialUSB and the hardware serial using Serial1 to send characters using an XBee at 9600 baud. The code will briefly toggle A5 to reset an XBee 3 when the board is powered up in our custom function called xbee3_RESET(). Once we are finished initializing, the LED will blink three times. Then we will listen to the serial monitor for any characters in an if() statement. If a character is sent through the serial terminal, we will pass the character on to the XBee and echo it back to the serial monitor for debugging.
1.2: Receiving
For this part of the experiment, we are going to have the RedBot receive a character from the first controller.
Hardware Hookup
If you have not already, insert the XBee into the RedBot. Then connect the Redbot to your computer via USB cable.
Open the Sketch
Copy and paste the following code into the Arduino IDE. Since we are uploading code for the RedBot Mainboard, we will need to select Arduino/Genuino Uno for the RedBot mainboard, select the corresponding COM port that it enumerated on, and flip the POWER switch to the ON position. Once these settings are adjusted, you can hit the upload button.
/* 1_2_XBee_Receive_Basic_ATmega328P.ino XBee Receive Basic ATmega328P Example Written by: Ho Yun Bobby Chan Date: 2/15/19 SparkFun Electronics license: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) Do whatever you'd like with this code, use it for any purpose. Please attribute and keep this license. The first step to controlling the RedBot remotely is to first drive it from the Serial Monitor in a tethered setup. This is example code for the RedBot Mainboard with ATmega328P. After uploading this sketch, keep the RedBot tethered to your computer with the USB cable. Flip the switches to the respective sides: MOTOR => RUN and POWER => ON. You will also need to have UART flipped to the XBee_SW_Serial side. Assuming that you have a pair of XBees 1s (or 3 configured with 802.15.4 protocol) on the same channel, a character will be transmitted wirelessly between the XBees. Any charactered received from the XBee connected to the software serial defined pins will be passed to the Serial Monitor. For troubleshooting, any character sent through the Serial Monitor will be echoed back. */ #include <RedBot.h> //include RedBot library char c_data; // variable for holding incoming data from XBee to Arduino // We'll use RedBot SoftwareSerial to communicate with the XBee: // For Atmega328P's // XBee's DOUT (TX) is connected to pin 14 (Arduino's Software RX) // XBee's DIN (RX) is connected to pin 15 (Arduino's Software TX) #include <RedBotSoftwareSerial.h> RedBotSoftwareSerial RedBotXBee; //make instance of Software Serial, pins defined already in modified Software Serial Library //LED to check if the LED is initialized. const int status_LED = 13; void setup() { // Set up both ports at 9600 baud. This value is most important // for the XBee. Make sure the baud rate matches the config // setting of your XBee. RedBotXBee.begin(9600);// Initialize SW for XBee for receiving serial Serial.begin(9600);// Initialize HW for Serial Monitor for DEBUGGING //Status LED to see if the RedBot is initializing pinMode(status_LED, OUTPUT); for (int i = 0; i < 3; i++) { digitalWrite(status_LED, HIGH);//set Status LED on delay(50); digitalWrite(status_LED, LOW); //set Status LED off delay(50); } Serial.println("RedBot Initialized!"); }//end setup void loop() { if (RedBotXBee.available() || Serial.available()) { if (RedBotXBee.available()) { c_data = RedBotXBee.read();//store received value from XBee into variable } else if (Serial.available()) { c_data = Serial.read();//store received value from Serial Monitor into variable } Serial.println("Character Received, "); Serial.write(c_data);//send it out to serial monitor Serial.println(); digitalWrite(status_LED, HIGH); //turn ON Status LED delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } digitalWrite(status_LED, LOW); //turn OFF Status LED }//end loop
Code to Note
The code for the RedBot is similar to the SAMD21. However, since we are using the ATmega328, we will be setting up the software serial to receive characters from the XBee. The RedBot uses a custom software serial so we will need to include the <RedBotSoftwareSerial.h>. We will initialize the serial monitor for debugging using Serial and the software serial using using RedBotXBee to receive the characters from the XBee at 9600 baud. When using an XBee 3 with the RedBot mainboard, the XBee 3 did not have any issues during its initial power up so there was no need to toggle the XBee 3's reset pin. Once we are finished initializing, the LED will blink three times again. Then we will listen to the serial monitor or software serial for any characters received in the if() statement. If a character is received, we will display the character in the serial monitor for debugging.
What You Should See
We'll open a serial terminal for each board to see if a character was sent from the controller to the RedBot. For the controller, we'll open a serial terminal at 9600 that the controller enumerated on. For the RedBot, we'll use the Arduino serial monitor at 9600 since we just uploaded code to the board. Sending any character in the serial terminal will echo back and the have controller's XBee wirelessly transmit a character to the RedBot's XBee. Once received, the character will display in th Arduino serial monitor.
Congratulations, you have successfully sent a character wirelessly between two Arduinos!
Experiment 2: Wirelessly Driving Forward
Introduction
Now that we have successfully sent a character, the next step is to have the controller receive an input before sending a character. Once the receiving robot receives the character, we'll have the motors drive forward.
Parts Needed
You will need the following parts from the required materials:
2x XBees (Configured to Series 1 Firmware)
1x Cerberus Cable (or 1x micro-B USB and 1x mini-B USB Cable)
1x Assembled Shadow Chassis w/ RedBot Mainboard
4x AA Batteries1x Assembled Wireless Joystick
1x LiPo Battery
2.1: Remote Control w/ the SAMD21
For this part of the experiment, we are going to send a character from the controller based on the input. For simplicity, we will send a character when a button is pressed (D2) and the left joystick is in the up position.
Note: If you soldered a joystick on the right side of the board as well, pressing down on the joystick will also be acceptable!
Hardware Hookup
If you have not already, connect the controller to your computer via USB cable.
Open the Sketch
Copy and paste the following code into the Arduino IDE. Remember to select the SAMD21 DEV Breakout for the controller, select the COM port that it enumerated on, flip the Wireless Joystick's switch to the ON position, and hit upload.
/* 2_1_Remote_Control_SAMD21.ino Remote Control SAMD21 Example Written by: Ho Yun Bobby Chan Date: 2/15/19 SparkFun Electronics license: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) Do whatever you'd like with this code, use it for any purpose. Please attribute and keep this license. This is example code for the Wireless Joystick with SAMD21. Any character entered through the Serial Monitor or when a condition statement is satisfied will be sent to the hardware UART pins. Assuming that you have a pair of XBees Series 1 modules (or Series 3 modules configured with 802.15.4 protocol) on the same channel, a character will be transmitted wirelessly between the XBees. The receiving XBee will then pass the character to the an ATmega328P microcontroller to move the robot forward. Pressing down on D2 (if you soldered the joystick on the right or a button) will check the joystick on the left. A character will be transmitted when moving the joystick: up = forward The RedBot will need to be programmed to read those values. Note: You may need to connect A5 to the XBee Series 3's reset pin on the Wireless Joystick for certain XBee Series 3 modules. For more details, check out the xbee3_RESET() function. */ #define FORWARD_REVERSE_JOYSTICK A3 // Pin used for left joystick's y-component #define TURN_JOYSTICK A2 // Pin used for left joystick x-component int buttonACCELERATE_State; //value to store the state of the button press #define ACCELERATE_BUTTON 2 // Pin used for right trigger // We'll store the the analog joystick values here int16_t forward_reverse_Stick_value; int16_t turnStick_value; char c_data;//send values through the serial monitor for debugging //LED to check if the LED is initialized. const int status_LED = 13; //needed for certain XBee Series 3 modules #define xbee_reset A5 void setup() { SerialUSB.begin(9600);// Initialize Serial Monitor for DEBUGGING //Uncomment this if you want to wait until the serial monitor is open. //while (!SerialUSB); //Wait for Serial Monitor to Open SerialUSB.println("Wireless Joystick Controller Initializing"); Serial1.begin(9600); // Start serial communication with XBee at 9600 baud xbee3_RESET();//in case XBee3 has issues initializing, hardware reset pinMode(ACCELERATE_BUTTON, INPUT_PULLUP); // Enable pullup resistor for accelerate button D2 //Status LED to see if the RedBot is initializing pinMode(status_LED, OUTPUT); for (int i = 0; i < 3; i++) { digitalWrite(status_LED, HIGH);//set Status LED on delay(50); digitalWrite(status_LED, LOW); //set Status LED off delay(50); } SerialUSB.println("Wireless Joystick Controller's XBee Ready to Communicate"); delay(10); }//end setup void loop() { //initialize variables to read buttons buttonACCELERATE_State = digitalRead(ACCELERATE_BUTTON); /***button1state - LOW or 0 means pressed - HIGH or 1 means not pressed ****/ //Store values read joystick forward_reverse_Stick_value = analogRead(FORWARD_REVERSE_JOYSTICK); turnStick_value = analogRead(TURN_JOYSTICK); //send commands via serial monitor for testing here if (SerialUSB.available()) { c_data = SerialUSB.read();//take character from serial monitor and store in variable Serial1.print(c_data);//send to XBee //echo back what was sent to serial monitor SerialUSB.println("Sending Character Here, "); SerialUSB.println(c_data); digitalWrite(status_LED, HIGH); //turn ON Status LED } if (buttonACCELERATE_State == LOW) { SerialUSB.println("Accelerate Button has been pressed!"); if (forward_reverse_Stick_value > 1000) { SerialUSB.println("Forward"); Serial1.print('A');//transmit to RedBot via XBees on the same channel digitalWrite(status_LED, HIGH); //turn ON Status LED } //Debug left analog joystick here //Boundaries vary depending on the joystick's read value //You may need to adjust the values in the condition statements to calibrate //Additional condition statements will need to be written for pivoting //and turning in reverse SerialUSB.print("forward_reverse_Stick_value = "); //~1023 up, ~7-9 down SerialUSB.println(forward_reverse_Stick_value); SerialUSB.println("turnStick_value = "); //~1023 left, ~5-6 right SerialUSB.println(turnStick_value); } delay(100); //add short delay for LED for feedback, this can be commented out if it is affecting performance digitalWrite(status_LED, LOW); //turn OFF Status LED }//end loop void xbee3_RESET() { //HARDWARE RESET /* - XBee Series 3 Hardware Reference Manual - Pg 31 Power Supply Design recommends decoupling capacitor between Vcc and GND. Tested with 10uF capacitor and without. This was not necessary. - Pg 60 Brown Out Detection. This is REQUIRED. Add a jumper between the XBee's Reset and A5 https://www.digi.com/resources/documentation/digidocs/pdfs/90001543.pdf - Power cycle XBee Series 3 by grounding RESET Pin to avoid dicontinuities in ramp up and brown out detection https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2017/06/14/rmu_e203_avdd_ramp-j176 - Minimum Time to Force Reset: - EFM32 devices = 50ns; EFM32PG/JG: Pearl and Jade Gecko =100ns https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2016/07/22/minimum_reset_holdt-PglD */ pinMode(xbee_reset, OUTPUT); digitalWrite(xbee_reset, HIGH); delayMicroseconds(1); digitalWrite(xbee_reset, LOW); delayMicroseconds(1); digitalWrite(xbee_reset, HIGH); /* //SOFTWARE RESET //Software reset does not work with XBee Series 3... Needs a hardware reset delay(500);//wait until XBee Series 3 to start up after hardware reset Serial1.write("+++"); //Enter Command Mode delay(500);//short delay as the XBee gets into command mode Serial1.write("ATFR");//AT command for software reset Serial1.write("\r");//carriage return Serial1.write("\n");//new line */ }
Code to Note
Adding on to the code in 1.1, we'll set up the pins for the joystick. Since the joystick has two potentiometers to determine it's position, we'll set up the analog read pins and have a variable to store the readings. We'll also set up the pin for the button connected to D2 and create a variable to determine the button state.
After initializing the joystick, we'll read the button state and the analog pins before storing the values in their respective variables. We'll leave the section of code that takes in serial characters from the serial monitor for debugging. Finally, we'll check if the button D2 has been pressed and send a character when the joystick is in the up position. If we are connected to a computer, we'll echo the character back for debugging.
2.2 Robot Receive w/ the ATmega328P
For this part of the experiment, we are going to receive a character from the controller and have the RedBot drive forward.
Hardware Hookup
If you have not already, connect the Redbot to your computer via USB cable.
Open the Sketch
Copy and paste the following code into the Arduino IDE. Remember, we will need to select Arduino/Genuino Uno for the RedBot mainboard, select the corresponding COM port that it enumerated on, and flip the POWER switch to the ON position. Once these settings are adjusted, you can hit the upload button.
/* 2_2_Robot_Receive_ATmega328P.ino Robot Receive ATmega328P Example Written by: Ho Yun Bobby Chan Date: 2/15/19 SparkFun Electronics license: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) Do whatever you'd like with this code, use it for any purpose. Please attribute and keep this license. The first step to controlling the RedBot remotely is to first drive it from the Serial Monitor in a tethered setup. This is example code for the RedBot Mainboard with ATmega328P. After uploading this sketch, keep the RedBot tethered to your computer with the USB cable. Flip the switches to the respective sides: MOTOR => RUN and POWER => ON. You will also need to have UART flipped to the XBee_SW_Serial side. Assuming that you have a pair of XBees 1s (or 3 configured with 802.15.4 protocol) on the same channel, a character will be transmitted wirelessly between the XBees. Any charactered received from the XBee connected to the software serial defined pins will be passed to the Serial Monitor. For troubleshooting, any character sent through the Serial Monitor will be echoed back. Try testing the controller to see if the robot will move forward or sending the following character through the Serial Monitor. A = forward If your motors are not moving forward when you send the forward command, simply flip the wiring. You can adjust the code but that would require adjusting more than one line of code. This does not account for motor intensity like the example that is used with the Wireless Joystick Example and RedBot Experiment 9. WARNING: Make sure to flip the switch to the XBEE_SW_SERIAL when you are uploading to the RedBot Mainboard. You will have issues uploading code and possibly brick your XBee. */ #include <RedBot.h> //include RedBot library RedBotMotors motors; //make instance of RedBot char c_data; // variable for holding incoming data from XBee to Arduino // We'll use RedBot SoftwareSerial to communicate with the XBee: // For Atmega328P's // XBee's DOUT (TX) is connected to pin 14 (Arduino's Software RX) // XBee's DIN (RX) is connected to pin 15 (Arduino's Software TX) #include <RedBotSoftwareSerial.h> RedBotSoftwareSerial RedBotXBee; //make instance of Software Serial, pins defined already in modified Software Serial Library //LED to check if the LED is initialized. const int status_LED = 13; void setup() { // Set up both ports at 9600 baud. This value is most important // for the XBee. Make sure the baud rate matches the config // setting of your XBee. RedBotXBee.begin(9600);// Initialize SW for XBee for receiving serial Serial.begin(9600);// Initialize HW for Serial Monitor for DEBUGGING //Status LED to see if the RedBot is initializing pinMode(status_LED, OUTPUT); for (int i = 0; i < 3; i++) { digitalWrite(status_LED, HIGH);//set Status LED on delay(50); digitalWrite(status_LED, LOW); //set Status LED off delay(50); } Serial.println("RedBot Initialized!"); }//end setup void loop() { if (RedBotXBee.available() || Serial.available()) { if (RedBotXBee.available()) { c_data = RedBotXBee.read();//store received value from XBee into variable } else if (Serial.available()) { c_data = Serial.read();//store received value from Serial Monitor into variable } Serial.println("Character Received, "); Serial.write(c_data);//send it out to serial monitor Serial.println(); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance if (c_data == 'A') { Serial.println("Drive Forward"); RedBotXBee.write('A'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.drive(255); //forward } else { //nothing was received, do nothing } } delay(100); // short pause so we are not constantly receiving characters motors.stop();//turn off motors digitalWrite(status_LED, LOW); //turn OFF Status LED }//end loop
Code to Note
Since we are using the RedBot's motors, we'll need to set up the motors right after including the library. Again, we'll leave the section of code that takes in serial characters from the serial monitor for debugging. Note that this section of code also takes in characters received from the XBee and saves it in a variable.
Shortly after, we'll check to see what if the character matches what we sent from the controller. If the character matches, we'll move the wheels forward at full power. A short delay was added to have the robot move forward before shutting off the motors. For debugging, we'll send a message to the serial monitor indicating that we received a character to drive forward and light the LED briefly.
What You Should See
Disconnect the controller and robot from your computer. Insert the batteries to the boards. Pressing on the button connected to D2 and moving the left joystick to the up position will send a character out from the controller. The receiving RedBot should drive forward remotely!
Experiment 3: Wirelessly Controlling a Robot
Introduction
Now that we are able to wirelessly move our robot forward, we will want additional commands for turning and driving in reverse.
Parts Needed
You will need the following parts from the required materials:
2x XBees (Configured to Series 1 Firmware)
1x Cerberus Cable (or 1x micro-B USB and 1x mini-B USB Cable)
1x Assembled Shadow Chassis w/ RedBot Mainboard
4x AA Batteries
1x Assembled Wireless Joystick
1x LiPo Battery
3.1: Full Remote Control w/ the SAMD21
For this part of the experiment, we will repeat the steps in 2.1 to transmit commands for turning or driving in reverse.
Hardware Hookup
Reconnect the controller to your computer via USB cable.
Open the Sketch
Copy and paste the following code into the Arduino IDE. Remember to select the SAMD21 DEV Breakout for the controller, select the COM port that it enumerated on, flip the Wireless Joystick's switch to the ON position, and hit upload.
/* 3_1_Full_Remote_Control_SAMD21.ino Full Remote Control SAMD21 Example Written by: Ho Yun Bobby Chan Date: 2/15/19 SparkFun Electronics license: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) Do whatever you'd like with this code, use it for any purpose. Please attribute and keep this license. This is example code for the Wireless Joystick with SAMD21. Any character entered through the Serial Monitor or when a condition statement is satisfied will be sent to the hardware UART pins. Assuming that you have a pair of XBees Series 1 modules (or Series 3 modules configured with 802.15.4 protocol) on the same channel, a character will be transmitted wirelessly between the XBees. The receiving XBee will then pass the character to the an ATmega328P microcontroller to move the robot forward. Pressing down on D2 (if you soldered the joystick on the right or a button) will check the joystick on the left. A character will be transmitted when moving the joystick. up = forward right = forward turn right down = reverse left = forward turn left center = coast When D2 is not being pressed, a character will be sent to stop the motors. The RedBot will need to be programmed to read those values. Note: You may need to connect A5 to the XBee Series 3's reset pin on the Wireless Joystick for certain XBee Series 3 modules. For more details, check out the xbee3_RESET() function. */ #define FORWARD_REVERSE_JOYSTICK A3 // Pin used for left joystick's y-component #define TURN_JOYSTICK A2 // Pin used for left joystick x-component int prev_buttonACCELERATE_State; //value to store the previous state of the button press int current_buttonACCELERATE_State; //value to store the current state of the button press #define ACCELERATE_BUTTON 2 // Pin used for right trigger // We'll store the the analog joystick values here int16_t forward_reverse_Stick_value; int16_t turnStick_value; char c_data;//send values through the serial monitor for debugging //LED to check if the LED is initialized. const int status_LED = 13; //needed for certain XBee Series 3 modules #define xbee_reset A5 void setup() { SerialUSB.begin(9600);// Initialize Serial Monitor for DEBUGGING //Uncomment this if you want to wait until the serial monitor is open. //while (!SerialUSB); //Wait for Serial Monitor to Open SerialUSB.println("Wireless Joystick Controller Initializing"); Serial1.begin(9600); // Start serial communication with XBee at 9600 baud xbee3_RESET();//in case XBee3 has issues initializing, hardware reset pinMode(ACCELERATE_BUTTON, INPUT_PULLUP); // Enable pullup resistor for accelerate button D2 //Status LED to see if the Controller is initializing pinMode(status_LED, OUTPUT); for (int i = 0; i < 3; i++) { digitalWrite(status_LED, HIGH);//set Status LED on delay(50); digitalWrite(status_LED, LOW); //set Status LED off delay(50); } SerialUSB.println("Wireless Joystick Controller's XBee Ready to Communicate"); delay(10); }//end setup void loop() { //initialize variables to read buttons current_buttonACCELERATE_State = digitalRead(ACCELERATE_BUTTON); /***button1state - LOW or 0 means pressed - HIGH or 1 means not pressed ****/ //Store values read joystick forward_reverse_Stick_value = analogRead(FORWARD_REVERSE_JOYSTICK); turnStick_value = analogRead(TURN_JOYSTICK); //send commands via serial monitor for testing here if (SerialUSB.available()) { c_data = SerialUSB.read();//take character from serial monitor and store in variable Serial1.print(c_data);//send to XBee //echo back what was sent to serial monitor SerialUSB.println("Sending Character Here, "); SerialUSB.println(c_data); } if (current_buttonACCELERATE_State == LOW) { SerialUSB.println("Accelerate Button has been pressed!"); if (forward_reverse_Stick_value > 1000) { SerialUSB.println("Forward"); Serial1.print('A');//transmit to RedBot via XBees on the same channel digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } else if ( turnStick_value < 20) { SerialUSB.println("Turn Right"); Serial1.print('B'); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } else if (forward_reverse_Stick_value < 20) { SerialUSB.println("Reverse"); Serial1.print('C'); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } else if (turnStick_value > 1000) { SerialUSB.println("Turn Left"); Serial1.print('D'); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } else { SerialUSB.println("Coast"); digitalWrite(status_LED, HIGH); //turn ON Status LED Serial1.print('J'); } //Debug left analog joystick here //Boundaries vary depending on the joystick's read value //You may need to adjust the values in the condition statements to calibrate //Additional condition statements will need to be written for pivoting //and turning in reverse SerialUSB.print("forward_reverse_Stick_value = "); //~1023 up, ~7-9 down SerialUSB.println(forward_reverse_Stick_value); SerialUSB.println("turnStick_value = "); //~1023 left, ~5-6 right SerialUSB.println(turnStick_value); } else {//current_buttonACCELERATE_State == HIGH //if not sending a command to drive, automatically have the robot stop moving SerialUSB.println("Stop"); digitalWrite(status_LED, HIGH); //turn ON Status LED Serial1.print('K'); } prev_buttonACCELERATE_State = current_buttonACCELERATE_State; //save current state delay(100); //add short delay for LED for feedback, this can be commented out if it is affecting performance digitalWrite(status_LED, LOW); //turn OFF Status LED }//end loop void xbee3_RESET() { //HARDWARE RESET /* - XBee Series 3 Hardware Reference Manual - Pg 31 Power Supply Design recommends decoupling capacitor between Vcc and GND. Tested with 10uF capacitor and without. This was not necessary. - Pg 60 Brown Out Detection. This is REQUIRED. Add a jumper between the XBee's Reset and A5 https://www.digi.com/resources/documentation/digidocs/pdfs/90001543.pdf - Power cycle XBee Series 3 by grounding RESET Pin to avoid dicontinuities in ramp up and brown out detection https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2017/06/14/rmu_e203_avdd_ramp-j176 - Minimum Time to Force Reset: - EFM32 devices = 50ns; EFM32PG/JG: Pearl and Jade Gecko =100ns https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2016/07/22/minimum_reset_holdt-PglD */ pinMode(xbee_reset, OUTPUT); digitalWrite(xbee_reset, HIGH); delayMicroseconds(1); digitalWrite(xbee_reset, LOW); delayMicroseconds(1); digitalWrite(xbee_reset, HIGH); /* //SOFTWARE RESET //Software reset does not work with XBee Series 3... Needs a hardware reset delay(500);//wait until XBee Series 3 to start up after hardware reset Serial1.write("+++"); //Enter Command Mode delay(500);//short delay as the XBee gets into command mode Serial1.write("ATFR");//AT command for software reset Serial1.write("\r");//carriage return Serial1.write("\n");//new line */ }
Code to Note
To add more commands, we simply add more if() statements to check the position of the joystick on the right, down, and left positions. If the joystick is in any of those position, send a command to move the RedBot forward toward the right, reverse, and forward toward the left, respectively. If the joystick is in the center, we'll send a command to have the RedBot coast a bit. Otherwise, we'll continually send a command to have the RedBot stop when we are not pressing on D2.
3.2 Full Robot Control w/ the ATmega328P
For this part of the experiment, we will repeat the steps in 2.2 to receive the commands before moving the robot. Instead of just driving forward, the robot can now turn, and reverse.
Hardware Hookup
Reconnect the Redbot to your computer via USB cable.
Open the Sketch
Copy and paste the following code into the Arduino IDE. Remember, we will need to select Arduino/Genuino Uno for the RedBot mainboard, select the corresponding COM port that it enumerated on, and flip the POWER switch to the ON position. Once these settings are adjusted, you can hit the upload button.
/* 3_2_Full_Robot_Control_ATmega328P.ino Full Robot Control ATmega328P Example Written by: Ho Yun Bobby Chan Date: 2/15/19 SparkFun Electronics license: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) Do whatever you'd like with this code, use it for any purpose. Please attribute and keep this license. The first step to controlling the RedBot remotely is to first drive it from the Serial Monitor in a tethered setup. This is example code for the RedBot Mainboard with ATmega328P. After uploading this sketch, keep the RedBot tethered to your computer with the USB cable. Flip the switches to the respective sides: MOTOR => RUN and POWER => ON. You will also need to have UART flipped to the XBee_SW_Serial side. Assuming that you have a pair of XBees 1s (or 3 configured with 802.15.4 protocol) on the same channel, a character will be transmitted wirelessly between the XBees. Any charactered received from the XBee connected to the software serial defined pins will be passed to the Serial Monitor. For troubleshooting, any character sent through the Serial Monitor will be echoed back. Try testing the controller to see if the robot will move forward or sending the following character through the Serial Monitor. A = forward B = forward turn right C = reverse D = forward turn left J = coast K = stop If your motors are not moving forward when you send the forward command, simply flip the wiring. You can adjust the code but that would require adjusting more than one line of code. This does not account for motor intensity like the example that is used with the Wireless Joystick Example and RedBot Experiment 9. WARNING: Make sure to flip the switch to the XBEE_SW_SERIAL when you are uploading to the RedBot Mainboard. You will have issues uploading code and possibly brick your XBee. */ #include <RedBot.h> //include RedBot library RedBotMotors motors; //make instance of RedBot char c_data; // variable for holding incoming data from XBee to Arduino // We'll use RedBot SoftwareSerial to communicate with the XBee: // For Atmega328P's // XBee's DOUT (TX) is connected to pin 14 (Arduino's Software RX) // XBee's DIN (RX) is connected to pin 15 (Arduino's Software TX) #include <RedBotSoftwareSerial.h> RedBotSoftwareSerial RedBotXBee; //make instance of Software Serial, pins defined already in modified Software Serial Library //LED to check if the LED is initialized. const int status_LED = 13; void setup() { // Set up both ports at 9600 baud. This value is most important // for the XBee. Make sure the baud rate matches the config // setting of your XBee. RedBotXBee.begin(9600);// Initialize SW for XBee for receiving serial Serial.begin(9600);// Initialize HW for Serial Monitor for DEBUGGING //Status LED to see if the RedBot is initializing pinMode(status_LED, OUTPUT); for (int i = 0; i < 3; i++) { digitalWrite(status_LED, HIGH);//set Status LED on delay(50); digitalWrite(status_LED, LOW); //set Status LED off delay(50); } Serial.println("RedBot Initialized!"); }//end setup void loop() { if (RedBotXBee.available() || Serial.available()) { if (RedBotXBee.available()) { c_data = RedBotXBee.read();//store received value from XBee into variable } else if (Serial.available()) { c_data = Serial.read();//store received value from Serial Monitor into variable } Serial.println("Character Received, "); Serial.write(c_data);//send it out to serial monitor Serial.println(); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance if (c_data == 'A') { Serial.println("Drive Forward"); RedBotXBee.write('A'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.drive(255); //forward } else if (c_data == 'B') { Serial.println("Turn Right"); RedBotXBee.write('B'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.leftMotor(-200); // Turn on left motor power (motorPower = ) motors.rightMotor(100); // Turn on right motor power (motorPower = ) } else if (c_data == 'C') { Serial.println("Reverse"); RedBotXBee.write('C'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.drive(-255); //reverse } else if (c_data == 'D') { Serial.println("Turn Left"); RedBotXBee.write('D'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.leftMotor(-100); // Turn on left motor power (motorPower = ) motors.rightMotor(200); // Turn on right motor power (motorPower = ) } else if (c_data == 'J') { Serial.println("Coast"); RedBotXBee.write('J'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.coast(); } else if (c_data == 'K') { Serial.println("Stop"); RedBotXBee.write('K'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.stop(); } } //delay(100); // short pause so we are not constantly receiving characters digitalWrite(status_LED, LOW); //turn OFF Status LED }//end loop
Code to Note
Similar to 3.1, we'll add additional if() statements to move the RedBot if the character matches what was sent. We'll adjust the motor power and direction for each condition when we receive the command to forward toward the right, reverse, forward toward the left, coast, or stop.
What You Should See
Disconnect the controller and robot from your computer. Press on D2 and move the joystick around. You should see the RedBot move toward the direction relative to the position of the joystick!
Experiment 4: Wirelessly Triggering Audio
Introduction
Remember making sounds with the RedBot? In this section, we'll wirelessly control the buzzer to make a familiar sound.
Parts Needed
You will need the following parts from the required materials:
2x XBees (Configured to Series 1 Firmware)
1x Cerberus Cable (or 1x micro-B USB and 1x mini-B USB Cable)
1x Assembled Shadow Chassis w/ RedBot Mainboard
1x Piezo Buzzer
4x AA Batteries
1x Assembled Wireless Joystick
1x LiPo Battery
4.1: Adding Audio Commands w/ the SAMD21
For this part of the experiment, we will add a few commands to trigger a familiar sound.
Hardware Hookup
If you have not already, insert the XBee and battery into the controller. Then connect the controller to your computer via USB cable.
Open the Sketch
Copy and paste the following code into the Arduino IDE. Remember to select the SAMD21 DEV Breakout for the controller, select the COM port that it enumerated on, flip the Wireless Joystick's switch to the ON position, and hit upload.
/* 4_1_Full_Remote_Control_SAMD_Audio.ino Full Remote Control SAMD21 Example with Buzzer Written by: Ho Yun Bobby Chan Date: 2/15/19 SparkFun Electronics license: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) Do whatever you'd like with this code, use it for any purpose. Please attribute and keep this license. This is example code for the Wireless Joystick with SAMD21. Any character entered through the Serial Monitor or when a condition statement is satisfied will be sent to the hardware UART pins. Assuming that you have a pair of XBees Series 1 modules (or Series 3 modules configured with 802.15.4 protocol) on the same channel, a character will be transmitted wirelessly between the XBees. The receiving XBee will then pass the character to the an ATmega328P microcontroller to move the robot forward. Pressing down on D2 (if you soldered the joystick on the right or a button) will check the joystick on the left. A character will be transmitted when moving the joystick. up = forward right = forward turn right down = reverse left = forward turn left center = coast When D2 is not being pressed, a character will be sent to stop the motors. Pressing down on D6 (left trigger) or D3 (right trigger) will send another character left trigger = coin right trigger = fireball The RedBot will need to be programmed to read those values. Note: You may need to connect A5 to the XBee Series 3's reset pin on the Wireless Joystick for certain XBee Series 3 modules. For more details, check out the xbee3_RESET() function. */ #define L_TRIG 6 // Pin used for left trigger #define R_TRIG 3 // Pin used for right trigger boolean prev_buttonL_State = HIGH; //value to store the previous state of the button press boolean current_buttonL_State = HIGH; //value to store the current state of the button press boolean prev_buttonR_State = HIGH; //value to store the previous state of the button press boolean current_buttonR_State = HIGH; //value to store the current state of the button press #define FORWARD_REVERSE_JOYSTICK A3 // Pin used for left joystick's y-component #define TURN_JOYSTICK A2 // Pin used for left joystick x-component boolean current_buttonACCELERATE_State; #define ACCELERATE_BUTTON 2 // Pin used for right trigger // We'll store the the analog joystick values here int16_t forward_reverse_Stick_value; int16_t turnStick_value; char c_data;//send values through the serial monitor for debugging //LED to check if the LED is initialized. const int status_LED = 13; //needed for certain XBee Series 3 modules #define xbee_reset A5 void setup() { pinMode(L_TRIG, INPUT_PULLUP); // Enable pullup resistor for left trigger pinMode(R_TRIG, INPUT_PULLUP); // Enable pullup resistor for right trigger SerialUSB.begin(9600);// Initialize Serial Monitor for DEBUGGING //Uncomment this if you want to wait until the serial monitor is open. //while (!SerialUSB); //Wait for Serial Monitor to Open SerialUSB.println("Wireless Joystick Controller Initializing"); Serial1.begin(9600); // Start serial communication with XBee at 9600 baud xbee3_RESET();//in case XBee3 has issues initializing, hardware reset pinMode(ACCELERATE_BUTTON, INPUT_PULLUP); // Enable pullup resistor for accelerate button D2 //Status LED to see if the Controller is initializing pinMode(status_LED, OUTPUT); for (int i = 0; i < 3; i++) { digitalWrite(status_LED, HIGH);//set Status LED on delay(50); digitalWrite(status_LED, LOW); //set Status LED off delay(50); } SerialUSB.println("Wireless Joystick Controller's XBee Ready to Communicate"); delay(10); }//end setup void loop() { current_buttonL_State = digitalRead(L_TRIG); current_buttonR_State = digitalRead(R_TRIG); //initialize variables to read buttons current_buttonACCELERATE_State = digitalRead(ACCELERATE_BUTTON); /***button1state - LOW or 0 means pressed - HIGH or 1 means not pressed ****/ //Store values read joystick forward_reverse_Stick_value = analogRead(FORWARD_REVERSE_JOYSTICK); turnStick_value = analogRead(TURN_JOYSTICK); //send commands via serial monitor for testing here if (SerialUSB.available()) { c_data = SerialUSB.read();//take character from serial monitor and store in variable Serial1.print(c_data);//send to XBee //echo back what was sent to serial monitor SerialUSB.println("Sending Character Here, "); SerialUSB.println(c_data); } if (current_buttonACCELERATE_State == LOW) { SerialUSB.println("Accelerate Button has been pressed!"); if (forward_reverse_Stick_value > 1000) { SerialUSB.println("Forward"); Serial1.print('A');//transmit to RedBot via XBees on the same channel digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } else if ( turnStick_value < 20) { SerialUSB.println("Turn Right"); Serial1.print('B'); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } else if (forward_reverse_Stick_value < 20) { SerialUSB.println("Reverse"); Serial1.print('C'); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } else if (turnStick_value > 1000) { SerialUSB.println("Turn Left"); Serial1.print('D'); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance } else { SerialUSB.println("Coast"); digitalWrite(status_LED, HIGH); //turn ON Status LED Serial1.print('J'); } //Debug left analog joystick here //Boundaries vary depending on the joystick's read value //You may need to adjust the values in the condition statements to calibrate //Additional condition statements will need to be written for pivoting //and turning in reverse SerialUSB.print("forward_reverse_Stick_value = "); //~1023 up, ~7-9 down SerialUSB.println(forward_reverse_Stick_value); SerialUSB.println("turnStick_value = "); //~1023 left, ~5-6 right SerialUSB.println(turnStick_value); } else {//current_buttonACCELERATE_State == HIGH //if not sending a command to drive, automatically have the robot stop moving SerialUSB.println("Stop"); digitalWrite(status_LED, HIGH); //turn ON Status LED Serial1.print('K'); } if (current_buttonL_State == LOW) { if (prev_buttonL_State != current_buttonL_State) { SerialUSB.println("R Trigger Button has been pressed!"); SerialUSB.println("Coin Sound"); Serial1.print('X'); digitalWrite(status_LED, HIGH); //turn ON Status LED } } if (current_buttonR_State == LOW) { if (prev_buttonR_State != current_buttonR_State) { SerialUSB.println("R Trigger Button has been pressed!"); SerialUSB.println("Fireball Sound"); Serial1.print('Y'); digitalWrite(status_LED, HIGH); //turn ON Status LED } } prev_buttonL_State = current_buttonL_State; //save current state prev_buttonR_State = current_buttonR_State; //save current state delay(100); //add short delay for LED for feedback, this can be commented out if it is affecting performance digitalWrite(status_LED, LOW); //turn OFF Status LED }//end loop void xbee3_RESET() { //HARDWARE RESET /* - XBee Series 3 Hardware Reference Manual - Pg 31 Power Supply Design recommends decoupling capacitor between Vcc and GND. Tested with 10uF capacitor and without. This was not necessary. - Pg 60 Brown Out Detection. This is REQUIRED. Add a jumper between the XBee's Reset and A5 https://www.digi.com/resources/documentation/digidocs/pdfs/90001543.pdf - Power cycle XBee Series 3 by grounding RESET Pin to avoid dicontinuities in ramp up and brown out detection https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2017/06/14/rmu_e203_avdd_ramp-j176 - Minimum Time to Force Reset: - EFM32 devices = 50ns; EFM32PG/JG: Pearl and Jade Gecko =100ns https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2016/07/22/minimum_reset_holdt-PglD */ pinMode(xbee_reset, OUTPUT); digitalWrite(xbee_reset, HIGH); delayMicroseconds(1); digitalWrite(xbee_reset, LOW); delayMicroseconds(1); digitalWrite(xbee_reset, HIGH); /* //SOFTWARE RESET //Software reset does not work with XBee Series 3... Needs a hardware reset delay(500);//wait until XBee Series 3 to start up after hardware reset Serial1.write("+++"); //Enter Command Mode delay(500);//short delay as the XBee gets into command mode Serial1.write("ATFR");//AT command for software reset Serial1.write("\r");//carriage return Serial1.write("\n");//new line */ }
Code to Note
Adding to the current list of defined commands, we'll define two more buttons at the top for the left and right triggers. You'll notice that there is additional code to keep track of the previous and current states of the two buttons.
Further down in the loop() after the commands, we create a nested if() statement for each button so that we only send the command to trigger the buzzer once when the button is pressed. We'll want to send these audio commands only after letting go of the button.
4.2 Adding Audio w/ the ATmega328P
For this part of the experiment, we will receive characters to control the piezo buzzer on the RedBot.
Hardware Hookup
We'll assume that the buzzer is attached to pin 9 like the assembly guide. If you have not already, insert the XBee into the RedBot. Then connect the Redbot to your computer via USB cable.
Open the Sketch
Copy and paste the following code into the Arduino IDE.
/* 4_2_Full_Remote_Control_SAMD_Audio.ino Full Robot Control ATmega328P Example with Buzzer Written by: Ho Yun Bobby Chan Date: 2/15/19 SparkFun Electronics license: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) Do whatever you'd like with this code, use it for any purpose. Please attribute and keep this license. The first step to controlling the RedBot remotely is to first drive it from the Serial Monitor in a tethered setup. This is example code for the RedBot Mainboard with ATmega328P. After uploading this sketch, keep the RedBot tethered to your computer with the USB cable. Flip the switches to the respective sides: MOTOR => RUN and POWER => ON. You will also need to have UART flipped to the XBee_SW_Serial side. Assuming that you have a pair of XBees 1s (or 3 configured with 802.15.4 protocol) on the same channel, a character will be transmitted wirelessly between the XBees. Any charactered received from the XBee connected to the software serial defined pins will be passed to the Serial Monitor. For troubleshooting, any character sent through the Serial Monitor will be echoed back. Try testing the controller to see if the robot will move forward or sending the following character through the Serial Monitor. A = forward B = forward turn right C = reverse D = forward turn left J = coast K = stop X = coin cointer sound effect Y = fireball sound effect If your motors are not moving forward when you send the forward command, simply flip the wiring. You can adjust the code but that would require adjusting more than one line of code. This does not account for motor intensity like the example that is used with the Wireless Joystick Example and RedBot Experiment 9. WARNING: Make sure to flip the switch to the XBEE_SW_SERIAL when you are uploading to the RedBot Mainboard. You will have issues uploading code and possibly brick your XBee. */ #include "pitches.h" //include pitches.h from tab #include <RedBot.h> //include RedBot library RedBotMotors motors; //make instance of RedBot char c_data; // variable for holding incoming data from XBee to Arduino // We'll use RedBot SoftwareSerial to communicate with the XBee: // For Atmega328P's // XBee's DOUT (TX) is connected to pin 14 (Arduino's Software RX) // XBee's DIN (RX) is connected to pin 15 (Arduino's Software TX) #include <RedBotSoftwareSerial.h> RedBotSoftwareSerial RedBotXBee; //make instance of Software Serial, pins defined already in modified Software Serial Library //LED to check if the LED is initialized. const int status_LED = 13; int coin_counter = 0;//counter for coins and 1-up void setup() { // Set up both ports at 9600 baud. This value is most important // for the XBee. Make sure the baud rate matches the config // setting of your XBee. RedBotXBee.begin(9600);// Initialize SW for XBee for receiving serial Serial.begin(9600);// Initialize HW for Serial Monitor for DEBUGGING //Status LED to see if the RedBot is initializing pinMode(status_LED, OUTPUT); for (int i = 0; i < 3; i++) { digitalWrite(status_LED, HIGH);//set Status LED on delay(50); digitalWrite(status_LED, LOW); //set Status LED off delay(50); } pinMode(9, OUTPUT); //buzzer tone(9, NOTE_E6, 125); delay(130); noTone(9); Serial.println("RedBot Initialized!"); }//end setup void loop() { if (RedBotXBee.available() || Serial.available()) { if (RedBotXBee.available()) { c_data = RedBotXBee.read();//store received value from XBee into variable } else if (Serial.available()) { c_data = Serial.read();//store received value from Serial Monitor into variable } Serial.println("Character Received, "); Serial.write(c_data);//send it out to serial monitor Serial.println(); digitalWrite(status_LED, HIGH); //turn ON Status LED //delayMicroseconds(500);//add short delay for LED for feedback, this can be commented out if it is affecting performance if (c_data == 'A') { Serial.println("Drive Forward"); RedBotXBee.write('A'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.drive(255); //forward } else if (c_data == 'B') { Serial.println("Turn Right"); RedBotXBee.write('B'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.leftMotor(-200); // Turn on left motor power (motorPower = ) motors.rightMotor(100); // Turn on right motor power (motorPower = ) } else if (c_data == 'C') { Serial.println("Reverse"); RedBotXBee.write('C'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.drive(-255); //reverse } else if (c_data == 'D') { Serial.println("Turn Left"); RedBotXBee.write('D'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.leftMotor(-100); // Turn on left motor power (motorPower = ) motors.rightMotor(200); // Turn on right motor power (motorPower = ) } else if (c_data == 'J') { Serial.println("Coast"); RedBotXBee.write('J'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.coast(); } else if (c_data == 'K') { Serial.println("Stop"); RedBotXBee.write('K'); digitalWrite(status_LED, HIGH); //turn ON Status LED motors.stop(); } else if (c_data == 'X') { // Play coin sound Serial.println("Coin Sound"); if (coin_counter < 100) { coin_counter = coin_counter + 1; //add 1 coin Serial.print("Coin Counter = "); Serial.println(coin_counter); RedBotXBee.write('X'); digitalWrite(status_LED, HIGH); // turn the LED on tone(9, NOTE_B5, 100); delay(50); tone(9, NOTE_E6, 850); delay(400); noTone(9); } else if (coin_counter <= 100) { coin_counter = 0;//set back coins to 0; Serial.print("100 Coins Received! 1-Up"); Serial.print("Coin Counter reset to = "); Serial.println(coin_counter); RedBotXBee.write('X'); digitalWrite(status_LED, HIGH); //turn ON Status LED tone(9, NOTE_E6, 125); delay(130); tone(9, NOTE_G6, 125); delay(130); tone(9, NOTE_E7, 125); delay(130); tone(9, NOTE_C7, 125); delay(130); tone(9, NOTE_D7, 125); delay(130); tone(9, NOTE_G7, 125); delay(125); noTone(9); } } else if (c_data == 'Y') { // Play coin sound Serial.println("Fireball Sound"); RedBotXBee.write('Y'); digitalWrite(status_LED, HIGH); //turn ON Status LED // Play Fireball sound tone(9, NOTE_G4, 35); delay(35); tone(9, NOTE_G5, 35); delay(35); tone(9, NOTE_G6, 35); delay(35); noTone(9); } } //delay(100); // short pause so we are not constantly receiving characters digitalWrite(status_LED, LOW); //turn OFF Status LED }//end loop
Adding a Tabbed File
Along with the example, you will need to include the following pitches.h header file that was originally written by Brett Hagman. You may remember this file being named notes.h. To make the pitches.h file, either click on the arrow button just below the serial monitor icon and choose "New Tab", or use Ctrl+Shift+N shortcut. Name the file as pitches.h to help break up the example sketch.
Copy and paste the following code the Arduino IDE's new tab and save. As a result, a new file will be included in the same folder as the example code. Remember, we will need to select Arduino/Genuino Uno for the RedBot mainboard, select the corresponding COM port that it enumerated on, and flip the POWER switch to the ON position. Once these settings are adjusted, you can hit the upload button.
/************************************************* * Public Constants *************************************************/ #define NOTE_B0 31 #define NOTE_C1 33 #define NOTE_CS1 35 #define NOTE_D1 37 #define NOTE_DS1 39 #define NOTE_E1 41 #define NOTE_F1 44 #define NOTE_FS1 46 #define NOTE_G1 49 #define NOTE_GS1 52 #define NOTE_A1 55 #define NOTE_AS1 58 #define NOTE_B1 62 #define NOTE_C2 65 #define NOTE_CS2 69 #define NOTE_D2 73 #define NOTE_DS2 78 #define NOTE_E2 82 #define NOTE_F2 87 #define NOTE_FS2 93 #define NOTE_G2 98 #define NOTE_GS2 104 #define NOTE_A2 110 #define NOTE_AS2 117 #define NOTE_B2 123 #define NOTE_C3 131 #define NOTE_CS3 139 #define NOTE_D3 147 #define NOTE_DS3 156 #define NOTE_E3 165 #define NOTE_F3 175 #define NOTE_FS3 185 #define NOTE_G3 196 #define NOTE_GS3 208 #define NOTE_A3 220 #define NOTE_AS3 233 #define NOTE_B3 247 #define NOTE_C4 262 #define NOTE_CS4 277 #define NOTE_D4 294 #define NOTE_DS4 311 #define NOTE_E4 330 #define NOTE_F4 349 #define NOTE_FS4 370 #define NOTE_G4 392 #define NOTE_GS4 415 #define NOTE_A4 440 #define NOTE_AS4 466 #define NOTE_B4 494 #define NOTE_C5 523 #define NOTE_CS5 554 #define NOTE_D5 587 #define NOTE_DS5 622 #define NOTE_E5 659 #define NOTE_F5 698 #define NOTE_FS5 740 #define NOTE_G5 784 #define NOTE_GS5 831 #define NOTE_A5 880 #define NOTE_AS5 932 #define NOTE_B5 988 #define NOTE_C6 1047 #define NOTE_CS6 1109 #define NOTE_D6 1175 #define NOTE_DS6 1245 #define NOTE_E6 1319 #define NOTE_F6 1397 #define NOTE_FS6 1480 #define NOTE_G6 1568 #define NOTE_GS6 1661 #define NOTE_A6 1760 #define NOTE_AS6 1865 #define NOTE_B6 1976 #define NOTE_C7 2093 #define NOTE_CS7 2217 #define NOTE_D7 2349 #define NOTE_DS7 2489 #define NOTE_E7 2637 #define NOTE_F7 2794 #define NOTE_FS7 2960 #define NOTE_G7 3136 #define NOTE_GS7 3322 #define NOTE_A7 3520 #define NOTE_AS7 3729 #define NOTE_B7 3951 #define NOTE_C8 4186 #define NOTE_CS8 4435 #define NOTE_D8 4699 #define NOTE_DS8 4978
Code to Note
We'll include the pitches.h file at the beginning of the example to reference the notes. Then we'll setup the buzzer and play a sound to ensure that the buzzer is working as expected. Further in the loop() function after our condition statements, we'll add a few lines to make the buzzer play a sequence of notes. If one of the triggers is pressed 100 times, we'll play a special sequence of notes.
What You Should See (and Hear)
Press the triggers on the controller. You should hear a familiar 8-bit sound effect from a popular game coming from the piezo buzzer! Press one of the triggers 100 times to hear yet another familiar sound!
Coding Challenges
Broadcasting to an Army of Robots
Remember the GIF shown at the beginning of the tutorial? They were used to stress test the XBee 3's and examples used in this tutorial. Instead of controlling one robot, try broadcasting the commands from one controller to several robots! Just make sure to configure your XBees with unique addresses and adjust the controller's configuration for broadcasting.
More with Buttons
The RedBot motor speed was set at one intensity. Instead of one set motor intensity for each character, try dividing the motor intensity for different characters by utilizing the other buttons. Or try adjusting the code to have the robot pivot left or right.
Methods of Transmitting Serial
Instead of sending one character to move, try adjusting the code to transmit different motor intensities and utilize the XBee's API packet structure. Or try sending serial through a mesh network configuration. You'll need to parse the data into an array and convert the string into numbers similar to the example code provided in the Remote Tank Steering Motor Controller. Instead of sending a character to a RedBot, the example had sent a string of characters to an Arduino with the Serial Controlled Motor Driver.
Controlling with Sensors
Instead of using buttons and a joystick, try using a motion sensor to control the RedBot based on movement like the RedBot''s accelerometer included in the kit. Or make a glove to control the RedBot based on gestures.
Hardware Upgrades
Remember, there are spots for additional Actobotics hardware cut into the Shadow Chassis!
Try adding a servo claw to pick up a small object like a pen.
Servo - Generic (Sub-Micro Size)
Pan/Tilt Bracket Kit (Multi Attachment)
Aluminum Channel - 4.50"
Micro Gripper Kit B - Hub Mount
LiPo Battery Monitoring
If you looked through the guide for the wireless controller, you'll notice that there are examples to monitor your LiPo battery! Try to combine code to control the RedBot with the LiPo Battery Monitor and micro OLED display.
Sensing the Environment
Try sending data back from the line following sensors or encoders used in the RedBot kit back to the controller. Better yet, add the air quality sensor or humidity & temperature sensor to monitor the environment at a distance like a planetary rover. You'll need either a serial monitor or micro OLED connected to be able to view the data.
SparkFun Air Quality Breakout - CCS811
SparkFun Humidity and Temperature Sensor Breakout - Si7021
Efficiently Sending Commands
Try modifying the code to be efficient and save power instead of constantly sending commands. Currently, the controller repeatedly sends a command to notify the RedBot to stop, even when we are not pressing any buttons.
Troubleshooting
Not working as expected? Below are a few troubleshooting tips to get your micro:bits working as expected. For your convenience, relevant troubleshooting tips from the RedBot experiment guide were included below.
Having issues uploading?
Make sure your USB cable is plugged into both the robot and the computer you're using to write code.
Make sure the "POWER" switch is switched to "ON."
Double check that you have the right serial port selected under the "Tools" menu. The easiest way to check is to see which item disappears from the menu when you unplug the USB cable, and select that one when you plug the board back in.
If you have an Xbee module plugged in, make sure the Serial Select switch at the top edge of the board is switched to "XBEE SW SERIAL."
Check that you have the right board selected under the "Tools" menu. The Wireless Joystick uses the "SparkFun SAMD21 Dev Breakout" while the RedBot Mainboard uses "Arduino Uno". Also make sure that you have the correct COM port selected for each respective board.
My RedBot is not moving!
Make sure that the switches are set to the correct position for POWER, MOTORS, and XBEE SW Serial.
If you are using batteries, make sure that they have enough power.
Make sure that the XBees are configured correctly.
My RedBot is not driving straight! It is spinning or driving backward!
Make sure that the motor wires are wired correctly.
You can also adjust the code to tell what direction the motors to spin. Since the code is based on the setup used in the RedBot assembly guide, it would be easier to adjust the physical wire connection.
My RedBot is not driving straight! It drives in a curve!
This is a pretty common thing for the RedBot, and for all robots with independent drive wheels. There are lots of reasons for it, but it's something that simply must be dealt with. Here are a few possible reasons:
First -- check to make sure that there is nothing rubbing on either the wheels or on the magnetic motor encoder. Move the wheels out so that they are not rubbing, but still tightly seated into the motor. Any added friction on one side will cause one side to drive faster than the other (resulting in the RedBot pulling to one side.)
Second -- Driving straight requires equal power on both wheels. This requires equal amounts of traction on both wheels. Running the motors up at full power sometimes causes the wheels to "spin out" and lose traction. Try reducing the motorPower to something lower than 255.
Third -- use an encoder from the kit to ensure that both wheels turn the same distance each time.
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum