Sunday, October 30, 2016

Raspberry Pi & Arch Linux - Day 17 - Visualization in terminal and KeyboardInterrupt handler



Happy Halloween!




Last time, we saw that the robot car could run without any direction and speed control. To make the robot more intelligent, we should first make sure that it can interact with the environment. All the communication between the robot car and the environment go through the radar in the front of the car. It consists of a stepper motor as the base and a ultrasonic distance sensor which measure the distance to the obstacles.

As we add more components to the robot car, the number of parameters in the system increase dramatically. (probably it is a good idea to have an overview of all the parameters currently used in the robot car). Before we code the direction and speed control algorithm, it is necessary to configure all the parameters so that the robot car can function properly. The parameters of the most interests are

  • the range of the radar
  • the angle speed of the radar
  • the frequency of the sampling (radar base and distance sensor)
  • the buffer size of the data

One of the problems is how we can visualize the distance map in the terminal. There are two approaches:
  • gnuplot
  • bashplotlib in python
If we use gnuplot, we need to start a subprocess in python and sometimes it is very difficult to deal with the subprocess, especially when we want to load the outputs of the subprocess. So for our testing purpose, we choose the bashplotlib package. 

The function we use is plot_hist because the distance map is essentially a histogram. The x-axis is the degree, which indicates the position of the radar base (stepper motor); the y-axis is the distance to the obstacles. To plot the histogram, we need to convert the floating distance to int. 

I do not know if I missing something about the bashplotlib package. It seems to me that the plot_hist function only accepts the raw data, which means we can not pass a dictionary or pd.Series to it. So if you have a pd.Series 


In[4]: ts
Out[4]: 
-1    3
 0    2
 1    5
dtype: int64


You need to manually convert it to [-1,-1,-1,0,0,1,1,1,1,1].

The figures below present the plot in terminal. It is not very fancy but it is much better than looking at an array of 100 numbers. :)





To make the testing more convenient, we want the radar to go back to its zero or initial position when the process is interrupt by the ctr-c. When we enter the ctr-c, the python interpreter will raise a KeyboardInterrupt error in the "main" process and all the subprocess as well. It means that we need to handle the keyboard interrupt error in both the main script and the scripts that use multiprocessing.Process. Fortunately, all components that are running concurrently are wrapped in the ContinuousComponentWrapper. So we just need to add a exception handler in the run method of the ContinuousComponentWrapper

    # ContinuousComponentWrapper
    def run(self):
        """
        Running the component in the infinite loop. To change the status of the component, one can send command to the command queue.
        #TODO: add a stop-pill
        """
        try:

            while True:
                while not self._cmd_Q.empty():
                    cmd = self._cmd_Q.get()
                    if cmd == CMD_EXIT or cmd == (CMD_EXIT,):
                        return 
                    self._component.parse_and_execute(cmd)


                self._component.run()
                self._component.send_msg(self._output_Q)

        except KeyboardInterrupt:
            if hasattr(self._component, 'KeyboardInterruptHandler'):
                self._component.KeyboardInterruptHandler()
            print('{} property exit after KeyboardInterrupt.'.format(self._component.name))

and create a KeyboardInterruptHandler method for the DistanceRadarBaseComponent.

    # DistanceRadarBaseComponent
   
    def KeyboardInterruptHandler(self):
        self._stepper_motor.back_to_zero_pos(delay=self._delay)

--END---

No comments:

Post a Comment