I have a small class for Python 2.7 on the Raspberry Pi.
Basically, it works ok. But only once! I unplug the maestro from the Rpi USB, plug it back in, send it a setTarget and the servo will move, however, after that, it seems to ignore any further setTarget commands.
I have three servos connected, they all work fine with the windows program. If I issue getPosition and getErrors, I see the same position and no errors, no matter what setTarget I send.
Any ideas?
Just a quick edit, I’ve tried the Mini SSC protocol and that works just fine.
import serial
import time
class ServoController:
def __init__(self):
usbPort = '/dev/ttyACM0'
self.sc = serial.Serial(usbPort, timeout=1)
def closeServo(self):
self.sc.close()
def sendPosition(self, servo, position):
poslo = (position & 0x7f)
poshi = (position >> 7) & 0x7f
chan = servo &0x7f
data = [
chr(0xaa),
chr(0x0c),
chr(0x04),
chr(chan),
chr(poslo),
chr(poshi)
]
for i in data:
print ord(i),
self.sc.write(i)
print
def getPosition(self, servo):
chan = servo &0x7f
data = [
chr(0xaa),
chr(0x0c),
chr(0x10),
chr(chan)
]
for i in data:
self.sc.write(i)
w1 = ord(self.sc.read())
w2 = ord(self.sc.read())
return w1, w2
def getErrors(self):
data = [
chr(0xaa),
chr(0x0c),
chr(0x21)
]
for i in data:
self.sc.write(i)
w1 = ord(self.sc.read())
w2 = ord(self.sc.read())
return w1, w2
Maestro = ServoController()
while(1):
chan = int(raw_input("enter chan "))
pos = int(raw_input("position "))
Maestro.sendPosition(chan, pos)
print Maestro.getPosition(chan)
print Maestro.getErrors()
Maestro.closeServo()
What targets are you trying to set with the Set Target command? Are you aware that the units are quarter-microseconds? It would be helpful if you could post here a screenshot or text version of your shell session showing how you reproduce the problem, with comments about when you unplugged or plugged in the Maestro. This would let us see exactly what you are doing and what your program is printing.
Here is another thread where someone was controlling a Maestro with Python, which might be useful to you: Micro Maestro USB on Mac
I noted the target values on the PC app and used those. Perhaps I’m unsure what I’m doing with respect to exactly what ‘targets’ are? From what I see on the PC app- the targets, as you move the slider and the servo rotates, are from 992.00 to 2000.00. I used those as low and high endpoints.
As I mentioned, I do get good results using the Mini SSC protocol which will suit my purposes for now. I have not tested the trigger of scripts yet, which will probably be what I will use the most in my particular application.
I was also wondering if there is a way to download the scripts via a simple serial command rather than all the overhead of using USB protocols?
I had no luck with PyUSB.
I unplug the controller from the RPi just to reset it. Once back in, I send the commands as above. Each servo will move for the first command I send, and then not again until I unplug it (USB) and plug it back in. I do not have this problem with the SSC protocol.
As per the first rule of programming, I’m probably doing something really dumb, but I’m not sure what it is after much trial and error.
The position and target values displayed in the Status tab of the Maestro Control Center are in units of microseconds, but the Set Target serial command takes a value in units of quarter microseconds, so you will need to multiply by four. Typical values passed to the Set Target command would be between 4000 and 8000.
There is no serial command for modifying or setting the internal script.
Martan,
I’m no expert by far! I have barely gotten my Mini Maestro working myself, but from what it sounds like to me, you’re sending it an improper number of bits and it’s getting ‘confused’ when the data overlaps. When you use the Mini SSC command, whenever the Maestro sees the 0xFF it starts interpreting the data after that point, and reacts. I could, however, be way off. Here’s the code, albeit Java, that I am using.
String pos = Integer.toBinaryString(position * 20 + 6000);
// convert +-100 to quarter-microseconds then convert to
// a string of zeros and ones
pos = ("00000000000000" + pos).substring(pos.length());
// pad the value to 14 bits
try{
outputStream.flush();
//flush the serial stream
outputStream.write((byte) 0x84);
//write the command byte (With MSB set (1))
outputStream.write((byte) channel);
//write the channel as a byte
outputStream.write((byte) Integer.parseInt(pos.substring(7,14), 2));
//split the first 7 bits of the 14 bit string and convert to byte
outputStream.write((byte) Integer.parseInt(pos.substring(0,7), 2));
//split the second 7 bits of the 14 bit string and convert to byte
}catch(Exception e){
System.out.println(e.getMessage());
}
Multiplying position by 20 then adding 6000 to it allows me to feed a value from -100 to +100 which is more meaningful to my brain about servo position.
Then, the binary equivalent of the target value is being split into 2 blocks of 7 bits rather than 2 blocks of 8 bits. (each are being parsed with a leading zero).
I also just realized that I’m flushing the serial line with each issued command. This could be eliminating any problems that would cause the same problem you’re having.
So, got it all working, added the tornado web server to the RPi and some HTML5 and now I can control the Maestro from my Android Tablet using the touch screen! Great fun!
If anyone is interested, I’ve posted the code for the servo controller, the tornado server and the html I’m using: http://martinsant.net/?p=407