Advertisement
Guest User

Untitled

a guest
Aug 30th, 2014
302
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.18 KB | None | 0 0
  1. #!/usr/bin/python
  2. ###########################################################################################
  3. # Filename:
  4. #     Device.py
  5. ###########################################################################################
  6. # Project Authors:
  7. #     Juhapekka Piiroinen
  8. #     Brian Wu
  9. #
  10. # Changes:
  11. #     June 14, 2010 by Juhapekka Piiroinen - changes committed to svn
  12. #           - added comments for the device commands according to the manual from Pololu
  13. #           - added latest draft code for rotating base servo (Parallax Continuous Rotating Servo)
  14. #           - note! you should be able to clear error flags with .get_errors function according to the manual
  15. #           - renamed CameraDriver to LegacyCameraDriver as Brian Wu has done better one
  16. #           - integrated batch of changes provided by Brian Wu
  17. #
  18. #     June 11, 2010 by Brian Wu - Changes committed thru email
  19. #           - Decoupling the implementation from the program
  20. #
  21. #     April 19, 2010 by Juhapekka Piiroinen
  22. #           - Initial Release
  23. #
  24. # Email:
  25. #     juhapekka.piiroinen@gmail.com
  26. #
  27. # License:
  28. #     GNU/GPLv3
  29. #
  30. # Description:
  31. #     A python-wrapper for Pololu Micro Maestro 6-Channel USB Servo Controller
  32. #
  33. ############################################################################################
  34. # /!\ Notes /!\
  35. # You will have to enable _USB Dual Port_ mode from the _Pololu Maestro Control Center_.
  36. #
  37. ############################################################################################
  38. # Device Documentation is available @ http://www.pololu.com/docs/pdf/0J40/maestro.pdf
  39. ############################################################################################
  40. # (C) 2010 Juhapekka Piiroinen
  41. #          Brian Wu
  42. ############################################################################################
  43. import serial
  44. import time
  45.  
  46. from base import log
  47.  
  48.  
  49. class MaestroControl(object):
  50.     def __init__(self,con_port="COM4",ser_port="COM5"): #/dev/ttyACM0  and   /dev/ttyACM1  for Linux
  51.         ############################
  52.         # lets introduce and init the main variables
  53.         self.con = None
  54.         self.ser = None
  55.         self.isInitialized = False
  56.        
  57.         ############################
  58.         # lets connect the TTL Port
  59.         try:
  60.             self.con = serial.Serial(con_port,baudrate=9600)
  61.             #self.con.close()
  62.             #self.con.open()
  63.             log("Link to Command Port -", con_port, "- successful")
  64.  
  65.         except  serial.serialutil.SerialException as e:
  66.             print (e)
  67.             log("Link to Command Port -", con_port, "- failed")
  68.  
  69.         if self.con:
  70.             #####################
  71.             #If your Maestro's serial mode is "UART, detect baud rate", you must first send it the baud rate indication byte 0xAA on
  72.             #the RX line before sending any commands. The 0xAA baud rate indication byte can be the first byte of a Pololu protocol
  73.             #command.
  74.             #http://www.pololu.com/docs/pdf/0J40/maestro.pdf - page 35
  75.             #self.con.write(str.encode(chr(0xAA)))
  76.             #self.con.flush()
  77.             #log("Baud rate indication byte 0xAA sent!")
  78.             pass
  79.        
  80.         ###################################
  81.         # lets connect the TTL Port
  82.         try:
  83.             self.ser = serial.Serial(ser_port)
  84.             self.ser.close()
  85.             self.ser.open()
  86.             log("Link to TTL Port -", ser_port, "- successful")
  87.         except serial.serialutil.SerialException as e:
  88.             print (e)
  89.             log("Link to TTL Port -", ser_port, "- failed!")
  90.        
  91.         self.isInitialized = (self.con!=None and self.ser!=None)
  92.         #if (self.isInitialized):
  93.             #err_flags = self.get_errors()
  94.             #log("Device error flags read (",err_flags,") and cleared")
  95.         log("Device initialized:",self.isInitialized)
  96.  
  97.     ###########################################################################################################################
  98.     ## common write function for handling all write related tasks
  99.     def write(self,*data):
  100.         if not self.isInitialized: log("Not initialized"); return
  101.         if not self.ser.writable():
  102.             log("Device not writable")
  103.             return
  104.         for d in data:
  105.             self.ser.write(str.encode(chr(d)))
  106.         self.ser.flush()
  107.  
  108.     ###########################################################################################################################
  109.     ## Go Home
  110.     # Compact protocol: 0xA2
  111.     # --
  112.     # This command sends all servos and outputs to their home positions, just as if an error had occurred. For servos and
  113.     # outputs set to "Ignore", the position will be unchanged.
  114.     # --
  115.     # Source: http://www.pololu.com/docs/pdf/0J40/maestro.pdf
  116.     def go_home(self):
  117.         if not self.isInitialized: log("Not initialized"); return
  118.         self.write(0xA2)
  119.  
  120.     ###########################################################################################################################
  121.     ## Set Target
  122.     # Compact protocol: 0x84, channel number, target low bits, target high bits
  123.     # --
  124.     # The lower 7 bits of the third data byte represent bits 0-6 of the target (the lower 7 bits), while the lower 7 bits of the
  125.     # fourth data byte represent bits 7-13 of the target. The target is a non-negative integer.
  126.     # --
  127.     # Source: http://www.pololu.com/docs/pdf/0J40/maestro.pdf
  128.     def set_target(self,servo,value):
  129.         if not self.isInitialized: log("Not initialized"); return
  130.         if not self.ser.writable():
  131.             log("Device not writable")
  132.             return
  133.         value = int(value)*4
  134.         log("servo: {} value: {}".format(servo, value))
  135.         commandByte = chr(0x84)
  136.         channelByte = chr(servo)
  137.         lowTargetByte = chr(value & 0x7F)
  138.         highTargetByte = chr((value >> 7) & 0x7F)
  139.  
  140.         command = commandByte + channelByte + lowTargetByte + highTargetByte
  141.         for d in command:
  142.             self.con.write(str.encode(d))
  143.         self.con.flush()
  144.  
  145.     ###########################################################################################################################
  146.     ## Set Speed
  147.     # Compact protocol: 0x87, channel number, speed low bits, speed high bits
  148.     # --
  149.     # This command limits the speed at which a servo channel's output value changes. The speed limit is given in units of (0.25 us)/(10 ms)
  150.     # --
  151.     # For example, the command 0x87, 0x05, 0x0C, 0x01 sets
  152.     # the speed of servo channel 5 to a value of 140, which corresponds to a speed of 3.5 us/ms. What this means is that if
  153.     # you send a Set Target command to adjust the target from, say, 1000 us to 1350 us, it will take 100 ms to make that
  154.     # adjustment. A speed of 0 makes the speed unlimited, so that setting the target will immediately affect the position. Note
  155.     # that the actual speed at which your servo moves is also limited by the design of the servo itself, the supply voltage, and
  156.     # mechanical loads; this parameter will not help your servo go faster than what it is physically capable of.
  157.     # --
  158.     # At the minimum speed setting of 1, the servo output takes 40 seconds to move from 1 to 2 ms.
  159.     # The speed setting has no effect on channels configured as inputs or digital outputs.
  160.     # --
  161.     # Source: http://www.pololu.com/docs/pdf/0J40/maestro.pdf
  162.     def set_speed(self,servo,speed):
  163.         if not self.isInitialized: log("Not initialized"); return
  164.         highbits,lowbits = divmod(speed,32)
  165.         self.write(0x87,servo,lowbits << 2,highbits)
  166.  
  167.     ###########################################################################################################################
  168.     ## Set Acceleration
  169.     # Compact protocol: 0x89, channel number, acceleration low bits, acceleration high bits
  170.     # --
  171.     # This command limits the acceleration of a servo channel's output. The acceleration limit is a value from 0 to 255 in units of (0.25 us)/(10 ms)/(80 ms),
  172.     # --
  173.     # A value of 0 corresponds to no acceleration limit. An acceleration limit causes the speed of a servo to slowly ramp up until it reaches the maximum speed, then
  174.     # to ramp down again as position approaches target, resulting in a relatively smooth motion from one point to another.
  175.     # With acceleration and speed limits, only a few target settings are required to make natural-looking motions that would
  176.     # otherwise be quite complicated to produce.
  177.     # --
  178.     # At the minimum acceleration setting of 1, the servo output takes about 3 seconds to move smoothly from a target of 1 ms to a target of 2 ms.
  179.     # The acceleration setting has no effect on channels configured as inputs or digital outputs.
  180.     # --
  181.     # Source: http://www.pololu.com/docs/pdf/0J40/maestro.pdf
  182.     def set_acceleration(self,servo,acceleration):
  183.         if not self.isInitialized: log("Not initialized"); return
  184.         highbits,lowbits = divmod(acceleration,32)
  185.         self.write(0x89,servo,lowbits << 2,highbits)
  186.  
  187.     ###########################################################################################################################
  188.     ## Get Position
  189.     # Compact protocol: 0x90, channel number
  190.     # Response: position low 8 bits, position high 8 bits
  191.     # --
  192.     # This command allows the device communicating with the Maestro to get the position value of a channel. The position
  193.     # is sent as a two-byte response immediately after the command is received.
  194.     # --
  195.     # If the specified channel is configured as a servo, this position value represents the current pulse width that the Maestro
  196.     # is transmitting on the channel, reflecting the effects of any previous commands, speed and acceleration limits, or scripts
  197.     # running on the Maestro.
  198.     # --
  199.     # If the channel is configured as a digital output, a position value less than 6000 means the Maestro is driving the line low,
  200.     # while a position value of 6000 or greater means the Maestro is driving the line high.
  201.     # --
  202.     # If the channel is configured as an input, the position represents the voltage measured on the channel. The inputs on
  203.     # channels 0-11 are analog: their values range from 0 to 1023, representing voltages from 0 to 5 V. The inputs on channels
  204.     # 12-23 are digital: their values are either exactly 0 or exactly 1023.
  205.     # --
  206.     # Note that the formatting of the position in this command differs from the target/speed/acceleration formatting in the
  207.     # other commands. Since there is no restriction on the high bit, the position is formatted as a standard little-endian two-
  208.     # byte unsigned integer. For example, a position of 2567 corresponds to a response 0x07, 0x0A.
  209.     # --
  210.     # Note that the position value returned by this command is equal to four times the number displayed in the Position box
  211.     # in the Status tab of the Maestro Control Center.
  212.     # --
  213.     # Source: http://www.pololu.com/docs/pdf/0J40/maestro.pdf
  214.     def get_position(self,servo):
  215.         if not self.isInitialized: log("Not initialized"); return None
  216.         self.write(0x90,servo)
  217.         data = self.ser.read(2)
  218.         if data:    
  219.             return data #(ord(data[0])+(ord(data[1])<<8))/4
  220.                         #commented out "ORD": bytes objects in Python 3 are already treated as arrays as integers so the extra conversion using ord() isn't needed
  221.         else:
  222.             return None
  223.  
  224.     ###########################################################################################################################    
  225.     ## Get Moving State
  226.     # Compact protocol: 0x93
  227.     # Response: 0x00 if no servos are moving, 0x01 if servos are moving
  228.     # --
  229.     # This command is used to determine whether the servo outputs have reached their targets or are still changing, limited
  230.     # by speed or acceleration settings. Using this command together with the Set Target command, you can initiate several
  231.     # servo movements and wait for all the movements to finish before moving on to the next step of your program.
  232.     # --
  233.     # Source: http://www.pololu.com/docs/pdf/0J40/maestro.pdf
  234.     def get_moving_state(self):
  235.         if not self.isInitialized: log("Not initialized"); return None
  236.         self.write(0x93)
  237.         data = self.ser.read(1)
  238.         if data:
  239.             return data #ord(data[0])
  240.                         #commented out "ORD": bytes objects in Python 3 are already treated as arrays as integers so the extra conversion using ord() isn't needed
  241.         else:
  242.             return None
  243.  
  244.     ###########################################################################################################################    
  245.     ## Get Errors
  246.     # Compact protocol: 0xA1
  247.     # --
  248.     # Response: error bits 0-7, error bits 8-15
  249.     # --
  250.     # Use this command to examine the errors that the Maestro has detected.
  251.     # --
  252.     # The error register is sent as a two-byte response immediately after the command is received,
  253.     # then all the error bits are cleared. For most applications using serial control, it is a good idea to check errors continuously
  254.     # and take appropriate action if errors occur.
  255.     # --
  256.     # Source: http://www.pololu.com/docs/pdf/0J40/maestro.pdf
  257.     def get_errors(self):
  258.         if not self.isInitialized: log("Not initialized"); return None
  259.         self.write(0xA1)
  260.         data = self.ser.read(2)
  261.         if data:
  262.             return data #ord(data[0])+(ord(data[1])<<8)
  263.                         #commented out "ORD": bytes objects in Python 3 are already treated as arrays as integers so the extra conversion using ord() isn't needed
  264.         else:
  265.             return None
  266.  
  267.     ###########################################################################################################################
  268.     ## a helper function for Set Target
  269.     def wait_until_at_target(self):
  270.         while (self.get_moving_state()):
  271.             time.sleep(0.1)
  272.  
  273.     ###########################################################################################################################
  274.     ## Lets close and clean when we are done
  275.     def __del__(self):
  276.         if (self.ser):
  277.             self.ser.close()
  278.         if (self.con):
  279.             self.con.close()
  280.         del(self.ser)
  281.         del(self.con)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement