Guest User

Untitled

a guest
Mar 11th, 2023
29
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.43 KB | None | 0 0
  1. import sys # We need sys so that we can pass argv to QApplication
  2. import asyncio
  3. from uio.ti.icss import Icss
  4. from uio.ti.pwmss import Pwmss
  5. from ctypes import c_uint32 as uint32, c_uint8 as uint8, c_uint16 as uint16, c_uint64 as uint64, c_char as char, c_int32 as int32, c_bool as boolean, Structure
  6. from ctypes import sizeof as c_sizeof
  7. from pathlib import Path
  8. from time import sleep
  9. import numpy as np
  10.  
  11.  
  12. pruss = Icss( "/dev/uio/pruss/module" )
  13. core_1 = pruss.core1
  14. frequency= 10000
  15. period = None
  16. divider = 1
  17. position = None
  18. weight = None
  19. pruvars = None
  20. top_motor_speed = period
  21. current_motor_speed = None
  22. maxloadposition = None
  23. minloadposition = None
  24. last_timestamp_cycles = 0
  25. stepper_step = None
  26. stepper_direction = None
  27. server1 = None
  28. server2 = None
  29. coro1 = None
  30. coro2 = None
  31. data_queue = None
  32. active_run = None
  33. shut_down = None
  34. NUM_MSGS = None
  35. ddr_layout = None
  36. shmem = None
  37. msgbuf = None
  38. ddr_widx = None
  39. ddr_layout = None
  40. rdix = 0
  41. wdix = 0
  42. lastid = 0
  43. timestamp_cycles = 0
  44. last_encoder_count = uint32(0)
  45. last_encoder_angle = 0
  46. encoder_count = uint32(0)
  47. encoder_angle = 0
  48. tare_coeff = None
  49. emi_coeff = None
  50. val_stream = None
  51. line_count = 0
  52. pruss.initialize()
  53. period = round( 100e6 / divider / frequency )
  54. top_motor_speed = period
  55. pruss.uart.initialize(baudrate = 460800)
  56. magnet = Pwmss( "/dev/uio/pwmss1" ).pwm
  57. magnet.initialize(period,divider)
  58. current_magnet_speed = 0
  59. magnet_direction = Gpio('magnet_dir')
  60. magnet_direction.set_value( 0 )
  61. data_queue = asyncio.Queue()
  62. stop_active_run = False
  63. shut_down = False
  64. ddr = pruss.ddr
  65.  
  66. # used to communicate ddr layout to C program
  67. class DDRLayout( Structure ):
  68. _fields_ = [
  69. ( 'msgbuf', uint32 ),
  70. ( 'num_msgs', uint16 ),
  71. ( 'msg_size', uint16 ),
  72. ]
  73.  
  74. # volatile variables in pruss shared memory
  75. class SharedVars( Structure ):
  76. _fields_ = [
  77. ( 'abort_file', uint32 ),
  78. ( 'abort_line', uint32 ),
  79. ( 'ridx', uint16 ),
  80. ( 'cycle_limit', uint16),
  81. ( 'time_limit', uint16),
  82. ( 'signal_length', uint16),
  83. ( 'signal', uint16*2000)
  84. ]
  85.  
  86. class Message( ctypes.Structure ):
  87. _fields_ = [
  88. ( 'id', uint32 ),
  89. ('timestamp', uint32),
  90. ('position', uint32),
  91. ('control_signal', int32),
  92. ('motor_effort', int32),
  93. ('force', int16),
  94. ('padding', int16)
  95. ]
  96.  
  97. class Gpio:
  98. def __init__( self, name ):
  99. self.name = name
  100. self._value_path = Path( '/dev/gpio', name, 'value' )
  101.  
  102. def get_value( self ):
  103. return int( self._value_path.read_text() )
  104.  
  105. def set_value( self, value ):
  106. self._value_path.write_text( str( value ) )
  107.  
  108.  
  109. def check_core(self):
  110. if not self.core_1.halted:
  111. return
  112. if self.core_1.state.crashed:
  113. msg = f'core crashed at pc={self.core_1.pc}'
  114. elif self.shmem.abort_file == 0:
  115. msg = f'core halted at pc={self.core_1.pc}'
  116. else:
  117. # FIXME figure out better way to read C-string from PRU memory
  118. abort_file = self.core_1.read( char * 32, self.shmem.abort_file ).value
  119. abort_file = abort_file.decode("ascii")
  120. msg = f'core aborted at pc={self.core_1.pc} ({abort_file}:{self.shmem.abort_line})'
  121. # dump some potentially interesting information:
  122. msg += f'\n ridx = {self.ridx}'
  123. msg += f'\n shmem.ridx = {self.shmem.ridx}'
  124. msg += f'\n ddr_widx = {self.ddr_widx.value}'
  125. exit( msg )
  126. astid = 0
  127.  
  128. def recv_messages():
  129. # read updated write-pointer
  130. widx = ddr_widx.value
  131. assert widx < NUM_MSGS # sanity-check
  132.  
  133. if widx == self.ridx:
  134. return # nothing to do
  135.  
  136. txdata = ''
  137.  
  138. # process batch of messages
  139.  
  140. # note: it may be faster to copy a batch of messages from shared memory
  141. # instead of directly accessing individual messages and their fields.
  142. while ridx != widx:
  143. msg = msgbuf[ self.ridx ]
  144.  
  145. # sanity-check that message id increments monotonically
  146. # (i.e. no messages from pru got dropped)
  147. dropped = ( msg.id - lastid - 1 ) & 0xffffffff
  148. if dropped != 0:
  149. raise RuntimeError( f'{dropped} messages dropped by PRU (0x{self.lastid:08x} -> 0x{msg.id:08x})' )
  150. lastid = msg.id
  151.  
  152. # get 32-bit timestamp (in cycles) from message and unwrap it:
  153. timestamp_cycles += ( msg.timestamp - timestamp_cycles ) & 0xfffffff
  154.  
  155. # convert to timestamp in seconds
  156.  
  157. force = int(msg.force )
  158. timestamp_ms = timestamp_cycles // 200000
  159. timestamp_s = ( timestamp_ms % 60000 ) / 1000
  160. timestamp_m = timestamp_ms // 60000
  161. timestamp_h = timestamp_m // 60
  162. timestamp_m = timestamp_m % 60
  163. timestamp_label = f'{timestamp_h:02d}:{timestamp_m:02d}:{timestamp_s:06.3f}'
  164. time = timestamp_s + timestamp_m*60 + timestamp_h *360
  165. txmsg = [time, timestamp_label, force, angle]
  166. txdata += ','.join(map( str, txmsg )) + '\n'
  167. # or just: txdata += f'{self.timestamp_cycles},{force},{angle}\n'
  168.  
  169. # consume message and update read pointer
  170. ridx += 1
  171. if (ridx == NUM_MSGS):
  172. ridx = 0
  173. del msg
  174. shmem.ridx = ridx # direct access to message forbidden beyond this point
  175.  
  176. # send data to client
  177. writer.write( txdata.encode('ascii') )
  178.  
  179. # TODO maybe bail out with an error if too much data buffered in the writer?
  180. # you can check with writer.get_write_buffer_size()
  181.  
  182. print( f'\ridx=0x{self.ridx:04x} id=0x{self.lastid:08x} time={timestamp_label} angle={angle:5.2f} position= {position:08d} force={force:08d}', end='', flush=True )
  183.  
  184. core_1.load('pid_control.out')
  185. # if you don't want the ringbuffer at the start of the ddr region, specify offset here
  186. MSGBUF_OFFSET = 0
  187. # you can use a fixed ringbuffer size:
  188. #NUM_MSGS = 1024
  189. # or you can scale the ringbuffer to fit the size of the ddr region:
  190. NUM_MSGS = (ddr.size - MSGBUF_OFFSET - c_sizeof( uint16 ) ) // c_sizeof( Message )
  191. NUM_MSGS = min( NUM_MSGS, 65535 ) # make sure number of messages fits in u16
  192. # map shared memory variables
  193. ddr_layout = core_1.map( DDRLayout, 0x10000 )
  194. shmem = core_1.map( SharedVars, 0x10100 )
  195. msgbuf = ddr.map( Message * NUM_MSGS, MSGBUF_OFFSET )
  196. ddr_widx = ddr.map( uint16, MSGBUF_OFFSET + c_sizeof( msgbuf ) )
  197. # inform pru about layout of shared ddr memory region
  198. ddr_layout.msgbuf = ddr.address + MSGBUF_OFFSET
  199. ddr_layout.num_msgs = NUM_MSGS
  200. ddr_layout.msg_size = c_sizeof( Message )
  201.  
  202. # local copies of read-pointer and write-pointer
  203. ridx = 0
  204. widx = 0
  205.  
  206. # initialize pointers in shared memory
  207. shmem.ridx = ridx
  208. ddr_widx.value = widx
  209.  
  210.  
  211. #loading wave profile
  212. with open('./under_double_hump.csv','r') as f:
  213. signal_reader = csv.reader(f)
  214. for line in signal_reader:
  215. shmem.signal[line_count] = int(line[0])
  216. line_count += 1
  217. print(f' Loaded {line_count} lines in the file')
  218.  
  219. #open file for writing
  220. data_file = open('run_data.csv', 'w', newline='')
  221. writer = csv.writer(data_file)
  222. header = ['timestamp', 'force_g', 'voltage','signal']
  223. writer.writerow(header)
  224. # ready, set, go!
  225.  
  226. print('lauching core 1')
  227. pruss.ecap.pwm.initialize( 2**32 )
  228. core_1.run()
  229. sleep(.00001)
  230. try:
  231. while (self.stop_active_run == False and self.shut_down == False):
  232. recv_messages()
  233. check_core()
  234. sleep(0)
  235.  
  236. except KeyboardInterrupt:
  237. pass
  238.  
  239. finally:
  240. print( '', flush=True )
  241. _StopEM100()
  242. core_1.halt()
  243.  
  244.  
  245.  
Add Comment
Please, Sign In to add comment