Show Posts
Pages: [1] 2 3 ... 12
1  Using Arduino / Sensors / Re: ITG-3200 with Leonardo on: March 02, 2013, 03:12:13 pm
Okay I must be having some issues with the sensors for I am still only getting back the one address. I'm going to work on the board a little and get back to you with an update in the next couple hours. LMK if you think of anything else.
2  Using Arduino / Sensors / Re: ITG-3200 with Leonardo on: March 02, 2013, 01:38:35 pm
Thanks Erdin for the reply, I just uploaded the code and ran it through a test. I got one address back(0x3C). But, I have a total of four i2c devices on the circuit board. Shouldn't I be receiving an address from them as well? If so I must be having some problem reading those three sensors?
3  Using Arduino / Sensors / Re: ITG-3200 with Leonardo on: March 02, 2013, 12:10:59 am
I checked the data sheet for the atmega32u4 and double checked the wiring. It's connected correctly. I have the pull-ups enabled. Do you think That because the level converter isn't necessary it's causing problems with the signal?
4  Using Arduino / Sensors / Re: ITG-3200 with Leonardo on: February 27, 2013, 10:29:38 pm
Any Ideas?
5  Using Arduino / Sensors / ITG-3200 with Leonardo on: February 27, 2013, 07:52:18 pm
I've been building an IMU for the past couple days that uses the i2c ITG-3200. The ITG operates @ 3.3v so I used a logic converter for the two communication lines. The problem I am having is reading the values from the ITG. When I open up the serial port, The only values that I get back are 0. I just used the stock ITG example code from spark fun:
Code:
/*
3/16/11
Basic Example Sketch for the ITG-3200 (http://www.sparkfun.com/products/9801)
SparkFun Electronics 2011
Ryan Owens

This code is public domain buy you buy me a beer if you use this and we meet someday (Beerware license).

To use this example code, attach:
Arduino  :  ITG-3200 Breakout
3.3V  :  VDD
3.3V  :  VIO
GND   :  GND
SDA   :  A4
SCL   :  A5

Load the sketch and open the serial window at 9600 bps. Arduino will output the raw X,Y and Z axis data being read from the gyroscope.

*/

//The Wire library is used for I2C communication
#include <Wire.h>

//This is a list of registers in the ITG-3200. Registers are parameters that determine how the sensor will behave, or they can hold data that represent the
//sensors current status.
//To learn more about the registers on the ITG-3200, download and read the datasheet.
char WHO_AM_I = 0x00;
char SMPLRT_DIV= 0x15;
char DLPF_FS = 0x16;
char GYRO_XOUT_H = 0x1D;
char GYRO_XOUT_L = 0x1E;
char GYRO_YOUT_H = 0x1F;
char GYRO_YOUT_L = 0x20;
char GYRO_ZOUT_H = 0x21;
char GYRO_ZOUT_L = 0x22;

//This is a list of settings that can be loaded into the registers.
//DLPF, Full Scale Register Bits
//FS_SEL must be set to 3 for proper operation
//Set DLPF_CFG to 3 for 1kHz Fint and 42 Hz Low Pass Filter
char DLPF_CFG_0 = (1<<0);
char DLPF_CFG_1 = (1<<1);
char DLPF_CFG_2 = (1<<2);
char DLPF_FS_SEL_0 = (1<<3);
char DLPF_FS_SEL_1 = (1<<4);

//I2C devices each have an address. The address is defined in the datasheet for the device. The ITG-3200 breakout board can have different address depending on how
//the jumper on top of the board is configured. By default, the jumper is connected to the VDD pin. When the jumper is connected to the VDD pin the I2C address
//is 0x69.
char itgAddress = 0x69;

//In the setup section of the sketch the serial port will be configured, the i2c communication will be initialized, and the itg-3200 will be configured.
void setup()
{
  //Create a serial connection using a 9600bps baud rate.
  Serial.begin(9600);
 
  //Initialize the I2C communication. This will set the Arduino up as the 'Master' device.
  Wire.begin();
 
  //Read the WHO_AM_I register and print the result
  char id=0;
  id = itgRead(itgAddress, 0x00); 
  Serial.print("ID: ");
  Serial.println(id, HEX);
 
  //Configure the gyroscope
  //Set the gyroscope scale for the outputs to +/-2000 degrees per second
  itgWrite(itgAddress, DLPF_FS, (DLPF_FS_SEL_0|DLPF_FS_SEL_1|DLPF_CFG_0));
  //Set the sample rate to 100 hz
  itgWrite(itgAddress, SMPLRT_DIV, 9);
}

//The loop section of the sketch will read the X,Y and Z output rates from the gyroscope and output them in the Serial Terminal
void loop()
{
  //Create variables to hold the output rates.
  int xRate, yRate, zRate;

  //Read the x,y and z output rates from the gyroscope.
  xRate = readX();
  yRate = readY();
  zRate = readZ();

  //Print the output rates to the terminal, seperated by a TAB character.
  Serial.print(xRate);
  Serial.print('\t');
  Serial.print(yRate);
  Serial.print('\t');
  Serial.println(zRate); 

  //Wait 10ms before reading the values again. (Remember, the output rate was set to 100hz and 1reading per 10ms = 100hz.)
  delay(10);
}

//This function will write a value to a register on the itg-3200.
//Parameters:
//  char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
//  char registerAddress: The address of the register on the sensor that should be written to.
//  char data: The value to be written to the specified register.
void itgWrite(char address, char registerAddress, char data)
{
  //Initiate a communication sequence with the desired i2c device
  Wire.beginTransmission(address);
  //Tell the I2C address which register we are writing to
  Wire.write(registerAddress);
  //Send the value to write to the specified register
  Wire.write(data);
  //End the communication sequence
  Wire.endTransmission();
}

//This function will read the data from a specified register on the ITG-3200 and return the value.
//Parameters:
//  char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
//  char registerAddress: The address of the register on the sensor that should be read
//Return:
//  unsigned char: The value currently residing in the specified register
unsigned char itgRead(char address, char registerAddress)
{
  //This variable will hold the contents read from the i2c device.
  unsigned char data=0;
 
  //Send the register address to be read.
  Wire.beginTransmission(address);
  //Send the Register Address
  Wire.write(registerAddress);
  //End the communication sequence.
  Wire.endTransmission();
 
  //Ask the I2C device for data
  Wire.beginTransmission(address);
  Wire.requestFrom(address, 1);
 
  //Wait for a response from the I2C device
  if(Wire.available()){
    //Save the data sent from the I2C device
    data = Wire.read();
  }
 
  //End the communication sequence.
  Wire.endTransmission();
 
  //Return the data read during the operation
  return data;
}

//This function is used to read the X-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int xRate = readX();
int readX(void)
{
  int data=0;
  data = itgRead(itgAddress, GYRO_XOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_XOUT_L); 
 
  return data;
}

//This function is used to read the Y-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int yRate = readY();
int readY(void)
{
  int data=0;
  data = itgRead(itgAddress, GYRO_YOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_YOUT_L); 
 
  return data;
}

//This function is used to read the Z-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int zRate = readZ();
int readZ(void)
{
  int data=0;
  data = itgRead(itgAddress, GYRO_ZOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_ZOUT_L); 
 
  return data;
}

I checked with my oscilloscope that the signals are being converted properly and that the ITG was wired correctly. Does anyone know if there are any differences with the leonardos i2c than the other arduinos, or what my issue could be? Thank you.
6  Using Arduino / Programming Questions / Re: PID SOS on: January 22, 2013, 12:39:38 am
anybody? Please, any information will help.
7  Using Arduino / Programming Questions / PID SOS on: January 21, 2013, 07:06:54 pm
Hello, I've been working on making my rc plane self-stabilize in mid air using its ailerons. I have a gyro and accelerometer taking readings and outputting a kalman filtered reading from 0 to 359 degrees. What i have done is set my Output limits(Servo limits) to (1000, 2000). In the PID library example it looks like the Input value is an analog vaule from 0, 1023. So, I mapped my filtered angle from (0, 359) to (0, 1023) and made it equal the Input. I made the Setpoint variable equal to 762(~270 degrees) and mapped it as so:
Code:
AileServo = map(Output, 0, 1024, 1100, 1900);
When I upload the code, the aileron goes in the up position and wont budge, even when I move the plane from side to side. I know im doing something very wrong here. Any help is appreciated.
8  Using Arduino / Programming Questions / Re: Convert ITG-3200's raw readings into degrees/sec on: January 16, 2013, 12:08:00 am
Yeah, in my first post I gave you all the subroutines because in the loop I would just call the readY, readX, readZ subroutines over and over.

Here is an example code from SparkFun:
Code:
/*
3/16/11
Basic Example Sketch for the ITG-3200 (http://www.sparkfun.com/products/9801)
SparkFun Electronics 2011
Ryan Owens

This code is public domain buy you buy me a beer if you use this and we meet someday (Beerware license).

To use this example code, attach:
Arduino  :  ITG-3200 Breakout
3.3V  :  VDD
3.3V  :  VIO
GND   :  GND
SDA   :  A4
SCL   :  A5

Load the sketch and open the serial window at 9600 bps. Arduino will output the raw X,Y and Z axis data being read from the gyroscope.

*/

//The Wire library is used for I2C communication
#include <Wire.h>

//This is a list of registers in the ITG-3200. Registers are parameters that determine how the sensor will behave, or they can hold data that represent the
//sensors current status.
//To learn more about the registers on the ITG-3200, download and read the datasheet.
char WHO_AM_I = 0x00;
char SMPLRT_DIV= 0x15;
char DLPF_FS = 0x16;
char GYRO_XOUT_H = 0x1D;
char GYRO_XOUT_L = 0x1E;
char GYRO_YOUT_H = 0x1F;
char GYRO_YOUT_L = 0x20;
char GYRO_ZOUT_H = 0x21;
char GYRO_ZOUT_L = 0x22;

//This is a list of settings that can be loaded into the registers.
//DLPF, Full Scale Register Bits
//FS_SEL must be set to 3 for proper operation
//Set DLPF_CFG to 3 for 1kHz Fint and 42 Hz Low Pass Filter
char DLPF_CFG_0 = (1<<0);
char DLPF_CFG_1 = (1<<1);
char DLPF_CFG_2 = (1<<2);
char DLPF_FS_SEL_0 = (1<<3);
char DLPF_FS_SEL_1 = (1<<4);

//I2C devices each have an address. The address is defined in the datasheet for the device. The ITG-3200 breakout board can have different address depending on how
//the jumper on top of the board is configured. By default, the jumper is connected to the VDD pin. When the jumper is connected to the VDD pin the I2C address
//is 0x69.
char itgAddress = 0x69;

//In the setup section of the sketch the serial port will be configured, the i2c communication will be initialized, and the itg-3200 will be configured.
void setup()
{
  //Create a serial connection using a 9600bps baud rate.
  Serial.begin(9600);
 
  //Initialize the I2C communication. This will set the Arduino up as the 'Master' device.
  Wire.begin();
 
  //Read the WHO_AM_I register and print the result
  char id=0;
  id = itgRead(itgAddress, 0x00); 
  Serial.print("ID: ");
  Serial.println(id, HEX);
 
  //Configure the gyroscope
  //Set the gyroscope scale for the outputs to +/-2000 degrees per second
  itgWrite(itgAddress, DLPF_FS, (DLPF_FS_SEL_0|DLPF_FS_SEL_1|DLPF_CFG_0));
  //Set the sample rate to 100 hz
  itgWrite(itgAddress, SMPLRT_DIV, 9);
}

//The loop section of the sketch will read the X,Y and Z output rates from the gyroscope and output them in the Serial Terminal
void loop()
{
  //Create variables to hold the output rates.
  int xRate, yRate, zRate;

  //Read the x,y and z output rates from the gyroscope.
  xRate = readX();
  yRate = readY();
  zRate = readZ();

  //Print the output rates to the terminal, seperated by a TAB character.
  Serial.print(xDegrees);
  Serial.print('\t');
  Serial.print(yDegrees);
  Serial.print('\t');
  Serial.println(zDegrees); 

  //Wait 10ms before reading the values again. (Remember, the output rate was set to 100hz and 1reading per 10ms = 100hz.)
  delay(10);
}

//This function will write a value to a register on the itg-3200.
//Parameters:
//  char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
//  char registerAddress: The address of the register on the sensor that should be written to.
//  char data: The value to be written to the specified register.
void itgWrite(char address, char registerAddress, char data)
{
  //Initiate a communication sequence with the desired i2c device
  Wire.beginTransmission(address);
  //Tell the I2C address which register we are writing to
  Wire.send(registerAddress);
  //Send the value to write to the specified register
  Wire.send(data);
  //End the communication sequence
  Wire.endTransmission();
}

//This function will read the data from a specified register on the ITG-3200 and return the value.
//Parameters:
//  char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
//  char registerAddress: The address of the register on the sensor that should be read
//Return:
//  unsigned char: The value currently residing in the specified register
unsigned char itgRead(char address, char registerAddress)
{
  //This variable will hold the contents read from the i2c device.
  unsigned char data=0;
 
  //Send the register address to be read.
  Wire.beginTransmission(address);
  //Send the Register Address
  Wire.send(registerAddress);
  //End the communication sequence.
  Wire.endTransmission();
 
  //Ask the I2C device for data
  Wire.beginTransmission(address);
  Wire.requestFrom(address, 1);
 
  //Wait for a response from the I2C device
  if(Wire.available()){
    //Save the data sent from the I2C device
    data = Wire.receive();
  }
 
  //End the communication sequence.
  Wire.endTransmission();
 
  //Return the data read during the operation
  return data;
}

//This function is used to read the X-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int xRate = readX();
int readX(void)
{
  int data=0;
  data = itgRead(itgAddress, GYRO_XOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_XOUT_L); 
 
  return data;
}

//This function is used to read the Y-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int yRate = readY();
int readY(void)
{
  int data=0;
  data = itgRead(itgAddress, GYRO_YOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_YOUT_L); 
 
  return data;
}

//This function is used to read the Z-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second.
//Usage: int zRate = readZ();
int readZ(void)
{
  int data=0;
  data = itgRead(itgAddress, GYRO_ZOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_ZOUT_L); 
 
  return data;
}
9  Using Arduino / Programming Questions / Re: Convert ITG-3200's raw readings into degrees/sec on: January 15, 2013, 07:41:36 pm
I tried that but it goes over 2000 degrees per second, which is its maximum... and I can spin the board about the x or y axis approximately 360 degrees per second and itll read ~1000 degrees/sec.
10  Using Arduino / Programming Questions / Convert ITG-3200's raw readings into degrees/sec on: January 15, 2013, 05:06:35 pm
I have been scouring the internet for solutions to this question for a long time.I can read the raw signals using this code here:
Code:
void itgWrite(char address, char registerAddress, char data){
  Wire.beginTransmission(address);
  Wire.write(registerAddress);
  Wire.write(data);
  Wire.endTransmission();
}
unsigned char itgRead(char address, char registerAddress){
  unsigned char data=0;
  Wire.beginTransmission(address);
  Wire.write(registerAddress);
  Wire.endTransmission();
  Wire.beginTransmission(address);
  Wire.requestFrom(address, 1);
  if(Wire.available()){
    data = Wire.read();
  }
  Wire.endTransmission();
  return data;
}
int readX(void){
  int data=0;
  data = itgRead(itgAddress, GYRO_XOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_XOUT_L); 
  return data;
}
int readY(void){
  int data=0;
  data = itgRead(itgAddress, GYRO_YOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_YOUT_L); 
  return data;
}
int readZ(void){
  int data=0;
  data = itgRead(itgAddress, GYRO_ZOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_ZOUT_L); 
  return data;
}

in the 3200 datasheet it says: Digital-output X-, Y-, and Z-Axis angular rate sensors (gyros) on one integrated circuit with a sensitivity of 14.375 LSBs per °/sec and a full-scale range of ±2000°/sec.
Im not sure how to use the 14.375 LSBs per degrees/sec to give me my converted reading. can somebody please help me get and understanding of how to convert my readings.
11  Using Arduino / Programming Questions / Re: Help with decreasing program loop time on: August 24, 2012, 10:21:37 pm
any suggestions on how to scroll the text?
12  Using Arduino / Programming Questions / Re: Help with decreasing program loop time on: August 24, 2012, 08:16:38 pm
Thanks anyway fixed my own problem. I took out the digitalwrites and used port manipulation.
13  Using Arduino / Programming Questions / Re: Help with decreasing program loop time on: August 24, 2012, 08:05:22 pm
The delayMicroseconds is called twice. I changed it to only have one delay but its not changing the flickering much.
14  Using Arduino / Programming Questions / Help with decreasing program loop time on: August 24, 2012, 07:29:46 pm
I am building a 13x13 rgb led multiplexed display. With 13 leds in one row that gives me a total of 39(and 13 gound) pins that have to be controlled. I am using 6 shift registers and two darlington arrays for my outputs. Everything is working great I'm independently controlling leds and doing simple animations. The problem I am having is that when I have a lot of the leds on at a time they start to flicker. Does anyone have any ideas on how I can decrease the loop time and in turn update the leds much faster?

Here is the code for you to take a look at.
Code:
int SER_Pin = 7;  
int RCLK_Pin = 9;  
int SRCLK_Pin = 8;
int DELAY = 50;
int redpins[13] = {
  1,4,7,10,16,19,22,25,28,34,37,40,43};
int grnpins[13] = {
  0,3,6,9,12,18,21,24,27,33,36,39,42};
int blupins[13] = {
  2,5,8,11,17,20,23,26,32,35,38,41,44};
int colpins[13] = {
  14,15,16,17,18,19,0,1,2,3,4,5,6};
int face[13][13] = {
  {0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,1,0,0,0,0,0,1,0,0,0},
  {0,0,0,1,0,0,0,0,0,1,0,0,0},
  {0,0,0,0,0,0,3,0,0,0,0,0,0},
  {0,0,0,0,0,0,3,0,0,0,0,0,0},
  {0,2,0,0,0,0,0,0,0,0,0,2,0},
  {0,2,0,0,0,0,0,0,0,0,0,2,0},
  {0,0,2,0,0,0,0,0,0,0,2,0,0},
  {0,0,0,2,2,2,2,2,2,2,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0,0,0,0,0},
  };
  int C[13][13] = {
  {0,0,0,0,1,1,1,1,1,0,0,0,0},
  {0,0,0,1,1,1,1,1,1,1,0,0,0},
  {0,0,1,1,0,0,0,0,0,1,1,0,0},
  {0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,1,1,0,0,0,0,0,0,0,0,0},
  {0,0,1,1,0,0,0,0,0,1,1,0,0},
  {0,0,0,1,1,1,1,1,1,1,0,0,0},
  {0,0,0,0,1,1,1,1,1,0,0,0,0}};
 
  int allon[13][13] = {
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1}};
 
#define number_of_74hc595s 6
#define numOfRegisterPins number_of_74hc595s * 8

boolean registers[numOfRegisterPins];

void setup(){

  pinMode(SER_Pin, OUTPUT);
  pinMode(RCLK_Pin, OUTPUT);
  pinMode(SRCLK_Pin, OUTPUT);
  clearRegisters();
  for(int x = 14; x < 20; x++){
    pinMode(x, OUTPUT);
    digitalWrite(x, LOW);
  }
  for(int x = 0; x < 7; x++){
    pinMode(x, OUTPUT);
    digitalWrite(x, LOW);
  }
  for(int x = 0; x < 48; x++){
    setRegisterPin(x, LOW);
  }
}              

void loop(){
  for(int x = 0; x < 250; x++){
    Display(C);
  }
}

void writeRegisters(){

  digitalWrite(RCLK_Pin, LOW);

  for(int i = numOfRegisterPins - 1; i >=  0; i--){
    digitalWrite(SRCLK_Pin, LOW);

    int val = registers[i];
    digitalWrite(SER_Pin, val);
    digitalWrite(SRCLK_Pin, HIGH);

  }
  digitalWrite(RCLK_Pin, HIGH);

}

void setRegisterPin(int index, int value){
  registers[index] = value;
}

void clearRegisters(){
  for(int i = numOfRegisterPins - 1; i >=  0; i--){
    registers[i] = LOW;
  }
}

void Display(int image[13][13]){
  for(int x = 0; x < 13; x++){
    for(int y = 0; y < 13; y++){
      if(image[x][y] == 3){
        setRegisterPin(blupins[y], HIGH);
        digitalWrite(colpins[x], HIGH);
        writeRegisters();
        delayMicroseconds(DELAY);
        setRegisterPin(blupins[y], LOW);
        digitalWrite(colpins[x], LOW);
        writeRegisters();
        delayMicroseconds(DELAY);
      }
      if(image[x][y] == 2){
        setRegisterPin(grnpins[y], HIGH);
        digitalWrite(colpins[x], HIGH);
        writeRegisters();
        delayMicroseconds(DELAY);
        setRegisterPin(grnpins[y], LOW);
        digitalWrite(colpins[x], LOW);
        writeRegisters();
        delayMicroseconds(DELAY);
      }
      if(image[x][y] == 1){
        setRegisterPin(redpins[y], HIGH);
        digitalWrite(colpins[x], HIGH);
        writeRegisters();
        delayMicroseconds(DELAY);
        setRegisterPin(redpins[y], LOW);
        digitalWrite(colpins[x], LOW);
        writeRegisters();
        delayMicroseconds(DELAY);
      }
    }
  }
}


15  Using Arduino / Programming Questions / Re: Wireless RFID reader on: August 19, 2012, 05:20:21 pm
It doesnt look as if there is any code that sends information out using the Xbee.... That is what im guessing is wrong.
Pages: [1] 2 3 ... 12