Advertisement
Guest User

Untitled

a guest
Mar 11th, 2023
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.07 KB | None | 0 0
  1. #!/usr/bin/python3
  2. from pathlib import Path
  3. from uio.utils import fix_ctypes_struct
  4. from uio.ti.icss import Icss
  5. from uio.ti.pwmss import Pwmss
  6. import ctypes
  7. from ctypes import c_uint32 as uint32, c_uint16 as uint16, c_int32 as int32, c_int16 as int16, c_int8 as int8
  8. from time import sleep
  9. from sys import exit
  10. import numpy as np
  11. import csv
  12.  
  13. class Gpio:
  14. def __init__( self, name ):
  15. self.name = name
  16. self._value_path = Path( '/dev/gpio', name, 'value' )
  17.  
  18. def get_value( self ):
  19. return int( self._value_path.read_text() )
  20.  
  21. def set_value( self, value ):
  22. self._value_path.write_text( str( value ) )
  23.  
  24. class Pru0_Poll_Vars( ctypes.Structure ):
  25. _fields_ = [
  26. ("position", uint32),
  27. ]
  28.  
  29. class Message( ctypes.Structure ):
  30. _fields_ = [
  31. ( 'id', uint32 ),
  32. ('timestamp', uint32),
  33. ('position', uint32),
  34. ('control_signal', int32),
  35. ('counter', uint32),
  36. ('force', int16),
  37. ('motor_effort', int16)
  38. ]
  39.  
  40. # used to communicate ddr layout to C program
  41. class DDRLayout( ctypes.Structure ):
  42. _fields_ = [
  43. ( 'msgbuf', uint32 ),
  44. ( 'num_msgs', uint16 ),
  45. ( 'msg_size', uint16 ),
  46. ]
  47.  
  48. # volatile variables in pruss shared memory
  49. class SharedVars( ctypes.Structure ):
  50. _fields_ = [
  51. ( 'abort_file', uint32 ),
  52. ( 'abort_line', uint32 ),
  53. ( 'ridx', uint16 ),
  54. ( 'signal', uint16*1000),
  55. ]
  56.  
  57. data_file = open('control_data.csv', 'w', newline='')
  58. writer = csv.writer(data_file)
  59. header = ['timestamp', 'motor_input','position', 'motor_effort']
  60. writer.writerow(header)
  61. pruss = Icss( "/dev/uio/pruss/module" )
  62. pruss.initialize()
  63. ddr = pruss.ddr
  64. pruss.uart.initialize(baudrate = 460800)
  65. frequency= 10000
  66. divider = 1
  67. period = round( 100e6 / divider / frequency )
  68. motor = Pwmss( "/dev/uio/pwmss1" ).pwm
  69. motor.initialize(period,divider)
  70. motor_direction = Gpio('motor_dir')
  71. core_1 = pruss.core1
  72. core_1.load( 'fw-c/pid_control.out' )
  73.  
  74. core_0 = pruss.core0
  75. core_0.load( 'fw/decoder.bin' )
  76. pru0_vars = pruss.dram0.map( Pru0_Poll_Vars )
  77.  
  78. # if you don't want the ringbuffer at the start of the ddr region, specify offset here
  79. MSGBUF_OFFSET = 0
  80.  
  81. # you can use a fixed ringbuffer size:
  82. #NUM_MSGS = 1024
  83. # or you can scale the ringbuffer to fit the size of the ddr region:
  84. NUM_MSGS = ( ddr.size - MSGBUF_OFFSET - ctypes.sizeof( uint16 ) ) // ctypes.sizeof( Message )
  85. NUM_MSGS = min( NUM_MSGS, 65535 ) # make sure number of messages fits in u16
  86.  
  87. # map shared memory variables
  88. ddr_layout = core_1.map( DDRLayout, 0x10000 )
  89. shmem = core_1.map( SharedVars, 0x10100 )
  90. msgbuf = ddr.map( Message * NUM_MSGS, MSGBUF_OFFSET )
  91. ddr_widx = ddr.map( uint16, MSGBUF_OFFSET + ctypes.sizeof( msgbuf ) )
  92.  
  93. # inform pru about layout of shared ddr memory region
  94. ddr_layout.msgbuf = ddr.address + MSGBUF_OFFSET
  95. ddr_layout.num_msgs = NUM_MSGS
  96. ddr_layout.msg_size = ctypes.sizeof( Message )
  97.  
  98. # local copies of read-pointer and write-pointer
  99. ridx = 0
  100. widx = 0
  101. id_value = 0
  102. timestamp_cycles = 0
  103.  
  104.  
  105. # initialize pointers in shared memory
  106. shmem.ridx = ridx
  107. ddr_widx.value = widx
  108.  
  109. line_count = 0
  110. with open('./double_hump_profile.csv','r') as f:
  111. signal_reader = csv.reader(f)
  112. for line in signal_reader:
  113. shmem.signal[line_count] = int(line[0])
  114. line_count += 1
  115.  
  116. print(f' Loaded {line_count} lines in the file')
  117.  
  118. # ready, set, go!
  119. pruss.ecap.pwm.initialize( 2**32 )
  120. core_0.run()
  121. pru0_vars.position = 0
  122. core_1.run()
  123.  
  124. def check_core():
  125. if not core_1.halted:
  126. return
  127.  
  128. if core_1.state.crashed:
  129. msg = f'core crashed at pc={core_1.pc}'
  130. elif shmem.abort_file == 0:
  131. msg = f'core halted at pc={core_1.pc}'
  132. else:
  133. # FIXME figure out better way to read C-string from PRU memory
  134. abort_file = core_1.read( ctypes.c_char * 32, shmem.abort_file ).value
  135. abort_file = abort_file.decode("ascii")
  136. msg = f'core aborted at pc={core_1.pc} ({abort_file}:{shmem.abort_line})'
  137.  
  138. # dump some potentially interesting information:
  139. msg += f'\n ridx = {ridx}'
  140. msg += f'\n shmem.ridx = {shmem.ridx}'
  141. msg += f'\n ddr_widx = {ddr_widx.value}'
  142.  
  143. exit( msg )
  144.  
  145. lastid = 0
  146.  
  147. def recv_messages():
  148. global ridx, widx, lastid, timestamp_cycles
  149.  
  150. # read updated write-pointer
  151. widx = ddr_widx.value
  152. assert widx < NUM_MSGS # sanity-check
  153.  
  154. if ridx == widx:
  155. return # no messages received
  156.  
  157. # process messages
  158. while ridx != widx:
  159. # note: it may be faster to copy a batch of messages from shared memory
  160. # instead of directly accessing individual messages and their fields.
  161. msg = msgbuf[ ridx ]
  162.  
  163. # sanity-check that message id increments monotonically
  164. lastid = ( lastid + 1 ) & 0xffffffff
  165. assert msg.id == lastid
  166.  
  167. # get 32-bit timestamp (in cycles) from message and unwrap it:
  168. timestamp_cycles += ( msg.timestamp - timestamp_cycles ) & 0xffffffff
  169.  
  170. # process rest of message
  171. position = msg.position
  172. force = msg.force
  173. motor_input = msg.control_signal
  174. motor_effort = msg.motor_effort
  175. counter = msg.counter
  176. if (motor_effort > 0):
  177. motor_direction.set_value( 0 )
  178. else:
  179. motor_direction.set_value( 1 )
  180.  
  181. # consume message and update read pointer
  182. del msg # direct access to message forbidden beyond this point
  183. ridx += 1
  184. if ridx == NUM_MSGS:
  185. ridx = 0
  186. shmem.ridx = ridx
  187.  
  188. # update user interface
  189. ts_ms = timestamp_cycles // 200000
  190. ts_s = ( ts_ms % 60000 ) / 1000
  191. ts_m = ts_ms // 60000
  192. ts_h = ts_m // 60
  193. ts_m = ts_m % 60
  194. test = timestamp_cycles *-1
  195. test2 = timestamp_cycles // 200000
  196. data = [f'{ts_m:02d}:{ts_s:06.3f}', f'{motor_input:+09d}',f'{position:+09d}', f'{motor_effort:+09d}', f'{counter:+05d}']
  197. writer.writerow(data)
  198. print(f'\rtime={ts_h:02d}:{ts_m:02d}:{ts_s:06.3f} position={position:08d} force={force:08d} signal = {motor_input:+09d} effort = {motor_effort:+09d}', end='', flush = True )
  199.  
  200. try:
  201. while True:
  202. recv_messages()
  203. check_core()
  204. sleep( 0.01 )
  205.  
  206. except KeyboardInterrupt:
  207. pass
  208.  
  209. finally:
  210. print( '', flush=True )
  211. core_0.halt()
  212. core_1.halt()
  213. pruss.uart.io.write( b'FFV\r', discard=True, flush=True ) # interrupt continuous transmission
  214. sleep( 0.01 ) # make sure that response has been received
  215. pruss.uart.io.discard() # discard response
  216.  
  217.  
  218. control_signal += A[0] * error[0] + A[1] * error[1] + A[2] * error[2];
  219.  
  220. if( control_signal < 0 ) {
  221. if( control_signal < -(4000 << 16) )
  222. control_signal = -(4000 << 16);
  223. EPWM1A = (-control_signal) >> 16;
  224. gpio_set_one_low( &GPIO0, 31 );
  225. } else {
  226. if( control_signal > (4000 << 16) )
  227. control_signal = (4000 << 16);
  228. EPWM1A = control_signal >> 16;
  229. gpio_set_one_high( &GPIO0, 31 );
  230. }
  231.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement