diff --git "a/ros2/UI/ \360\237\232\227 Homepage.py" "b/ros2/UI/ \360\237\232\227 Homepage.py" new file mode 100644 index 000000000..27668693f --- /dev/null +++ "b/ros2/UI/ \360\237\232\227 Homepage.py" @@ -0,0 +1,61 @@ +import streamlit as st +from streamlit import runtime +from streamlit.web import cli as stcli +import sys + + +def runner(): + st.header("Welcome to the IGVC Homepage!") + st.markdown(''' + Please select an option on the sidebar to the right: This specifies which UI file you'd like to run + + + Streamlit supports fast reloads: Just refresh the python script to get going! + + + Docs are here: https://docs.streamlit.io/library/api-reference + ''') + st.divider() + st.markdown(''' + For the freshmen: This UI is designed to serve multiple purposes + + #1. We need a way to render all of the openCV data we have: This is stuff like the lane or object detection. + + #2. We need a way to tune parameters in an easy way, without refreshing every single page for small little tweaks. + + #3. We need to be able to control the state machines on the car: Each of the function tests is effectively it's own state machine. + We need to be able to control which test we're in, and visualize any important data in a direct manner. + + + #4. It makes us look professional, and adds quite a bit of useful fluff for our design report. + ''') + st.divider() + st.markdown(''' + Of course, not a lot of this is in your control: We haven't built the state machines or finished all of our algorithms. + However, Lane Detection is in the perfect place for you to familiarize yourself with both streamlit and the entire tech stack. + I'm detailing all immediate tasks here: Please allocate amongst yourselves. + I have taken the liberty of building a bespoke ros2 publisher and subscriber system (was not trivial), that should provide a solid framework. + However, it will get extremely tedious to build a proper UI if you don't exploit some of the advantages of python. + Read about list comprehension and get good. + #1: Connecting all datastreams from the lane_detection algorithm into here. + Everything that is cv.imshow() is rendered in that, in a clean and effective manner. + #2: Parametrizing all constants in that: anything that had a slider should be here, and it should be published. + #3: Beautifying, and building more tabs & systems so this is the only interface we need with the car. + We should not be opening up or handling multiple windows with the judges. + Debugging systems, sensor messages (E.g IMU, CAN) should all live here. + + ''') + st.warning("FIRST PRIORITY: https://docs.streamlit.io/develop/api-reference/widgets/st.page_link CHANGE THE PAGES SO NO MORE EMOJIS") + + +# This allows the system to run without being in a dedicated streamlit session: +if __name__ == "__main__": + if runtime.exists(): + st.set_page_config( + page_title="IGVC Homepage", + page_icon="🚗") + st.sidebar.success("Select a System above.") + runner() + else: + sys.argv = ["streamlit", "run", sys.argv[0]] + sys.exit(stcli.main()) diff --git a/ros2/UI/Homepage.py b/ros2/UI/Homepage.py deleted file mode 100644 index 29d44a6e7..000000000 --- a/ros2/UI/Homepage.py +++ /dev/null @@ -1,28 +0,0 @@ -import streamlit as st -from streamlit import runtime -from streamlit.web import cli as stcli -import sys - -def runner(): - st.header("Welcome to the IGVC Homepage!") - st.write("Please select an option on the sidebar to the right.") - st.write("For the freshmen: You guys can beautify this up however you'd like") - st.write( - "Streamlit supports fast reloads, just refresh the python script to get going!") - st.write("Docs are here: https://docs.streamlit.io/library/api-reference") - st.write("This is also extremely relevant: https://stackoverflow.com/questions/67382181/how-to-use-streamlit-in-ros") - st.write("For Siann: You should love yourself, now!") - - - -# This allows the system to run without being in a dedicated streamlit session: -if __name__ == "__main__": - if runtime.exists(): - st.set_page_config( - page_title="IGVC Homepage", - page_icon="🚗") - st.sidebar.success("Select a demo above.") - runner() - else: - sys.argv = ["streamlit", "run", sys.argv[0]] - sys.exit(stcli.main()) diff --git "a/ros2/UI/pages/\360\237\233\243 Lane_Detection.py" "b/ros2/UI/pages/\360\237\233\243 Lane_Detection.py" index 1700568da..0f0191907 100644 --- "a/ros2/UI/pages/\360\237\233\243 Lane_Detection.py" +++ "b/ros2/UI/pages/\360\237\233\243 Lane_Detection.py" @@ -6,10 +6,10 @@ from rclpy.qos import qos_profile_sensor_data from cv_bridge import CvBridge import time +from std_msgs.msg import String - +## This class currently subscribes to some topics in cam_publisher, which I used to test. Please rewrite for lane Detection. class Image_Handler(Node): - def __init__(self): self._tabs = None self._img = None @@ -27,27 +27,41 @@ def __init__(self): self.hsvData_callback, qos_profile_sensor_data) - - def tabs(self,tabs): + def tabs(self, tabs): self._tabs = tabs # SRC is cv2.VideoCapture FOR NOW: Will need to be tweaked in the future to rossify self._frame_containers = [tab.empty() for tab in self._tabs] - def camData_callback(self, msg_in): raw = msg_in img = self._bridge.imgmsg_to_cv2(raw) self._frame_containers[0].image(img) - + def hsvData_callback(self, msg_in): raw = msg_in img = self._bridge.imgmsg_to_cv2(raw) self._frame_containers[1].image(img) - +#This class is your publisher: Flesh it out and integrate accordingly +class Publisher(Node): + def __init__(self): + super().__init__('Streamlit_Button_Publisher') + self.logger = self.get_logger() + self.button_pub = self.create_publisher(String, '/streamlit/button',10) + +def demo_publish(): + msg = String() + msg.data = "Streamlit Button!" + st.session_state["pub_node"].button_pub.publish(msg) + st.success("Message Published!") + + + + # See ../../ros2/src/lanefollowingtest/LaneDetection.py -# This page should render ALL images in there, as well as publish +# This page should render ALL images in there, as well as publish important update data if __name__ == "__main__": + #How we Configure the page st.set_page_config( page_title="Lane Detection", page_icon="🛣") @@ -58,20 +72,30 @@ def hsvData_callback(self, msg_in): "This should render all of the images related to Lane Detection, and relevant parameters.") tabs = st.tabs(["Original", "HSV", "Sliding Windows"]) - if "node" not in st.session_state: - try: - rclpy.init() - except RuntimeError: - st.warning("something went wrong performance may be degraded. Try restarting fully") - finally: - handler = Image_Handler() - handler.tabs(tabs) - st.session_state["node"] = handler + + #This hunk initializes the ROS2 nodes without breaking anything :) + if "sub_node" not in st.session_state: + try: + rclpy.init() + except RuntimeError: + st.warning( + "something went wrong performance may be degraded. Try restarting fully.") + finally: + handler = Image_Handler() + handler.tabs(tabs) + st.session_state["sub_node"] = handler + if "pub_node" not in st.session_state: + st.session_state["pub_node"] = Publisher() + + + st.button("Ros Topic Publisher Demo!",on_click=demo_publish) + # As this is an infinite loop, it should only be run at the end of the file. if render: - while(True): - try: - rclpy.spin_once(st.session_state['node']) - time.sleep(0.01) - except: - st.warning("Something went wrong, perhaps tabs were clicked too quickly? Try restarting.") - break + while (True): + try: + rclpy.spin_once(st.session_state['sub_node']) + time.sleep(0.01) + except: + st.warning( + "Something went wrong, perhaps tabs were clicked too quickly? Try restarting.") + break