Tutorial - Mapping

Now that we’re able to construct periodic data pipelines with @STREAMify, the next step would be combining them together. We currently have a camera data stream generated by the camera at the top of the intersection and information from the CAV that combines both its camera and LIDAR data. We want to use both of these in our global sensor fusion function to get a more accurate estimate of the location of these cars at the intersection.

We first need to define the separate ensembles in our application. We have 2 CAVs (connected autonomous vehicles) and the IS (infrastructure sensor camera at the top of the intersection). We also have an RSU (Road Side Unit) coupled with the IS to handle the global vehicular tracking. For the purposes of this example, we have left the IS out of the tutorial code examples for conciseness and clarity.

@GRAPHify
def streamify_test(trigger):
    with TTClock.root() as root_clock:
        ...

        # Cav 0
        with TTConstraint(name=["cav0"]):
            cav_0 = 0
            cam_sample = camera_sampler(cav_0, sample_window, TTClock=root_clock, TTPeriod=2500000, TTPhase=0, TTDataIntervalWidth=2500000/2)
            lidar_sample = lidar_sampler(cav_0, sample_window, TTClock=root_clock, TTPeriod=2500000, TTPhase=0, TTDataIntervalWidth=2500000/2)
            cam_output = process_camera(cam_sample)
            lidar_output = process_lidar(lidar_sample)
            fusion_result = local_fusion(cam_output, lidar_output, cav_0)

        # CAV 1
        with TTConstraint(name=["cav1"]):
            cav_1 = 1
            cam_sample2 = camera_sampler(cav_1, sample_window, TTClock=root_clock, TTPeriod=2500000, TTPhase=0, TTDataIntervalWidth=2500000/2)
            lidar_sample2 = lidar_sampler(cav_1, sample_window, TTClock=root_clock, TTPeriod=2500000, TTPhase=0, TTDataIntervalWidth=2500000/2)
            cam_output2 = process_camera(cam_sample2)
            lidar_output2 = process_lidar(lidar_sample2)
            fusion_result2 = local_fusion(cam_output2, lidar_output2, cav_1)

        # Global fusion
        with TTConstraint(name=["rsu"]):
            global_fusion_result = global_fusion(fusion_result, fusion_result2)
            result = write_to_file(global_fusion_result)

The code shown above describes how both CAVs get a version of the camera_sampler and lidar_sampler. The construct TTConstraint allows the programmer to exactly specify what type of ensemble the SQ goes onto. The runtime manager is given a list of ensembles with descriptors as named arguments such as name and components, and it can do a reasonable mapping with this information. The programmer doesn’t need to overspecify the location of the SQs by default: the runtime manager will make a decision subject to the programmer’s specified constraints. This allows generality and flexibility to the system when it is unclear to which ensemble the SQ should be mapped while still retaining preciseness of the location of the SQ if the programmer desires.

Now, check out Steps 8 and 9 to see how to use the TTConstraint in practice.