From 56f3ec11e256ca6eafaa59b3d54fcf48a65b5c3c Mon Sep 17 00:00:00 2001 From: j0ndough Date: Sat, 20 Jul 2024 14:35:26 -0700 Subject: [PATCH 1/4] revert to serial, add script to test serial --- lightstrip.py | 86 ++++++++++++----------------------------- main.py | 3 +- main_loop.py | 3 +- patterns.py | 48 +++++++++++++---------- serial_loop.py | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ test_serial.sh | 7 ++++ 6 files changed, 165 insertions(+), 85 deletions(-) create mode 100644 serial_loop.py create mode 100644 test_serial.sh diff --git a/lightstrip.py b/lightstrip.py index 49a6712..37c3320 100644 --- a/lightstrip.py +++ b/lightstrip.py @@ -3,32 +3,14 @@ # Serial Data Modes modes = { - "READY_WITHOUT_NOTE": "1", + "AMP_SIGNAL": "1", "READY_TO_SHOOT": "2", "ROBOT_CONTAINS_NOTE": "3", - "CENTER_CAM_SEES_NOTE": "4", - "SIDE_CAM_SEES_NOTE": "7", - "PURELY_ENABLED": "5", # None of modes 1-4 are active - "ALL_CAMS_WORKING_DEFAULT": "8", - "NO_CAMS_WORKING_DEFEAULT": "9", - "SOME_CAMS_WORKING_DEFAULT": "10", - "ALL_CAMS_WORKING_CUSTOM": "11", - "NO_CAMS_WORKING_CUSTOM": "12", - "SOME_CAMS_WORKING_CUSTOM": "13", - "ROBOT_NOCODE": "15" -} - -colors = { - "GREEN": (0, 255, 0), - "CYAN": (0, 255, 255), - "ORANGE": (255, 140, 0), - "YELLOW": (255, 255, 0), - "HOT_PINK": (255, 105, 180), - "PURPLE": (160, 32, 240), - "BLUE": (0, 0, 255), - "WHITE": (255, 255, 255), - "RED": (255, 0, 0), - "NO_COLOR": (0, 0, 0) + "VISION_SEES_NOTE": "4", + "DISABLED_WITHOUT_AUTO": "32", + "DISABLED_WITH_AUTO": "33", + "PURELY_ENABLED": "34", # None of modes 1-4 are active + "ROBOT_NOCODE": "31" } @@ -60,54 +42,34 @@ def assign_mode(self, current_mode: str, last_mode: str): self.pattern_starting_loop = patterns.loopcount # Update color and pattern on light to display - if current_mode == modes["READY_TO_SHOOT"]: + if current_mode == modes["AMP_SIGNAL"]: + self.pattern_function = patterns.rainbow + + elif current_mode == modes["READY_TO_SHOOT"]: # Ready to shoot, railgun pattern (requested by drivers) - self.primary = colors["GREEN"] + self.primary = (0, 255, 0) self.pattern_function = patterns.railgun - elif current_mode == modes["READY_WITHOUT_NOTE"]: - self.primary = colors["GREEN"] - self.pattern_function = patterns.static - elif current_mode == modes["ROBOT_CONTAINS_NOTE"]: - self.primary = colors["ORANGE"] + self.primary = (255, 165, 0) self.pattern_function = patterns.static - elif current_mode == modes["CENTER_CAM_SEES_NOTE"]: - self.primary = colors["YELLOW"] - self.pattern_function = patterns.wavy - - elif current_mode == modes["SIDE_CAM_SEES_NOTE"]: - self.primary = colors["YELLOW"] - self.pattern_function = patterns.breathing - - elif current_mode == modes["ALL_CAMS_WORKING_DEFAULT"]: - self.primary = colors["PURPLE"] - self.pattern_function = patterns.static - - elif current_mode == modes["SOME_CAMS_WORKING_DEFAULT"]: - self.primary = colors["PURPLE"] - self.pattern_function = patterns.wavy - - elif current_mode == modes["NO_CAMS_WORKING_DEFEAULT"]: - self.primary == colors["PURPLE"] - self.pattern_function = patterns.breathing - - elif current_mode == modes["ALL_CAMS_WORKING_CUSTOM"]: - self.primary == colors["HOT_PINK"] - self.pattern_function = patterns.static + elif current_mode == modes["VISION_SEES_NOTE"]: + self.primary = (173, 216, 230) + self.secondary = (255, 255, 255) + self.pattern_function = patterns.alternating - elif current_mode == modes["SOME_CAMS_WORKING_CUSTOM"]: - self.primary == colors["HOT_PINK"] - self.pattern_function = patterns.wavy + elif current_mode == modes["DISABLED_WITHOUT_AUTO"]: + # TO-DO + pass - elif current_mode == modes["NO_CAMS_WORKING_CUSTOM"]: - self.primary == colors["HOT_PINK"] - self.pattern_function = patterns.breathing + elif current_mode == modes["DISABLED_WITH_AUTO"]: + # TO-DO + pass elif current_mode == modes["PURELY_ENABLED"]: - self.primary = colors["WHITE"] + self.primary = (255, 255, 255) self.pattern_function = patterns.static else: - self.primary = colors["RED"] + self.primary = (255, 0, 0) self.pattern_function = patterns.static \ No newline at end of file diff --git a/main.py b/main.py index 3136517..7ac902f 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,5 @@ -from main_loop import main +# from main_loop import main +from serial_loop import main if __name__ == "__main__": main() \ No newline at end of file diff --git a/main_loop.py b/main_loop.py index 960b1fe..af283c1 100644 --- a/main_loop.py +++ b/main_loop.py @@ -104,7 +104,8 @@ def main_loop(): patterns.loopcount = patterns.loopcount + 1 # Read data sent by RoboRIO - current_mode = str(get_binary_data()) + # current_mode = str(get_binary_data()) + current_mode = "11" # Match lights with serial data and update lights #for lightstrip in lightstrips: diff --git a/patterns.py b/patterns.py index 6cf0026..3625dc5 100644 --- a/patterns.py +++ b/patterns.py @@ -1,4 +1,6 @@ from rainbowio import colorwheel +# from lightstrip import LightStrip +# import lightstrip from math import sin frames_per_second = 12 @@ -7,23 +9,41 @@ # Constant color -def static(light): +def static(light: LightStrip): for pixel in range(light.PIXEL_COUNT): light.neopixel[pixel] = light.primary light.neopixel.show() -# Gradient breathing -def breathing(light): +# Gradient flashing +def flashing(light: LightStrip): multiplier = sin(loopcount / 5) + 1 for pixel in range(light.PIXEL_COUNT): light.neopixel[pixel] = tuple(x * (multiplier/2) for x in light.primary) light.neopixel.show() + +# Alternates between two color of lights, Ex. +# Loop 1: All green +# Loop 2: All red +def alternating(light: LightStrip): + global alternating_loopcount + for pixel in range(light.PIXEL_COUNT): + # Alternate appproximately 2 times a second + if loopcount % (frames_per_second // 2) != light.pattern_starting_loop % (frames_per_second // 2): + continue + + alternating_loopcount += 1 + if alternating_loopcount % 2 == 0: + light.neopixel[pixel] = light.primary + else: + light.neopixel[pixel] = light.secondary + light.neopixel.show() + # Think of this pattern as if you are static and cars in front of you # Are constantly driving by (one direction) -def wavy(light): +def wavy(light: LightStrip): for pixel in range(light.PIXEL_COUNT): multiplier = max(0, min(sin(pixel + loopcount), 1)) light.neopixel[pixel] = tuple(x * multiplier for x in light.primary) @@ -31,30 +51,16 @@ def wavy(light): # Disco party baby! -def rainbow(light): +def rainbow(light: LightStrip): for pixel in range(light.PIXEL_COUNT): light.neopixel[pixel] = colorwheel(((255 / frames_per_second) * loopcount) % 255) light.neopixel.show() # Charge up -def railgun(light): - for pixel in range(light.PIXEL_COUNT): - if ((loopcount - light.pattern_starting_loop) % light.PIXEL_COUNT) > pixel: - light.neopixel[pixel] = light.primary - else: - light.neopixel[pixel] = (0, 0, 0) - light.neopixel.show() - - -def flashing(light): - global alternating_loopcount - loop = loopcount - light.pattern_starting_loop - if loop % (frames_per_second // 2) == 0: - alternating_loopcount += 1 - +def railgun(light: LightStrip): for pixel in range(light.PIXEL_COUNT): - if alternating_loopcount % 2 == 0: + if loopcount - light.pattern_starting_loop > pixel: light.neopixel[pixel] = light.primary else: light.neopixel[pixel] = (0, 0, 0) diff --git a/serial_loop.py b/serial_loop.py new file mode 100644 index 0000000..10ed4c6 --- /dev/null +++ b/serial_loop.py @@ -0,0 +1,103 @@ +""" +MODES: +[31] No code on robot: +RoboRIO inactive/not receiving serial data from RoboRIO + +[32] Disabled without auto +RoboRIO is disabled, and has NO autonomous program set + +[33] Disabled with auto +RoboRIO is disabled, and DOES have autonomous program set + + +--< Modes for when RoboRIO is enabled >-- +Priority: 1 > 2 > 3 > 4 > 34 + +[34] Enabled +RoboRIO is enabled, but none of the above are active. + +[1] Signal: +For communication with teammates to activate amplifier + +[2] Ready to shoot: +The robot shooter and arm is in position, ready to shoot note + +[3] Has note: +The robot currently is holding a note + +[4] Vision: +The robot spots a note (tells the driver that they can press a button for +robot to retrieve a note) +""" + + +import supervisor +import board +from lightstrip import LightStrip, modes +import patterns +import time +import sys + +# Serial data variables +serial = sys.stdin +tolerance = 2 +tolerance_count = 0 +current_mode = modes["ROBOT_NOCODE"] +last_mode = modes["ROBOT_NOCODE"] + +# Create light objects +strip1 = LightStrip(board.D5, 8) +lightstrips: tuple[LightStrip] = (strip1,) + + +# Retrieves and returns serial data sent by Java side +def get_serial_data() -> str: + global tolerance_count + + # Return serial data if any + if supervisor.runtime.serial_bytes_available: + data = serial.readline() + if data: + print(data) + tolerance_count = 0 + return data.strip() + + # Check tolerance and return previous, if tolerance count reached, "31" + # Tolerance is for if there are no serial data sent from the Java side + # *There may be some delay if both sides are sending at same or similar rate* + # Tolerance count is 2, therefore it will tolerate two frames/fps seconds + if tolerance_count >= tolerance: + tolerance_count = 0 + return modes["ROBOT_NOCODE"] + tolerance_count += 1 + return last_mode + + +def main_loop(): + global current_mode + global last_mode + + # Increment loopcount + patterns.loopcount += 1 + + # Read serial data sent by RoboRIO + # current_mode = str(get_serial_data()) + # test_arr = ["1", "2", "3", "4", "31", "32", "33", "34"] + + # # Match lights with serial data and update lights + # # for lightstrip in lightstrips: + # for i in range(len(test_arr)): + # print(test_arr[i]) + # time.sleep(5) + strip1.assign_mode(current_mode, last_mode) + strip1.pattern_function(strip1) + # if i == len(test_arr) - 1: + # i = 0 + + last_mode = current_mode + + +def main(): + while True: + main_loop() + time.sleep(1 / patterns.frames_per_second) \ No newline at end of file diff --git a/test_serial.sh b/test_serial.sh new file mode 100644 index 0000000..ecf34b5 --- /dev/null +++ b/test_serial.sh @@ -0,0 +1,7 @@ +testArr=("1" "2" "3" "4" "31" "32" "33" "34") +for i in ${!testArr[@]}; do + echo "${testArr[$i]}" + if [ "$i" -ge "${#testArr[@]}" ]; then + i=0 + fi +done \ No newline at end of file From 627b8cb874632f30ac935bb6aaa5a5480103fb2f Mon Sep 17 00:00:00 2001 From: j0ndough Date: Sat, 27 Jul 2024 14:41:57 -0700 Subject: [PATCH 2/4] batch file to automate serial input, wip mode rework --- serial_loop.py | 17 +++++++++-------- test_serial.bat | 14 ++++++++++++++ test_serial.sh | 7 ------- 3 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 test_serial.bat delete mode 100644 test_serial.sh diff --git a/serial_loop.py b/serial_loop.py index 10ed4c6..6428100 100644 --- a/serial_loop.py +++ b/serial_loop.py @@ -66,22 +66,22 @@ def get_serial_data() -> str: # Tolerance is for if there are no serial data sent from the Java side # *There may be some delay if both sides are sending at same or similar rate* # Tolerance count is 2, therefore it will tolerate two frames/fps seconds - if tolerance_count >= tolerance: - tolerance_count = 0 - return modes["ROBOT_NOCODE"] - tolerance_count += 1 + # if tolerance_count >= tolerance: + # tolerance_count = 0 + # return modes["ROBOT_NOCODE"] + # tolerance_count += 1 return last_mode def main_loop(): global current_mode - global last_mode + global last_mode # Increment loopcount patterns.loopcount += 1 # Read serial data sent by RoboRIO - # current_mode = str(get_serial_data()) + current_mode = str(get_serial_data()) # test_arr = ["1", "2", "3", "4", "31", "32", "33", "34"] # # Match lights with serial data and update lights @@ -89,8 +89,9 @@ def main_loop(): # for i in range(len(test_arr)): # print(test_arr[i]) # time.sleep(5) - strip1.assign_mode(current_mode, last_mode) - strip1.pattern_function(strip1) + for ls in lightstrips: + ls.assign_mode(current_mode, last_mode) + ls.pattern_function(ls) # if i == len(test_arr) - 1: # i = 0 diff --git a/test_serial.bat b/test_serial.bat new file mode 100644 index 0000000..1d7e4bc --- /dev/null +++ b/test_serial.bat @@ -0,0 +1,14 @@ +REM how to run: ./test_serial.bat + +@echo off +REM define variables +set COM_PORT = COM15 +set BAUD_RATE = 115200 + +( + echo "" + for /l %%x in (1, 1, 4) do ( + echo %%x + timeout /t 5 + ) +) | plink.exe -batch -v -serial COM15 -sercfg 115200,8,1,n,N \ No newline at end of file diff --git a/test_serial.sh b/test_serial.sh deleted file mode 100644 index ecf34b5..0000000 --- a/test_serial.sh +++ /dev/null @@ -1,7 +0,0 @@ -testArr=("1" "2" "3" "4" "31" "32" "33" "34") -for i in ${!testArr[@]}; do - echo "${testArr[$i]}" - if [ "$i" -ge "${#testArr[@]}" ]; then - i=0 - fi -done \ No newline at end of file From c8a620ceb0dc040188937abd4fc8dfc727f25896 Mon Sep 17 00:00:00 2001 From: j0ndough Date: Sat, 10 Aug 2024 13:19:08 -0700 Subject: [PATCH 3/4] fix logic of switching modes for serial --- serial_loop.py | 14 +++++++++++--- test_serial.bat | 3 +-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/serial_loop.py b/serial_loop.py index 6428100..6f0dc62 100644 --- a/serial_loop.py +++ b/serial_loop.py @@ -57,9 +57,17 @@ def get_serial_data() -> str: # Return serial data if any if supervisor.runtime.serial_bytes_available: data = serial.readline() - if data: - print(data) - tolerance_count = 0 + + # print debugging + # print('current contents of data: ' + data) + # print('are the current contents only whitespace? ' + str(str(data).isspace())) + # print('current length of data: ' + str(len(data))) + # print('') + + if not data.isspace(): + # if data: + # tolerance_count = 0 + print('current value of data: ' + str(data)) return data.strip() # Check tolerance and return previous, if tolerance count reached, "31" diff --git a/test_serial.bat b/test_serial.bat index 1d7e4bc..9fbdeb8 100644 --- a/test_serial.bat +++ b/test_serial.bat @@ -6,9 +6,8 @@ set COM_PORT = COM15 set BAUD_RATE = 115200 ( - echo "" for /l %%x in (1, 1, 4) do ( echo %%x - timeout /t 5 + timeout /t 2 >nul ) ) | plink.exe -batch -v -serial COM15 -sercfg 115200,8,1,n,N \ No newline at end of file From fed658039798fbbaaf632183ff8ce77c12cde835 Mon Sep 17 00:00:00 2001 From: j0ndough Date: Tue, 17 Sep 2024 11:33:34 -0700 Subject: [PATCH 4/4] refactor code --- serial_loop.py | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/serial_loop.py b/serial_loop.py index 6f0dc62..c4ce24d 100644 --- a/serial_loop.py +++ b/serial_loop.py @@ -58,26 +58,16 @@ def get_serial_data() -> str: if supervisor.runtime.serial_bytes_available: data = serial.readline() - # print debugging + # Print debugging statements # print('current contents of data: ' + data) # print('are the current contents only whitespace? ' + str(str(data).isspace())) # print('current length of data: ' + str(len(data))) # print('') if not data.isspace(): - # if data: - # tolerance_count = 0 print('current value of data: ' + str(data)) return data.strip() - # Check tolerance and return previous, if tolerance count reached, "31" - # Tolerance is for if there are no serial data sent from the Java side - # *There may be some delay if both sides are sending at same or similar rate* - # Tolerance count is 2, therefore it will tolerate two frames/fps seconds - # if tolerance_count >= tolerance: - # tolerance_count = 0 - # return modes["ROBOT_NOCODE"] - # tolerance_count += 1 return last_mode @@ -90,18 +80,11 @@ def main_loop(): # Read serial data sent by RoboRIO current_mode = str(get_serial_data()) - # test_arr = ["1", "2", "3", "4", "31", "32", "33", "34"] # # Match lights with serial data and update lights - # # for lightstrip in lightstrips: - # for i in range(len(test_arr)): - # print(test_arr[i]) - # time.sleep(5) for ls in lightstrips: ls.assign_mode(current_mode, last_mode) ls.pattern_function(ls) - # if i == len(test_arr) - 1: - # i = 0 last_mode = current_mode