Arduino constantly switching COM ports when python script is run

When I run the following python script, the arduino instantly changes ports (between ttyACM0 and ttyACM1) and the script fails because it gets disconnected. The script just waits for the user to input two numbers and then sends them over the serial port to the arduino. I can use other scripts/arduino code with serial communication (both ways) and they do not have this issue. I tried a simpler version of some old code I had and it runs better, but still the arduino changes ports after some time (maybe a couple of minutes). I am running on Ubuntu 14.04 with the newest arduino software.

Simplified Code (disconnects after a few minutes)

import serial
import struct
import time
import os
import thread
import numpy as np


default_input = 2.5
PW_buffer = 0.05
#duty_cycle = 2000
min_value = 0#PW_buffer * duty_cycle
max_value = 5#(1-PW_buffer) * duty_cycle
data_obj = {}
data_obj['stop'] = False
data_obj['input'] = default_input


def user_input_thread(data_obj):
    while not data_obj['stop']:
        raw_in = raw_input('Enter PWM width (%i - %i): ' % 
                           (min_value, max_value))
        if raw_in == 'q':
            data_obj['stop'] = True
        elif not raw_in.isdigit():
	    print("INVALID INPUT")
	else:
            raw_in = max(min(int(raw_in), max_value), min_value)
            data_obj['input'] = raw_in

if os.name == 'nt':
    port = 'COM4'
else:
    port = '/dev/ttyACM1'
baudrate = 115200

ser = serial.Serial(port, baudrate, timeout=0)

#thread.start_new_thread(user_input_thread, (data_obj, ))

min_time = 0.005
while not data_obj['stop']:
    raw_in = raw_input('Enter PWM width (%i - %i): ' % 
                           (min_value, max_value))
    #m1 = float(raw_in)
    #m2 = 1000
    #m3 = 1000
    m1, m2= [10000 * (float(x)) for x in raw_in.split(',')]
    ser_str = struct.pack('>3H', 65535, np.copy(m1),np.copy(m2))
    #ser_str = struct.pack('>4H', 65535, m1, m2, m3)
    ser.write(ser_str)
    time.sleep(min_time)
    print m1, m2

ser.close()

Full code (disconnects as soon as script is run)

import serial
import struct
import time
import os
import thread
import numpy as np
import math

startMarker1 = 0xFF#60
startMarker2 = 0xFF
endMarker = 62
#startMarker = "<"
#endMarker = ">"

default_input = 512  #position 0-2Pi == 0-1024
PW_buffer = 0.05
duty_cycle = 2000
min_value = 0#PW_buffer * duty_cycle
max_value = 3.14#(1-PW_buffer) * duty_cycle
data_obj = {}
data_obj['stop'] = False
data_obj['input'] = default_input
output_angles = {}
output_angles['start'] = startMarker1
output_angles['end'] = endMarker 
flag = False
xyz_coordinates = [-.31, .25, .25, 0, 0, 0, 0, 0, 0]
input_string = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
end_reached = False

#===================================== 
#  Function Definitions
#---------------------------Check if input is float------------------------------
def is_float(input):
  try:
    num = float(input)
  except ValueError:
    return False
  return True
#-----------------------------Receive from Arduino-------------------------------
def arduino_output_thread(data_obj):
#output_feed = "z"
  prev_serial_data = [0,0,0]
  angles = [0,0,0]
  while True:
    serial_data = ser.read(1)
    if serial_data == chr(255):
      serial_data = ser.read(1)
      if serial_data == chr(255):
        serial_data = ser.read(6)
        angles = struct.unpack('<3H', serial_data)
        if angles != prev_serial_data: 
          print angles
          prev_serial_data = angles
#------------------------------Get user PW----------------------------------------
def user_input_thread(data_obj):
    global flag, xyz_coordinates

    while not data_obj['stop']:
        raw_in = raw_input('Enter x,y,z coordinates (thousandths accuracy, q to quit): ') 
        if raw_in == 'q':
            data_obj['stop'] = True
        else:
            flag = True
            xyz_coordinates = [float(x) for x in raw_in.split(',')]
#=====================================

# START OF MAIN

#=====================================
try: 
  if os.name == 'nt':
      port = 'COM4' #COM1 at home
  else:
      port = '/dev/ttyACM0'#port = '/dev/arduino'
  baudrate = 115200

  ser = serial.Serial(port, baudrate, timeout=1)



  #thread.start_new_thread(user_input_thread, (data_obj, ))
  thread.start_new_thread(arduino_output_thread, (data_obj, ))#(output_angles, ))

  min_time = 0.005
  while not data_obj['stop']:
      #print 'pos : ', data_obj['input']
      raw_in = raw_input('Enter joint angles rotation and translation (%i - %i, 2.5,2.5 for rest pos): ' % 
                         (0,5))#(min_value, max_value))
      try: 
          #m1, m2, m3, m4, m5, m6, m7, m8, m9 = [10000 * (float(x)) for x in raw_in.split(',')]
          #print m1, m2, m3, m4, m5, m6, m7, m8, m9
          """ser_str = struct.pack('>10H', 65535, np.copy(m1),
                                          np.copy(m2),
                                          np.copy(m3),
                                          np.copy(m4),
                                          np.copy(m5),
                                          np.copy(m6),
                                          np.copy(m7),
                                          np.copy(m8),
                                          np.copy(m9))"""
          m4, m5= [10000 * (float(x)) for x in raw_in.split(',')]
          ser_str = struct.pack('>3H', 65535, np.copy(m4),
                                          np.copy(m5))
          

          ser.write(ser_str)
          
      except: 
          print 'Invalid input.'
          pass 
finally: 
   ser = serial.Serial(port, baudrate)
   ser.close()

Any thoughts as to what the problem could be? Any thoughts / ideas are greatly appreciated!

The Arduino reboots when a Serial connection is made. Could this be the cause of the problem ?

Your Python code should open the serial port and allow time for the Arduino to reset. Then it should keep the port open until it is completely finished with the Arduino.

See this Python - Arduino demo

...R

Robin2:
Your Python code should open the serial port and allow time for the Arduino to reset. Then it should keep the port open until it is completely finished with the Arduino.

See this Python - Arduino demo

...R

Hi Robin2, could you explain more about the demo, I was wondering which part is essential that allow time for Arduino to reset and keep the port open. Thank you for your help. Appreciated your demo!

Tammy

I am also using python script that running on raspberry pi to send data to arduino uno, try to power six servo motor. Then I encountered the same problem as this thread has mentioned.

I have posted an updated and simpler example. The Python function waitForArduino() is the part that waits for the Arduino to reset.

...R

Robin2:
I have posted an updated and simpler example. The Python function waitForArduino() is the part that waits for the Arduino to reset.

...R

Thank you for your reply Robin! I would like to know if this program is suitable for an Arduino Board that disable the auto-reset function?

teletummies:
Thank you for your reply Robin! I would like to know if this program is suitable for an Arduino Board that disable the auto-reset function?

If you want the Python program to start receiving data from an Arduino program that is already running then don't call the waitForArduino() function.

These are things that you could easily find out yourself by carrying out some tests. The Arduino system is great for learning-by-doing. Testing early and often is a good habit to acquire.

...R

Robin2:
If you want the Python program to start receiving data from an Arduino program that is already running then don't call the waitForArduino() function.

These are things that you could easily find out yourself by carrying out some tests. The Arduino system is great for learning-by-doing. Testing early and often is a good habit to acquire.

...R

Sorry that I am a newbie to python and arduino and there is a lot I need to learn. Thank you for your suggestions and tips! I will keep in mind.