Использование tkinter и python для управления arduino

Я задавал этот вопрос раньше, и пользователь был достаточно хорош, чтобы ответить на него. Я воспользовался его предложениями и обнаружил, что код вообще не работает, после исследования и возни с ним я зашел в тупик. Вот что я хочу сделать:

Я хочу управлять двумя Arduino, используя последовательное соединение между Arduino и Raspberry Pi, и я использую Python для управления ими. Я использую интерфейс GUI и библиотеку tkinter для создания кнопок.

Первоначальная проблема заключалась в том, что информация будет проходить через Arduino только тогда, когда пользователь перестанет нажимать кнопку, и мне нужно было, чтобы информация отправлялась, как только кнопка была нажата, и непрерывно, пока кнопка не была отпущена. Участник предложил использовать lambda.

Хотя это не сработало, как было предложено, я чувствую, что у него могла быть правильная идея, вот код, который я придумал после его предложения.

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() 

person JohnC    schedule 08.02.2016    source источник
comment
Программа может выйти из строя по-разному... Я заметил, что вы инициализируете self.char = [], но проверяете None. И это self.send_data = [], но затем вы пытаетесь запланировать его как вызываемый метод в self.job=self.after(100,self.send_data).   -  person tdelaney    schedule 08.02.2016
comment
Рассмотрим более короткий пример, который мы действительно можем запустить, и более подробное описание, чем то, что не работает... это облегчает понимание того, что происходит.   -  person tdelaney    schedule 08.02.2016


Ответы (2)


Ваша теория работоспособна, просто у нее есть некоторые проблемы с реализацией. Я взломал меньший тест из вашего исходного кода и исправил несколько ошибок. Этот пишет на экран для тех немногих из нас, у кого нет Arduino, подключенной к нашим компьютерам, и у которых есть только одна кнопка, но он показывает, как это должно работать.

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() 

Код не учитывает реальные проблемы, такие как закрытие последовательного порта или заполнение его очереди, но это только начало.

person tdelaney    schedule 08.02.2016

В коде есть как минимум две довольно очевидные ошибки.

Во-первых, код зависит от того, является ли self.char либо None, либо символом. Если это не None, он отправит все, что установлено в self.char.

В вашем коде вы инициализируете self.char пустым списком ([]), поэтому код, который отправляет данные, будет постоянно пытаться отправить строковое представление этого до тех пор, пока вы не нажмете клавишу в первый раз. При запуске вы отправляете "[]" по порту десять раз в секунду.

Чтобы исправить это, вам нужно инициализировать self.char до None.

Во-вторых, вы неправильно звоните send_data. Вы делаете send_data(self), когда должны делать self.send_data(). И хотя это ни на что не влияет, вы должны инициализировать self.job значением None и/или установить его при первом вызове send_data:

self.job = self.send_data()

Наконец, если код все еще не работает, вам может понадобиться вызвать ser.flush() после записи символа в последовательный порт.

person Bryan Oakley    schedule 08.02.2016