jueves, 23 de marzo de 2017

Python Control LED with Serial Communication RS232


UPDATE : 7/14/2014 : 1) Controlling a robot via a Python GUI added 2) Video demonstrating GUI control added.
UPDATE: 7/5/2014 : Lighting up specific colours in an RGB LED via a Python GUI added.
UPDATE: 7/4/2014 : Short info on PyGame vs msvcrt library added.
Hello everyone,
Welcome to this guide that will teach you how to build an app using Python. This tutorial will cover everything from the installation of Python to configuring the Python Environment and doing some "Hello World" stuff in Python to blinking LEDs using a simple app. At the end of this tutorial, you will easily be able to control your robot using easy-to-create Python GUIs, keyboard strokes, and many other interfaces. This tutorial focuses on Python + Arduino communication and control, on Windows. 
So, what is Python? Correct, it's a killer snake found in Africa and other areas. 
Python!
But, in technical terms, Python is a killer programming language. This short blurb on their website sums it all up:

Python is powerful... and fast;
plays well with others;
runs everywhere;
is friendly & easy to learn;
is Open.


Let's get started...
Things that you will/might need  :
1) An Arduino along with a serial cable
2) A computer connected to the Internet (for downloading, Python, Libraries, etc.)
3) LEDs or a robot or any sensor module for additional testing.
4) Bluetooth Modules, RF Modules, etc. if you want to control your robot wirelessly.
5) Motors and Motor drivers, chassis, batteries (in general, a robot)

CONTENTS:
 1) DOWNLOADING AND INSTALLING PYTHON
·         Downloading the Python Files
·         Installing Python on Windows
·         Configuring Environment Variables
·         Sample Python Programming
      2)  PROGRAMMING AND DEVELOPING PYTHON APPS
·         PySerial and Tkinter
·         Downloading and Installing the PySerial Library
·         Tutorials – Serial Communication
 Ø  Blinking an LED (Automatic)
Ø  Turning an LED On or Off via a simple Python GUI 
Ø  Lighting up specific colours in an RGB LED via another simple Python GUI
·         Tutorials – Serial + Wireless Communication using RF Modules (Controlling a Robot)
Ø  Control using keyboard strokes via the msvcrt library (works only on windows) 
Ø  Control through mouse clicks via the Tkinter GUI library

1) DOWNLOADING AND INSTALLING PYTHON
  • Downloading Python Files
Obviously, to program in Python, you'll need to download it first. Head over to the download page in the Official Python Website.
You'll find a cluster of releases out there and you might be confused in selecting the correct version. If you are a Windows user, select a windows release. If you're on Linux, Mac OS X, etc. select the appropriate releases for them. Configuring the environment might be slightly different on those platforms. But Python is Python. The code won't be any different, and so, although I'm moving ahead in this tutorial in Windows, you might find some of co-incidences even if you are on a different platform. However, certain libraries might work on Windows while they might not be supported on MacOS or Linux.
Ok, I found out a release for my OS. But should I go with Python 2 or 3?
There are a couple of different versions of Python, 2.x and 3.x. The latest releases for these versions are 2.7.7 and 3.4.1 respectively. So which one should you use? Well, the 3.x version is definitely a newer version with more enhancements, but 2.x is more like a classic. 2.x has existed for a long time around and you'll find more support, communities, and libraries for it. (Not that you will be singled out when using 3.x) There are also minor differences in library inclusions.To import a GUI library called Tkinter (more on that soon), you'll need to type it Tkinter if you are on Python 2 and tkinter if you are on Python 3. I will be using Python 2.7.6 in this tutorial.
But my knowledge on this debate is limited. Visit this page if you want to deeply understand the differences between these versions. If you're using Python 3.x, the code used in the examples of this tutorial might give you errors. So in that case, be prepared to put on your thinking cap!


  • Installing Python on Windows
Let's install Python on Windows and configure everything to jump right into Python App Development. If you have already installed and configured Python, head over to the programming and development section.
Once you have downloaded the Windows Installer, double-click on it to begin the installation process for Python. You can check either of the options as per your desire. After that, click Next.

Select a location where you want the Python files to reside by. The default location is in C:\Python27\ and it's a nice idea to stick to the default location. Click Next

Here, you can see the various features that you can select while installing Python. You can leave it as it is and click on Next.

However, on the previous window, you can also click on the "Advanced" button and tick-mark the check-box shown above if you want to view bytecodes for your python files. (Python files have an extension .py)

Then, just wait a bit for the installation process to finish. Shouldn't take a long time.

And that's how you install Python on Windows. Really Simple.


  • Configuring the Python Environment
But just installing Python won't do. You need to configure the environment variables to be able to properly execute Python commands from a Windows Shell (Command Prompt).
Sorry that I am on Windows 8. But the idea is : to configure the environment variables you need to go to the advanced settings option. Open up File Explorer.

Right Click on My Computer and go to Properties.

Click on Advanced Settings

At the bottom, you should see "Environment Variables". Click on it.

Under System Variables, locate the "Path" variable. Click on it once and select edit.

Add " ;C:\Python27\" or the location where you installed Python to what you already have present there in the Variable Value. Remember to use the"  ; " at the beginning and " \ ' at the end. Click OK. And then click on Apply. You have then successfully configured the Python Environment. 
You need to configure the Environment Variables to specify the installation location of the Python Files. Otherwise the command prompt will give you an error " xxxx is not recognized as an internal or external command, operable program or batch file" while executing Python related commands. This is not limited to just Python. You might need to do the same while installing Java and other environments.


  • Sample Python Programming
Press the Windows Key + R that pops up the Run Window. Type "cmd" and press Enter. That should open up the command prompt.

To check whether Python has been properly installed and configured, type python and press Enter and you should get something similar to what is seen above.


  •   Doing Some Hello World! 
You should be able to start programming using Python after that. Give it a go. Try typing print "Hello World!"
It's not that you always need to open up command prompt and program in Python from there. You can do that with Python's in-built IDE i.e. Idle. But using notepad++ is much more easy, and cool! So, if you don't have notepad++ installed yet, download it right away. Python is an interpreted language i.e. it's converted into machine code one line at a time ( unlike Arduino C which we compile at the end). Command prompt plays the role of a command line interpreter for Python. 
A couple of things in Python might bug you (if you are new to Python), and so, I will mention a few important things:
1. Use Notepad++ for coding in Python. It's much easier than IDLE.
 2. Make sure to save your files with an extension .py
3. Python does not use parentheses '{' , '}'. Instead you use tabs. Let me show you an example while defining functions :
4. As you can see in the example above, functions are defined in Python using the 'def' keyword. Similarly, you can make use of other control flow statements but with a few minor changes.
  • If statements : 'if', 'elif' (instead of elseif), else
  • 'for' and 'while' statements and many more.
5. In C, or as you may have programmed in Arduino, statements terminate with the ';' symbol. Python doesn't use the semi colon symbol to terminate a statement. An enter key is enough. For eg :
In Python: Port = serial.Serial(12, 9600)
In Arduino: Serial.begin(9600);
6. You don't need to specify the variable type in Python. For eg :
num = 1
name = LMR
 You do not need to specify that num is an integer and name is a string! Unlike in Arduino C where that would have been  
int num = 1;
char name = LMR;
I won't dive into the depths of Python programming; that's beyond the scope of this tutorial, and my ability. However, you don't need to be an expert to build a simple app. At the same time, it's a great idea to Google for some Python related tutorials to learn more about the language. If you are familiar with some C or Arduino, this tutorial will be breezer, trust me.

2) PROGRAMMING AND DEVELOPING AN APP
Now that you have installed Python along with configuring the environment variables, we are all set to code. 
We will be developing a couple of Apps to control various devices, robots, etc. via a variety of interfaces. We will mainly be using two major Python Libraries in this tutorial. According to Wikipedia, "A library (in computing terms) is a collection of implementations of behaviors. Once you "include" these libraries in you code, you don't need to always make system calls inside the code. Here are the libraries that we will be using
  • PySerial and Tkinter
I'll sum up this in short.  PySerial is a communication library whereas Tkinter is a GUI library,  for Python. (There are other GUI libraries as well)
The major concept that lies in using Python apps to control an Arduino based project is communication between Python and the computer's serial port. 
  • Downloading and Installing the PySerial Library
Head over to this page for detailed PySerial documentation and this page to download the package.
On the download page, you might see a package named pyserial-2.7.tar.gz (md5).  Download it.
After Downloading the package, extract it with an extracting software such as 7zip.

After extracting it, you should get a folder named "pyserial2.7.tar".  

Double click it, and inside a folder named dist, you'll find another .tar file. Extract it once more.

You'll find another folder called 'pyserial2.7'

Double click the 'pyserial2.7' folder until you see a folder named serial. Copy it into the Python Lib folder.
That should be it. You have successfully installed the PySerial Library and now can start blinking LEDs via Python through serial communication over the Arduino.


  • Tutorials – Serial Communication 

  1.   Blinking an LED (Automatic)
I guess you are familiar with the plain simple Arduino code to blink an LED. To blink an onboard LED, the code using delays is :
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    delay(1000);
To blink an LED via Python, the idea is to send a character to the Arduino via serial so that the Arduino can perform the above routine. A talk with Python to do this would go something like this :
Hey Python, send a character 'b' to serial port 3 (i.e. to an Arduino connected to serial port 3).
And then the talk to Arduino would go something like this:
Hey Arduino, got the 'b' yet? Good. Now blink!
It's as simple as that. Let's do this using some Python code now.
It's not that we are using Python to program the blinking routine of the LED, that is done by Arduino itself. We are just using Python to send some sort of indication to the Arduino so that it knows it's time to perform.
First thing we need to do is importing the Serial library so that Python has the ability to communicate with the available serial ports. It's just like using #include<stdio.h> in C or #include<LiquidCrystal.h> in Arduino.
import serial # import the serial library
Next up, we need to open up the serial port to which the Arduino is connected to. Have a look at the what COM port your Arduino is using. The syntax is : port (or any other name) = serial.Serial("COMx", baudRate, timeOut(optional))  
arduinoSerialPort = serial.Serial("COM13", 9600)
arduinoSerialPort = serial.Serial(12, 9600)
Either is the same.
I'll try to make this program as simple as possible as it's our first python program. Now, it's time to send a character to Arduino over serial. For eg : 'b'
arduinoSerialPort.write('b')
And that's it. Let's sum things up.
import serial #import the serial library
arduinoSerialPort = serial.Serial(12, 9600)
arduinoSerialPort.write('b')
Using three lines of Python code, you can send a character to Arduino over serial communication! Type this code in Notepad++ and save the file in your Desktop as ledBlink.py (as you know, Python files have an extension .py)
Let's move on to the Arduino part.
First, let's define the onboard ledPin that's located at digital pin 13.
int ledPin = 13;

Then, let's setup Serial Communication to receive the incoming data from the Python program. The baud-rate here should match the baud-rate we had defined in the Python code.
void setup(){
  Serial.begin(9600);
}
Arduino reads incoming data in ASCII form. The character 'b' we have sent via Python is read as '98' by the Arduino. Next up, we need to read the incoming serial and if it equals '98', the Arduino will execute the blink routine.
void loop(){
 if (Serial.read() == '98'){
digitalWrite(led, HIGH);
delay(1000);
digitalWrite(led, LOW);
delay(1000);
  }
}
Let's sum up the entire Arduino program : 
int led = 13;
void setup(){
  Serial.begin(9600);
}
void loop(){
  if (Serial.available() == '98'){
    digitalWrite(led, HIGH);
    delay(1000);
    digitalWrite(led, LOW);
    delay(1000);
  }
}
Compile this program in the Arduino IDE, select the specific board you are using and also make sure that you check the correct serial port. Upload the program to your Arduino Board.
Running the Python program
You should see a file with the name ledBlink with a python logo in your Desktop (if you had saved it there earlier). If you double click it, it should open and you should also see the onboard LED blink a couple of times randomly. Voila!
Unless you made any errors in the code, or missed a few steps while installing and configuring Python, the program should work. If you are getting an error, do have a look above at each step closely. If you're still getting an error, you might google it and get the solution ( I found solutions to lots of errors at stackoverflow ). You can let me know in the comments as well.
But you might have noticed that the program opened the command prompt just for a short time, and terminated automatically. Why did this happen? It's because the program was simply done and dusted. There were no loops or other tasks left to be executed. We had told it to send the character 'b' over to the Arduino. It did it's job and went home.


 2) Turning an LED On or Off via a simple Python GUI
The previous example showed you how to code a Python program that does absolutely nothing but automatically send data to the Arduino and shut off. What if you could control the LED at the push of a button? That's cooler and that's what we are going to do right now.
To make the LED blink at the click of a mouse-button, we will need to build some sort of Graphical User Interface (GUI) using Python. The Tkinter GUI Library for Python makes this a piece of cake.  I'll show you how to build a simple GUI that let's you give total command over your LED : should it be ON or OFF ? (Psst! How about using an external LED this time?)
Unlike the PySerial module, Tkinter comes built-in with the Python files. You do not need to make any other addition to the Lib folder. To build a GUI App to control and LED, we need to import libraries first:
import serial # Import Serial Library ( you need this because you need to send data when buttons are clicked)
from Tkinter import * # import Tkinter Library (importing this way doesn't require calling the library every time)
Then, you need to create a window for you GUI:
appWindow = Tk() # creates the application window (you can use any name)
appWindow.wm_title("LED Control") # displays title at the top left
# insert app widgets here (radiobuttons, checkboxes, buttons, etc.)
appWindow.mainloop()# begins main loop
Save the program as firstGUI.py. If you run it, you should be able to see the following window :
Now, we need to insert two "radio-buttons" into our GUI so that we have the option of turning the LED either ON, or OFF. We have two groups of radio-buttons in this example : LED on and LED off. Each group needs to be associated with a single variable because only one can be checked at a time. Checking specific buttons changes the variable to a pre-defined value set in our code: 
var = IntVar() # define var as an integer variable
onButton = Radiobutton(appWindow, text="LED ON", variable = var, value = 1, command=ledOn)
onButton.pack( anchor = W ) # this part adjusts the radiobuttons to the parent window
offButton = Radiobutton(appWindow, text="LED OFF", variable = var, value = 2, command=ledOff)
offButton.pack( anchor = W ) # this part adjusts the radiobuttons to the parent window
As you can see, the syntax to insert Radiobuttons is buttonName = Radiobutton(window, text, command...). The command option executes a task (function) when a button is clicked. We will create two separate functions, namely on and off to send different characters to the Arduino, when each Radiobutton is clicked. You already know how to send data to the Arduino via Python as we had learned in the previous LED blink example:
def on():
 arduinoSerialPort.write('a1')
def off():
 arduinoSerialPort.write('a0')
arduinoSerialPort = serial.Serial(12, 9600)
Let's sum up the code:
import serial
from Tkinter import *

def ledOn(): # this is how you define functions in Python. ledOn() is executed if onButton is pressed
 arduinoSerialPort.write('a1') # sends 'a1' to the Arduino 
def ledOff(): # this is how you define functions in Python. ledOff() is executed if offButton is pressed
 arduinoSerialPort.write('a0') # sends 'a0' to the Arduino 

arduinoSerialPort = serial.Serial(12, 9600)
appWindow = Tk() #creates the application window
appWindow.wm_title("LED Control") #displays title at the top left

var = IntVar()

onButton = Radiobutton(appWindow, text="LED ON", variable = var, value = 1, command=ledOn)
onButton.pack( anchor = W )
offButton = Radiobutton(appWindow, text="LED OFF", variable = var, value = 2, command=ledOff)
offButton.pack( anchor = W )

appWindow.mainloop() # main loop. From here, the GUI starts updating and responding to user inputs.
Save the program, and you should see something like this: (Make sure to have your Arduino connected. We are communicating serially, so you might get an error if it's disconnected)
Let's move on to the Arduino code:
So, when we click on "LED ON" in our Python GUI, Arduino receives "a1". If the other button is clicked, Arduino gets "a0". A rough idea for our Arduino code would be:
If incoming data = "a1", LED status = HIGH or 1 and if incoming data = "a0", LED status = LOW or 0
First let's define few things, and initialize serial communication.
int led = 13; // give a name to our LED
int ledStatus; // status of the LED. It's either HIGH or LOW (0 or 1)

void setup() {                
  pinMode(led, OUTPUT);  // initialize the digital pin as an output.
Serial.begin(9600);  // begin serial communication at 9600 baud rate
}
In the main loop, first we check to see if there is any incoming data. If there is, we use the function serial.parseInt() to return any integer and reject any character present in the data. Finally, we store the integer into the ledStatus variable.
void loop() {
  if(Serial.available() > 0) {
    ledStatus = Serial.parseInt();
    digitalWrite(led, ledStatus);
  }
}
Let's sum up the entire code ( Just merging the above two)
int led = 13; // give a name to our LED
int ledStatus; // status of the LED. It's either HIGH or LOW (0 or 1)

void setup() {                
  pinMode(led, OUTPUT);  // initialize the digital pin as an output.
Serial.begin(9600);  // begin serial communication at 9600 baud
}

// main loop begins
void loop() {
  if(Serial.available() > 0) { // see if there is incoming data
    ledStatus = Serial.parseInt(); // parse the data and store the first integer, if available, into our variable. 
    digitalWrite(led, ledStatus); // Turn ON or Turn OFF the LED as per user input
  }
}
That's just about it. Upload the code into your Arduino and commence your rule over that puny LED!


3) Lighting up specific colours in an RGB LED via a Python GUI
By now, you must have understood how the communication process works in between Python and Arduino. You have learnt to blink an LED randomly and have also tamed it to turn on or off, at the presence of your command. Let's make things a tad more interesting now by building a Python GUI to light up colours in an RGB LED. The communication process remains the same, but our interface will move to a higher level. Let's begin.
Let's start from the Python GUI and later move towards Arduino.
As always, we start by importing libraries, setting up serial communications and defining a couple of functions that light up specific colours in an RGB LED.
import serial # import the serial library
import time # import the time library
from Tkinter import * #import Tkinter GUI library 

def red():
 arduino.write('r')

def green():
 arduino.write('g')
 

def blue():
 arduino.write('b')
 

def yellow():
 arduino.write('w')
 

def purple():
 arduino.write('s')
 

def aqua():
 arduino.write('a')

print 'Connecting...'
arduino = serial.Serial(12, 9600)
time.sleep(3)
print 'Connection established successfully'
Now, we shall move towards designing the Python GUI that will have a couple of colourful buttons on it. Remember the following code we used to create a simply GUI window?
appWindow = Tk() # creates the application window (you can use any name)
appWindow.wm_title("LED Control") # displays title at the top left
# insert app widgets here (radiobuttons, checkboxes, buttons, etc.)
appWindow.mainloop()# begins main loop

Let's make a couple of additions to this plain code. To make the GUI more interactive by filling it with buttons, creating frames, we use various "widgets" (like the radio-button we used above)
Let's begin by adding a frame which is an important organizational component of any Python GUI. Let's create the main frame first:
mainFrame = Frame(appWindow, bg="#037481") #define the main frame of the GUI
mainFrame.grid() #grid the frame into the App Window
Then let's create a frame inside the main frame that will hold the buttons:
btnFrame = Frame(mainFrame, bg="#037481") #define the frame within the main frame that holds buttons
btnFrame.grid(row=1, column=0) #grid the frame into the main frame
Finally let's add a couple of buttons inside the btnFrame
redLEDBtn = Button(btnFrame, text="RED", command=red, bg="red") #create a button inside the btnFrame with the given features
redLEDBtn.grid(row=0, column=1) #grid the button in a specific row and column within the btnFrame

greenLEDBtn = Button(btnFrame, text="GREEN", command=green, bg="green") #create a button inside the btnFrame with the given features
greenLEDBtn.grid(row=0, column=2) #grid the button in a specific row and column within the btnFrame

blueLEDBtn = Button(btnFrame, text="BLUE", command=blue, bg="blue") #create a button inside the btnFrame with the given features
blueLEDBtn.grid(row=0, column=3) #grid the button in a specific row and column within the btnFrame

yellowLEDBtn = Button(btnFrame, text="YELLOW", command=yellow, bg="yellow") #create a button inside the btnFrame with the given features
yellowLEDBtn.grid(row=1, column=1) #grid the button in a specific row and column within the btnFrame

purpleLEDBtn = Button(btnFrame, text="PURPLE", command=purple, bg="purple") #create a button inside the btnFrame with the given features
purpleLEDBtn.grid(row=1, column=2) #grid the button in a specific row and column within the btnFrame

aquaLEDBtn = Button(btnFrame, text="AQUA", command=aqua, bg="#028482") #create a button inside the btnFrame with the given features
aquaLEDBtn.grid(row=1, column=3) #grid the button in a specific row and column within the btnFrame
 Just like the radiobuttons executed a function to which the command option was directed to, the buttons in this GUI also do the same. When the redLEDBtn is pressed, the function red() is executed as we have specified so using the command option while creating the button.
Let's sum up the code now, shall we?
import serial # import the serial library
import time # import the time library
from Tkinter import * #import Tkinter GUI library 



def red():
 arduino.write('r')

def green():
 arduino.write('g')
 

def blue():
 arduino.write('b')
 

def yellow():
 arduino.write('w')
 

def purple():
 arduino.write('s')
 

def aqua():
 arduino.write('a')

print 'Connecting...'
arduino = serial.Serial(12, 9600)
time.sleep(3)
print 'Connection established successfully'

appWindow = Tk() # creates the application window (you can use any name)
appWindow.wm_title("RGB LED Control") # displays title at the top left
appWindow.config(bg ="#037481")

mainFrame = Frame(appWindow, bg="#037481") #define the main frame of the GUI
mainFrame.grid() #grid the frame into the App Window

btnFrame = Frame(mainFrame, bg="#037481") #define the frame within the main frame that holds buttons
btnFrame.grid() #grid the frame into the main frame

redLEDBtn = Button(btnFrame, text="RED", command=red, bg="red") #create a button inside the btnFrame with the given features
redLEDBtn.grid(row=0, column=1) #grid the button in a specific row and column within the btnFrame

greenLEDBtn = Button(btnFrame, text="GREEN", command=green, bg="green") #create a button inside the btnFrame with the given features
greenLEDBtn.grid(row=0, column=2) #grid the button in a specific row and column within the btnFrame

blueLEDBtn = Button(btnFrame, text="BLUE", command=blue, bg="blue") #create a button inside the btnFrame with the given features
blueLEDBtn.grid(row=0, column=3) #grid the button in a specific row and column within the btnFrame

yellowLEDBtn = Button(btnFrame, text="YELLOW", command=yellow, bg="yellow") #create a button inside the btnFrame with the given features
yellowLEDBtn.grid(row=1, column=1) #grid the button in a specific row and column within the btnFrame

purpleLEDBtn = Button(btnFrame, text="PURPLE", command=purple, bg="purple") #create a button inside the btnFrame with the given features
purpleLEDBtn.grid(row=1, column=2) #grid the button in a specific row and column within the btnFrame

aquaLEDBtn = Button(btnFrame, text="AQUA", command=aqua, bg="#028482") #create a button inside the btnFrame with the given features
aquaLEDBtn.grid(row=1, column=3) #grid the button in a specific row and column within the btnFrame

appWindow.mainloop()# begins main loop
That's it. Save the program with any name. (RGB.py) and open it up. If you have followed everything, you should get the following result:

The Arduino part should be fairly simple: receiving characters and lighting up corresponding colors. It's not mandatory to have an RGB LED. You can experiment this with almost anything. The Arduino code will be added later along with a demo video depicting GUI control. For now, here's an RGB LED Demo.
This was a demo of a simple GUI app using Tkinter and Python. I'll leave the rest up to you. Experiment with various widgets to see what results are produced! Scroll further below to see more on controlling a robot through a Python GUI.


  • Tutorials – Serial + Wireless Communication using RF Modules (Controlling a Robot)
Now that you are familiar with building apps and communicating with Arduino, using Python, let's spice up things a bit. Let's start controlling a robot wirlessly via a computer. In this tutorial, we will be using RF Modules for wireless communication. (You can use a bluetooth module as well). We will need two Arduinos : Arduino A at the transmitter end and Arduino B at the receiver end. We will learn to control the robot using 1) keyboard strokes 2) button-clicks via a Python GUI
1) Control using keyboard strokes via the msvcrt library (works only on windows) :
      Before moving into the depths of the msvcblablabla library, let's see what processes undergo when a robot is being controlled wirelessly using a keyboard through a Python App via RF modules. To learn more about using RF Modules and Arduino, visit Robodude's Instructable. You can also find information on the Virtual Wire Library there.
Like PySerial and Tkinter, msvcrt is a Python library that detect keyboard characters when they are pressed. It also comes along with the Python files like Tkinter. On knowing the pressed character, we can send data to the Arduino to perform a task, in this case, to control a robot. For eg: on pressing 'w', the robot moves forward and on pressing 'd', the robot turns right. For some reason which I do not know, Google told me that this library worked only on Windows.
UPDATE: Looks like the PyGame Library also supports key presses, and it's also available on major platforms. You might want to experiment with that too.
Why not do this directly from Arduino? Why use Python? because while sending data from the Arduino IDE through the Serial Monitor, we cannot do so in real time. We need press a character and unless we hit enter, we cannot send the character to the Arduino. Using Python and the msvcrt library, we can send characters in real-time. Data is sent to the Arduino as soon as a specific key is pressed.
So let's begin. First, as always, we need to import libraries that will be required in our Python code. In this case, the keyboard library i.e. msvcrt, the serial library, and the time library.
import serial # for serial communication
import msvcrt # to detect keys pressed
import time # to execute time functions ( gives the ability to use delay-like commands )
Next, let's establish serial port connections:
print "Connecting to Arduino...." # print something 
arduinoSerialPort = serial.Serial("COM13", 9600) 
time.sleep(2)# wait for 2 seconds
print "Connected Successfully!" 
Then, let's begin the Python main loop. This is similar to the void loop() used in Arduino:
while 1:
Now, let's make use of the msvcrt library to detect keystrokes and send a specific character to the Arduino when a specific key is pressed.
 if msvcrt.kbhit(): # if a key is pressed
  keypress = ord(msvcrt.getch()) # store the ASCII value of the character into our variable keypress
  if keypress == 119: #if 'w' is pressed (ASCII value of 'w' is 119)
   print 'up' #simply print 'up' in command prompt
   arduino.write('w') #send 'w' to Arduino
  if keypress == 115: #if 's' is pressed (ASCII value of 's' is 115)
   print 'down' #simply print 'down' in command prompt
   arduino.write('s') #send 's' to Arduino
  if keypress == 97: #if 'a' is pressed (ASCII value of 'a' is 97)
   print 'left' #simply print 'left' in command prompt
   arduino.write('a') #send 'a' to Arduino
  if keypress == 100: #if 'd' is pressed (ASCII value of 'd' is 100)
   print 'right'#simply print 'right' in command prompt
   arduino.write('d')  #send 'd' to Arduino
  if keypress == 101: #if 'e' is pressed (ASCII value of 'e' is 101)
   print 'stop' #simply print 'stop' in command prompt
   arduino.write('e') #send 'e' to Arduino
There. That's all for the Python code. But let's just sum things up in place.
import serial
import msvcrt 
import time

print "Connecting to Arduino..."  # print something 
arduino = serial.Serial(12, 9600)
time.sleep(2)
print "Connected Successfully!"

while 1:
 if msvcrt.kbhit(): # if a key is pressed
  keypress = ord(msvcrt.getch()) # store the ASCII value of the character into our variable keypress
  if keypress == 119: #if 'w' is pressed (ASCII value of 'w' is 119)
   print 'up' #simply print 'up' in command prompt
   arduino.write('w') #send 'w' to Arduino
  if keypress == 115: #if 's' is pressed (ASCII value of 's' is 115)
   print 'down' #simply print 'down' in command prompt
   arduino.write('s') #send 's' to Arduino
  if keypress == 97: #if 'a' is pressed (ASCII value of 'a' is 97)
   print 'left' #simply print 'left' in command prompt
   arduino.write('a') #send 'a' to Arduino
  if keypress == 100: #if 'd' is pressed (ASCII value of 'd' is 100)
   print 'right'#simply print 'right' in command prompt
   arduino.write('d')  #send 'd' to Arduino
  if keypress == 101: #if 'e' is pressed (ASCII value of 'e' is 101)
   print 'stop' #simply print 'stop' in command prompt
   arduino.write('e') #send 'e' to Arduino
Save the file as keyControl.py or something. Open up the program and you should see the following window:
The directional texts (up, left, down, right) don't come up initially. You see them because I had pressed corresponding keys.
After we have sent specific characters to Arduino via serial port, RF communication begins. RF Modules come in a pair : a TX (data tramsitter) pair and an RX (data receiver) pair. We will need to write a separate Arduino Code for the TX-pair and a separate Arduino code for the RX-pair. The RF Modules I am using have a frequency of 433 MHz and I am using the Virtual Wire Library to make data transfer easier.
Arduino Code for TX-pair (connected to Arduino A):
TX
First, let's include the VirtualWire Library:
 #include <VirtualWire.h>
And then, let's initialize Serial Communication to receive the incoming characters from the Python App:
void setup(){
  Serial.begin(9600);
  vw_setup(2000);  // Bits per sec
  vw_set_tx_pin(3); //Transmitter Data Pin to Digital Pin 3
}//close setup

Let's begin the main loop and start checking the incoming characters via Serial and transmitting the outgoing characters via RF:
void loop()
{
  if (Serial.available() > 0) // if there is incoming data
  {
    int sendByte = Serial.read();//Starts reading data from the serial monitor once condition is met
   switch (sendByte){
    
     case 'w':  // if w is pressed
      {

        char *msg2 = "w";
        digitalWrite(13, true); // Flash a light to show transmitting
        vw_send((uint8_t *)msg2, strlen(msg2));//send byte to the receiver
        vw_wait_tx(); // Wait until the whole message is gone
        digitalWrite(13, false);
        break;

      }
Similarly, we can write the code for the rest of the characters in the same way. Let's sum up the entire TX code.
#include <VirtualWire.h>

void setup(){
  Serial.begin(9600);
  vw_setup(2000);  // Bits per sec
  vw_set_tx_pin(3); //Transmitter Data Pin to Digital Pin 3
}//close setup

void loop()
{
  if (Serial.available() > 0) // if there is incoming data
  {
    int sendByte = Serial.read();//Starts reading data from the serial monitor once condition is met
   switch (sendByte){
    
     case 'w':  // if w is pressed
      {

        char *msg2 = "w";
        digitalWrite(13, true); // Flash a light to show transmitting
        vw_send((uint8_t *)msg2, strlen(msg2));//send byte to the receiver
        vw_wait_tx(); // Wait until the whole message is gone
        digitalWrite(13, false);
        break;

      }
    case 's':  // if s is pressed
      {
        char *msg2 = "s";
        digitalWrite(13, true); // Flash a light to show transmitting
        vw_send((uint8_t *)msg2, strlen(msg2));//send byte to the receiver
        vw_wait_tx(); // Wait until the whole message is gone
        digitalWrite(13, false);  
        break;
      }

    case 'a': // if a is pressed
      {
        char *msg2 = "a"; 
        digitalWrite(13, true); // Flash a light to show transmitting
        vw_send((uint8_t *)msg2, strlen(msg2));//send byte to the receiver
        vw_wait_tx(); // Wait until the whole message is gone
        digitalWrite(13, false);  
        break;
      }

    case 'd': // if d is pressed
      {  
        char *msg2 = "d"; 
        digitalWrite(13, true); // Flash a light to show transmitting
        vw_send((uint8_t *)msg2, strlen(msg2));//send byte to the receiver
        vw_wait_tx(); // Wait until the whole message is gone
        digitalWrite(13, false);    
        break;
      }     
    case 'e': // if e is pressed
      {
        char *msg2 = "e"; 
        digitalWrite(13, true); // Flash a light to show transmitting
        vw_send((uint8_t *)msg2, strlen(msg2));//send byte to the receiver
        vw_wait_tx(); // Wait until the whole message is gone
        digitalWrite(13, false);   
        break;
      }
    default://if any other value is entered
      {
 Serial.println("wrong entry");//print wrong entry in the serial monitor
      }
    }// close switch-case
  }//close if 
}//close loop

Arduino Code for RX-pair (connected to Arduino B):
RX
Now, let's discuss the code for the RX-part. We start by including the Virtual Wire Library again :
#include <VirtualWire.h>
To move your robot around , you need motors. To control the speed and direction of the motors, you need a motor driver. I am using an L293D motor driver. Refer to the datasheet of the motor driver you are using to know the respective pin definitions. Time to define the pin connections:
#define rightMotor1 5 // INPUT A1 to digital pin 5
#define rightMotor2 6 // INPUT A2 to digital pin 6
#define leftMotor1 3  // INPUT B1 to digital pin 3
#define leftMotor2 11 // INPUT B2 to digital pin 11

Let's initialize the serial communication and configure the Arduino pin modes.
void setup() {
    vw_setup(2000);  // Bits per sec
    vw_set_rx_pin(2);//Receiver at Digital Pin 2
    vw_rx_start();// Start the receiver PLL running
  pinMode(rightMotor1, OUTPUT);
  pinMode(rightMotor2, OUTPUT);
  pinMode(leftMotor1, OUTPUT);
  pinMode(leftMotor2, OUTPUT);
}

Now, we begin to receive incoming characters via the RX-pair. Let's enter into the main loop:
void loop() {
   
 uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    

    if (vw_get_message(buf, &buflen)) // if RX-pair receives a character
    {
 int i;

        digitalWrite(13, true); // Flash a light to show received good message
 
 for (i = 0; i < buflen; i++)
 {
     Serial.print(buf[i]);
        if(buf[i] == 'w')
        {
          forward();//go forward when w is pressed
        }
        if(buf[i] == 's')
      {
        backward();//go backward when s is pressed
      }
        if(buf[i] == 'e')
      {
        stop();//stop/brake when e is pressed
      }
        if(buf[i] == 'a')
      {
        left();//go left when a is presed
      }
        if(buf[i] == 'd')
        {
          right();//go right when d is pressed
        }   
 }//close for loop
 }
}
 But who is going to define the movement routines?
void forward(){
analogWrite( rightMotor1, 150);
analogWrite(rightMotor2, 0);
analogWrite(leftMotor1, 150);
analogWrite(leftMotor2,0);
}

void left(){
analogWrite( rightMotor1, 150);
analogWrite(rightMotor2, 0);
analogWrite(leftMotor1, 0);
analogWrite(leftMotor2,100);
}

void stop(){
  analogWrite( rightMotor1, 0);
analogWrite(rightMotor2, 0);
analogWrite(leftMotor1, 0);
analogWrite(leftMotor2,0);
}
And in a similar way, you can complete the rest. Let us sum up the entire code for the RX-part:
#include <VirtualWire.h>
 
#define rightMotor1 5 
#define rightMotor2 6
#define leftMotor1 3
#define leftMotor2 11

void setup() {
    vw_setup(2000);  // Bits per sec
    vw_set_rx_pin(2);//Receiver at Digital Pin 2
    vw_rx_start();// Start the receiver PLL running
  pinMode(rightMotor1, OUTPUT);
  pinMode(rightMotor2, OUTPUT);
  pinMode(leftMotor1, OUTPUT);
  pinMode(leftMotor2, OUTPUT);
}   

void loop() {   
 uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
 int i;

        digitalWrite(13, true); // Flash a light to show received good message
 
 for (i = 0; i < buflen; i++)
 {
     Serial.print(buf[i]);
        if(buf[i] == 'w')
        {
          forward();//go forward when w is pressed
        }
        if(buf[i] == 's')
      {
        backward();//go backward when s is pressed
      }
        if(buf[i] == 'e')
      {
        stop();//stop/brake when e is pressed
      }
        if(buf[i] == 'a')
      {
        left();//go left when a is presed
      }
        if(buf[i] == 'd')
        {
          right();//go right when d is pressed
        }   
 }//close for loop
 }
}

void forward(){
analogWrite( rightMotor1, 150);
analogWrite(rightMotor2, 0);
analogWrite(leftMotor1, 150);
analogWrite(leftMotor2,0);
}

void backward(){
analogWrite( rightMotor1, 0);
analogWrite(rightMotor2, 150);
analogWrite(leftMotor1, 0);
analogWrite(leftMotor2,150);
}

void right(){
analogWrite( rightMotor1, 0);
analogWrite(rightMotor2, 100);
analogWrite(leftMotor1, 150);
analogWrite(leftMotor2,0);
}

void left(){
analogWrite( rightMotor1, 150);
analogWrite(rightMotor2, 0);
analogWrite(leftMotor1, 0);
analogWrite(leftMotor2,100);
}

void stop(){ 
  analogWrite( rightMotor1, 0);
analogWrite(rightMotor2, 0);
analogWrite(leftMotor1, 0);
analogWrite(leftMotor2,0);
}

And that's it! You have just learned to control your robot in real-time through a computer keyboard via RF modules using the powerful and versatile programming language we all know, Python.

  • Tutorials - Control through mouse clicks via the Tkinter GUI library
The idea in controlling your robot via a Python GUI is very similar to that of controlling it via keyboard strokes. In the previous tutorial, there wasn't a GUI (Graphical User Interface). We simply sent character over to the robot through the command prompt. In this tutorial, we will do that through a GUI. The communication process between the two Arduinos remains the same. We'll just need to tweak our Python code to build a GUI (as we did in the RGB LED tutorial).
By now, you kind of have an idea about building a GUI. It's pretty similar to the RGB LED GUI but this one makes use of more well defined widgets
The first part of the code must be buzzing in your mind by now:
import serial # import the serial library
import time # import the time library
import msvcrt #import keyboard library
from Tkinter import * #import Tkinter GUI library 
 

def Up():
 arduino.write('w')
 
def Down():
 arduino.write('s')
 

def Left():
 arduino.write('a')
 

def Right():
 arduino.write('d')
 

def Stop():
 arduino.write('e')


print 'Connecting...'
arduino = serial.Serial(12, 9150)
time.sleep(3)
print 'Connection established successfully'
Now, we'll create a GUI window, with well-designed frames and well-positioned buttons. To do that, we make use of more options such as cell padding, highlightthickness, etc.
#Control Frame and its contents
controlFrame = Frame(appWindow, width=150, height = 150, bg="#037481", highlightthickness=2, highlightbackground="#111") #defines the control frame
controlFrame.grid() #positions the control frame with the corresponding parameters

btnFrame = Frame(controlFrame, width=150, height = 150, bg="#037481")# defines the button frame with these characteristics
btnFrame.grid() #positions the button frame inside which control buttons will reside
upBtn = Button(btnFrame, text="UP", command=Up, bg="green") #defines the UP button
upBtn.grid(row=2, column=2, padx=5, pady=5) #positions the UP button within the button frame

downBtn = Button(btnFrame, text="DOWN", command=Down, bg="yellow") #defines the DOWN button
downBtn.grid(row=4, column=2, padx=5, pady=5) #positions the UP button within the button frame

leftBtn = Button(btnFrame, text="LEFT", command=Left, bg="orange") #defines the LEFT button
leftBtn.grid(row=3, column=0, padx=5, pady=5) #positions the LEFT button within the button frame

rightBtn = Button(btnFrame, text="RIGHT", command=Right, bg="blue") #defines the RIGHT button
rightBtn.grid(row=3, column=3, padx=5, pady=5) #positions the RIGHT button within the button frame

stopBtn = Button(btnFrame, text="STOP", command=Stop, bg="red") #defines the STOP button
stopBtn.grid(row=3, column=2, padx=5, pady=5) #positions the STOP button within the button frame

appWindow.mainloop()# begins main loop
Once you merge the two slices of code above, save the file as  GUI.py or something. You should get the following window:
GUI Control A
You can also use the widget "label" to add some text of your own, such as your name, or application options and instructions, etc. For eg:
name = Label(btnFrame, width=12, height=1, text="GUI CONTROL", font="bold", justify=CENTER, bg="#037481")
name.grid(row=0, column=2)
Using two lines of code, you can add text into your GUI:
GUI CONTROL B
Summing up the entire code , just to get things clearer:
import serial # import the serial library
import time # import the time library
import msvcrt #import keyboard library
from Tkinter import * #import Tkinter GUI library 
 

def Up():
 arduino.write('w')
 
def Down():
 arduino.write('s')
 

def Left():
 arduino.write('a')
 

def Right():
 arduino.write('d')
 

def Stop():
 arduino.write('e')


print 'Connecting...'
arduino = serial.Serial(12, 9150)
time.sleep(3)
print 'Connection established successfully'

appWindow = Tk() # creates the application window (you can use any name)
appWindow.wm_title("GUI CONTROL") #Makes the title that will appear in the top left
appWindow.config(bg = "#828481")


#Control Frame and its contents
controlFrame = Frame(appWindow, width=150, height = 150, bg="#037481", highlightthickness=2, highlightbackground="#111") #defines the control frame
controlFrame.grid() #positions the control frame with the corresponding parameters

btnFrame = Frame(controlFrame, width=150, height = 150, bg="#037481")# defines the button frame with these characteristics
btnFrame.grid() #positions the button frame inside which control buttons will reside

about = "GUI CONTROL"
name = Label(btnFrame, width=12, height=1, text=about, font="bold", justify=CENTER, bg="#037481")
name.grid(row=0, column=2)

upBtn = Button(btnFrame, text="UP", command=Up, bg="green") #defines the UP button
upBtn.grid(row=2, column=2, padx=5, pady=5) #positions the UP button within the button frame

downBtn = Button(btnFrame, text="DOWN", command=Down, bg="yellow") #defines the DOWN button
downBtn.grid(row=4, column=2, padx=5, pady=5) #positions the UP button within the button frame

leftBtn = Button(btnFrame, text="LEFT", command=Left, bg="orange") #defines the LEFT button
leftBtn.grid(row=3, column=0, padx=5, pady=5) #positions the LEFT button within the button frame

rightBtn = Button(btnFrame, text="RIGHT", command=Right, bg="blue") #defines the RIGHT button
rightBtn.grid(row=3, column=3, padx=5, pady=5) #positions the RIGHT button within the button frame

stopBtn = Button(btnFrame, text="STOP", command=Stop, bg="red") #defines the STOP button
stopBtn.grid(row=3, column=2, padx=5, pady=5) #positions the STOP button within the button frame

appWindow.mainloop()# begins main loop
The Arduino communication remains the same, as I mentioned earlier. Please refer to the earlier tutorial of Control using keyboard strokes via the msvcrt library for that portion. Once everything is settled, you can control a robot via a Python GUI like this.


FUTURE UPDATES:
There are a couple of more updates to come so watch out! I am learning a couple of things using Python GTK and Glade to build GUIs and will update once I get some working results. Using GLADE + pyGTK is going to be even more interesting opening up wider possibilities while designing a GUI, such as easier creation of GUIs and cross-platform compatibility.


There might have been some errors in this tutorial as I myself just started playing around with Python not very long ago. And so, I would be grateful if you point them out just in case you pass by them. This tutorial is also not in the best of organized forms at the moment and I plan to work on that part as well Thanks for passing by and going through this tutorial. Feedback is much appreciated.
See you in the ShotBox, LMRians (try the new SB popout, it's cool!)
-Ashim
References : 
Python Official Website
Robotic Controls (Very awesome site. Learnt most things about Python GUI development right here)
Robodude's Instructable (Robodude's tutorial made it straightforward to intgerate RF Modules) You can also manually download the Virtual Wire Library here.
StackOverFlow (for tackling various errors encountered. Updates on a few soon, hopefully)
Google (Always your best friend on the internet)

No hay comentarios:

Publicar un comentario