Serial port communication with the Raspberry Pi

As mentioned earlier, the weather data is obtained by the Raspberry Pi and communicates the data with control characters via the serial port. We will discuss the control signals used in this project.

Engage thrusters

Let's get started by reviewing the Python script used to operate the weather display.

Python program for the Weasley clock

  1. In this section, we will discuss the Python code for the weather clock. The important requirement for this project is the Python weather API. We need to download and install it to get started. If subversion is not installed on the Raspberry Pi, it can be installed using the following command:
    sudo apt-get install subversion
    
  2. Once the installation is complete, the Python weather API repository can be cloned as follows:
    svn checkout http://python-weather-api.googlecode.com/svn/trunk/ python-weather-api-read-only
    
  3. The Python weather API has a Python3 requirement and is installed as follows:
    cd python-weather-api-read-only
    python3 setup.py build
    python3 setup.py install
    
  4. Let's review the Python script used to operate the weather display. We will import the serial port, pywapi, and time (for delay) modules for the project:
    #!/usr/bin/env python 
    import serial
    import glob
    import pprint
    import pywapi
    from time import sleep
    • We will determine and establish connection to the serial port. The scan() function identifies all the serial ports available on the Raspberry Pi:
      # Establish serial port communication
      def scan():
          return glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*')+ glob.glob('/dev/ttyACM*')
      sport_data = scan()
      
      for name in scan():
          serialport = serial.Serial(name,9600)
          sleep(5)
          serialport.write(bytes("A",'ascii'))
          sleep(1)
          response = serialport.read()
          if(response==b'A'):
              sport = name
              serialport.close()
              break
      seport = serial.Serial(sport,9600,timeout=45)
  5. Once the serial ports have been identified, we test them by sending a byte A and await a response. When a response with the byte A is received, we identify and save the serial port. After identification, we will establish a connection with the Arduino.
  6. In this project, we are using the NOAA website to obtain the weather data. We have to identify the city's weather code to obtain the current location's weather station code. This could be simply obtained by entering the zip code on their website. For example, the weather station code for Chicago is KORD.
    Python program for the Weasley clock

    Weather station for Chicago, IL

    • The weather data is obtained as follows:
      result = pywapi.get_weather_from_noaa('KORD')
    • The temperature data is retrieved as follows:
      temperature = int(float(result['temp_f']))
    • The retrieved data is written to the serial port:
      temperature_string= "S"+str(temperature)
      #print(temperature_string)
      seport.write(bytes(temperature_string,'ascii'))
    • Based on the temperature data, the RGB strip, BlinkM control data, and 8x8 matrix data are written to the Arduino:
      if(temperature>40):
          seport.write(bytes("G",'ascii'))
          sleep(5)
          seport.write(bytes("P4",'ascii'))
          sleep(5)
          seport.write(bytes("M1",'ascii'))
          sleep(5)
    • We will set the weather clock to point at a weather forecast based on the data obtained:
      if(result['weather']=='Light Snow') or (result['weather']=='Snow') or (result['weather']=='Flurries'):
          seport.write(bytes("H",'ascii'))
          sleep(5)
          seport.write(bytes("T-2",'ascii'))
          sleep(5)
  7. Let's review the code for the control from the Raspberry Pi and the corresponding acknowledgment signals.

Arduino acknowledgement to control signal

Let us review on the control signal and control flow of the weather clock.

Control flow for the weather clock

The following flowchart shows what happens in the Arduino when a control character is received from the Raspberry Pi.

Control flow for the weather clock

The weather clock program flow

  1. The Raspberry Pi tries to identify the Arduino by sending a character A. The Arduino responds with an acknowledgement character A:
    if(serial_read=='A'){
               Serial.print("A");
             }
  2. This is a foolproof mechanism to identify and establish a communication with the weather clock controller from the Raspberry Pi.

Temperature data

  1. The Raspberry Pi temperature data is sent to the Arduino with the letter / character S. The received data is converted to a signed integer and passed as an argument to the 7-Segment display libraries:
    if(serial_read=='S') {
              while(Serial.available()){
              sb = Serial.read();
              sevenseg_string[serInIndx] = sb;
              serInIndx++;
              temp=0;
              }
              temp=atoi(sevenseg_string);
              memset(sevenseg_string,0,9);
            }
  2. When the character S is received, we read all the characters into the buffer sevenseg_string. The string is converted to an integer using the atoi function and stored in the temp variable. The buffer is cleared at the end of the cycle. This method takes sub-zero temperatures into consideration.

Control of the RGB LED strip

  1. The individual colors of the RGB LED are controlled individually using the ASCII characters R, G, and, B respectively. Each color indicates a unique weather condition, namely, blue indicates cold weather, green indicates fair weather conditions, and red color indicates impeding danger in weather conditions:
    if(serial_read=='R' || serial_read=='G' ||
               serial_read=='B') {
                 color_bit=serial_read;          
            }
    if(color_bit=='R'){
       lightsequence_red();
     }
     else if(color_bit=='G'){
       lightsequence_green();
     }
     else if(color_bit=='B'){
       lightsequence_blue();
     }
  2. When the character is received, the corresponding light sequence is turned on.

Control of stepper via serial port

  1. Earlier, we discussed the control of the stepper motor using a power Darlington driver and the control routine for one full rotation. In this section, we will discuss how to control the direction and the number of steps based on the input from the serial port. In this example, the clockwise direction is indicated by +, and counterclockwise direction is indicated by -.
    • For example, in order to move 45 steps in a clockwise direction, the command would be +45 preceded by the letter P. Hence, it would be P+45. Similarly, the counterclockwise direction command would be P-45:
        if( serial_read == 'P' ) { 
               while(Serial.available())
               {
                sb = Serial.read();
                serInString[serInIndx] = sb;
                serInIndx++;
               }
              }
  2. We await the serial character P and store the rest of the string in a buffer. Once the data is stored in the buffer, we will determine whether the first character is + or -.
    • The ASCII number for the + sign is 43 and 45 for the - sign. We compare the first character in the buffer and execute the command accordingly. Serial communications usually transmit ASCII numbers and hence the numbers are converted into their decimal equivalents:
      if(serInString[0]==43){
      int var_serial=0;
         for(serOutIndx=1;serOutIndx<serInIndx;serOutIndx++)
          {
            var_serial = var_serial*10+(serInString[serOutIndx]-48);
          }
         motorSpeed=20;
         for(int i=0;i<var_serial;i++){
           clockwise();
           
         }
    • We convert the received serial data into their decimal equivalent at this step:
      var_serial = var_serial*10+(serInString[serOutIndx]-48);
    • Once converted, we move the stepper for the desired number of steps in either direction using the clockwise() and counterclockwise() functions.
  3. We want the stepper motor to reach the home position every time before pointing to a particular weather condition. This system is an open loop and so it is necessary to move the arrow to the home position before pointing to the current weather condition.

    Note

    The stepper motor moves in a counterclockwise direction to point at all weather conditions and a clockwise direction to move towards the home position.

  4. Hence, when the letter H is transmitted via the serial port, the arrow is moved towards the home position:
    if(serial_read=='H'){
              reset_stepper();
              lightsequence();
            }
    • The reset_stepper()function takes care of setting the arrow to the home position:
      void reset_stepper(void){
        uint8_t val;
       // Get the value from the sensor
         if (ReadByte(sensorAddr, 0x0, &val) == 0)
         {
            // The second LSB indicates if something was not detected, i.e.,
            // LO = object detected, HI = nothing detected
            while(val & 0x2)
            {
               motorSpeed=20;
               Serial.println("Nothing detected");
               if(ReadByte(sensorAddr, 0x0, &val) == 0){
                 clockwise();//We keep going clockwise until the arrow is detected
               }
            }
          
         }
         else
         {
            Serial.println("Failed to read from sensor");
         }
      }
    • In the reset_stepper() function, we will execute the stepper motor's clockwise routine until the object is detected. The sensor reference manual mentions that an object is detected if the second LSB is set to low. Hence, the stepper rotates in the clockwise direction until a low signal is detected.

Programming the weather forecast position

  1. In the previous section, we discussed the stepper motor control via the serial port. Since we are using a stepper motor, it is possible to point at each weather forecast condition based on a predetermined number of steps from the step. So, we will determine the number of steps required to point at each weather forecast condition and program these positions into the flash memory of the Arduino.
    • We should use the PROGMEM keyword to store the position data in the flash memory of the Arduino since they are a constant:
      const int mydata[6][2] PROGMEM = {
           1, 10,
           2, 18,
           3, 28,
           4, 43,
           5, 54,
           6, 66};
    • The numbers 1 through 6 in the array correspond to the weather forecast indicators starting in the counterclockwise direction. The second position indicates the number of positions from the home position to point to that particular weather condition.
    • The command for indicating weather data is preceded by the letter T. In order to point to the weather forecast, Rain, the command would be T-6. When a character T is received, we store the data received in a buffer. It is confirmed that the second character received after the letter T is a number between 1 and 6. We will retrieve the corresponding position data from the flash memory using the pgm_read_word_near() function. Once the data is retrieved, the stepper motor control routine is executed for the desired number of steps.
    • Now we will retrieve the data from the flash memory as follows:
      if( serial_read == 'T' ) { 
               while(Serial.available())
               {
                sb = Serial.read();
                serInString[serInIndx] = sb;
                serInIndx++;
               }
              }
      int var_serial=serInString[1]-48;
         serInIndx=0;
         if(var_serial>0 && var_serial <=6)
         {
           steps=pgm_read_word_near(&mydata[(var_serial-1)][1]);
           Serial.println(steps);
         }
         if(serInString[0]==45){
         
         motorSpeed=20;
         for(int i=0;i<steps;i++){
           counterclockwise();
         }

8x8 matrix control

  • We will control the LED matrix using the letter M. A smile is displayed if M1 is received and a frown if M2 is received:
    if(serial_read=='M'){
              sb=Serial.read();
              if(sb-'0'==1) {
                set_display(smile_bmp);
              }
              else if(sb-'0'==2) {
                set_display(frown_bmp);
              }
            }
BlinkM control
  • The BlinkM script is played whenever the letter P is received. The letter P is followed by the script number.
    if( serial_read == 'P' ) {
              while(Serial.available())
               {
                sb = Serial.read();
                serInString[serInIndx] = sb;
                serInIndx++;
               }
          BlinkM_playScript( BlinkM_addr,serInString[0]-48,0,0 );
        }

Objective complete – mini debriefing

In this section, we discussed the overall control of the weather clock and its interface to the Internet. We also discussed the interfacing of the sensors and displaying the weather data.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.199.122