Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raspberry Pi + Arduino + Pressure Sensors & Solenoid Valves, Nanpy Serial Timeout Error #99

Open
kunaijake opened this issue Jul 20, 2017 · 1 comment

Comments

@kunaijake
Copy link

Hello reader! My project involves filling a tank with a liquid called ox and fu. I have to make sure the pipelines and tank are at certain pressures. Using Nanpy, the Pi tells the Arduino to measure pressures and to trigger relays which triggers solenoid valves as well.

My problem is that my program runs well but will eventually result in a timeout error (error outlined in below).

I have a system consisting of the following: Raspberry Pi 3 Model B, Arduino Mega 2560 Rev3, powered USB hub, Sainsmart 16-channel relay module, 5 pressure transducers and 7 solenoid valves. The setup is below.

The connections are as follows:
*Pi3 to powered USB hub to Mega via USB
*Mega connected to pressure transducers (pins A0 to A4) and relay board (pins 22 to 38)
*relay board connected to solenoids.

I apologize for the long code. I removed a lot of the other essential parts and reduced it to its absolute core.

Your Python code

from nanpy import (ArduinoApi, SerialManager)
from time import sleep
from timeit import default_timer as timer
import time
import datetime
import RPi.GPIO as GPIO 
import sys
import numpy 
import random
from threading import Thread
import curses

#connect to arduino
connection = SerialManager('/dev/ttyACM1', 9600)
a = ArduinoApi(connection=connection)

#start timer
start_time = time.time() #needed to measure runtime before program crashes :(

#curses options
stdscr = curses.initscr()#for the non-blocking text
#This allows the program to continue running after waiting for input for a limited amount of time.
stdscr.nodelay(1) #set input to non-blocking mode.
curses.noecho() #echoing of input characters is turned off
stdscr.nodelay(1) #set getch() non-blocking

#Used to zero the pressure transducers.
global zero_pt
zero_pt = False

# allows the safety solenoids to vent when tanks are overpressurized.
auto_safety = 'YES'

#arms the system and powers the solenoids 
armed = 'OFF'

#setting the pinmodes for the Sainsmart 16 channel relay board.
a.pinMode(34, a.OUTPUT) #fuel safety solenoids
a.digitalWrite(34, 1)
a.pinMode(29, a.OUTPUT) #Oxygen safety solenoids
a.digitalWrite(29, 1)
sleep(0.1)
a.pinMode(31, a.OUTPUT) #Arming relay
a.digitalWrite(31, 1)
sleep(0.1)
a.pinMode(22, a.OUTPUT) # Normally CLOSED solenoid (Main Pressure Solenoid).
a.digitalWrite(22, 1)
sleep(0.1)
a.pinMode(23, a.OUTPUT) # Normally OPEN solenoid. (Venting Open Solenoid).
a.digitalWrite(23, 1)
sleep(0.1)
a.pinMode(24, a.OUTPUT) # Normally OPEN solenoid. (Venting Close Solenoid).
a.digitalWrite(24, 1)
sleep(0.1)
a.pinMode(25, a.OUTPUT) # Normally OPEN solenoid. (Mainshut Solenoid).
a.digitalWrite(25, 1)
sleep(0.1)
a.pinMode(26, a.OUTPUT) # Normally OPEN solenoid.  (Mainopen Solenoid).
a.digitalWrite(26, 1)
sleep(0.1)
a.pinMode(27, a.OUTPUT) #Oxygen Pump Heater
a.digitalWrite(27, 1)
sleep(0.1)
a.pinMode(28, a.OUTPUT) #Fuel Pump Heater
a.digitalWrite(28, 1)
sleep(0.1)
a.pinMode(30, a.OUTPUT)
a.digitalWrite(30, 1)
sleep(0.1)
a.pinMode(32, a.OUTPUT)
a.digitalWrite(32, 1)
sleep(0.1)
a.pinMode(33, a.OUTPUT)
a.digitalWrite(33, 1)
sleep(0.1)
sleep(0.1)
a.pinMode(35, a.OUTPUT)
a.digitalWrite(35, 1)
sleep(0.1)
a.pinMode(36, a.OUTPUT)
a.digitalWrite(36, 1)
sleep(0.1)
a.pinMode(37, a.OUTPUT)
a.digitalWrite(37, 1)

		#defining functions to operate solenoids
#Arduino digital channels 22 to 37. HIGH (1) in arduino corresponds to off on relay board
#Currently, the pressure transducers have not been zeroed.

#***Pressurization Functions***
def presson(): #The D2061-LN2-C203 is normally closed. 0Ard => 1Relay => Open Valve.
  press = 22
  a.digitalWrite(press,0) #Open Valve
##  print "Pressurizing ox and fu ON"
def pressoff(): #The D2061-LN2-C203 is normally closed. 1Ard => 0Relay => Closed Valve.
  press = 22
  a.digitalWrite(press,1) #Close Valve
##  print"Pressurizing ox and fu OFF"

#***Venting Functions***
def ventopenon(): #The A3021-T-T0-C203 is normally closed. 0Ard => 1Relay => Open Valve
  ventopen = 24
  a.digitalWrite(ventopen,0)
##  print "Venting ox and fu (Solenoid ON)"
def ventopenoff():
  ventopen = 24
  a.digitalWrite(ventopen,1)
##  print "Venting ox and fu (Solenoid OFF)"
def ventcloseon():
  ventclose = 23
  a.digitalWrite(ventclose,0)
##  print "NOT Venting ox and fu (Solenoid ON)"
def ventcloseoff():
  ventclose = 23
  a.digitalWrite(ventclose,1)
##  print "NOT Venting ox and fu (Solenoid OFF)"

#***Main Valve Functions***
def mainshuton():
  mainshut= 25
  a.digitalWrite(mainshut, 0)
##  print "main shut ON"
def mainshutoff():
  mainshut=25
  a.digitalWrite(mainshut, 1)
##  print "main shut OFF"
def mainopenon():
  mainopen = 26
  a.digitalWrite(mainopen, 0)
##  print "\n main open ON \n"
def mainopenoff():
  mainopen=26
  a.digitalWrite(mainopen, 1)
##  print "\n main open OFF \n"

## Safety solenoids
def oxsafetyoff():
  oxsafety=29
  a.digitalWrite(oxsafety,0) #close the LOX safety
##  print "\n Ox safety CLOSED"
def oxsafetyon():
  oxsafety=29
  a.digitalWrite(oxsafety,1) #open the LOX safety
##  print "\n Ox safety OPENED"

def fusafetyoff():
  fusafety=34
  a.digitalWrite(fusafety,0) #close the PP safety
##  print "\n PP safety CLOSED"
def fusafetyon():
  fusafety=34
  a.digitalWrite(fusafety,1) #open the PP safety
##  print "\n PP safety OPENED"

# Arming Relay
def armingon():
  arming = 31
  a.digitalWrite(arming, 0)
  global armed
  armed = 'ON'
##  print "arming on"
def armingoff():
  arming = 31
  a.digitalWrite(arming, 1)
  global armed
  armed = 'OFF'
##  print "arming off"

#Pump Heaters
def oxheateron():
  oxheater = 27
  a.digitalWrite(oxheater, 0)
##  print "Oxygen pump heater ON."
def oxheateroff():
  oxheater = 27
  a.digitalWrite(oxheater, 1)
##  print "Oxygen pump heater OFF."
def fuheateron():
  fuheater = 28
  a.digitalWrite(fuheater,0)
##  print "Fuel pump heater ON."
def fuheateroff():
  fuheater= 28
  a.digitalWrite(fuheater,1)
##  print "Fuel pump heater OFF"

#Combination functions.
def waitenter():
  try:
    input("Press Enter to Continue")
  except SyntaxError:
    pass

def mainopen(): #Opens the main valve
  mainopenon()
  sleep (1.0)
  mainopenoff()

def mainclose(): #Closes the main valves
  mainshuton()
  sleep(1.0)
  mainshutoff()

def ventopen(): #Opens the venting valves
  ventopenon()
  sleep(1.0)
  ventopenoff()
def ventclose():  #Closes the venting valves
  ventcloseon()
  sleep(1.0)
  ventcloseoff()

def purge():      #Purge the line
  purgeon()
  sleep(1)
  purgeoff()

def sleepmes(secs):
  print "wait ",
  print secs,
  print " seconds"
  sleep(secs)

#***Pressure Transducer Functions***
  #These are the functions needed to measure the pressure from the pressure transducer.
def press_volt(x, in_min, in_max, out_min, out_max):
  return (x - in_min)*(out_max-out_min)/(in_max-in_min)+out_min

def psiox_measure():
  PT1_slope = 23.81173
  PT1_intercept = -0.60496
  PT1_volt_correct = 0.0038
  PT1_voltage = press_volt(a.analogRead(0), 0.0, 1023.0, 0.0, 5.0)+PT1_volt_correct
  return PT1_voltage*PT1_slope+PT1_intercept # [psi] A0 pin, PT1
##  return PT1_voltage
##  return a.analogRead(0)

def psifu_measure():
  PT2_slope = 24.10409
  PT2_intercept = -0.95421
  PT2_volt_correct = 0.0186
  PT2_voltage = press_volt(a.analogRead(1), 0.0, 1023.0, 0.0, 5.0)+PT2_volt_correct
  return PT2_voltage*PT2_slope+PT2_intercept # [psi] A1 pin, PT2
##  return PT2_voltage
##  return a.analogRead(1)

def psiox_pump_measure():
  PT3_slope = 277.962127
  PT3_intercept = -130.83277
  PT3_volt_correct = 0.021531378
  PT3_voltage = press_volt(a.analogRead(2), 0.0, 1023.0, 0.0, 5.0)+PT3_volt_correct
  return PT3_voltage*PT3_slope+PT3_intercept # [psi] A2 pin, PT3
##  return PT3_voltage
##  return a.analogRead(2)

def psifu_pump_measure():
  PT4_slope = 281.237104
  PT4_intercept = -139.852626
  PT4_volt_correct = 0.015977517
  PT4_voltage = press_volt(a.analogRead(3), 0.0, 1023.0, 0.0, 5.0)+PT4_volt_correct
  return PT4_voltage*PT4_slope+PT4_intercept # [psi] A3 pin, PT4
##  return PT4_voltage
##  return a.analogRead(3)

def psichamb_measure():
  PT5_slope = 279.899666
  PT5_intercept = -136.618869
  PT5_volt_correct = 0.020039101
  PT5_voltage = press_volt(a.analogRead(4), 0.0, 1023.0, 0.0, 5.0)+PT5_volt_correct
  return PT5_voltage*PT5_slope+PT5_intercept # [psi] A4 pin, PT5
##  return PT5_voltage
##  return a.analogRead(4)

def timer(first_time):
  end_time = time.time()
  time_period = (end_time - first_time)/60 #time in minutes
  return time_period
  

# ------------------------MAIN FUNCTION===================

fopen = open('LogData'+str(time.strftime("%m%d%y%H%M")),'w') #will create new file named LogDataMMDDYYHHMM
fappend = open('LogData'+str(time.strftime("%m%d%y%H%M")),'a') #defines fappend to append data to log file
fname = 'LogData'+str(time.strftime("%m%d%y%H%M")) #static file name
print "Log file opened in ~/pi/Teststand: LogData"+str(time.strftime("%m%d%y%H%M"))
#write a header for each log entry
fappend.write('Log Data Date: ')
fappend.write(str(time.strftime("%c"))) #formatted time and date
fappend.write('\n')

print_once = True
try:
  while True:
    # Zero the pressure transducers or print the values as they are.
    if zero_pt == True:
      psiox = psiox_measure() - z_psiox
      psifu = psifu_measure() - z_psifu
      psioxpump = psiox_pump_measure() - z_psioxpump
      psifupump = psifu_pump_measure() - z_psifupump
      psichamb = psichamb_measure() - z_psichamb
    else:
      psiox = psiox_measure()
      psifu = psifu_measure()
      psioxpump = psiox_pump_measure()
      psifupump = psifu_pump_measure()
      psichamb = psichamb_measure()

    #calculate the elapsed time  
    elapsed_time = timer(start_time)

    #Safety release valves.
    if auto_safety == 'YES':
      #Keep the valves open if tank is overpressurized 
      if (psiox >= 50 and armed == 'ON') or (psifu >= 50 and armed == 'ON'):
        oxsafetyon()
        fusafetyon()
        sleep(0.1)
      #Keep the valves closed if tank is not overpressurized
      elif (psiox <= 50 and armed == 'ON') or (psifu <= 50 and armed == 'ON'):
        oxsafetyoff()
        fusafetyoff()
        sleep(0.1)
    elif auto_safety == 'NO':
      oxsafetyon()
      fusafetyon()
  
    stdscr.addstr(0,0, "%d oxtankpress[psi]" %int(psiox))
    stdscr.addstr(1,0, "%d futankpress[psi]" %int(psifu))
    stdscr.addstr(2,0, "%d oxpumppress[psi]" %int(psioxpump))
    stdscr.addstr(3,0, "%d fupumppress[psi]" %int(psifupump))
    stdscr.addstr(4,0, "%d psichambpress[psi]" %int(psichamb))
    stdscr.addstr(5,0, "%.2f time elapsed [min]" %elapsed_time)

    #Printing the pressure values
    if print_once == True:
    
      fappend.write(" oxtankpress[psi] \t  futankpress[psi] \t oxpumppress[psi] \
\t fupumppress[psi] \t psichambpress[psi] \t elapsed time[min]\n")
      print_once = False
      
    fappend.write(str(psiox))
    fappend.write(" \t\t ")
    fappend.write(str(psifu))
    fappend.write(" \t\t ")
    fappend.write(str(psioxpump))
    fappend.write(" \t\t ")
    fappend.write(str(psifupump))
    fappend.write(" \t ")
    fappend.write(str(psichamb))
    fappend.write(" \t ")
    fappend.write(str(elapsed_time))
    fappend.write(" \t ")

    #Print the Options menu
    (y_win, x_win) = stdscr.getmaxyx()
    mid_screen = int(x_win/2)
    stdscr.addstr(7, mid_screen-8, "***Main Menu***")
    stdscr.addstr(8, 0, "1=Armed \t 2=Unarmed \t 3=Open Vent \t 4=Close Vent")
    stdscr.addstr(9, 0, "5=Open Main \t 6=Close Main \t 7=Pressurization")
    stdscr.addstr(10,0, "8=Pressure Stopped\t 9=Ox/Fu Safety OPEN \t 10=Ox/Fu Safety CLOSED")
    stdscr.addstr(11,0, "11=Zero Pressures \t 12= Pump Heaters ON \t 13= Pump Heaters OFF")
    stdscr.addstr(12,0, "14= Auto Safety ON \t 15= Auto Safety OFF\t 16=")

    sleep(1)    #Wait to get command response
    cmd = stdscr.getstr()   #get the command response

    #Command option responses
    if cmd == '1':
      armingon()
      stdscr.addstr(15,0,"Arming ON                              ")
    elif cmd == '2':
      oxsafetyon()
      sleep(0.1)
      fusafetyon()
      armingoff()
      stdscr.addstr(15,0,"Arming OFF                             ")
    elif cmd == '3':
      ventopen()
      stdscr.addstr(15,0,"Vent OPEN                              ")
    elif cmd == '4':
      ventclose()
      stdscr.addstr(15,0,"Vent CLOSE                             ")      
    elif cmd == '5':
      mainopen()
      stdscr.addstr(15,0,"Main OPEN                              ")
    elif cmd == '6':
      mainclose()
      stdscr.addstr(15,0,"Main CLOSED                            ")
    elif cmd == '7':
      presson()
      stdscr.addstr(15,0,"Pressurizing                           ")
    elif cmd == '8':
      pressoff()
      stdscr.addstr(15,0,"Pressured Stopped                      ")
    elif cmd == '9':
        oxsafetyon()
        sleep(0.1)
        fusafetyon()
        stdscr.addstr(15,0,"Ox/Fu Safety OPEN                    ")
    elif cmd == '10':
      if armed == 'ON':
        oxsafetyoff()
        sleep(0.1)
        fusafetyoff()
        stdscr.addstr(15,0,"Ox/Fu Safety CLOSED                  ")
      elif armed == 'OFF':
        stdscr.addstr(15,0, "Solenoids are not yet armed!        ")
    elif cmd == '11':
      zero_pt = True
      z_psiox = psiox_measure()
      z_psifu = psifu_measure()
      z_psioxpump = psiox_pump_measure()
      z_psifupump = psifu_pump_measure()
      z_psichamb = psichamb_measure()
      stdscr.addstr(15,0, "All Pressures Zeroed                  ")
    elif cmd == '12':
      oxheateron()
      fuheateron()
      stdscr.addstr(15,0, "Ox/Fu Pump Heater ON                  ")
    elif cmd == '13':
      oxheateroff()
      fuheateroff()
      stdscr.addstr(15,0, "Ox/Fu Pump Heater OFF                  ")
    elif cmd == '14':
      auto_safety = 'YES'
      stdscr.addstr(15,0, "Auto Safety ON                         ")
    elif cmd == '15':
      auto_safety = 'NO'
      stdscr.addstr(15,0, "Auto Safety OFF                        ")      
    elif cmd == 'q':
      break

finally:
  pressoff()
  armingoff()
  curses.endwin()

Your log messages

File "10secfiretest_debug_RevD.py", line 472, in <module>
	pressoff()
File "10secfiretest_debug_RevD.py", line 130, in pressoff
 	a.digitalWrite(press,1) #Close Valve
File "/usr/local/lib/python2.7/dist-packages/nanpy/arduinoboard.py", line 125, in wrapper
 	return _call(cls_name, 0, call_pars, connection=connection)
File "/usr/local/lib/python2.7/dist-packages/nanpy/arduinoboard.py", line 47, in _call
 	ret = return_value(connection)
File "/usr/local/lib/python2.7/dist-packages/nanpy/arduinoboard.py", line 16, in return_value
 	return connection.readline().replace('\r\n', '')
File "/usr/local/lib/python2.7/dist-packages/nanpy/serialmanager.py", line 101, in readline
 	raise SerialManagerError('Serial timeout!')
nanpy.serialmanager.SerialManagerError: Serial timeout!
...

Your cfg.h

#define USE_Info                                    1
#pragma once


// only for ESP8266
#define USE_WIFI_CONNECTION                         0

// for WIFI connection
#define WIFI_SSID 		"***"
#define WIFI_PASSWORD 	"***"


// for serial connection
#define BAUDRATE 9600

// info about existence of other features
#define USE_Info                                    1

// definitions: MCU type, frequency, Arduino version,
// EEPROM size, RAM size, pin count, build time,..
#define USE_Define                                  1

// low level mapping of pins and ports
#define USE_ArduinoCore                             1

// read, write RAM
#define USE_RAM                                     1

// read, write EEPROM
#define USE_EEPROM                                  1

// read, write AVR registers
#define USE_Register                                0

// watchdog and reset
#define USE_Watchdog                                0

#define USE_Tone                                    0

#define USE_LiquidCrystal                           0

// I2C
#define USE_Wire                                    0

#define USE_Servo                                   0

#define USE_Stepper                                 0

// frequency counter,  USE_Tone should be off!
#define USE_Counter                                 0

///////////////////////////////////////////////////////////////////////
// external libraries should be installed for the following features:
///////////////////////////////////////////////////////////////////////

// https://github.com/PaulStoffregen/OneWire
#define USE_OneWire                                 0

// https://github.com/milesburton/Arduino-Temperature-Control-Library
#define USE_DallasTemperature                       0


#define USE_CapacitiveSensor                        0

// https://github.com/adafruit/DHT-sensor-library
#define USE_DHT                                     0

// https://bitbucket.org/fmalpartida/new-liquidcrystal
#define USE_LiquidCrystal_I2C                       0

// https://www.adafruit.com/products/1429
#define USE_TLC5947                                 0

As I have said before the program operates well. It shows the pressure readings in real time while giving me the option to input commands without an input block. I have noticed that when I adjust sleep() [the one before input options] by giving it 4 seconds the program is very stable and can run for an error without error but the time to accept the command is longer of course. When I decrease the value, the program has a higher tendency to fail early.

Currently, I am at a loss of what to do. I would very much appreciate any input any of you could give.

Thank you for your time.

Your hardware

  • Arduino board: Arduino Mega 2560
  • Additional hardware: Raspberry Pi 3
  • Additional hardware: Sainsmart 16 Channel Relay
  • Additional hardware: 5 Pressure Transducers
  • Additional hardware: 7 Valve Solenoids'
@leofabri
Copy link

I know that this is an outdated topic but how did you fix it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants