Re-evaluating a string?

John Machin sjmachin at lexicon.net
Sun Jul 23 22:08:42 EDT 2006


bugnthecode wrote:
> Thanks Tim, and John for your quick responses!
>
> Tim, I tested your function and it works!
> Though I don't completely
> understand how. Could you possibly explain this?
>
> John, I test your "MEDUIM_WAY"and it works as well.

Now try the struct module approach.

Are you 100% certain that the servo position can't be negative? What
would you do if it could be negative?

> How is it that
> putting the string together this way translates into a hex value to be
> transmitted to the serial port?

Like I tried to tell you before, there is no such thing as transmitting
a hex value. You are transmitting 8-bit bytes, one bit at a time. The
number 6 might be transmitted as 00000110 or 01100000 (the latter, IIRC
-- it's been a while). The number 6 can be represented in a computer
program as 6 or 0x6. As your write() function expects a string, you
need to represent it in your program as a string e.g. '\x06' or chr(6)
or "%c" % 6.

Read about chr() in the  manual:
http://docs.python.org/lib/built-in-funcs.html

Read about string formatting in the manual:
http://docs.python.org/lib/typesseq-strings.html

> When I manually tried to put a string
> together I couldn't get this to happen. I was trying:
>
> controlString = '!SC' + '\\' + ch.__str__() + '\\' + rate.__str__()
> ...etc

Ugh. FWIW, use str(foo) instead of foo.__str__()

>
> also I noticed you added another line to the code which appears to
> split the low and high bytes for me? If so thanks! Could you also offer
> an explanation on how this works. I tried a google search and couldn't
> get a decent explanation.

I presume you mean
    vhi, vlo = divmod(value, 256)
What did you search for?
If you are on Windows:
    do(click on Start, hover on All Programs, hover on Python 2.4,
click on Python Manuals, type in divmod, press Enter key twice)
else:
    deduce that divmod can only be a built-in function (I didn't
declare it, did I?)
    read web docs on built-in functions
(http://docs.python.org/lib/built-in-funcs.html)

> I implemented this a little differently as
> you can see in my Position class. Could you possibly offer any info on
> the benefits/drawbacks of the different methods?

No great difference. Better than both is to use the struct module.

>
> Thanks again to both of you for your quick responses and help.
>
> Will
>
> import serial
> import types
>
> class Position:

It is extreme overkill, IMHO, to use a class for this trivium.


>     def __init__(self, num):
>         """Takes the position as an int, and splits the low and high
> bytes
>
>         into instance members."""
>         self.lowByte = num & 0x00FF
>         self.highByte = (num & 0xFF00) >> 8

If you are sure that 0 <= num <= 0xFFFF, then you don't need the 0xFF00
mask. If you are unsure, then don't just silently transmit what may
well be rubbish; check, or use an assertion:
    assert 0 <= num <= 0xFFFF

>
>     def __str__(self):
>         """Mainly for debugging purposes. Allows meaningful output when
> printed"""

FFS. Use the repr() built-in, like I suggested.

>         return 'Low: ' + self.lowByte.__str__() + '\nHigh: ' +
> self.highByte.__str__()
>
> def makeString(a):
>     """Takes in  a list, and intelligentlly smashes everything
> together.
>
>     Outputs everything as a hex string.

No it doesn't.

>     Posted by: Tim Chase on comp.lang.python"""
>     return ''.join([type(x) != types.IntType and
>     str(x) or chr(x) for x in a])
>
> def getVer(localpsc):
>     """Gets the version from the PSC. Mainly just to verify a
> connection"""
>
>     localpsc.write('!SCVER?\r')
>     localpsc.read(8) #Discard the echo!
>     s = localpsc.read(3)
>     print s
>
> def moveServo(localpsc, ch, rate, position):
>     """Takes in a serial object, the desired channel, the ramp rate,
> and
>     the desired position of ther servo. Moves the servo to the desired
> postion."""
>
>     #localpsc.write('!SC', ch, rate, position.low, position.high, '\r')
>     #controlString = makeString(['!SC', ch, rate, position.lowByte,
> position.highByte, '\r'])
>     #localpsc.write(controlString)
>     #localpsc.flushInput() #discard the echo!
>
>     """Following line from John Machin"""
>     controlString = "!SC%c%c%c%c\r" % (ch, rate, position.lowByte,
> position.highByte)
>     localpsc.write(controlString)
>
> psc = serial.Serial(1, 2400)
>
> mypos = Position(2500)
>
> moveServo(psc, 0, 5, mypos)
> psc.close()

import struct
DEBUG = True

def moveServo(localpsc, ch, rate, position):
    """Takes in a serial object, the desired channel, the ramp rate,
and
        the desired position of the servo. Moves the servo to the
desired
        position."""
    assert 0 <= ch <= 255 # or tighter bounds from manuf's spec
    assert 0 <= rate <= 255
    assert 0 <= position <= 65535 # aka 0xFFFF
    cmd = "!SC" + struct.pack("<BBH", ch, rate, position) + "\r"
    if DEBUG:
        print "moveServo:", repr(cmd)
    localpsc.write(cmd)

It's that simple. If you are ever going to do more than this one
script, it will pay to investigate the struct module. Python has
"batteries included". You don't need to find a lead mine and look up
"sal ammoniac" in your grandparents' encyclopedia :-)

Cheers,
John




More information about the Python-list mailing list