this project is based on the natural movement of droplet on leaf surface,while the droplet moves due to gravity and the shape of the leaf here in the project Led_light -droplet- moves due to the angles of tendency that calculated by inertial measurement unit (IMU) module and send message to modules to turn on or off LEDs.
First: Planning
We always design the appearance of the project before starting work, so we drew the modules with a number for each programmable modules only.The two modules on both sides of the project, the first(H03R00) is to DC-DC buck power supply and the other (H00R0)to control the led-light movement easier.
Second:Assemble
In this step, we're going to weld the modules together, as in the picture above.
Third: Programming
After we assembled the modules,formed an array and put the IMU module in the center.
We will number modules from 1 through 13 - except the DC-DC Module- to create a fixed-topology and upload code in processors so that they can communicate with each other and know their neighbors.
After we have numbered them, we will enter the fixed-topology to create a code and using µVision Keil IDE..
go to project.h as shown in the photo below and un-comment the header.
for more information about how to build fixed topology, you can always visit
https://hexabitz.com/docs/how-to/make-a-pre-built-array-topology-file/
after creating topology you must know that we have two projects one for IMU module(H0BR0) and the other for RGB-LED(H01R0) modules
we need to build our files for both projects.
in H0BR0 we actually need to do anything. However,in H01R0 we will create files for models 2 to 13 as the IMU module's number is 1 and we do this as follows:
for more information about how you can create files in µVision Keil IDE please check the video below
We will explain the code step by step, do not be worried the code may look long but it is repeated in several sections..
First of all, we're going to talk briefly about IMU.
An inertial measurement unit
(IMU) is an electronic device that measures and reports a body's specific force, angular rate, and sometimes the orientation of the body, using a combination of accelerometers, gyroscopes, and sometimes magnetometers. IMUs are typically used to maneuver aircraft (an attitude and heading reference system), including unmanned aerial vehicles (UAVs), among many others, and spacecraft, including satellites and landers. Recent developments allow for the production of IMU-enabled GPS devices. An IMU allows a GPS receiver to work when GPS-signals are unavailable, such as in tunnels, inside buildings, or when electronic interference is present
for more information, you can read about it this in the following article:
http://students.iitk.ac.in/roboclub/2017/12/21/Beginners-Guide-to-IMU.html
We're going to calculate Roll & Pitch on the x,y axes using the following equations.
Roll=arctg(y/z)*180/pi
pitch=arctg(-x/sqrt(y^2+z^2)*180/pi
- After calculating the angles we will select the module Id.
- each module has id depending on its locations.
- we have two ids: the first one is newly calculated that we need to turn it on and we define it as (id_new) and the other is old one we want to turn it off we define it as(id_old).
- We will send (on-message) to the module(id_new) and at the same time, we will send (off-module) to the former one(id_old).
volatile int16_t state;
volatile int16_t Response1;
volatile bool delay1;
static float x,y,z;
static int Roll,Pitch;
static float velocity;
static int id_new;
static int id_old;
void UserTask(void * argument)
{
BOS.trace=TRACE_NONE;
BOS.response=BOS_RESPONSE_NONE;
AddBOSvar(FMT_INT16,(uint32_t) &state);
AddBOSvar(FMT_INT16,(uint32_t) &Response1);
AddBOSvar(FMT_BOOL,(uint32_t) &delay1);
/* Infinite loop */
for(;;)
{ begin:
if(delay1==true)
{
velocity=0.5;
}
else
{
velocity=1;
}
SampleAccG(&x,&y,&z);
Roll = atan2(y, z) * 57.3*velocity;
Pitch = atan2(-x, sqrt(y*y + z*z)) * 57.3;
if(Roll>=2 && Roll<8)
{
if(Pitch>=3)
{
id_new=3;
}
else if (Pitch<=-3)
{
id_new=11;
}
else
{
id_new=7;
}
}
else if(Roll>=8 && Roll<16)
{
if(Pitch>=3)
{
id_new=2;
}
else if(Pitch<=-3)
{
id_new=10;
}
else
{
id_new=6;
}
}
else if(Roll<=-2 && Roll>-8)
{
if(Pitch>=3)
{id_new=4;
}
else if(Pitch<=-3)
{id_new=12;
}
else
{
id_new=8;
}
}
else if(Roll<=-8 && Roll>-16)
{
if(Pitch>=3)
{
id_new=5;
}
else if(Pitch<=-3)
{
id_new=13;
}
else
{id_new=9;
}
}
else
{IND_blink(100);
SendMessageToModule(id_old,CODE_H01R0_OFF,0);
goto begin;
}
if(id_old!=id_new && id_old!=0)
{ do
{state=2;
WriteRemote(id_old, (uint32_t) &state, 1, FMT_INT16, 0);
Delay_ms(50);
}
while(Response1!=id_old);
}
do
{state=1;
WriteRemote(id_new, (uint32_t) &state, 1, FMT_INT16, 0);
Delay_ms(50);
}
while(Response1!=id_new);
Response1=0;
id_old=id_new;
}
}
We'll use function:
AddBOSvar(format,(uint32_t) &nameofvarible);
This function is responsible for adding variables to remote addresses in BOS
for more information:
https://hexabitz.com/docs/code-overview/remote-memory-access/
and we use
/* --- Write a value to a remote module.
WriteRemote(uint8_t module, uint32_t localAddress, uint32_t remoteAddress, varFormat_t format, uint32_t timeout)
module: Remote module ID.
localAddress: Local memory address (RAM or Flash).
remoteAddress: Remote memory address (RAM or Flash). Use the 1 to MAX_BOS_VARS to write BOS variables.
format: Local format sent to remote module (FMT_UINT8, FMT_INT8, FMT_UINT16, FMT_INT16, FMT_UINT32, FMT_INT32, FMT_FLOAT, FMT_BOOL)
timeout: Write confirmation timeout in msec. Use 0 to disable confirmation.
*/
since we do not have acknowledgment yet in array communication messaging we use the do-while loop to make sure that our message is completely reached.
all of these in the IMU Module now we move on to RGB-LED Modules:
note: the code is the same for all RGB-LEDs Modules except for modules 6 and we will know why later.
/**
******************************************************************************
* File Name : main.c
* Description : Main program body
******************************************************************************
*
* COPYRIGHT(c) 2015 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/*
MODIFIED by Hexabitz for BitzOS (BOS) V0.1.6 - Copyright (C) 2017-2019 Hexabitz
All rights reserved
*/
/* Includes ------------------------------------------------------------------*/
#include "BOS.h"
/* Private variables ---------------------------------------------------------*/
volatile int16_t state;
volatile int16_t Response1;
volatile bool delay1;
/* Private function prototypes -----------------------------------------------*/
/* Main functions ------------------------------------------------------------*/
int main(void)
{
/* MCU Configuration----------------------------------------------------------*/
/* Reset all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all user peripherals */
/* Initialize BitzOS */
BOS_Init();
/* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
while (1)
{
}
}
/*-----------------------------------------------------------*/
/* User Task */
void UserTask(void * argument)
{BOS.trace=TRACE_NONE;
AddBOSvar(FMT_INT16,(uint32_t) &state);
AddBOSvar(FMT_INT16,(uint32_t) &Response1);
AddBOSvar(FMT_BOOL,(uint32_t) &delay1);
BOS.response = BOS_RESPONSE_NONE;
#if _module==6
AddPortButton(MOMENTARY_NO,P4);
SetButtonEvents(P4,1,1,0,0,0,0,0,0,0);
#endif
/* Infinite loop */
for(;;)
{
#if _module==2
if(state==1)
{ RGB_LED_on(50);
Response1=2;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=2;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==3
if(state==1)
{ RGB_LED_on(50);
Response1=3;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=3;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==4
if(state==1)
{ RGB_LED_on(50);
Response1=4;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=4;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==5
if(state==1)
{ RGB_LED_on(50);
Response1=5;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=5;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==6
if(state==1)
{ RGB_LED_on(50);
Response1=6;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=6;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==7
if(state==1)
{ RGB_LED_on(50);
Response1=7;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=7;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==8
if(state==1)
{ RGB_LED_on(50);
Response1=8;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=8;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==9
if(state==1)
{ RGB_LED_on(50);
Response1=9;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=9;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==10
if(state==1)
{ RGB_LED_on(50);
Response1=10;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=10;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==11
if(state==1)
{ RGB_LED_on(50);
Response1=11;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=11;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==12
if(state==1)
{ RGB_LED_on(50);
Response1=12;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=12;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
#if _module==13
if(state==1)
{ RGB_LED_on(50);
Response1=13;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
else if(state==2)
{
RGB_LED_off();
Response1=13;
WriteRemote(1, (uint32_t) &Response1, 2, FMT_INT16, 0);
state=0;
}
#endif
}}
void buttonClickedCallback(uint8_t port)
{
delay1=true;
IND_blink(10);
WriteRemote(1, (uint32_t) &delay1, 3, FMT_BOOL, 0);
}
void buttonDblClickedCallback(uint8_t port)
{delay1=false;
IND_blink(10);
WriteRemote(1, (uint32_t) &delay1, 3, FMT_BOOL, 0);
}
/*-----------------------------------------------------------*/
/************************ (C) COPYRIGHT HEXABITZ *****END OF FILE****/
BOS.trace=TRACE_NONE;
its only purpose is to prevent the indicators LED from turning on/off while sending messages through the array.
BOS.response = BOS_RESPONSE_NONE;
to prevent sending responses to every message.
#if _module==6
AddPortButton(MOMENTARY_NO,P4);
SetButtonEvents(P4,1,1,0,0,0,0,0,0,0);
#endif
void buttonClickedCallback(uint8_t port)
{
delay1=true;
IND_blink(10);
WriteRemote(1, (uint32_t) &delay1, 3, FMT_BOOL, 0);
}
void buttonDblClickedCallback(uint8_t port)
{delay1=false;
IND_blink(10);
WriteRemote(1, (uint32_t) &delay1, 3, FMT_BOOL, 0);
this part of code is only for module 6 because we add push button on port 4 to increase and decrease the speed of moving LEDs.
the first function is when clicking the button once this allows us to decrease the velocity to half and the other one is called when we double-click the button this will make the velocity back to normal.
the final result:
Comments