Difference between revisions of "Simple Embedded System Project"

From Embedded Systems Learning Academy
Jump to: navigation, search
Line 1: Line 1:
 
== Objective ==
 
== Objective ==
Work together as a group to create an LED lighting system.  Your board contains wireless mesh network allowing you to freely connect many boards together and they can all communicate with each other.  You will exploit this capability to do something creative, and ultimately learn, and have fun.
+
Work together as a group to create an LED lighting system.  Your board contains wireless mesh network allowing you to freely connect many boards together and they can all communicate with each other.
  
 
Think outside the box; you can do much more :
 
Think outside the box; you can do much more :
Line 8: Line 8:
  
 
== Structure ==
 
== Structure ==
For simplicity, the minimum requirement is that a team of two is able to control an LED strip wirelessly and you have to make it interactive such as turning on the LEDs upon light sensor or another trigger.  Before you proceed further, please come up with a wireless communication protocol as follows :
+
For simplicity, the minimum requirement is that a team of two is able to control an LED strip wirelessly and you have to make it interactive such as turning on the LEDs upon light sensor or another trigger.
 
 
{| class="wikitable"
 
!colspan="2"| Lights Wireless Protocol
 
|-
 
| Wireless Channel
 
| 2580
 
|-
 
| Wireless bitrate
 
| 2000
 
|-
 
| Wireless Address
 
| 110
 
|-
 
!colspan="2"| Command List
 
|-
 
| Lights ON
 
| Send data value of 1
 
|-
 
| Lights OFF
 
| Send data value of 2
 
|-
 
| Lights Auto
 
| Send data value of 3
 
|}
 
 
 
{| class="wikitable"
 
!colspan="3"| Sensor Node Wireless Protocol
 
|-
 
| Wireless Channel
 
| 2580
 
|-
 
| Wireless bitrate
 
| 2000
 
|-
 
| Wireless Address
 
| 125
 
|-
 
!colspan="3"| Command List
 
|-
 
| Get Light Sensor
 
| Send data value of 1
 
|  2-byte data returned as uint16_t
 
|-
 
| Get Temperature Sensor
 
| Send data value of 2
 
|  2-byte data returned as int16_t
 
|}
 
 
 
A good suggestion to follow is that the commander node always initiates communication and other nodes only "speak when spoken to".  This can generally simplify your project.  In other words, instead of unsolicited messages from nodes, the commander node shall initiate communication or "ask" for data.  This way, multiple nodes will not speak at the same time causing wireless data to collide and "vanish" in mid-air.
 
 
 
=== Lights Node ===
 
This node shall act like a wireless node that is responsible to turn on and off lights.  This will involve some hardware design such that you can connect your board to some high-power LEDs.  Look-up “super bright led” at sparkfun.com for examples.
 
 
 
=== Commander Node ===
 
This node shall be responsible to put it all together and serve as a single commanding node to get sensor input and control the lights.  This node shall provide the interface for the user, so try to provide user options to configure features such as automatic lights, or remote controlled operation.
 
  
 
<BR/>
 
<BR/>
Line 112: Line 57:
  
 
<BR/>
 
<BR/>
 
 
== Challenges & Hints ==
 
== Challenges & Hints ==
 
=== Challenges ===
 
=== Challenges ===
Line 120: Line 64:
 
*  How will you collaborate in your team?
 
*  How will you collaborate in your team?
 
*  How will you balance your budget and keep parts cost to a minimum?
 
*  How will you balance your budget and keep parts cost to a minimum?
*  How will you design your network protocol such that each team understands a command and response system well?
 
 
*  How will you make your project more creative?  How will it stand out?
 
*  How will you make your project more creative?  How will it stand out?
*  What if you command a light output node that is not responding?
 
*:  How will you report this to the user and what would you do?
 
  
 
=== Hints ===
 
=== Hints ===
*  For the commander, implement a "ping" packet that is sent to everyone once a second.
+
TODO
*:  If an ACK is received, turn on an LED, otherwise turn it off (one LED per remote node).
 
*:  This will immediately help diagnose connection issues.
 
 
 
<BR/>
 
== Sample Code ==
 
In Eclipse, with your project open, press Ctrl+Shift+R and type "sys_config.h" and open the file.  Modify the following settings, and note that after you change this file, you should also perform '''Project'''-->'''Clean''' and rebuild your software code.
 
*  WIRELESS_CHANNEL
 
*: All nodes must use the same channel
 
*: Use a value different than the rest of the class.
 
*  WIRELESS_ADDRESS
 
*: Each node should have a different address
 
 
 
<BR/>
 
=== Commander Node ===
 
You should try the '''Light Sensor Node''' and '''Commander Node''' code below in your group of 2 to get familiar with how to communicate wirelessly.
 
 
 
<syntaxhighlight lang="c">
 
#include <stdio.h>
 
#include "wireless.h"
 
#include "utilities.h"
 
 
 
    /* Keep an enum of addresses in all your nodes */
 
    enum {
 
        lights_addr = 100,
 
        commander_addr = 200,
 
    };
 
    /* Same enum as lights controller */
 
    enum {
 
        lights_on  = 1,
 
        lights_off = 2,
 
    };
 
 
 
int main(void)
 
{
 
    /* *********************************************************************
 
    * If the destination is far away, max_hops being 1 allows the pkt to
 
    * travel through 1 intermediate node to get to the final destination.
 
    *
 
    * Node address is set automatically based on sys_config.h
 
    * so setting node address again is not necessarily needed.
 
    */
 
    char cmd = 0;
 
    const char max_hops = 1;
 
    mesh_set_node_address(commander_addr);
 
 
 
    /* We will send "NACK" packet.  No acknowledge or retries will be done
 
    * if the packet gets lost on its way.  This is okay for a simple demo.
 
    * We copy 1 byte from &cmd before the packet is sent.
 
    */
 
    while (1) {
 
        puts("Lights on!");
 
        cmd = lights_on;
 
        wireless_send(lights_addr, mesh_pkt_nack, &cmd, 1, max_hops);
 
        delay_ms(1000);
 
 
 
        puts("Lights off :(");
 
        cmd = lights_off;
 
        wireless_send(lights_addr, mesh_pkt_nack, &cmd, 1, max_hops);
 
        delay_ms(1000);
 
    }
 
 
 
    return 0;
 
}
 
</syntaxhighlight>
 
 
 
<BR/>
 
 
 
=== LED Node ===
 
<syntaxhighlight lang="c">
 
#include <stdio.h>
 
#include "wireless.h"
 
#include "io.hpp"
 
 
 
    /* Keep an enum of addresses in all your nodes */
 
    enum {
 
        lights_addr = 100,
 
        commander_addr = 200,
 
    };
 
    /* Enum of our commands */
 
    enum {
 
        lights_on  = 1,
 
        lights_off = 2,
 
    };
 
 
 
void process_command(char command);
 
 
 
int main(void)
 
{
 
    mesh_set_node_address(lights_addr);
 
 
 
    while (1) {       
 
        mesh_packet_t pkt;
 
        if (wireless_get_rx_pkt(&pkt, 1000)) {  /* Check if we get a packet within 1 second : */
 
            puts("Rx pkt!");
 
            char cmd = pkt.data[0];            /* Assume first byte is our command */
 
            process_command(cmd);
 
        }
 
    }
 
    return 0;
 
}
 
 
 
void process_command(char command)
 
{
 
    switch(command) {
 
        case lights_on:
 
            LE.on(1);  /* Turn on LED#1 on the board */
 
        break;
 
 
 
        case lights_off:
 
            LE.off(1);  /* Turn OFF LED#1 on the board */
 
        break;
 
 
 
        default:
 
            printf("ERROR: INVALID COMMAND!\n");
 
        break;
 
    }
 
}
 
</syntaxhighlight>
 
 
 
<BR/>
 
 
 
=== Ping! ===
 
This code sample not only shows how to "ping" another node, but it also shows how we can ask for an "ACK" or acknowledgement that the packet was delivered.  Note that we send '''<code>mesh_pkt_ack</code>''' type of packet, and then we wait some time for an acknowledgement packet through '''<code>wireless_get_ack_pkt()</code>'''
 
 
 
<syntaxhighlight lang="c">
 
#include <stdio.h>
 
#include "io.hpp"
 
#include "wireless.h"
 
#include "soft_timer.hpp"
 
 
 
void ping_and_set_led(uint8_t addr, uint8_t led_num)
 
{
 
    /* Sending NULL packet is a "PING" packet.
 
    * No special code is required at the other node since the
 
    * other node will automatically send the ACK back.
 
    */
 
    const char max_hops = 2;
 
    mesh_packet_t pkt;
 
    wireless_send(addr, mesh_pkt_ack, NULL, 0, max_hops);
 
 
 
    /* Turn LED on or off based on if we get ACK packet within 100ms */
 
    if (wireless_get_ack_pkt(&pkt, 100)) {
 
        LE.on(led_num);
 
    }
 
    else {
 
        LE.off(led_num);
 
        printf("No response from %i\n", addr);
 
    }
 
}
 
 
 
int main(void)
 
{
 
    /* Keep an enum of addresses in all your nodes */
 
    enum {
 
        lights_addr = 100,
 
        sensor_addr = 125,
 
        commander_addr = 200,
 
    };
 
 
 
    /* Use a software timer "object" with 2000ms duration. */
 
    SoftTimer ping_timer;
 
    ping_timer.reset(2000);
 
 
 
    while (1) {
 
        /* If timer expires, restart it again and ping everyone. */
 
        if (ping_timer.expired()) {
 
            ping_timer.restart();
 
 
 
            ping_and_set_led(lights_addr, 1);
 
            ping_and_set_led(sensor_addr, 2);
 
        }
 
    }
 
 
 
    return 0;
 
}
 
</syntaxhighlight>
 
 
 
<BR/>
 
 
 
=== Send & Receive Data Variables ===
 
In this example, a commander sends an "Application Acknowledge" packet, meaning that the destination will have to manually send an acknowledge packet back.  In other words, instead of auto-acknowledge, we send the ACK back with the requested data.  Furthermore, we show you how data variables can be exchanged between two boards. '''Note that the wireless can only transport 24-bytes through a single packet.'''
 
 
 
<syntaxhighlight lang="c">
 
#include <stdio.h>
 
#include <stdint.h>
 
#include "wireless.h"
 
#include "io.hpp"
 
 
 
    /* Common between commander and sensor node
 
    * This identifies "what" the commander is asking for
 
    */
 
    enum {
 
        req_light = 1, /* Request light sensor reading      */
 
        req_all = 2,
 
    };
 
 
 
void commander(void)
 
{
 
    char hops = 1;
 
    char addr = 100;
 
    char cmd  = req_light; /* Request light sensor data */
 
 
 
    /* mesh_pkt_ack_app means the destination should ACK manually
 
    * with our data, and an auto-ack is not performed.
 
    */
 
    wireless_send(addr, mesh_pkt_ack_app, &cmd, 1, hops);
 
 
 
    mesh_packet_t pkt;
 
    if (wireless_get_ack_pkt(&pkt, 100)) {
 
        /* We need to deform packet the same way it was formed */
 
        /* Parameters should be same after 4th parameter into wireless_form_pkt() */
 
        uint16_t light = 0;
 
        wireless_deform_pkt(&pkt, 1, &light, sizeof(light));
 
    }
 
}
 
 
 
void sensor(void)
 
{
 
    mesh_packet_t pkt;
 
    uint16_t light = 0;
 
 
 
    if (wireless_get_rx_pkt(&pkt, 100)) {
 
        /* Check if we were asked for an application ACK */
 
        if (wireless_is_ack_required(&pkt)) {
 
 
 
            /* Send the packet back based on the commanded byte */
 
            const char cmd = pkt.data[0];
 
            switch (cmd) {
 
                case req_light :
 
                    /* Send packet back to network source: pkt.nwk.src */
 
                    light = LS.getRawValue();
 
                    wireless_form_pkt(&pkt, pkt.nwk.src, mesh_pkt_ack_rsp, 1,
 
                                      1,
 
                                      &light, sizeof(light));
 
                break;
 
 
 
                case req_all :
 
                    /* TODO: You figure this out.  You can send up to 24 bytes of data */
 
                break;
 
 
 
                default:
 
                    printf("ERROR: Invalid data requested!\n");
 
                break;
 
            }
 
 
 
            wireless_send_formed_pkt(&pkt);
 
        }
 
    }
 
}
 
</syntaxhighlight>
 
 
 
<BR/>
 
 
 
=== Wireless Functions Quick Reference ===
 
<syntaxhighlight lang="c">
 
#include <stdio.h>
 
#include <stdint.h>
 
#include "wireless.h"
 
 
 
void quick_reference(void)
 
{
 
    char hops = 1;
 
    char addr = 100;
 
    mesh_packet_t pkt;
 
 
 
    /* Send a packet without an ACK or retries */
 
    wireless_send(addr, mesh_pkt_nack, "HELLO", 5, hops);
 
 
 
    /* Send a packet to everyone.  ACK not possible for broadcast messages */
 
    wireless_send(MESH_BROADCAST_ADDR, mesh_pkt_nack, "HELLO", 5, hops);
 
 
 
    /* Send a "PING" Packet with an ACK request */
 
    wireless_send(addr, mesh_pkt_ack, NULL, 0, hops);
 
    /* Wait for response of ping packet and print it */
 
    if (wireless_get_ack_pkt(&pkt, 1000)) {
 
        printf("Node response: ");
 
        for (int i=0; i < pkt.info.data_len; i++) {
 
            putchar( pkt.data[i] );
 
        }
 
        printf("\n");
 
    }
 
 
 
    /* Send a packet with "HELLO" (which is 5 data bytes) with an ACK request*/
 
    wireless_send(addr, mesh_pkt_ack, "HELLO", 5, hops);
 
    /* We should wait for the ACK if it was requested.  ACK typically takes 10ms per hop */
 
    if (wireless_get_ack_pkt(&pkt, 25)) {
 
    }
 
 
 
    /* Flush all incoming data (maybe for stale ACKs) */
 
    wireless_flush_rx();
 
 
 
    /* Send a packet and wait for ack for 1000ms (1 sec) */
 
    wireless_send(addr, mesh_pkt_ack, "HELLO", 5, hops);
 
    if (wireless_get_ack_pkt(&pkt, 1000)) {
 
        /* Got an ACK */
 
    }
 
 
 
    /* Try to get a packet destined for us with 100ms timeout*/
 
    if (wireless_get_rx_pkt(&pkt, 100)) {
 
    }
 
 
 
    /* Send a packet with two data variables */
 
    int var1 = 0;
 
    float var2 = 0;
 
    wireless_form_pkt(&pkt, addr, mesh_pkt_ack, hops,
 
                      2,                    /* 2 Pairs below */
 
                      &var1, sizeof(var1),  /* Pair 1 */
 
                      &var2, sizeof(var2));  /* Pair 2 */
 
    /* Packet was formed above, now send it */
 
    wireless_send_formed_pkt(&pkt);
 
 
 
    /* Manually set data bytes of a packet, but need to form the header first */
 
    wireless_form_pkt(&pkt, addr, mesh_pkt_ack, hops, 0);
 
    /* Modify the data bytes AFTER forming the packet header */
 
    pkt.data[0] = 10;
 
    pkt.data[1] = 11;
 
    pkt.data[2] = 12;
 
    pkt.info.data_len = 3;
 
    /* Finally, send the packet */
 
    wireless_send_formed_pkt(&pkt);
 
}
 
</syntaxhighlight>
 
 
 
<BR/>
 
 
 
== Troubleshooting ==
 
'''My boards cannot communicate.'''
 
*  Double check '''sys_config.h''' to make sure wireless channels are the same.
 
*  Did you use correct source and destination address?  Double check the wireless address set at '''sys_config.h'''
 
*  Are the wireless boards too far away from each other?
 
*  Try doing '''Project''' --> '''Clean''' and build/compile your code again.
 
<BR/>
 
'''Sometimes wireless doesn't work'''
 
*  This is normal because sometimes wireless packets do not make it through due to interference.
 
*: Try using another wireless channel.
 
*: The wireless mesh software will retry packets a few times, but in case packets still do not make it through your software needs to be able to cope with this behavior.
 

Revision as of 01:56, 5 June 2014

Objective

Work together as a group to create an LED lighting system. Your board contains wireless mesh network allowing you to freely connect many boards together and they can all communicate with each other.

Think outside the box; you can do much more :

  • You can create an alarm clock and turn on LEDs on/off
  • Orientation or rotation of commander node can turn on/off lights or change colors.
  • You can combine your group with another group to make your project look better!

Structure

For simplicity, the minimum requirement is that a team of two is able to control an LED strip wirelessly and you have to make it interactive such as turning on the LEDs upon light sensor or another trigger.


Requirements

Technical

Your grade will depend on how well you follow the following requirements :

  1. You must use a switch / case code section in your code.
  2. You must use a state machine in at least one of your nodes.
    This could be as simple as a state machine for "Manual Lights" vs. "Automatic Lights"
  3. All functions used shall be no larger than 50 lines of code.
    Split into smaller sub-functions.
  4. You must utilize functions that use pass-by-value and pass-by-reference.
  5. Project should be self-contained
    • Project should be enclosed, with no wires visible.
    • Project should not require the Hercules Terminal to operate.
    • Project should preferably operate with its own independent power source (or battery pack).
  6. All buttons should be labeled.
    An operator should be able to operate without reading an instruction manual.

Items to Submit

At the end of the project, the following items need to be submitted :

  • Full source-code of all the projects
  • Individual evaluations about team members and their contribution
    This will be confidential, and you can submit as one per person (at Canvas).

Project Report

You must submit a full, documented report for your project (one per group of six). The following are minimum sections required in your PDF submitted report:

  1. Introduction
    • What does your project do?
    • Try to sell your project in this section.
    • Add a sub-section called "Features & Communication Table"
      List the features of each node and the communication table.
      At least four unique features per node should be listed.
  2. Schematics
    • List the hardware you used.
    • Use "LibreOffice Draw" to draw the schematics
  3. Implementation
    • Show your software workings using a flow-chart
    • Use bullets and pictures to show the "how" part.
    • Show what Software you used to control your Hardware.
  4. Testing
    • What kind of tests did you perform?
    • What kind of problems did you solve?
  5. Conclusion
    • What did you learn?
    • What worked, and what didn't work?
    • How would you improve your project?


Challenges & Hints

Challenges

Over the course of the project, you will encounter some real-world problems such as :

  • How will you design your project to be user friendly?
  • How will you collaborate in your team?
  • How will you balance your budget and keep parts cost to a minimum?
  • How will you make your project more creative? How will it stand out?

Hints

TODO