2013-08-09 4 views
0

이것이 제 첫 질문입니다! (내가 사용한 적이있는 프로그래밍 질문에 대한 대부분의 대답을 찾을 수있는 사이트를 사용하고 있음에도 불구하고)SocketServer가 원격으로 PiBot을 제어하는 ​​데 사용됩니다 (파이썬)

필자는 랩탑에서 실행할 계획 인 PiBotController를 만들었습니다 (화살표 키에서 입력) 내 로봇을 제어하는 ​​나무 딸기 파이에. 이제이 하드웨어 측면은 화살표 키 입력에 응답하는 프로그램을 만든 문제가 아니며 ssh 연결을 통해 pi에 모터를 제어 할 수 있습니다.

온라인 검색 간단한 문자열을 보내는 데 사용할 수있는 socketserver를 사용하여 다음과 같은 기본 서버 및 클라이언트 코드를 찾았습니다.

서버 :

import socketserver 

class MyTCPHandler(socketserver.BaseRequestHandler): 
""" 
The RequestHandler class for our server. 

It is instantiated once per connection to the server, and must 
override the handle() method to implement communication to the 
client. 
""" 

    def handle(self): 
     # self.request is the TCP socket connected to the client 
     self.data = self.request.recv(1024).strip() 
     print("{} wrote:".format(self.client_address[0])) 
     print(self.data) 
     # just send back the same data, but upper-cased 
     self.request.sendall(self.data.upper()) 

if __name__ == "__main__": 
    HOST, PORT = "localhost", 9999 

# Create the server, binding to localhost on port 9999 
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) 

# Activate the server; this will keep running until you 
# interrupt the program with Ctrl-C 
server.serve_forever() 

클라이언트 :

import socket 
import sys 

HOST, PORT = "192.168.2.12", 9999 
data = "this here data wont send!! " 


# Create a socket (SOCK_STREAM means a TCP socket) 
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

try: 
    # Connect to server and send data 
    sock.connect((HOST, PORT)) 
    sock.sendall(bytes(data + "\n", "utf-8")) 

    # Receive data from the server and shut down 
    received = str(sock.recv(1024), "utf-8") 
finally: 
    sock.close() 

print("Sent:  {}".format(data)) 
print("Received: {}".format(received)) 

이제이 잘 작동하고 결과를 출력을 내 라즈베리 파이 (서버)에 내 노트북 ​​(클라이언트) 그러나 내가 시도 복수에 모두 시간을 내 컨트롤러에서와 같이 내 키 누르기 '및 해제'와 함께 활성화되는 기능으로 결합 할 수 있습니다.

이 프로그램은 서버에 데이터를 전송하지 않습니다 다음 잘 컴파일하지만

#import the tkinter module for the GUI and input control 
try: 
    # for Python2 
    import Tkinter as tk 
    from Tkinter import * 
except ImportError: 
    # for Python3 
    import tkinter as tk 
    from tkinter import * 

import socket 
import sys 

#variables 
Drive = 'idle' 
Steering = 'idle' 




#setting up the functions to deal with key presses 
def KeyUp(event): 
    Drive = 'forward' 
    drivelabel.set(Drive) 
    labeldown.grid_remove() 
    labelup.grid(row=2, column=2) 
def KeyDown(event): 
    Drive = 'reverse' 
    drivelabel.set(Drive) 
    labelup.grid_remove() 
    labeldown.grid(row=4, column=2) 
def KeyLeft(event): 
    Steering = 'left' 
    steeringlabel.set(Steering) 
    labelright.grid_remove() 
    labelleft.grid(row=3, column=1) 
def KeyRight(event): 
    Steering = 'right' 
    steeringlabel.set(Steering) 
    labelleft.grid_remove() 
    labelright.grid(row=3, column=3) 
def key(event): 
    if event.keysym == 'Escape': 
     root.destroy() 

#setting up the functions to deal with key releases 
def KeyReleaseUp(event): 
    Drive = 'idle' 
    drivelabel.set(Drive) 
    labelup.grid_remove() 
def KeyReleaseDown(event): 
    Drive = 'idle' 
    drivelabel.set(Drive) 
    labeldown.grid_remove() 
def KeyReleaseLeft(event): 
    Steering = 'idle' 
    steeringlabel.set(Steering) 
    labelleft.grid_remove() 
def KeyReleaseRight(event): 
    Steering = 'idle' 
    steeringlabel.set(Steering) 
    labelright.grid_remove() 

#connection functions 
def AttemptConnection(): 
    connectionmessagetempvar = connectionmessagevar.get() 
    connectionmessagevar.set(connectionmessagetempvar + "\n" + "Attempting to  connect...") 

def transmit(event): 
    HOST, PORT = "192.168.2.12", 9999 
    data = "this here data wont send!! " 


    # Create a socket (SOCK_STREAM means a TCP socket) 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    try: 
     # Connect to server and send data 
     sock.connect((HOST, PORT)) 
     sock.sendall(bytes(data + "\n", "utf-8")) 

     # Receive data from the server and shut down 
     received = str(sock.recv(1024), "utf-8") 
    finally: 
     sock.close() 

    print("Sent:  {}".format(data)) 
    print("Received: {}".format(received)) 





#setting up GUI window   
root = tk.Tk() 
root.minsize(300,140) 
root.maxsize(300,140) 
root.title('PiBot Control Centre') 
root.grid_columnconfigure(0, minsize=50) 
root.grid_columnconfigure(1, minsize=35) 
root.grid_columnconfigure(2, minsize=35) 
root.grid_columnconfigure(3, minsize=35) 
root.grid_rowconfigure(2, minsize=35) 
root.grid_rowconfigure(3, minsize=35) 
root.grid_rowconfigure(4, minsize=35) 
root.configure(background='white') 
root.option_add("*background", "white") 




#set up the labels to display the current drive states 
drivelabel = StringVar() 
Label(root, textvariable=drivelabel).grid(row=0, column=1, columnspan=2) 
steeringlabel = StringVar() 
Label(root, textvariable=steeringlabel).grid(row=1, column=1, columnspan=2) 
Label(root, text="Drive: ").grid(row=0, column=0, columnspan=1) 
Label(root, text="Steering: ").grid(row=1, column=0, columnspan=1) 

#set up the buttons and message for connecting etc.. 
messages=tk.Frame(root, width=150, height=100) 
messages.grid(row=1,column=4, columnspan=2, rowspan=4) 


connectionbutton = Button(root, text="Connect", command=AttemptConnection) 
connectionbutton.grid(row=0, column=4) 
connectionmessagevar = StringVar() 
connectionmessage = Message(messages, textvariable=connectionmessagevar, width=100,) 
connectionmessage.grid(row=1, column=1, rowspan=1, columnspan=1) 
disconnectionbutton = Button(root, text="Disconnect") 
disconnectionbutton.grid(row=0, column=5) 







#pictures 
photodown = PhotoImage(file="down.gif") 
labeldown = Label(root, image=photodown) 
labeldown.photodown = photodown 
#labeldown.grid(row=4, column=1) 

photoup = PhotoImage(file="up.gif") 
labelup = Label(root, image=photoup) 
labelup.photoup = photoup 
#labelup.grid(row=2, column=1) 

photoleft = PhotoImage(file="left.gif") 
labelleft = Label(root, image=photoleft) 
labelleft.photoleft = photoleft 
#labelleft.grid(row=3, column=0) 

photoright = PhotoImage(file="right.gif") 
labelright = Label(root, image=photoright) 
labelright.photoright = photoright 
#labelright.grid(row=3, column=2) 

photoupleft = PhotoImage(file="upleft.gif") 
labelupleft = Label(root, image=photoupleft) 
labelupleft.photoupleft = photoupleft 
#labelupleft.grid(row=2, column=0) 

photodownleft = PhotoImage(file="downleft.gif") 
labeldownleft = Label(root, image=photodownleft) 
labeldownleft.photodownleft = photodownleft 
#labeldownleft.grid(row=4, column=0) 

photoupright = PhotoImage(file="upright.gif") 
labelupright = Label(root, image=photoupright) 
labelupright.photoupright = photoupright 
#labelupright.grid(row=2, column=2) 

photodownright = PhotoImage(file="downright.gif") 
labeldownright = Label(root, image=photodownright) 
labeldownright.photodownright = photodownright 
#labeldownright.grid(row=4, column=2) 




#bind all key presses and releases to the root window 
root.bind_all('<Key-Up>', KeyUp) 
root.bind_all('<Key-Down>', KeyDown) 
root.bind_all('<Key-Left>', KeyLeft) 
root.bind_all('<Key-Right>', KeyRight) 

root.bind_all('<KeyRelease-Up>', KeyReleaseUp) 
root.bind_all('<KeyRelease-Down>', KeyReleaseDown) 
root.bind_all('<KeyRelease-Left>', KeyReleaseLeft) 
root.bind_all('<KeyRelease-Right>', KeyReleaseRight) 

root.bind_all('<Key>', key) 
root.bind_all('<Key>', transmit) 




#set the labels to an initial state 
steeringlabel.set('idle') 
drivelabel.set('idle') 
connectionmessagevar.set ('PiBotController Initiated') 

#initiate the root window main loop 
root.mainloop() 

PiBotController? (나는 여전히 문자열을 보내는 것을 알고 있지만 쉽게 시작할 수있는 뭔가가 있다고 생각했는데 ... 아마도 잘 붙어서 최상의 결과를 얻었을 것입니다.)

그냥 문자열 보내기 만하면됩니다. 또는 그들이 변화 할 때마다 varibales 운전 및 조타를 보내는 것은 중대하게 평가 될 것입니다.

데이브 XX

EDIT 여기

내가 그것을 가지고 전송 기능은, 그러나 그것은 (내가 전에 원처럼) 내가 키 누름/해제를 할 때마다 데이터를 전송하는 의미에서 작품입니다 '유휴'변수에 대한 초기 설정 만 보냅니다. 지금 코드를 살펴보면 아마 호스트와 포트 정보를 가져 와서 매번 실행되는 함수에서 소켓 연결을 만들어야한다고 생각합니까? 그러나 확실하지 않은 여기의 i는 지금 내가 어떻게해서든지있는 것을 가지고있다.

def transmit(): 
    HOST, PORT = "192.168.2.12", 9999 
    DriveSend = drivelabel.get 
    SteeringSend = steeringlabel.get 


    # Create a socket (SOCK_STREAM means a TCP socket) 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    try: 
     # Connect to server and send data 
     sock.connect((HOST, PORT)) 
     sock.sendall(bytes(Drive + "\n", "utf-8")) 
     sock.sendall(bytes(Steering + "\n", "utf-8")) 

     # Receive data from the server and shut down 
     received = str(sock.recv(1024), "utf-8") 
    finally: 
     sock.close() 

    print("Sent:  {}".format(Steering)) 
    print("Sent:  {}".format(Drive)) 
    print("Received: {}".format(received)) 

답변

1

문제는 Tkinter를가 키 이벤트를 캐치 할 때, 그것은 더 구체적인 바인딩 첫 번째 (예를 들어 '키 업')을 유발한다는 것입니다, 그리고 이벤트 ('키'바인딩보다 일반적인 전달되지 않습니다). 따라서 'up'키를 누르면 KeyUp이 호출되지만 전송은 절대 호출되지 않습니다.

이 문제를 해결하는 한 가지 방법은 모든 콜백 함수 (KeyUp, KeyDown 등) 내에서 transmit()를 호출하는 것입니다.

예를 들어,의 keyup는

def KeyUp(event): 
    Drive = 'forward' 
    drivelabel.set(Drive) 
    labeldown.grid_remove() 
    labelup.grid(row=2, column=2) 
    transmit() 

이 그럼 당신은 '키'에 바인딩 이벤트 제거 할 수 될 것입니다.

또 다른 옵션은 "드라이브"와 "스티어링"을 Tkinter로 만드는 것입니다.StringVar 개체, 다음과 같이 "추적"을 사용하여 이벤트를 작성하는 바인딩 : 당신이 그들을 받아 들일 transmit을 편집해야 할 것이다, 그래서

Drive = tk.StringVar() 
Drive.set('idle') 
Drive.trace('w', transmit) 

trace 즉, 콜백 인수의 무리를 보냅니다. 세 가지가 있습니다 -

편집

좋아, 내가 문제를 참조하십시오. 당신이 당신의 콜백 함수에서

Drive = 'forward' 

쓰기

1. 당신이 당신의 모듈 네임 스페이스에서 변수 Drive를 설정 하지있어, 로컬 기능 네임 스페이스에 Drive을 설정, 그래서 모듈이있어 -namespace Drive은 변경되지 않으므로 transmit이 액세스 할 때 항상 동일합니다.

2. transmit, 당신이 좋은 생각입니다,하지만 당신은 단지 그들을 호출하지 않는 기능을 참조하고

DriveSend = drivelabel.get 
SteeringSend = steeringlabel.get 

물품. 당신은 transmit에서

DriveSend = drivelabel.get() 
SteeringSend = steeringlabel.get() 

3.이 필요합니다, 당신은 소켓을 통해 보내는 값은 오히려 DriveSendSteeringSend보다 (문제 # 1에 따라 변경되지 않습니다) 모듈 수준 변수 DriveSteering 있습니다.

솔루션 :

내가 전적으로 모든 DriveSteering 변수를 멀리하고, 단지 StringVars 'drivelabel and steeringlabel`를 사용하는 것이 좋습니다 것입니다. 따라서 귀하의 콜백이 될 수 있습니다

:

def KeyUp(event): 
# Drive = 'forward' (this doesn't actually do any harm, but to avoid confusion I'd just get rid of the Drive variables altogether) 
    drivelabel.set('forward') 
    labeldown.grid_remove() 
    labelup.grid(row=2, column=2) 

(등등에 대한 콜백의 나머지) 및 전송 기능 (OP)에서

def transmit(): 
    HOST, PORT = "192.168.2.12", 9999 
    DriveSend = drivelabel.get()  # Note the() 
    SteeringSend = steeringlabel.get() 

    # Create a socket (SOCK_STREAM means a TCP socket) 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    try: 
     # Connect to server and send data 
     sock.connect((HOST, PORT)) 
     sock.sendall(bytes(DriveSend + "\n", "utf-8")) # Note Drive ==> DriveSend 
     sock.sendall(bytes(SteeringSend + "\n", "utf-8")) # Note Steering ==> SteeringSend 

     # Receive data from the server and shut down 
     received = str(sock.recv(1024), "utf-8") 
    finally: 
     sock.close() 

    print("Sent:  {}".format(SteeringSend)) # Note Steering ==> SteeringSend 
    print("Sent:  {}".format(DriveSend))  # Note Drive ==> DriveSend 
    print("Received: {}".format(received)) 

수정 솔루션이 될 것이다 잠시 동안이 방법으로 놀고있는 동안, 키가 눌려져 있기 때문에 매 100ms마다 변수가 끊임없이 변하는 것을 발견했습니다. 예를 들어 단지 driv 일 때 모터 제어의 부드러움과 함께 문제가 발생합니다. 앞으로. 이 문제를 해결하기 위해 전 그렇지는 수정, 각 기능

def KeyUp(event): 
    if drivelabel.get() == "forward": 
     pass 
    else: 
     drivelabel.set("forward") 
     labeldown.grid_remove() 
     labelup.grid(row=2, column=2) 
     transmit() 
     print (drivelabel.get()) 

그것이 아무것도하지 않는 경우 varibale 이미와 관계있는 방향으로 설정되어있는 경우 코드는 현재 검사에 다음의 수정을 사용했다. 인쇄 라인이 제대로 작동하고 있는지 확인하고 제거하거나 주석 처리 할 수 ​​있는지 확인하기위한 것입니다.

+0

이것은 매우 간단한 해결책이었습니다! 이제 유용한 것을 전송하는 것을 분류하려고합니다 : P –

+0

내 변수를 보냈습니다 ... 그 변수가 처음에 설정된 것을 보냈습니다.나는 실제로 동일한 방법입니다 : S –

+0

죄송합니다 - 당신이 당신의'transmit' 함수를 빌드 한 방법을 알 수없는 한 진단하기가 쉽지 않은 것을 사용하여 벌금을 업데이트하는 레이블이 있다는 사실에도 불구하고 업데이트 된 값을 보내도록하는 것 같습니다. . 새로운'transmit' 함수로 질문 끝 부분에 EDIT를 추가하고 싶다면 그 부분을 살펴 보겠습니다. – Brionius

관련 문제