SunTracker_BLE

Dependencies:   BLE_API X_NUCLEO_6180XA1 X_NUCLEO_IDB0XA1 X_NUCLEO_IHM01A1 X_NUCLEO_IKS01A1 mbed

Fork of SunTracker_BLE by ST Expansion SW Team

Overview

The SunTracker is a demo application running on ST Nucleo-F401RE stacking a set of ST X-NUCLEO expansion boards.
Main features provided are:

  • A solar panel follows the light source, orienting the panel in order to achieve the best panel efficiency.
  • Orientation is controlled thanks to a couple of VL6180X FlightSense light sensors mounted on a X-NUCLEO-6180XA1 expansion board and driven by X-NUCLEO-IHM01A1 controlled stepper motor acting as actuator to orientate the panel.
  • The system features a progressive control on the stepper motor in order to modulate the panel rotation speed according to the light angle.
  • The application is also able to control the panel productivity reading the panel voltage through an ADC and proving feedback on the local display.
  • A manual orientation is possible by using the accelerometer on a X-NUCLEO-IKS01A1 expansion board that, according on board tilt, controls the speed and the rotate direction.
  • A remote control is available using a X-NUCLEO-IDB04A1 or a X-NUCLEO-IDB05A1 Bluetooth Low Energy expansion board. Remote control software is here.

/media/uploads/fabiombed/suntracker_server-client.png

Working Status

  • SunTracker has 3 working status visible on FlightSense display and switchable by pressing the User Button:

Status 0 (Idle)

  • Motor: Free Turning
  • Display: Waiting for User Button

Status 1

  • Motor: Driven by Light
  • Display: Direction and Light Intensity = Direction and Motor Speed

Status 2

  • Motor: Driven by Light
  • Display: Solar Panel Efficiency

Status 3

  • Motor: Driven by Accelerometer
  • Display: Direction and Accelerometer Intensity

Server Startup

  • When you plug the power supply, the word ‘PUSH’ is shown on display.
  • You can manually rotate the structure to assign the ‘Zero Point’. Then press the User Button to launch the application.
  • The display will show this status, which means that the structure is oriented to maximize the efficiency of the solar panel.
  • If there is a light displacement, the structure will rotate, left or right, to follow the light source and on display is shown the direction and the speed.
  • You can press the User Button to show the panel efficiency with 4 digits that represent the range from 0v (0000) to 3,3v (3300).
  • Further pressing the User Button you will manual rotate the panel by tilt the Server or Client accelerometer depending by BLE connection.

Client Startup

  • The Client application can remotely control the User Button and the Accelerometer functions.
  • Power on the Client AFTER the Server, it will automatically search for the SunTracker and will establish a BLE connection.
  • The Green Led on Nucleo Client board will be powered on.

Rotation Features

  • It has been implemented a block of rotation to avoid cables twist.
  • The blocking point can be set in the firmware by changing a constant.
  • You can manually rotate the structure to assign the ‘Zero Point’ before press the User Button to launch the application.
  • The system features a progressive control on the stepper motor in order to modulate the rotation speed according to the light or accelerometer angle.

List of Components

SERVER SunTracker_BLE

  • Stepper Motor 400’’ (Part Number 5350401) - To orientate the Mechanical Structure.
  • Solar Panel 0.446w (Part Number 0194127) - To capture sunlight and generate electrical current.
  • Power Supply 12v (Part Number 7262993) - To provide power supply at the Stepper Motor.
  • Flat Cable 6 ways (Part Number 1807010) - To plug VL6180X-SATEL with X-NUCLEO-6180XA1 (60cm length each x2).
  • Cable Connector (Part Number 6737694) - To plug the Flat Cable (x4).
  • Power Connector (Part Number 0487842) - To provide Power Supply to X-NUCLEO-IHM01A1.

CLIENT SunTracker_BLE_Remote

MECHANICAL STRUCTURE

Find here the STL files to print with a 3D printer.

/media/uploads/fabiombed/assembly.png

/media/uploads/fabiombed/mechanical_structure_and_motor_legs.png

FLAT CABLE ASSEMBLY

/media/uploads/fabiombed/flat_cable.png

HARDWARE SETUP

Nucleo ADC + Solar Panel

Connect Solar Panel cables to Nucleo Morpho PC_3 (white) and Nucleo Morpho GND (black). Connect a capacitor 10uF between PC_3 and GND to stabilize its voltage value shown on display.

EasySpin (L6474) + BLE

Hardware conflict between EasySpin DIR1 and BLE Reset, both on same Arduino Pin PA_8. Disconnect PA_8 between EasySpin and Nucleo by fold EasySpin Pin. PB_2 has been configured as EasySpin DIR1 in the firmware . Connect Nucleo Morpho PB_2 to FlightSense Arduino PA_8 by a wire.

FlightSense Satellites

In case of instability with I2C due to long flat cables, solder 4 SMD capacitors 47pF on FlightSense board in parallel between R15, R16, R17, R18 and plug 2 capacitors 15pF between FlightSense Arduino PB_8 and PB_9 to GND pin to cut-off noises over 720 KHz.

Arduino & Morpho Pinout

/media/uploads/fabiombed/arduino_pinout.png /media/uploads/fabiombed/morpho_pinout.png

Revision:
19:b2c04428ffed
Parent:
18:319a1bb8f837
Child:
21:6948443b29e6
--- a/main.cpp	Fri Apr 22 14:40:14 2016 +0000
+++ b/main.cpp	Tue May 10 13:36:00 2016 +0000
@@ -3,7 +3,7 @@
  * @file    main.cpp
  * @author  Fabio Brembilla
  * @version V2.0.0
- * @date    April, 2016
+ * @date    May, 2016
  * @brief   SunTracker + BLE (Server) Vertical Application
  *          This application use IHM01A1, 6180XA1, IKS01A1, IDB0XA1 expansion boards
  ******************************************************************************
@@ -42,6 +42,7 @@
 #define EasySpin    //IHM01A1 Main (remove only for debug)
 #define Sensors     //IKS01A1 Option
 #define Ble         //IDB0XA1 Option
+//#define Debug       //Verbose about Printf
 
 /* Includes ------------------------------------------------------------------*/
 
@@ -89,10 +90,10 @@
 } cns_t;
 
 #define BLE_DEV_NAME "SunTracker"
-//#define BLE_DEV_MAC 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF // SERVER address (must be set into CLIENT BLE_peer_address_BE)
-#define BLE_DEV_MAC 0xFD,0x66,0x05,0x13,0xBE,0xBA // Default ST address (must be set into CLIENT BLE_peer_address_BE)
-#define BLE_ADVERTISING_INTERVAL 1000
-
+#define BLE_DEV_MAC 0xFC,0x03,0x02,0x01,0xFB,0xFA // SERVER address (must be set into CLIENT BLE_peer_address_BE)
+#define BLE_ADVERTISING_INTERVAL 100
+uint8_t dat[] = {0x01,0x80,0x00,0x00,0x78,0x00}; // Data Sent during Advertising, must respect a Standard ST
+    
 #include "CustomControlService.h"
 #include "CustomSensorsService.h"
 
@@ -117,9 +118,9 @@
 #define TOLLERANCE 80   // Tollerance between Left and Right before Start Movement
 #define RANGE_1 250     // Range 1 for Motor Speed
 #define RANGE_2 500     // Range 2 for Motor Speed
-#define TIMEOUT_STA 1   // Timeout for Ticker Status (in second)
-#define TIMEOUT_DIF 0.5 // Timeout for Ticker Difference (in second)
-#define TIMEOUT_POS 0.5 // Timeout for Ticker Position (in second)
+#define TIMEOUT_STA 0.5 // Timeout for Ticker Status (in second)
+#define TIMEOUT_DIF 0.1 // Timeout for Ticker Difference (in second)
+#define TIMEOUT_POS 0.1 // Timeout for Ticker Position (in second)
 #define TIMEOUT_SUN 0.5 // Timeout for Ticker SunPanel (in second)
 
 /* Variables -----------------------------------------------------------------*/
@@ -143,6 +144,7 @@
 bool tickerDif=false;
 bool tickerPos=false;
 bool tickerSun=false;
+bool BLEConnected=false;// BLE Connection Status
 
 /* Initializations ------------------------------------------------------------*/
 
@@ -193,8 +195,7 @@
 
     Status++;
 
-//#ifdef Sensors
-#ifdef Ble
+#ifdef Sensors //#ifdef Ble
     if (Status>3)  { Status=1; }
 #else
     if (Status>2)  { Status=1; }
@@ -235,22 +236,30 @@
 
     if (p_customsensorservice->isStatusHandle(eventDataP->handle))
     {   
-        printf("\n\r\n\rSend BLE Display Status %d", Status);
+        #ifdef Debug
+            printf("\n\r\n\rSend BLE Display Status %d", Status);
+        #endif
         p_customsensorservice->sendEnvStatus(Status, TimeStamp);
         
-    } else if (p_customsensorservice->isDifferenceHandle(eventDataP->handle)) {
-
-        printf("\n\rSend BLE Difference %d lux/mems", diff); // Send BLE diff, no diff_abs
+    } else if (p_customsensorservice->isDifferenceHandle(eventDataP->handle))
+    {
+        #ifdef Debug
+            printf("\n\rSend BLE Difference %d lux/mems", diff); // Send BLE diff, no diff_abs
+        #endif
         p_customsensorservice->sendEnvDifference(diff, TimeStamp);
 
-    } else if (p_customsensorservice->isPositionHandle(eventDataP->handle)) {
-
-        printf("\n\rSend BLE Position %d", pos);
+    } else if (p_customsensorservice->isPositionHandle(eventDataP->handle))
+    {
+        #ifdef Debug
+            printf("\n\rSend BLE Position %d", pos);
+        #endif    
         p_customsensorservice->sendEnvPosition(pos, TimeStamp);
 
-    } else if (p_customsensorservice->isSunpanelHandle(eventDataP->handle)) {
-
-        printf("\n\rSend BLE Sunpanel %d mV", measure);            
+    } else if (p_customsensorservice->isSunpanelHandle(eventDataP->handle))
+    {
+        #ifdef Debug
+            printf("\n\rSend BLE Sunpanel %d mV", measure);
+        #endif    
         p_customsensorservice->sendEnvSunpanel(measure, TimeStamp);
 
     }
@@ -265,7 +274,7 @@
     {       
         // From CLIENT it receives a command in this format: Feature (4) + Type (1) + Data (2)        
         uint32_t Feature = eventDataP->data[0]<<24 | eventDataP->data[1]<<16 | eventDataP->data[2]<<8 | eventDataP->data[3];
-        uint8_t Type = eventDataP->data[4];
+        //uint8_t Type = eventDataP->data[4];
         int16_t Data = eventDataP->data[5]<<8 | eventDataP->data[6];
         
         //printf("\r\n\r\nmyonDataWriteCallback (Feature %x)", Feature);
@@ -282,7 +291,9 @@
                 break;
      
             case FeatureDifference:
-                printf("\r\n\r\nReceived DIFF %d", Data);
+                #ifdef Debug
+                    printf("\r\n\r\nReceived DIFF %d", Data);
+                #endif
                 diff = Data;
                 break;
  
@@ -302,12 +313,14 @@
 static void onConnectionCallback(const Gap::ConnectionCallbackParams_t * connectionParams)
 {
     printf("\r\n\r\nonConnectionCallback (Line %d)", __LINE__);   
+    BLEConnected=true;
 }
 
 static void onDisconnectionCallback(const Gap::DisconnectionCallbackParams_t * disConnectionReason)
 {
     printf("\r\n\r\nonDisconnectionCallback (Line %d)", __LINE__);
     p_BLEdev->gap().startAdvertising();
+    BLEConnected=false;
 }
 
 #endif
@@ -344,7 +357,6 @@
     // Setup BLE Advertising
     const static char DEVICE_NAME[] = BLE_DEV_NAME;
     p_BLEdev->gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
-    uint8_t dat[] = {0x01,0x80,0x00,0x00,0x78,0x00}; // Data Sent during Advertising, must respect a Standard ST
     p_BLEdev->gap().accumulateScanResponse(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA,dat,6);    
     p_BLEdev->gap().accumulateAdvertisingPayload(GapAdvertisingData::UNKNOWN);
     p_BLEdev->gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
@@ -546,8 +558,10 @@
     //printf("Measure = %.0f mV\r\n", measure);
     //board->display->DisplayDigit("A", 0);
 
+    //if (abs(measure-prev_meas)>(prev_meas*0.1)) { prev_meas = measure; }
+    //if (Status==2) { sprintf(DisplayStr, "%d", prev_meas); }
+    
     if (Status==2) { sprintf(DisplayStr, "%d", measure); }
-     
 }
 
 /* Ticker --------------------------------------------------------------------*/
@@ -578,9 +592,10 @@
     // Loop until push User Button to Set 0 Point
     printf("\r\nWait PUSH Button");
     strcpy(DisplayStr,"pusH");
-    while(Status==0) {
+    while(Status==0)
+    {
         #ifdef FlightSense
-        board->display->DisplayString(DisplayStr, 4);
+        board->display->DisplayString(DisplayStr, strlen(DisplayStr)); // if I set fix len=4, it aligns digit from left
         //printf("%s\n\r", DisplayStr);
         #endif
         
@@ -588,7 +603,9 @@
         if (p_customsensorservice->isStatusNotificationEn()) {
             if (tickerSta) {
                 tickerSta=false;
-                printf("\n\r\n\rSend BLE Display Status %d", Status);
+                #ifdef Debug
+                    printf("\n\r\n\rSend BLE Display Status %d", Status);
+                #endif
                 //p_customsensorservice->sendEnvStatus(Status, TimeStamp);
                 p_customsensorservice->updateEnvStatus(Status, TimeStamp);    
             }
@@ -611,26 +628,33 @@
 
     // Main Loop
     while(true)
-    {
+    {  
         if (Status==1 | Status==2)    { Measure_Babybear(); }
         
-        #ifndef Ble // without BLE it uses Accelerometer from SERVER, otherwise receive the value from CLIENT
-        if (Status==3)                { Measure_Accelerometer(); }
-        #endif
+        // If BLE is not connected, it uses Accelerometer from SERVER, otherwise receive the value from CLIENT
+        if (BLEConnected==false) {
+            if (Status==3)            { Measure_Accelerometer(); }
+        }
         
         Control_Motor();
         Measure_SolarPanel();
         
         #ifdef FlightSense
-        board->display->DisplayString(DisplayStr, 4);
+        board->display->DisplayString(DisplayStr, strlen(DisplayStr)); // if I set fix len=4, it aligns digit from left
         //printf("%s\n\r", DisplayStr);
         #endif
         
         #ifdef Ble 
+        //if (Status==3 & BLEConnected==false) { diff=0; }
+        //if Status 3 and BLE not connected set diff=0 (no more useful if use SERVER Accelerometer)
+        //After disconnect CLIENT, until it receive the timeout/notify to be really disconnected, it not receive diff!
+        
         if (p_customsensorservice->isStatusNotificationEn()) {
             if (tickerSta) {
                 tickerSta=false;
-                printf("\n\r\n\rSend BLE Display Status %d", Status);
+                #ifdef Debug
+                    printf("\n\r\n\rSend BLE Display Status %d", Status);
+                #endif
                 //p_customsensorservice->sendEnvStatus(Status, TimeStamp);
                 p_customsensorservice->updateEnvStatus(Status, TimeStamp);    
             }
@@ -638,35 +662,38 @@
         if (p_customsensorservice->isDifferenceNotificationEn()) {
             if (tickerDif) {
                 tickerDif=false;
-                printf("\n\rSend BLE Difference %d lux/mems", diff); // Send BLE diff, no diff_abs
+                #ifdef Debug
+                    printf("\n\rSend BLE Difference %d lux/mems", diff); // Send BLE diff, no diff_abs
+                #endif
                 //p_customsensorservice->sendEnvDifference(diff, TimeStamp);
                 p_customsensorservice->updateEnvDifference(diff, TimeStamp);
             }
         }
         if (p_customsensorservice->isPositionNotificationEn()) {
             if (tickerPos) {
-                tickerPos=false;       
-                printf("\n\rSend BLE Position %d", pos);
+                tickerPos=false;
+                #ifdef Debug      
+                    printf("\n\rSend BLE Position %d", pos);
+                #endif
                 //p_customsensorservice->sendEnvPosition(pos, TimeStamp);
                 p_customsensorservice->updateEnvPosition(pos, TimeStamp);
             }
         }
         if (p_customsensorservice->isSunpanelNotificationEn()) {
             if (tickerSun) {
-                tickerSun=false;      
-                printf("\n\rSend BLE SunPanel %d mV", measure);            
+                tickerSun=false;
+                #ifdef Debug   
+                    printf("\n\rSend BLE SunPanel %d mV", measure); 
+                #endif           
                 //p_customsensorservice->sendEnvSunpanel(measure, TimeStamp);
                 p_customsensorservice->updateEnvSunpanel(measure, TimeStamp);
             }
         }
-        //diff=0; // To reset it in case from Accelerometer doesn't arrive a future value (is better that Acc. always send a value)
          
         p_BLEdev->waitForEvent();
         #endif
-        
     }
 
     //status_l=board->sensor_left->StopMeasurement(als_continuous_polling);
     //status_r=board->sensor_right->StopMeasurement(als_continuous_polling);
-
 }
\ No newline at end of file