1

I have posted this question before, and a user was good enough to answer it. I used his suggestions and found that the code was not working at all, after researching and tinkering with it, I came to an impasse. Here is what I want to do:

I want to control two arduinos using the serial connection between the arduinos and the Raspberry Pi and I am using Python to control them. I am using a GUI interface and tkinter library to create the buttons.

The original problem was that the information would only go through the Arduino when the user stopped pressing the button and I needed the information to be sent as soon as the button was pressed and continuously until the button was released. The member suggested using lambda.

Although did not work as proposed, I feel that he might have had the right idea, here is the code that I came up with after his suggestion.

import serial
running = True
ser = serial.Serial('/dev/ttyUSB0')
def send_data(self):
    if self.char is not None:
        ser.write(self.char)
    #run again in 100ms. Here is where you control how fast
    #to send the data.  The first parameter to after is a number
    #of milliseconds to wait befor calling the function
    self.job=self.after(100,self.send_data)

class Application(Frame):
    """Defining the remote control buttons"""
    def __init__(self,master):
        self.char = []
        self.job = []
        self.send_data = []
        """Initialize the frame"""
        Frame.__init__(self,master)
        self.grid() # How many times has the user clicked the button
        self.create_widgets()   
   def set_char(self,char):
        self.char=char

   def create_widgets(self):
        """Creates four buttons that move the servos"""
        #Create the 'up' button
        self.button1=Button(self,text="Up")
        self.button1.bind("<ButtonPress-1>",lambda x:self.set_char('1'))
        self.button1.bind("<ButtonRelease-1>",lambda x:self.set_char(None))
        self.button1.grid()
        send_data(self)

        #Create the 'down' button
        self.button2=Button(self,text="Down")
        self.button2.bind("<ButtonPress>",lambda x:self.set_char('2'))
        self.button2.bind("<ButtonRelease>",lambda x:self.set_char(None))
        self.button2.grid()

        #Create the 'left' button
        self.button3=Button(self,text="Left")
        self.button3.bind("<ButtonPress-3>",lambda x:self.set_char('3'))
        self.button3.bind("<ButtonRelease-3>",lambda x:self.set_char(None))
        self.button3.grid()

        #creeate the 'right' button
        self.button4=Button(self,text="Right")
        self.button4.bind("<ButtonPress-4>",lambda x:self.set_char('4'))
        self.button4.bind("<ButtonRelease-4>",lambda x:self.set_char(None))
        self.button4.grid()

#Main
root = Tk()
root.title("Remote control")
root.geometry("250x250")
app = Application(root)
root.mainloop() 
2
  • There are many ways a program can fail... I notice you initialize self.char = [] but check for None. And that self.send_data = [] but then you try to schedule it as a callbable method in self.job=self.after(100,self.send_data). Commented Feb 8, 2016 at 5:18
  • Consider a shorter example that we can actually run and a more of a description than "it doesn't work"... it makes it easier to figure out what's going on. Commented Feb 8, 2016 at 5:35

2 Answers 2

1

Your theory is workable, it just has some implementation issues. I hacked up a smaller test from your original code and fixed up several mistakes. This one writes to the screen for the few of us that don't have an arduino attached to our computers and only has one button, but it shows how it should work.

import sys
from tkinter import *
from tkinter.ttk import *

# mock serial class
class MockSer(object):

    def __init__(self):
        self.colcount = 0

    def write(self, data):
        sys.stdout.write(data)
        self.colcount += 1
        if self.colcount > 78:
            sys.stdout.write('\n')
            sys.colcount = 0
        sys.stdout.flush()


class Application(Frame):
    """Defining the remote control buttons"""
    def __init__(self, master, writer):
        Frame.__init__(self, master)
        self.writer = writer
        self.char = None
        self.grid() # How many times has the user clicked the button
        self.create_widgets()   

    def send_data(self):
        if self.char is not None:
            self.writer.write(self.char)
        #run again in 100ms. Here is where you control how fast
        #to send the data.  The first parameter to after is a number
        #of milliseconds to wait befor calling the function
        self.after(100,self.send_data)

    def set_char(self,char):
        self.char=char

    def create_widgets(self):
        """Creates four buttons that move the servos"""
        #Create the 'up' button
        self.button1=Button(self,text="Up")
        self.button1.bind("<ButtonPress-1>",lambda x:self.set_char('1'))
        self.button1.bind("<ButtonRelease-1>",lambda x:self.set_char(None))
        self.button1.grid()
        # start the send_data poll
        self.send_data()

root = Tk()
root.title("Remote control")
root.geometry("250x250")
writer = MockSer()
app = Application(root, writer)
root.mainloop() 

The code doesn't consider real world problems such as the serial port closing or its queue filling, but its a start.

Sign up to request clarification or add additional context in comments.

Comments

1

There are at least two fairly obvious mistakes in the code.

First, the code depends on self.char either being None or a character. If it is not None it will send whatever self.char is set to.

In your code, you're initializing self.char to an empty list ([]), so the code that sends data will constantly try to send the string representation of that until the first time you press a key. At startup you're sending "[]" down the port ten times a second.

To fix this you need to initialize self.char to None.

Second, you are calling send_data incorrectly. You're doing send_data(self) when you should be doing self.send_data(). And although this doesn't affect anything, you should initialize self.job to None, and/or set it when you call send_data the first time:

self.job = self.send_data()

Finally, if the code still isn't working, you might need to call ser.flush() after writing the character to the serial port.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.