Using Python to control servo on basic stamp 1 project board?
dmehling2
Posts: 21
I have a basic stamp 1 project board with a USB to serial adapter. I also have a servo motor. I would like to know if it is possible to create scripts in Python that I can use to control the servo? I will not be using the stamp independently, but need to periodically send commands from my computer to the servo.
Comments
Welcome to the Forums!!!!
In answer to your question, I don't see why not...
http://stackoverflow.com/questions/676172/full-examples-of-using-pyserial-package
...The real issue might be configuring the serial port depending on which platform you are running Python .... i.e. Windows, Linux, MAC, etc.
As far as communication to the BS1, You should construct some type of SYNC character in your data transmission that the BS1 can recognize as a unique pattern.
You want to keep the Baud to 2400 or less. The BS1 doesn't handle higher Bauds well at all.
When you say it periodically sends a request, how often would that be?
I also need to clarify something because I have little experience with servos. Does a servo constantly require power to maintain its position? If I were to turn off the project board, would the servo be able to maintain its current position?
Servo PAL:
http://www.parallax.com/product/28824
Edit:
In answer to your question ... "Does a servo constantly require power to maintain its position? If I were to turn off the project board, would the servo be able to maintain its current position?" - If you remove the pulse signal or power, the servo will remain in the last commanded position but will have no holding power or torque to keep it there. If an external force is applied, the Servo may be repositioned manually.
1) A Polling mechanism from the BS1 that makes a request to the PC might solve this.
2) ...or you could just blindly send several commands to the BS1 and hope that at least one will be read correctly. In this case though, if the BS1 doesn't properly "time out" then the pulse to the Servo might be dropped if it is not within the 20ms window.
"The stamp only has the servo and the serial connection. How likely would it be for me to have a problem under those circumstances? " - You will probably be just fine ... I was simply offering an alternative, that would allow the BS1 to have a little more overhead to do other things if you wanted to expand your project functionality.
The BS1 would then listen for a RS232 reply from the PC... if it didn't receive a reply it would need to timeout and continue operations
If it does receive a reply, then it would update the value representing the position of the servo, and then continue operations
In terms of configuring the serial port, does it matter that I have a USB to serial adapter rather than a direct connection to a serial port? Would the python script be the same? (I am running Windows 7).
How do I add a SYNC character to the data transmission? Is that something that's covered in a tutorial?
You just need to configure your PC so that Python can correctly communicate through the serial port ... This would be the first obstacle I would try to solve.
As far as sending data to the BS1 or receiving data from the BS1 using a sync, this is purely in software for data alignment. For example if you sent the position of 1000 serially you would need to break it down into two bytes, since serial data only sends bytes. So sending 1000 might look like this ....
3 , 232
1000 = 3 * 256 + 232
There is nothing (i.e. a SYNC) preventing the order of the numbers to get swapped along the way so they could end up as ...
232, 3
59395 = 232 * 256 + 3
So 59395 is obviously not the number you want to send, so you send a SYNC character(s) that you identify in software as a starting point. IOW don't do anything else unless the software "sees" the SYNC. Usually the SYNC is constructed so that it is unique in a way that any combination of the data you are sending can not be reproduced and mistaken as a SYNC.
i.e. !S would be two bytes a "!" or decimal 33 and a "S" or decimal 83, where upon your actual data would follow and the serial sequence might look something like ...
33 83 3 232
On the receiving end you look for the SYNC of 33 and 83 and don't process the remaining data (3 and 232) until the SYNC condition has been met.
What kind of corresponding code would I need to write in PBASIC?
Installing PySerial: (Linux)
http://pyserial.sourceforge.net/pyserial.html
Installing for Windows (contains more examples):
https://pypi.python.org/pypi/pyserial
PySerial code examples:
http://pyserial.sourceforge.net/shortintro.html#
EDIT: For reference ONLY:
Here is a project I did a few years ago that controlled the position of a laser pointer using a PC talking to a BS2.
The example shows how two different programs... one on the PC and the other on the BS2 communicate to drive two hobby servos.
http://forums.parallax.com/showthread.php/80452-Stamp-controlled-Laser-Pointer
Slight modification to the BS2 code would need to be done to convert it to BS1 code, but the idea is the same. In my BS2 code the SYNC characters are "LPO" followed by three bytes ... X position, Y position, and the Laser being ON or OFF.
#!/usr/bin/python
import serial
import time
import random
ser = serial.Serial(port = "/dev/ttyUSB0", baudrate=2400)
ser.close()
ser.open()
ser.write(5000)
On the last line, I threw in the number 5000. It's just a random number that doesn't properly correspond yet to the stamp code. In place of that number, what would I put instead? Would it be the value that I want to send to the servo?
At this point I'm still not clear about SYNC. Once I master the basics of pyserial maybe I will be able to work on figuring it out. That might take a few days.
' {$STAMP BS1}
' {$PBASIC 1.0}
SYMBOL SIn = 0
SYMBOL Baud = N2400
SYMBOL result = W1
Main:
SERIN SIn, Baud, ("ABCD"), #result
DEBUG #result, CR
GOTO Main
END
This seems to be a good start to me on knowing how to do basic serial communication. What corresponding Python code would work? Something like this:
#!/usr/bin/python
import serial
import time
import random
ser = serial.Serial(port = "/dev/ttyUSB0", baudrate=2400)
ser.close()
ser.open()
ser.write(ABCD, ??? )
After the ABCD, I'm not sure what kind of values I can use or what the exact format is. I have done a lot of googling, but can't find any examples of that little detail.
i.e.
N = 5000 ' defined as a WORD
BYTE_H = N >> 8 = 19 <--- shifts N 8 bits to the right (effectively an integer divide by 256)
BYTE_L = N & 255 = 136 <--- only looks at the lower byte
You can double check this by which is also how you can re-build the value when receiving, or you can align your variables in a way that there is no conversion required at all. (see below)
N = BYTE_H * 256 + BYTE_L
Basic Stamp I variable definition
By defining the variables like this in the Basic Stamp I, there is no need to apply the math... when you read the serial data just read it into Byte_H and Byte_L and N will automatically have the correct value.
So when sending the data from Python you would send the string "ABCD" followed by
On your last line, you wrote:
"So when sending the data from Python you would send the string "ABCD" followed by …"
Did I miss something, or were you about to write something else? That is the last little bit that I'm really confused about. As I said before, I can't find any sample code that explains that part.
Other than that, I think I have it just about figured out. I may come back here a few times in the next couple weeks to make sure I have all the details just right.
I don't know, I said at the beginning that I haven't written serial code for Python, but that the examples looked straight forward enough that it shouldn't be to difficult to figure out. Initially I just goggled "Serial programming in Python"
... The first hit was .... http://pyserial.sourceforge.net/
http://stackoverflow.com/questions/676172/full-examples-of-using-pyserial-package
based on the page above I would start with something like ... I know you can used the / and & operators to break the WORD variable, the question is if the serial routines are correct based on the examples provided on the web-page reference
Any luck with this from the Python side of things?
Wish I could help you more with the Python, but I think there is adequate examples by just doing a Google search to find the correct answer you are looking for.
Also, what is a high byte and a low byte?
i.e.
b'11100 & b'10101 would produce b'10100
As far as HIGH byte and LOW byte is concerned ... in the computer world a variable needs to be represented with 1's and 0's or BITS
1 - bit can only represent two numbers 0 and 1 since that is the only combination you can derive from a single BIT
2 - bits can represent 4 numbers since there are a total of 4 combinations you can derive ... 00 (0) , 01 (1) , 10 (2) , 11 (3)
4 - bits (Also called a NIBBLE) has 16 number combinations
8 - bits (Also called a BYTE) has 256 number combinations
16 - bits (Also called a WORD) has 65536 number combinations
So in order to represent a number greater then 255 you need to use a WORD... A WORD can be composed as two BYTEs and often referred to as a HIGH byte or a LOW byte. The HIGH byte contain the MSB(most significant BITs) while the LOW byte contains the LSB(least significant BITs)
Using the ampersand is an effective way of removing the HIGH byte and only looking ans isolating the LOW byte
Dividing by 256 simply moves the HIGH byte of the WORD into the position of the LOW byte