Print Sensor Data, Then Pull it Down from Serial Monitor and Use it?

I tried typing earlier and it crashed and I lost what I typed here.
EDITED: What the code is supposed to do:
While serial isn't connected: one potentiometer controls one servo each, total of 3 pots, 3 servos. This is for regular manual control of servos.
While serial IS connected: Read potentiometers, split the readings into 3 unique non overlapping number ranges, send up to serial, pull down and read same serial pot data, map it to control each servo. That serial data ought to be capable of copying from monitor, for pasting back in when pots are disconnected from circuit. This is for recording control data from the pots and replaying it autonomously via paste to monitor.

Here's my code which doesn't do anything properly, please help fix it!

#include <Servo.h>



Servo myservo1;  // create servo object to control a servo
Servo myservo2;
Servo myservo3;

int potpin1 = A1;  // analog pin used to connect the potentiometer
int potpin2 = A2;
int potpin3 = A3;
int val1;    // variable to read the value from the analog pin
int val2;
int val3;
int data = 0;
   
 

void setup()
{
  Serial.begin(9600);
  myservo1.attach(9);
  myservo2.attach(10);// attaches the servo on pin 9 to the servo object
  myservo3.attach(11);
  //Serial.println("0"); //Might not be neccessary if default of serial means zero.

}

void loop() 
{
 
  if (Serial.available() == 0) {
  
  
  val1 = analogRead(potpin1);            // reads the value of the potentiometer (value between 0 and 1023) 
  val1 = map(val1, 0, 1023, 0, 180);   // to scale pot reading to servo control range 
  myservo1.write(val1);
  delay(15); // waits for the servo to get there
 
  
  val2=analogRead(potpin2);
  val2= map (val2, 0, 1023, 0, 180); // to scale pot reading to servo control range
  myservo2.write(val2);
 
  delay(15);

  val3=analogRead(potpin3);
  val3 = map (val3, 0, 1023, 0, 180); // to scale pot reading to servo control range
  myservo3.write(val3);
    delay(15);
  }
    
  
  
   
       
        if (Serial.available() > 0) {
                // read the incoming byte:
                data = Serial.read();
        
        val1 = analogRead(potpin1);            // reads the value of the potentiometer (value between 0 and 1023) 
  val1 = map(val1, 0, 1023, 2000, 2999);   // to scale it and split each pot/servo combo distinctly and separately from the others. 
  
  Serial.println(val1);  // sets the servo position according to the scaled value 
  delay(15); // waits for the servo to get there
 
  
  val2=analogRead(potpin2);
  val2= map (val2, 0, 1023, 1000, 1999); // to scale it and split each pot/servo combo distinctly and separately from the others. 
  Serial.println(val2);
  delay(15);

  val3=analogRead(potpin3);
  val3 = map (val3, 0, 1023, 1, 999); // to scale it and split each pot/servo combo distinctly and separately from the others. 
  Serial.println(val3);
  delay(15);
  
   
  //When serial is connected, pot val doesn't go straight to the servo control, unlike when serial is disconnected... 
  //...Instead it goes to serial monitor and then back down to control the servos.
  // Disconnect middle pins on all pots (A1, A2, A3) when you want to control servos via serial monitor.
 //
// You have to wait for serial data sent to finish executing before reconnecting potentiometers.
        
                
                if (data > 0 && data < 1000) { 
                data= map(data, 1, 999, 0, 180);
                myservo3.write(data);
                delay(15);
                }
                
                if (data > 1000 && data < 1999) {
                data = map(data, 1000, 1999, 0, 180);
                myservo2.write(data);
                delay(15);
                }
                
                if (data > 1999 && data < 3000) {
                data = map(data, 2000, 2999, 0 ,180);
                myservo1.write(data);
                delay(15);
                }
                              
                  
                
                }  
  
}

Sorry, but this is all wrong (or extremely badly worded)

//When serial is connected, pot val doesn't go straight to the servo control, unlike when serial is disconnected...
//...Instead it goes to serial monitor and then back down to control the servos.
// Disconnect middle pins on all pots (A1, A2, A3) when you want to control servos via serial monitor.

You cannot send data to the serial monitor and then get it back unless someone types the same numbers into the serial monitor.

If you disconnect the middle pins on the pots the Arduino can get no measurement from them - so how could it send them to the serial monitor.

If you leave the pins connected it is trivial to have your program ignore the values from the ADC if that's what is required.

Please describe more clearly (in English rather than code) exactly what you want to achieve.

...R
Serial Input Basics
Planning and Implementing a Program

You can't pull it back from the serial monitor. You should save a copy of what you're going to print before you print it.

It's kind of like if I told you I was going to write you a letter with the specs for a new project and tell you that when you get it I need you to call me and give me those specs so I can build it. That would be ridiculous no? If I've got the specs to send to you then I could just write down a copy for myself.

Hi,
Thanks for the quick reply!
I want to have two different modes without having to upload a different sketch to the arduino board.
In one mode, I am trying to use 3 pots to control 3 servos, one pot per servo. I want to be able to read what commands are issued to the servos in order so that I can copy them as plain text. That part of the code is working. In a second mode, I want to be able to resend those copied commands to control the servos without needing to touch the pots at all.
The purpose is to use the pots to control the 3 servos which will be attached to the sticks on a r/c quadcopter remote controller. This allows me to use 1 pot as a throttle joystick, 1 other pot as altitude joystick, and the third pot which would control rotation on the quadcopter would be controlled via neck rotation while wearing FPV goggles.
Ideally, the first mode would not require a serial connection to work, but would still be compatible with serial if connected to a PC via USB.

The record/replay used in the second mode is for autonomous flight preprogrammed to mimic the recorded manual controls
Hopefully that clears things up a little.
Sorry for not being clear!

  • triops124
byte modeButton = 2;
void setup(){
pinMode (modeButton, INPUT_PULLUP); // input pit with internal pullup resistor
}
void loop(){
if (digitalRead(modeButton) == 0{  // modeButton connects pin to Gnd, or pin is pulled high
// do mode 0 code
}
else {
// do mode 1 code
}
}

More complex: Instead of reading a pin, look for a serial message coming in to toggle between modes.

if (Serial.available()>0){
command = Serial.read();
if (command == '0'){
mode = 0;
}
if command == '1'){
mode = 1;
}
// otherwise mode is not changed
}
// then similar to above
if (mode) == 0{  // mode set from serial data
// do mode 0 code
}
else {
// do mode 1 code
}

triops124:
Hi,
Thanks for the quick reply!
I want to have two different modes without having to upload a different sketch to the arduino board.
In one mode, I am trying to use 3 pots to control 3 servos, one pot per servo. I want to be able to read what commands are issued to the servos in order so that I can copy them as plain text. That part of the code is working. In a second mode, I want to be able to resend those copied commands to control the servos without needing to touch the pots at all.
The purpose is to use the pots to control the 3 servos which will be attached to the sticks on a r/c quadcopter remote controller. This allows me to use 1 pot as a throttle joystick, 1 other pot as altitude joystick, and the third pot which would control rotation on the quadcopter would be controlled via neck rotation while wearing FPV goggles.
Ideally, the first mode would not require a serial connection to work, but would still be compatible with serial if connected to a PC via USB.

The record/replay used in the second mode is for autonomous flight preprogrammed to mimic the recorded manual controls
Hopefully that clears things up a little.
Sorry for not being clear!

  • triops124

All doable but you have to save the commands somewhere other than the serial monitor. Save to EEPROM or an SD card.

I will use SD card at some point later on. Is storing in EEPROM or SD absolutely mandatory, or is it possible to use serial copying and pasting for the time being?

For me to analyze my own confusing code, I have split the code into two sketches; "RECORD" mode 1, and "RETRACE" Mode 2.
I am encountering an error message in the "RECORD mode1" sketch:
"ERROR: class hardware serial has no member named "PrintLn"

Why does this error message occur? How do I fix it?

//THIS IS THE RECORD MODE 1 SCRIPT FOR MANUAL CONTROL AND CAPTURING COMMAND DATA FOR USE WITH "RETRACE" SKETCH.


#include <Servo.h>



Servo myservo1;  // create servo object to control a servo
Servo myservo2;
Servo myservo3;

int potpin1 = A1;  // analog pin used to connect the potentiometer
int potpin2 = A2;
int potpin3 = A3;
int val1;    // variable to read the value from the analog pin
int val2;
int val3;
int valA;
int valB;
int valC;
int data = 0;
   
 

void setup()
{
  Serial.begin(9600);
  myservo1.attach(9);
  myservo2.attach(10);// attaches the servo on pin 9 to the servo object
  myservo3.attach(11);
  //Serial.println("0"); //Might not be neccessary if default of serial means zero.

}

void loop() 
{
 
  
  
  val1 = analogRead(potpin1);            // reads the value of the potentiometer (value between 0 and 1023) 
  val1 = map(val1, 0, 1023, 0, 180);   // to scale pot reading to servo control range 
  myservo1.write(val1);
  delay(15); // waits for the servo to get there
  valA = analogRead(potpin1);
 valA = map(val1, 0, 1023, 2000, 2999);
  Serial.Println(valA);
  
  val2=analogRead(potpin2);
  val2= map (val2, 0, 1023, 0, 180); // to scale pot reading to servo control range
  myservo2.write(val2); 
  delay(15);
   valB = analogRead(potpin2);
 valB = map(val2, 0, 1023, 1000, 1999);
 Serial.Println(valB);

  val3=analogRead(potpin3);
  val3 = map (val3, 0, 1023, 0, 180); // to scale pot reading to servo control range
  myservo3.write(val3);
    delay(15);
   valC = analogRead(potpin3);
 valC = map(val3, 0, 1023, 1, 999);
 Serial.Println(valC);
 
  }

And here is the "Mode 2 retrace" sketch, which doesn't seem to have any problems yet:

//*THIS IS THE READ-ONLY SCRIPT: TO RETRACE PREVIOUS...
//*FLIGHT USING CAPTURED SERIAL CONTROL DATA FROM THE MODE 1 SCRIPT, PASTE THAT TEXT INTO THE SERIAL MONITOR AFTER LOADING THIS SCRIPT.*




#include <Servo.h>



Servo myservo1;  // create servo object to control a servo
Servo myservo2;
Servo myservo3;

int potpin1 = A1;  // analog pin used to connect the potentiometer
int potpin2 = A2;
int potpin3 = A3;
int val1;    // variable to read the value from the analog pin
int val2;
int val3;
int valA;
int valB;
int valC;
int data = 0;
   
 

void setup()
{
  Serial.begin(9600);
  myservo1.attach(9);
  myservo2.attach(10);// attaches the servo on pin 9 to the servo object
  myservo3.attach(11);
  //Serial.println("0"); //Might not be neccessary if default of serial means zero.

}

void loop() 
{
 if (Serial.available() > 0) {
                // read the incoming byte:
                data = Serial.read();
        
   
   
  
                
                if (data > 0 && data < 1000) { 
                data= map(data, 1, 999, 0, 180);
                myservo3.write(data);
                delay(15);
                }
                
                if (data > 1000 && data < 1999) {
                data = map(data, 1000, 1999, 0, 180);
                myservo2.write(data);
                delay(15);
                }
                
                if (data > 1999 && data < 3000) {
                data = map(data, 2000, 2999, 0 ,180);
                myservo1.write(data);
                delay(15);
                }
                              
                  
                
                }  
  
}

Hi,
So you want to do a learn run and store it, then used the stored instructions to control the servos, the same way as in learn mode.

This is okay, but the quad-copter will probably not follow the same course, you have wind direction and strength to contend with, as well as battery condition'

You will have to make sure the quad-copter is initially oriented in exactly the same direction at takeoff, if the same course is followed.

Read potentiometers, split the readings into 3 unique non overlapping number ranges, send up to serial

You can send them as three separate numbers, without have to make them non overlaping.

Tom.... :slight_smile:

Hi Tom,
How would not using unique ranges work?
Would all pot values be printed as is, and then read by serial all at once?

Hi,
Check these links on serial communications, and check the examples in the IDE.

https://forum.arduino.cc/index.php?topic=288234.0

http://arduinobasics.blogspot.com.au/2012/07/arduino-basics-simple-arduino-serial.html

Tom... :slight_smile:

Serial.Println(valA);

C is case sensitive. println is not the same as Println.

And once again, there is absolutely no way for arduino to read anything off the Serial monitor. You'll have to save it somewhere else.

You could write a PC program to save to a file the values that are sent by Serial.print() and then at a later stage read the file and send the values to the Arduino.

One thing I have not seen mentioned so far in this Thread is the need to record the time when the changes to the pot values take place. It is no good sending back a series of numbers such as 10, 100, 700, 500, 1000, 300. with just a few millisecs between them.

I confess that I share the concerns in Reply #8. If you were building a record and playback system for a wheeled vehicle it may work. I think you will need proper position control for a flying vehicle - in other words sending it a series of positions to move to and let it figure out how to get there. That would not be an easy program to write even if there was a simple system for defining where the vehicle is in 3D space.

...R

Hi Robin,
Good idea about the PC program!

I have the code set in such a way that the 3 sensor readings are sent with a delay(15) between each, then grouped by newline. On the serial controlled code, there is another delay(15) between each to allows the servos to catch up. Do you think that would this solve the serial timing problem you mentioned?

I am aware that drift from wind and battery level would cause problems with the "playback" when using a flying r/c vehicle. My plan is to only use it indoors for flying toys, but with a wheeled vehicle I think it would have little need for error correction, I think it is sufficient as-is.

In the record/manual control sketch, I am getting an error message "error: expected primary expression before the ')' token." on the lines with serial printing.

Serial.print(val2,);

Why is that error occurring? How do I fix that?

Here are the two scripts so far:

record/manual control sketch:

//THIS IS THE MODE 1 SCRIPT FOR MANUAL CONTROL AND CAPTURING COMMAND DATA FOR USE WITH THE "RETRACE" SKETCH.


#include <Servo.h>



Servo myservo1;  // create servo object to control a servo
Servo myservo2;
Servo myservo3;

int potpin1 = A1;  // analog pin used to connect the potentiometer
int potpin2 = A2;
int potpin3 = A3;
int val1;    // variable to read the value from the analog pin
int val2;
int val3;
int valA;
int valB;
int valC;
int data = 0;
   
 

void setup()
{
  Serial.begin(9600);
  myservo1.attach(9);
  myservo2.attach(10);// attaches the servo on pin 9 to the servo object
  myservo3.attach(11);
  //Serial.println("0"); //Might not be neccessary if default of serial means zero.

}

void loop() 
{
 
  
  
  val1 = analogRead(potpin1);            // reads the value of the potentiometer (value between 0 and 1023) 
  valA = map(val1, 0, 1023, 0, 180);
  Serial.print(val1,);  // to scale pot reading to servo control range 
  myservo1.write(valA);
  delay(15); // waits for the servo to get there
  
 
  
  val2=analogRead(potpin2);
  valB= map (val2, 0, 1023, 0, 180); // to scale pot reading to servo control range
  Serial.print(val2,);
  myservo2.write(valB); 
  delay(15);
  
  val3=analogRead(potpin3);
  valC = map (val3, 0, 1023, 0, 180); // to scale pot reading to servo control range
  Serial.print(val3,);
  myservo3.write(valC);
    delay(15);
    serial.write("\n");
   
 
  }

Retrace/Replay Control sketch:

//*THIS IS THE MODE 2 SCRIPT: READ-ONLY, FOR RETRACING PREVIOUS...
//*FLIGHT PATH USING CAPTURED SERIAL CONTROL DATA FROM THE MODE 1 SCRIPT BY PASTING THAT TEXT INTO THE SERIAL MONITOR AFTER LOADING THIS SCRIPT.*

#include <Servo.h>



Servo myservo1;  // create servo object to control a servo
Servo myservo2;
Servo myservo3;

int potpin1 = A1;  // analog pin used to connect the potentiometer
int potpin2 = A2;
int potpin3 = A3;
int val1;    // variable to read the value from the analog pin
int val2;
int val3;
int valA;
int valB;
int valC;
//int data = 0; //I don't think this is needed.
   
 

void setup()
{
  Serial.begin(9600);
  myservo1.attach(9);
  myservo2.attach(10);// attaches the servo on pin 9 to the servo object
  myservo3.attach(11);
  
}
void loop(){
    if (Serial.available() > 0){
        int val1 = Serial.parseInt();
        int val2 = Serial.parseInt();
        int val3 = Serial.parseInt();
        
        if (Serial.read() == '\n') {
      
      valA = map(val1, 0, 1023, 0, 180); // Using "Constrain()" here might be neccessary for limiting servo rotation range based on limited pot movement range?
      valB = map(val2, 0, 1023, 0, 180); // Using "Constrain()"  here might be neccessary for limiting servo rotation range based on limited pot movement range?
      valC = map(val2, 0, 1023, 0, 180); // Using "Constrain()"  here might be neccessary for limiting servo rotation range based on limited pot movement range?

      // fade the red, green, and blue legs of the LED:
      myservo1.write(valA);
      delay(15);
      myservo2.write(valB);
      delay(15);
      myservo3.write(valC);
      delay(15);
    }
  }
}

Thanks in advance,

Triops124

Serial.print(val2,);

Really? You're looking at that line and don't see something extra in there that doesn't belong? Look closely now. Maybe look at some other examples of people using Serial.print if you still don't see it. There's something that this line has that just doesn't belong there.

If you take a measurement of the pot every 15 millisecs you will have 67 readings per second and nearly 240,000 in an hour for each pot.

You will need to calculate whether there is time for the Arduino to send (or receive) data that quickly.

It would make a lot more sense only to save the pot value when it changes and to record the time (the value of millis() ) as well. You should also ensure that very minor changes in the pot value are ignored.

...R

The comma? I put that there intentionally. It's for separating the printed val1, val2, & val3. So that the retrace sketch can tell the difference between the 3. That way it can separate them into 3 servo controls with a newline between every reading set.
It's just not working though.

Robin2:
If you take a measurement of the pot every 15 millisecs you will have 67 readings per second and nearly 240,000 in an hour for each pot.

You will need to calculate whether there is time for the Arduino to send (or receive) data that quickly.

It would make a lot more sense only to save the pot value when it changes and to record the time (the value of millis() ) as well. You should also ensure that very minor changes in the pot value are ignored.

...R

Good ideas! I will add those in later.

If you want a comma between values you must do that with a separate print statement - like this

Serial.print(mVal);
Serial.print(',');

...R

Wow thanks. That was so simple. I feel stupid lol. Additional print statement for each comma. Got it.

Thanks everyone for the help and ideas so far!
I'll be back later mostly likely in case I get stuck with the serial timing and serial simplification work.