Can't change variable via Python

Hi, I'm trying to make a fish feeder with my Arduino Uno that can be updated via Python.

For instance by default it feeds fish every 30 seconds (for debugging purposes)
I want to be able to set it to feed fish every 60 seconds (or whatever other time) via python.

Here is my Arduino code:

#include <SoftwareSerial.h>
#include <Servo.h> 
/*
  Credits to Blink for a lot of the code
  Feeds fish at a given time, can be set via Pyserial.
 */

Servo myservo;  // create servo object to control a servo 
// a maximum of eight servo objects can be created 
int led = 13;
int currentdelay = 5000;
int pos = 0;    // variable to store the servo position 
// the setup routine runs once when you press reset:

//long FEEDINGDELAY = 43200000; // 12 hours
//long FEEDINGDELAY = 57600000; // 16 hours
long FEEDINGDELAY = 30000;

long endtime; 
long now;

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);  
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
  Serial.println("FISH FEEDER 1.1");
  myservo.write(0);
  delay(15);


  // FEED THE FISH..
  Serial.print("FEEDING FISH NOW ");

  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree 
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
  {                                
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  }  
  // initialize the digital pin as an output.   

}

// the loop routine runs over and over again forever:
void loop() {
  delay(15);
  if (Serial.available()) {
    long c = Serial.read();
    if (c > 30000) { // Checks if time is more than 30 seconds
      digitalWrite(led, HIGH); // Turns on LED for debugging purposes
      FEEDINGDELAY = c; // Set feeding delay to c
    }
    else { // if it's smaller than 30 seconds, do not put on LED.
      digitalWrite(led, LOW);
    }
  }
  // process times
  now = millis();
  endtime = now + FEEDINGDELAY;

  while(now < endtime) {
    myservo.write(0);
    Serial.print("soon... ");
    Serial.println(endtime-now);
    delay(20000);
    now = millis();   
  }
  // FEED THE FISH..
  Serial.print("FEEDING FISH at ");
  Serial.println(now);

  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree 
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
  {                                
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  }
}

Here is my Python code:

import serial
import time
import copy
arduino = serial.Serial('COM7', 9600)
time.sleep(2)
arduino.write(60000)

As far as I know I don't get any errors, it just doesn't change the time from 30 seconds to 60 seconds.

I think I've included all the necessary information in this post, if any more is required please just let me know I'll add it ASAP. This is my first post on this forum and if there's anything wrong with it I'll be sure to pay attention to that when posting my next thread.

Are those serial messages you are sending at the beginning coming in?

  if (Serial.available()) {
    long c = Serial.read();
    if (c > 30000) { // Checks if time is more than 30 seconds
      digitalWrite(led, HIGH); // Turns on LED for debugging purposes
      FEEDINGDELAY = c; // Set feeding delay to c
    }
    else { // if it's smaller than 30 seconds, do not put on LED.
      digitalWrite(led, LOW);
    }
  }

read takes 1 byte from serial!

  now = millis();
  endtime = now + FEEDINGDELAY;

  while(now < endtime) {
    myservo.write(0);
    Serial.print("soon... ");
    Serial.println(endtime-now);
    delay(20000);
    now = millis();   
  }

Can the while ever be executed?

Use the serial monitor to start with not an extra load of python code.

Mark

PS. Get rid of all the delays (See blink without delay)

M

Serial.read() only reads one character at a time, not a long as your code assumes. In order to read in a long you need to read it byte by byte, assemble the bytes into a null terminated string (not a String) then, when all the bytes have been read, indicated by an 'end of input' character such as carriage return or line feed, turn the string into a long.

It is not as difficult as it sounds. Have a look at this page Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking

To turn the string into a long you can use the atol() function http://www.cplusplus.com/reference/cstdlib/atol/

Thanks everyone for your help so far.

I've tried to fix the problem with the help of your suggestions and links.
I think I've made some progress, but I'm still having a few issues that have me stumped. I think I must've reread this code a 100 times in the last few hours haha.

I've tried following the instructions on Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking for how to receive numbers

Here's my current arduino code:

#include <SoftwareSerial.h>
#include <Servo.h> 
/*
  Credits to Blink for a lot of the code
 Feeds fish at a given time, can be set via Pyserial.
 */

Servo myservo;  // create servo object to control a servo 
// a maximum of eight servo objects can be created 
int led = 13;
int currentdelay = 5000;
const char startOfNumberDelimiter = '<';
const char endOfNumberDelimiter   = '>';
int pos = 0;    // variable to store the servo position 
// the setup routine runs once when you press reset:

//long FEEDINGDELAY = 43200000; // 12 hours
//long FEEDINGDELAY = 57600000; // 16 hours
long FEEDINGDELAY = 30000;

long endtime; 
long now;

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);  
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
  Serial.println("FISH FEEDER 1.1");
  myservo.write(0);
  delay(15);


  // FEED THE FISH..
  Serial.print("FEEDING FISH NOW ");

  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree 
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
  {                                
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  }   

}

void processNumber (const long n)
{
  Serial.println (n); // Prints number
  FEEDINGDELAY = n; // changes feeding delay to new number
}

void processInput ()
{
  static long receivedNumber = 0;
  static boolean negative = false;

  byte c = Serial.read ();

  switch (c)
  {

  case endOfNumberDelimiter:  
    if (negative) 
      processNumber (- receivedNumber); 
    else
      processNumber (receivedNumber); 

    // fall through to start a new number
  case startOfNumberDelimiter: 
    receivedNumber = 0; 
    negative = false;
    break;

  case '0' ... '9': 
    receivedNumber *= 10;
    receivedNumber += c - '0';
    break;

  case '-':
    negative = true;
    break;

  } // end of switch  
}  // end of processInput

// the loop routine runs over and over again forever:
void loop() {
  if (Serial.available()) {
    processInput ();
    delay(5);
   if (FEEDINGDELAY > 30000) { // Checks if time is more than 30 seconds
     digitalWrite(led, HIGH); // Turns on LED for debugging purposes
   }
   else { // if it's smaller than 30 seconds, do not put on LED.
     digitalWrite(led, LOW);
   }    
  }
  // process times
  now = millis();
  endtime = now + FEEDINGDELAY;

  while(now < endtime) {
    myservo.write(0);
    Serial.print("soon... ");
    Serial.println(endtime-now);
    delay(20000);
    now = millis();   
  }
  // FEED THE FISH..
  Serial.print("FEEDING FISH at ");
  Serial.println(now);

  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree 
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
  {                                
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  }
}

And python:

import serial
import time
import copy

arduino = serial.Serial('COM7', 9600)
time.sleep(2)
arduino.write("<60000>")

I think the problem might be I haven't converted it to a long and it's still an int? I'm not sure how to do that though. I've read up on atol but I'm not sure what to use atol on.

Again I'm sorry if I'm being a complete noob and the answer seems obvious to you all. I'll try my best to come up with my own solutions as I can but any more pushes in the right direction would be lovely LOL

The processInput() function takes one character from the serial buffer if it is available. Next time through loop() it takes another and so on until the end of the number. This depends on loop() running continuously in order to process the input in a timely manner.

However, your code does not do this so the number is never complete.

Incidentally, to move the servo from 0 to 180 degrees and back you do not need to use 2 for loops, justmyservo.write(180);andmyservo.write(0);A short delay between the 2 commands would be a good idea to allow the servo to get to 180 degrees before the second command is executed.

Previous aquarium discussions that might be of interest.

https://www.google.com/search?as_q=aquarium&as_epq=&as_oq=&as_eq=&as_nlo=&as_nhi=&lr=&cr=&as_qdr=all&as_sitesearch=http%3A%2F%2Fforum.arduino.cc%2Findex&as_occt=any&safe=images&tbs=&as_filetype=&as_rights=