Advertisement
Guest User

Untitled

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