Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
We are on Kickstarter and we need your help!
Marta needs your help! We have to save the #TheIFS! Help us and share! #kickstarter
Get yours here
https://www.kickstarter.com/projects/theifs/new-toy-robot-game-makes-learning-to-code-childs-play
The first educational toy to teach coding without the need to know how to read. The Ifs is a family of robots with sensors through different color pieces that are placed on their heads. The different color pieces are instructions that are combined as if it were a code, from being able to light them when it's dark to making them communicate with each other. This allows kids to play with loops, statements, algorithms while also inventing their own stories. Their imagination is the only limit.More information:www.theifs.cc
DetailsCoding: It is child's play!
The Ifs are a family of robots that bring technology closer to children. With the help of their creativity and imagination, kids will learn how to code and develop logical thinking. These skills are essential so children can invent their own future.
Help us reach this goal by sharing our ideas with your friend.
Twitter - @playtheifs
https://twitter.com/playtheifs
Facebook - Playtheifs
https://m.facebook.com/playtheifs
Instagram - Playtheifs
https://instagram.com/playtheifs
Tangible programming without screens
The Ifs are full of sensors and actuators but they need some instructions in order to function.
Programming is as simple as placing physical blocks in their heads with the help of magnets. No screens are involved. Each block has a different image serving as an intuitive symbol to represent an instruction. This makes the game suitable for children from the age of three, even before learning to read or write.
We only need different color pieces that are placed on their heads. The different color pieces are instructions that are combined as if it were a code, from being able to light them when it's dark to making them communicate with each other. This allows kids to play with loops, statements, algorithms while also inventing their own stories. Their imagination is the only limit.
For girls and boys from 3+ / From 3+
The Ifs is an STEAMeducational toy that will teach your child the basics of computer programming. It consists of a family of four robots in which each member has different superpowers. Coding is only the beginning of the game. Children can imagine thousands of adventures and make them happen by programming the robots. The Ifs strengthen learning through play in early childhood and can also be used in middle childhood to learn more complex concepts.
Girls in Tech
Because technology is genderless, The Ifs' mission is to bring girls into technology from an early age. The Ifs is intended for boys and girls with colors, shapes and features that appeal to both of them.
The Ifs Website
Projects
Makeroni Labs
Files#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include "pitches.h"
#include "NRF24L01.h"
//neopixels
#define PIN 2
#define NUMBER_OF_LEDS 2
//RF
#define TX_ADR_WIDTH 5 // 5 unsigned chars TX(RX) address width
#define TX_PLOAD_WIDTH 1 // 32 unsigned chars TX payload
//////Slots//////
//ifs
#define getTap 1
#define darkness 2
#define faceDown 3
#define EmmaCalls 4
//thens
#define turnLight 1
#define playSound 2
#define callLiam 3
int ifSlot;
int thenSlot;
int luz=0;
int golpe;
int tap_detection;
////sound////
// notes in the melody:
int melody[] = {
NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
4, 8, 8, 4, 4, 4, 4, 4
};
////acelermetro////
byte Version[3];
int8_t x_data;
int8_t y_data;
int8_t z_data;
byte range=0x00;
float divi=16;
float x,y,z;
/////RF///////
unsigned char TX_ADDRESS[TX_ADR_WIDTH] =
{
0x34,0x43,0x10,0x10,0x01
}; // Define a static TX address
unsigned char rx_buf[TX_PLOAD_WIDTH];
unsigned char tx_buf[TX_PLOAD_WIDTH];
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMBER_OF_LEDS, PIN, NEO_GRB + NEO_KHZ800);
void setup() {
Serial.begin(9600);
//neopixels
strip.begin();
strip.show(); // Initialize all pixels to 'off'
SPI_DIR = ( CE + SCK + CSN + MOSI);
SPI_DIR &=~ ( IRQ + MISO);
// attachInterrupt(1, _ISR, LOW); // interrupt enable
init_io(); // Initialize IO port
unsigned char status=SPI_Read(STATUS);
//acelermetro
Wire.begin();
Wire.beginTransmission(0x0A); // address of the accelerometer
// range settings
Wire.write(0x22); //register address
Wire.write(range); //can be set at"0x00""0x01""0x02""0x03", refer to Datashhet on wiki
// low pass filter
Wire.write(0x20); //register address
Wire.write(0x05); //can be set at"0x05""0x04"......"0x01""0x00", refer to Datashhet on wiki
Wire.endTransmission();
}
void loop() {
//Acelermetro
switch(range) //change the data dealing method based on the range u've set
{
case 0x00:divi=16; break;
case 0x01:divi=8; break;
case 0x02:divi=4; break;
case 0x03:divi=2; break;
default: Serial.println("range setting is Wrong,range:from 0to 3.Please check!");while(1);
}
AccelerometerInit();
checkIfs();
checkThens();
/////getTap y TurnLight estn encajadas//////
if ((ifSlot ==1) && (thenSlot==1))
{
taps();
if ((golpe==1)&&(luz==0)){
colorWipe(strip.Color(255, 0, 0), 50);
Serial.println("getTap & turnONLight");
luz=1;
}
else {
if ((golpe==1)&&(luz==1))
{
colorWipe(strip.Color(0, 0, 0), 50);
Serial.println("getTap & turnOFFLight");
luz=0;
}
}}
else
/////getTap y PlaySound estn encajadas//////
{if ((ifSlot==1) && (thenSlot==2))
{
taps();
if (golpe==1)
{
music();
Serial.println("music");
}
}
else
/////Darkness y TurnLight estn encajadas////////
{if ((ifSlot==2) && (thenSlot==1))
{
if (analogRead(A3)>920)
{
colorWipe(strip.Color(0, 255, 0), 50);
}
else{ if ((analogRead(A3)>780)&&(analogRead(A3)<920)){
colorWipe(strip.Color(0, 0, 255), 50); }
else colorWipe(strip.Color(0, 0, 0), 50);
}
}
else
/////Darkness y PlaySound estn encajadas////////
{if ((ifSlot==2) && (thenSlot==2))
{
if (analogRead(A3)>900)
{
music();
Serial.println("music");
}
}
else
/////FaceDown y PlaySound estn encajadas////////
{if ((ifSlot==3) && (thenSlot==2))
{
AccelerometerInit();
if (z_data<0)
{
music();
Serial.println("music");
}
}
else
/////FaceDown y TurnLight estn encajadas////////
{if ((ifSlot==3) && (thenSlot==1)){
AccelerometerInit();
if (z_data<0)
{
colorWipe(strip.Color(255, 0, 255), 50);
}
else {colorWipe(strip.Color(0, 0, 0), 50);
}}
else
/////EmmaCalls y TurnLight estn encajadas////////
{if ((ifSlot==4) && (thenSlot==1)){
Serial.println("Emma Calls y Turn Light");
recibo();
if (rx_buf[0]==1){ colorWipe(strip.Color(255, 255, 0), 50);rx_buf[0]=0;
Serial.print(rx_buf[0],HEX);
}
else {colorWipe(strip.Color(0, 0, 0), 50); Serial.print(rx_buf[0],HEX);
}
}
else
/////EmmaCalls y Music estn encajadas////////
{if ((ifSlot==4) && (thenSlot==2)){
Serial.println("Emma Calls y Turn Light");
recibo();
if (rx_buf[0]==1){ music();rx_buf[0]=0;
Serial.print(rx_buf[0],HEX);
}
else {noTone(3); Serial.print(rx_buf[0],HEX);
}
}
else
/////FaceDown y CallLiam estn encajadas////////
{if ((ifSlot==3) && (thenSlot==3))
{
Serial.println("Face Down y Call Liam");
AccelerometerInit();
if (z_data<0)
{
envio();
}
}
else
/////GetTap y CallLiam estn encajadas////////
{if ((ifSlot==1) && (thenSlot==3))
{
Serial.println("Face Down y Call Liam");
taps();
if (golpe==1){
envio();
}}
else
/////Darkness y CallLiam estn encajadas////////
{if ((ifSlot==2) && (thenSlot==3))
{
Serial.println("Face Down y Call Liam");
if (analogRead(A3)>900)
{
envio();
}}
///Sino hay dos piezas encajadas
else{colorWipe(strip.Color(0, 0, 0), 50); noTone(3);}
////////////////////////////////
}}}}}}}}}}}
//////////////////// FUNCIONES ////////////////////
//////////////Checks-comprueba si hay if then y cual es su valor//////////////
void checkIfs(){
int sensorValue = analogRead(A2);
if ((sensorValue>322)&&(sensorValue<328)){
ifSlot = getTap;
}
else {if ((sensorValue>87)&&(sensorValue<94)){
ifSlot = darkness;
} else {if ((sensorValue>40)&&(sensorValue<47)){
ifSlot = faceDown;
}
else {if ((sensorValue>130)&&(sensorValue<136)){
ifSlot = EmmaCalls;
}
else ifSlot = 0;
}}}}
void checkThens(){
int sensorValue2 = analogRead(A1);
if ((sensorValue2>510)&&(sensorValue2<517)){
thenSlot = turnLight;
}
else {if ((sensorValue2>179)&&(sensorValue2<185)){
thenSlot = playSound;
}
else {if ((sensorValue2>20)&&(sensorValue2<25)){
thenSlot = callLiam;
}
else thenSlot = 0;
}}}
//Taps-comprueba si ha habido un golpe
int taps(){
if (z_data>20) {
Serial.println(z_data);
delay(100);
AccelerometerInit();
Serial.print("ahora");
Serial.println(z_data);
if (z_data<20){
return golpe=1;
}
else return golpe=0;
}
else return golpe=0;
}
//////////////Neopixels//////////////////
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
///////////Acelermetro//////////////////
int AccelerometerInit()
{
Wire.beginTransmission(0x0A); // address of the accelerometer
// reset the accelerometer
Wire.write(0x04); // Y data
Wire.endTransmission();
Wire.requestFrom(0x0A,1); // request 6 bytes from slave device #2
while(Wire.available()) // slave may send less than requested
{
Version[0] = Wire.read(); // receive a byte as characte
}
x_data=(int8_t)Version[0]>>2;
Wire.beginTransmission(0x0A); // address of the accelerometer
// reset the accelerometer
Wire.write(0x06); // Y data
Wire.endTransmission();
Wire.requestFrom(0x0A,1); // request 6 bytes from slave device #2
while(Wire.available()) // slave may send less than requested
{
Version[1] = Wire.read(); // receive a byte as characte
}
y_data=(int8_t)Version[1]>>2;
Wire.beginTransmission(0x0A); // address of the accelerometer
// reset the accelerometer
Wire.write(0x08); // Y data
Wire.endTransmission();
Wire.requestFrom(0x0A,1); // request 6 bytes from slave device #2
while(Wire.available()) // slave may send less than requested
{
Version[2] = Wire.read(); // receive a byte as characte
}
z_data=(int8_t)Version[2]>>2;
return z_data;
}
/////////////////PlaySound///////////////////
void music(){
// iterate over the notes of the melody:
for (int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000 / noteDurations[thisNote];
tone(3, melody[thisNote], noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(3);
}
}
//////////////RF//////////////////////
//**************************************************
// Function: init_io();
// Description:
// flash led one time,chip enable(ready to TX or RX Mode),
// Spi disable,Spi clock line init high
//**************************************************
void init_io(void)
{
SPI_PORT&=~CE; // chip enable
SPI_PORT|=CSN; // Spi disable
SPI_PORT&=~SCK; // Spi clock line init high
}
/**************************************************
* Function: SPI_RW();
*
* Description:
* Writes one unsigned char to nRF24L01, and return the unsigned char read
* from nRF24L01 during write, according to SPI protocol
**************************************************/
unsigned char SPI_RW(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++) // output 8-bit
{
if(Byte&0x80)
{
SPI_PORT |=MOSI; // output 'unsigned char', MSB to MOSI
}
else
{
SPI_PORT &=~MOSI;
}
SPI_PORT|=SCK; // Set SCK high..
Byte <<= 1; // shift next bit into MSB..
if(SPI_IN & MISO)
{
Byte |= 1; // capture current MISO bit
}
SPI_PORT&=~SCK; // ..then set SCK low again
}
return(Byte); // return read unsigned char
}
/**************************************************/
/**************************************************
* Function: SPI_RW_Reg();
*
* Description:
* Writes value 'value' to register 'reg'
/**************************************************/
unsigned char SPI_RW_Reg(unsigned char reg, unsigned char value)
{
unsigned char status;
SPI_PORT&=~CSN; // CSN low, init SPI transaction
status = SPI_RW(reg); // select register
SPI_RW(value); // ..and write value to it..
SPI_PORT|=CSN; // CSN high again
return(status); // return nRF24L01 status unsigned char
}
/**************************************************/
/**************************************************
* Function: SPI_Read();
*
* Description:
* Read one unsigned char from nRF24L01 register, 'reg'
/**************************************************/
unsigned char SPI_Read(unsigned char reg)
{
unsigned char reg_val;
SPI_PORT&=~CSN; // CSN low, initialize SPI communication...
SPI_RW(reg); // Select register to read from..
reg_val = SPI_RW(0); // ..then read register value
SPI_PORT|=CSN; // CSN high, terminate SPI communication
return(reg_val); // return register value
}
/**************************************************/
/**************************************************
* Function: SPI_Read_Buf();
*
* Description:
* Reads 'unsigned chars' #of unsigned chars from register 'reg'
* Typically used to read RX payload, Rx/Tx address
/**************************************************/
unsigned char SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
unsigned char status,i;
SPI_PORT&=~CSN; // Set CSN low, init SPI tranaction
status = SPI_RW(reg); // Select register to write to and read status unsigned char
for(i=0;i<bytes;i++)
{
pBuf[i] = SPI_RW(0); // Perform SPI_RW to read unsigned char from nRF24L01
}
SPI_PORT|=CSN; // Set CSN high again
return(status); // return nRF24L01 status unsigned char
}
/**************************************************/
/**************************************************
* Function: SPI_Write_Buf();
*
* Description:
* Writes contents of buffer '*pBuf' to nRF24L01
* Typically used to write TX payload, Rx/Tx address
/**************************************************/
unsigned char SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
unsigned char status,i;
SPI_PORT&=~CSN; // Set CSN low, init SPI tranaction
status = SPI_RW(reg); // Select register to write to and read status unsigned char
for(i=0;i<bytes; i++) // then write all unsigned char in buffer(*pBuf)
{
SPI_RW(*pBuf++);
}
SPI_PORT|=CSN; // Set CSN high again
return(status); // return nRF24L01 status unsigned char
}
/**************************************************/
/**************************************************
* Function: RX_Mode();
*
* Description:
* This function initializes one nRF24L01 device to
* RX Mode, set RX address, writes RX payload width,
* select RF channel, datarate & LNA HCURR.
* After init, CE is toggled high, which means that
* this device is now ready to receive a datapacket.
/**************************************************/
void RX_Mode(void)
{
SPI_PORT&=~CE;
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // Use the same address on the RX device as the TX device
SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // Enable Auto.Ack:Pipe0
SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // Enable Pipe0
SPI_RW_Reg(WRITE_REG + RF_CH, 40); // Select RF channel 40
SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); // Select same RX payload width as TX Payload width
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); // Set PWR_UP bit, enable CRC(2 unsigned chars) & Prim:RX. RX_DR enabled..
SPI_PORT|=CE; // Set CE pin high to enable RX device
// This device is now ready to receive one packet of 16 unsigned chars payload from a TX device sending to address
// '3443101001', with auto acknowledgment, retransmit count of 10, RF channel 40 and datarate = 2Mbps.
}
/**************************************************/
/**************************************************
* Function: TX_Mode();
*
* Description:
* This function initializes one nRF24L01 device to
* TX mode, set TX address, set RX address for auto.ack,
* fill TX payload, select RF channel, datarate & TX pwr.
* PWR_UP is set, CRC(2 unsigned chars) is enabled, & PRIM:TX.
*
* ToDo: One high pulse(>10us) on CE will now send this
* packet and expext an acknowledgment from the RX device.
**************************************************/
void TX_Mode(void)
{
SPI_PORT&=~CE;
SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // Writes TX_Address to nRF24L01
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // RX_Addr0 same as TX_Adr for Auto.Ack
SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // Enable Auto.Ack:Pipe0
SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // Enable Pipe0
SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a); // 500us + 86us, 10 retrans...
SPI_RW_Reg(WRITE_REG + RF_CH, 40); // Select RF channel 40
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // Set PWR_UP bit, enable CRC(2 unsigned chars) & Prim:TX. MAX_RT & TX_DS enabled..
SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);
SPI_PORT|=CE;
}
/**************************************************/
void envio()
{
TX_Mode(); // set TX mode
int k = 0;
for(int i=0; i<1; i++)
tx_buf[i] = 1;
unsigned char status = SPI_Read(STATUS); // read register STATUS's value
if(status&TX_DS) // if receive data ready (TX_DS) interrupt
{
SPI_RW_Reg(FLUSH_TX,0);
SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH); // write playload to TX_FIFO
}
if(status&MAX_RT) // if receive data ready (MAX_RT) interrupt, this is retransmit than SETUP_RETR
{
SPI_RW_Reg(FLUSH_TX,0);
SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH); // disable standy-mode
}
SPI_RW_Reg(WRITE_REG+STATUS,status); // clear RX_DR or TX_DS or MAX_RT interrupt flag
//delay(1000);
}
void recibo()
{
RX_Mode(); // set RX mode
unsigned char status = SPI_Read(STATUS); // read register STATUS's value
if(status&RX_DR) // if receive data ready (TX_DS) interrupt
{
SPI_Read_Buf(RD_RX_PLOAD, rx_buf, TX_PLOAD_WIDTH); // read playload to rx_buf
SPI_RW_Reg(FLUSH_RX,0); // clear RX_FIFO
for(int i=0; i<1; i++)
{
Serial.print(" ");
Serial.print(rx_buf[i],HEX); // print rx_buf
}
}
SPI_RW_Reg(WRITE_REG+STATUS,status); // clear RX_DR or TX_DS or MAX_RT interrupt flag
//delay(1000);
}
Comments
Please log in or sign up to comment.