1010import time
1111from typing import List
1212from typing import Union
13+ import csv
14+ import os
1315
1416from pslab .instrument .waveform_generator import PWMGenerator
17+ from datetime import datetime
1518
1619MICROSECONDS = 1e6
1720
@@ -96,7 +99,7 @@ def run_schedule(self, timeline: List[List[int]], time_step: float = 1.0) -> Non
9699 with angles corresponding to each servo.
97100
98101 time_step : float, optional
99- Delay in seconds between each timestep. Default is 1.0.
102+ Delay in seconds between each timestep. Default is 1.0.
100103 """
101104 if len (timeline [0 ]) != len (self .servos ):
102105 raise ValueError ("Each timestep must specify an angle for every servo" )
@@ -107,5 +110,60 @@ def run_schedule(self, timeline: List[List[int]], time_step: float = 1.0) -> Non
107110
108111 for tl in timeline :
109112 for i , s in enumerate (self .servos ):
110- s .angle = tl [i ]
113+ if tl [i ] is not None :
114+ s .angle = tl [i ]
111115 time .sleep (time_step )
116+
117+ def import_timeline_from_csv (self , filepath : str ) -> List [List [int ]]:
118+ """Import timeline from a CSV file.
119+
120+ Parameters
121+ ----------
122+ filepath : str
123+ Absolute or relative path to the CSV file to be read.
124+
125+ Returns
126+ -------
127+ List[List[int]]
128+ A timeline consisting of servo angle values per timestep.
129+ """
130+ timeline = []
131+
132+ with open (filepath , mode = "r" , newline = "" ) as csvfile :
133+ reader = csv .DictReader (csvfile )
134+ for row in reader :
135+ angles = []
136+ for key in ["Servo1" , "Servo2" , "Servo3" , "Servo4" ]:
137+ value = row .get (key , "" ).strip ().lower ()
138+ if value in ("" , "null" , "none" ):
139+ angles .append (None )
140+ else :
141+ angles .append (int (value ))
142+ timeline .append (angles )
143+
144+ return timeline
145+
146+ def export_timeline_to_csv (
147+ self , timeline : List [List [Union [int , None ]]], folderpath : str
148+ ) -> None :
149+ """Export timeline to a CSV file.
150+
151+ Parameters
152+ ----------
153+ timeline : List[List[Union[int, None]]]
154+ A list of timesteps where each sublist contains servo angles.
155+
156+ folderpath : str
157+ Directory path where the CSV file will be saved. The filename
158+ will include a timestamp to ensure uniqueness.
159+ """
160+ timestamp = datetime .now ().strftime ("%Y-%m-%d_%H-%M-%S" )
161+ filename = f"Robotic_Arm{ timestamp } .csv"
162+ filepath = os .path .join (folderpath , filename )
163+
164+ with open (filepath , mode = "w" , newline = "" ) as csvfile :
165+ writer = csv .writer (csvfile )
166+ writer .writerow (["Timestamp" , "Servo1" , "Servo2" , "Servo3" , "Servo4" ])
167+ for i , row in enumerate (timeline ):
168+ pos = ["null" if val is None else val for val in row ]
169+ writer .writerow ([i ] + pos )
0 commit comments