I'm trying to make an RC airplane with two Arduino Nanos, and using the VirtualWire library. I'm using the ServoTimer2 library because of the conflicting libraries with Servo.h and VirtualWire. My plan is to have a joystick that will control 2 servos (pitch and yaw) on the receiving side.
So far I have managed to spin one of the servos about 30 degrees when I move my joystick, but the direction of the joystick does not seem to affect the direction of the spin, nor does the servo stay in the same position. I am successfully receiving the data from the remote control, but the servos seem to ignore it.
Here is the transmitter code:
#include <VirtualWire.h>
int mapX = 0;
int mapY = 0;
const int Sensor1Pin = A0;
const int Sensor2Pin = A1;
int Sensor1Data;
int Sensor2Data;
char Sensor1CharMsg[4];
char Sensor2CharMsg[4];
void setup() {
pinMode(Sensor1Pin, INPUT);
pinMode(Sensor2Pin, INPUT);
// for debuggin
Serial.begin(9600);
// VirtualWire setup
vw_setup(8000); // Bits per sec
}
void loop() {
Sensor1Data = analogRead(Sensor1Pin);
Sensor2Data = analogRead(Sensor2Pin);
mapX = map(Sensor1Data, 0, 1023, 10, 40);
mapY = map(Sensor2Data, 0, 1023, 41, 70);
// Convert integer data to Char array directly
itoa(mapX, Sensor1CharMsg, 10);
itoa(mapY, Sensor2CharMsg, 10);
vw_send((uint8_t *)Sensor1CharMsg, strlen(Sensor1CharMsg));
vw_wait_tx(); // Wait until the whole message is gone
vw_send((uint8_t *)Sensor2CharMsg, strlen(Sensor1CharMsg));
vw_wait_tx(); // Wait until the whole message is gone
}
Receiver Code:
#include <VirtualWire.h>
#include <ServoTimer2.h>
ServoTimer2 updown;
ServoTimer2 leftright;
int z;
byte message[VW_MAX_MESSAGE_LEN]; // a buffer to store the incoming messages
byte messageLength = VW_MAX_MESSAGE_LEN; // the size of the message
void setup()
{
updown.attach(10);
leftright.attach(12);
Serial.begin(9600);
Serial.println("Device is ready");
// Initialize the IO and ISR
vw_setup(8000); // Bits per sec
vw_rx_start(); // Start the receiver
}
void loop()
{
if (vw_get_message(message, &messageLength)) // Non-blocking
{
Serial.print("Received: ");
for (int i = 0; i < messageLength; i++)
{
z=message[i];
Serial.write(z);
if (10 == z) {
updown.write(750);
}
if (11 == z) {
updown.write(783);
}
if (12 == z) {
updown.write(816);
}
if (13 == z) {
updown.write(849);
}
if (14 == z) {
updown.write(882);
}
if (15 == z) {
updown.write(915);
}
if (16 == z) {
updown.write(950);
}
if (17 == z) {
updown.write(982);
}
if (18 == z) {
updown.write(1015);
}
if (19 == z) {
updown.write(1050);
}
if (20 == z) {
updown.write(1082);
}
if (21 == z) {
updown.write(1115);
}
if (22 == z) {
updown.write(1150);
}
if (23 == z) {
updown.write(1183);
}
if (24 == z) {
updown.write(1215);
}
if (25 == z) {
updown.write(1250);
}
if (26 == z) {
updown.write(1283);
}
if (27 == z) {
updown.write(1315);
}
if (28 == z) {
updown.write(1350);
}
if (29 == z) {
updown.write(1383);
}
if (30 == z) {
updown.write(1415);
}
if (31 == z) {
updown.write(1450);
}
if (32 == z) {
updown.write(1483);
}
if (33 == z) {
updown.write(1515);
}
if (34 == z) {
updown.write(1550);
}
if (35 == z) {
updown.write(1583);
}
if (36 == z) {
updown.write(1615);
}
if (37 == z) {
updown.write(1650);
}
if (38 == z) {
updown.write(1683);
}
if (39 == z) {
updown.write(1715);
}
if (40 == z) {
updown.write(1750);
}
if (41 == z) {
leftright.write(750);
}
if (42 == z) {
leftright.write(783);
}
if (43 == z) {
leftright.write(815);
}
if (44 == z) {
leftright.write(850);
}
if (45 == z) {
leftright.write(883);
}
if (46 == z) {
leftright.write(915);
}
if (47 == z) {
leftright.write(950);
}
if (48 == z) {
leftright.write(983);
}
if (49 == z) {
leftright.write(1015);
}
if (50 == z) {
leftright.write(1050);
}
if (51 == z) {
leftright.write(1083);
}
if (52 == z) {
leftright.write(1115);
}
if (53 == z) {
leftright.write(1150);
}
if (54 == z) {
leftright.write(1183);
}
if (55 == z) {
leftright.write(1250);
}
if (56 == z) {
leftright.write(1283);
}
if (57 == z) {
leftright.write(1315);
}
if (58 == z) {
leftright.write(1350);
}
if (59 == z) {
leftright.write(1383);
}
if (60 == z) {
leftright.write(1415);
}
if (61 == z) {
leftright.write(1450);
}
if (62 == z) {
leftright.write(1483);
}
if (63 == z) {
leftright.write(1515);
}
if (64 == z) {
leftright.write(1550);
}
if (65 == z) {
leftright.write(1583);
}
if (66 == z) {
leftright.write(1615);
}
if (67 == z) {
leftright.write(1650);
}
if (68 == z) {
leftright.write(1683);
}
if (69 == z) {
leftright.write(1715);
}
if (70 == z) {
leftright.write(1750);
}
}
Serial.println();
}
}
If anyone has any ideas about how to shorten the receiver code, or how to get my servos to spin the right way, please post any ideas you have below.
nor does the servo stay in the same position
Do you actually have a servo or an electronically controlled motor sold as a continuous rotation "servo"
Can you please provide a link to where you got it from
You may find that 8000 bits per second is not reliable over long distances with the simple 433 MHz modules. Lower this to 2000 for better reliability. Also, you made a mistake in the receive code. The variable "messageLength" must be reset to VW_MAX_MESSAGE_LEN every time before attempting to receive a message.
If anyone has any ideas about how to shorten the receiver code
The complicated encoding/decoding scheme can be done away with entirely. My approach would be to send two bytes or two integers, depending on the 8 or 10 bit resolution you need.
For servos, 8 bits should be fine (rescale the bytes as appropriate for servo control). Suggestion for the two byte version, transmit code:
Sensor1Data = analogRead(Sensor1Pin);
Sensor2Data = analogRead(Sensor2Pin);
uint16_t data_to_send = ((Sensor1Data>>2)<<8) | (Sensor2Data>>2); //upper 8 bits of sensor 1 data in high byte, etc.
vw_send((uint8_t *) &data_to_send, 2); //send binary integer as the message
vw_wait_tx(); // Wait until the whole message is gone
...
receive code:
uint16_t message = 0; //not a char array
messageLength=VX_MAX_MESSAGE_LEN; //reset to max value is required.
if (vw_get_message((uint8_t *) &message, &messageLength)) // Non-blocking
{
if (messageLength == 2) { //got message of the correct length!
int Sensor1Data=message>>8; //high byte
int Sensor2Data=message&0xFF; //low byte
...
I think I did something wrong when editing my code, but I can't get the code to work. I can distinguish values in the serial monitor, but when I move the joystick on the x axis I just get question marks, and when I move the joystick on the y axis, I get random numbers and symbols when I move it down, and when I move it up I get question marks.
Here is my transmitter code:
#include <VirtualWire.h>
int mapX = 0;
int mapY = 0;
const int Sensor1Pin = A0;
const int Sensor2Pin = A1;
int Sensor1Data;
int Sensor2Data;
char Sensor1CharMsg[4];
char Sensor2CharMsg[4];
void setup() {
pinMode(Sensor1Pin, INPUT);
pinMode(Sensor2Pin, INPUT);
// for debuggin
Serial.begin(9600);
// VirtualWire setup
vw_setup(2000); // Bits per sec
}
void loop() {
Sensor1Data = analogRead(Sensor1Pin);
Sensor2Data = analogRead(Sensor2Pin);
//mapX = map(Sensor1Data, 0, 1023, 10, 40);
//mapY = map(Sensor2Data, 0, 1023, 41, 70);
// Convert integer data to Char array directly
uint16_t data_to_send = ((Sensor1Data >> 2) << 8) | (Sensor2Data >> 2); //upper 8 bits of sensor 1 data in high byte, etc.
vw_send((uint8_t *) &data_to_send, 2); //send binary integer as the message
vw_wait_tx(); // Wait until the whole message is gone
}
Here is my receiver code:
#include <VirtualWire.h>
#include <ServoTimer2.h>
ServoTimer2 updown;
ServoTimer2 leftright;
byte message[VW_MAX_MESSAGE_LEN]; // a buffer to store the incoming messages
byte messageLength = VW_MAX_MESSAGE_LEN; // the size of the message
void setup()
{
updown.attach(10);
leftright.attach(12);
Serial.begin(9600);
Serial.println("Device is ready");
// Initialize the IO and ISR
vw_setup(2000); // Bits per sec
vw_rx_start(); // Start the receiver
}
void loop() {
uint16_t message = 0; //not a char array
messageLength= VW_MAX_MESSAGE_LEN; //reset to max value is required.
if (vw_get_message((uint8_t *) &message, &messageLength)) // Non-blocking
{
if (messageLength == 2) { //got message of the correct length!
int Sensor1Data=message>>8; //high byte
int Sensor2Data=message&0xFF; //low byte
Serial.print("X Axis: ");
Serial.write(Sensor1Data);
Serial.println();
Serial.print("Y Axis: ");
Serial.write(Sensor2Data);
Serial.println();
}
}
}
I cannot find the problem in the code, what did I do wrong?
Don't use Serial.write() below, use Serial.print() instead. Serial.write() is used to send binary data.
Serial.print("X Axis: ");
Serial.write(Sensor1Data);
Serial.println();
Serial.print("Y Axis: ");
Serial.write(Sensor2Data);
Serial.println();
Thanks! That seems to work, you probably saved me a few hours of research. Thanks again!
Great!
Just for completeness, if you want to send all 10 bits from each analog channel, the revisions could be:
TX
uint16_t data_to_send[2];
data_to_send[0] = analogRead(Sensor1Pin);
data_to_send[1] = analogRead(Sensor2Pin);
vw_send((uint8_t *) data_to_send, 4); //send 2 binary integers, 4 bytes
RX
uint16_t message[2] = {0,0};
messageLength=VX_MAX_MESSAGE_LEN; //reset to max value is required.
if (vw_get_message((uint8_t *) message, &messageLength)) // Non-blocking
{
if (messageLength == 4) { //got message of the correct length!
int Sensor1Data=message[0];
int Sensor2Data=message[1]; //low byte
Note: The & or "address of" operator is not needed for arrays in the _send or _get_message function calls.
Sorry about continuing this, but I'm a beginner at coding. I cannot figure out how to make the servos move when I tell them to. I am receiving the right values in the serial monitor, but I can't make the servos move with them. Here is my transmitter code:
#include <VirtualWire.h>
int mapX = 0;
int mapY = 0;
const int Sensor1Pin = A0;
const int Sensor2Pin = A1;
int Sensor1Data;
int Sensor2Data;
char Sensor1CharMsg[4];
char Sensor2CharMsg[4];
void setup() {
pinMode(Sensor1Pin, INPUT);
pinMode(Sensor2Pin, INPUT);
// for debuggin
Serial.begin(9600);
// VirtualWire setup
vw_setup(2000); // Bits per sec
}
void loop() {
Sensor1Data = analogRead(Sensor1Pin);
Sensor2Data = analogRead(Sensor2Pin);
// Convert integer data to Char array directly
uint16_t data_to_send = ((Sensor2Data >> 2) << 8) | (Sensor1Data >> 2); //upper 8 bits of sensor 1 data in high byte, etc.
vw_send((uint8_t *) &data_to_send, 2); //send binary integer as the message
vw_wait_tx(); // Wait until the whole message is gone
}
Here is my receiver code:
#include <VirtualWire.h>
#include <ServoTimer2.h>
ServoTimer2 updown;
ServoTimer2 leftright;
byte message[VW_MAX_MESSAGE_LEN]; // a buffer to store the incoming messages
byte messageLength = VW_MAX_MESSAGE_LEN; // the size of the message
void setup()
{
updown.attach(10);
leftright.attach(12);
Serial.begin(9600);
Serial.println("Device is ready");
// Initialize the IO and ISR
vw_setup(2000); // Bits per sec
vw_rx_start(); // Start the receiver
}
void loop() {
uint16_t message = 0; //not a char array
messageLength= VW_MAX_MESSAGE_LEN; //reset to max value is required.
if (vw_get_message((uint8_t *) &message, &messageLength)) // Non-blocking
{
if (messageLength == 2) { //got message of the correct length!
int Sensor1Data = message>>8; //high byte
int Sensor2Data = message&0xFF; //low byte
Serial.print("Y Axis: ");
Serial.print(Sensor2Data);
updown.write(Sensor2Data);
delay(10);
Serial.print("X Axis: ");
Serial.print(Sensor1Data);
leftright.write(Sensor1Data);
delay(10);
}
}
}
Thanks!
What range values do you see when you print Sensor1Data and Sensor2Data ?
I see 0-255 for both the X axis and the Y axis.
Get the servos working with the simple sweep example included with the Arduino, and make sure you understand how everything works, before working with the radio.
You cannot use the Arduino 5V output to power servos (ignore tutorials that suggest to do that). Some sort of independent power supply is needed. A 4XAA battery pack will work for 1 or 2 small servos.
Be sure to connect all the grounds!
jacknewport:
I see 0-255 for both the X axis and the Y axis.
What range of values does the ServoTimer2 write() function require ?
HINT - it is not 0 to 180
You had fairly sensible numbers in the writes() in your original code, like 800, 1000. Now you have 0-255. You need to check the range of values that servoTimer2 write() expects.
Steve
I attached the Servos to a 4 AA power supply, but the servo arms still do the same thing. I tried to send the range of values (750 to 1750), but instead I only received 75-175, I think that it might be clipping the values, but I cannot figure out how to stop that.
It would be a great idea to have the sweep example with ServoTimer2 working by itself, for both servos, and understand it completely, before moving on.
If you use byte data transmission, you can send only values 0-255 per byte. For larger range per channel either send integers, or scale the bytes back up to 10 bits as follows (losing the bottom two data bits).
Serial.print("X Axis: ");
Serial.println(Sensor1Data*4);
Serial.print("Y Axis: ");
Serial.println(Sensor2Data*4);
I got it right! I changed the code a little by adding 750 to the Sensor data multiplied by 4, and when I move the joystick I was finally able to make the servos move! Thanks a lot guys!
Code:
Serial.print(" Y Axis: ");
Serial.println((Sensor2Data*4)+750);
updown.write((Sensor2Data*4)+750);
delay(10);
Serial.print(" X Axis: ");
Serial.println((Sensor1Data*4)+750);
leftright.write((Sensor1Data*4)+750);
delay(10);
I think I am almost done, I have (thanks to your help), been able to spin the servo arms, but as for turning the DC motor on and off, I am a little stuck. I know how to spin the motor at different speeds, but I cannot send the values from the potentiometer to the motor. Here is my transmitter code:
#include <VirtualWire.h>
int mapX = 0;
int mapY = 0;
const int Sensor1Pin = A0;
const int Sensor2Pin = A1;
const int Sensor3Pin = A2;
int converterconverted;
int Sensor1Data;
int Sensor2Data;
int Sensor3Data;
char Sensor1CharMsg[4];
char Sensor2CharMsg[4];
char Sensor3CharMsg[4];
void setup() {
pinMode(Sensor3Pin, INPUT);
pinMode(Sensor1Pin, INPUT);
pinMode(Sensor2Pin, INPUT);
// for debuggin
Serial.begin(9600);
// VirtualWire setup
vw_setup(2000); // Bits per sec
}
void loop() {
uint16_t data_to_send[3];
data_to_send[0] = analogRead(Sensor1Pin);
data_to_send[1] = analogRead(Sensor2Pin);
data_to_send[2] = analogRead(Sensor3Pin);
// Convert integer data to Char array directly
vw_send((uint8_t *) data_to_send, 4); //send 2 binary integers, 4 bytes
vw_wait_tx(); // Wait until the whole message is gone
}
And here is my receiver code:
#include <VirtualWire.h>
#include <ServoTimer2.h>
ServoTimer2 updown;
ServoTimer2 leftright;
int motorPin = 9;
int decoderofdecoded;
byte message[VW_MAX_MESSAGE_LEN]; // a buffer to store the incoming messages
byte messageLength = VW_MAX_MESSAGE_LEN; // the size of the message
void setup()
{
pinMode(motorPin, OUTPUT);
updown.attach(10);
leftright.attach(12);
Serial.begin(9600);
Serial.println("Device is ready");
// Initialize the IO and ISR
vw_setup(2000); // Bits per sec
vw_rx_start(); // Start the receiver
}
void loop() {
uint16_t message[2] = {0, 0};
messageLength = VW_MAX_MESSAGE_LEN; //reset to max value is required.
if (vw_get_message((uint8_t *) message, &messageLength)) // Non-blocking
{
if (messageLength == 4) { //got message of the correct length!
int Sensor1Data = message[0];
int Sensor2Data = message[1]; //low byte
int Sensor3Data = message[2];
updown.write((Sensor2Data * 2) + 750);
delay(10);
int speed = Sensor3Data/4;
if (speed >= 0 && speed <= 255) {
analogWrite(motorPin, speed);
}
leftright.write((Sensor1Data * 2) + 750);
delay(10);
}
}
}
Thanks!