Monday, November 29, 2010

The ACS712 Low Current Sensor Breakout has just arrived.

As I have mentioned before in a previous post, in order to make working the speed controllers it is necessary to initialize them first. This requires that previously the main board (Seeeduino Mega board) has been switched on, as it is the main board that makes the initialization. This procedure gives no problems when the sequence between the connections of the main board and the speed controllers is respected. However, if for any reason the main board have been previously switched on and after that it is switched off and then switched on again, the initialization happens twice even the speed controllers have already been initialized. This is because the status of the controllers it is not known and thus the motors can run up to the maximum speed. Therefore one needs a current sensor to detect whether the speed controllers are either switched on or off. I have  selected the sensor "ACS712 Low Current Sensor Breakout" which can be seen in the picture above. More information about this sensor can be found on page of its manufacturer. One of its advantage is that one can use it for example, to monitorize the power consumption of motors.

Friday, November 26, 2010

How to convert a string of Euler angles characters read by the 9DOF Razor IMU board into numeric values.

To guide the quadcopter in the space I will use the 9DOF Razor IMU board with the 9 Degree of Measurement Attitude and Heading Reference System (AHRS) code base. This board with AHRS code has the advantage of doing all the calculations and corrections for me. All I need to do is work out the interface. With the code one can chooses three options for receiving the data according to the constants that we define. If one sets the defined value "PRINT_DCM" to 1 then one will print the whole direction cosine matrix. If one sets the defined value "PRINT_ANALOG" to 1 then one will print the analog raw data. If one sets the defined value "PRINT_EULER" to 1 then one will print the Euler angles roll, pitch and yaw. These options are selected in the AHRS code before being compiled.
But first one needs to get the data in a format that can then be used by the Seeeduino Mega board to do the calculations to orient and stabilize the quadcopter. Reading the stream data from the 9DOF Razor IMU to the Seeeduino Mega board is a simple task and it has been shown in a previous post in which the data was transferred via a serial connection between the two boards - the diagram of the assembly can be seen in the image of the this previous post.
The data that I choose consist of the Euler angles roll, pitch and yaw and are sent by the 9DOF Razor IMU board sequentially in a text line. The line has the following format: "!ANG:0.00,0.00,0.00\r\n". To use the angles are necessary to split the line and then convert the numeric characters string parts to a numeric value (in this case a floating point number). After several failed attempts to read stream data sequentially I discovered that if I did not blocking the serial reads until the 9DOF Razor IMU board send the data often do not find the end of the text line which results in incorrect values and buffer overflow problems. To solve the problem of the serial reads may block permanently due to faulty connection with the 9DOF Razor IMU board was added a timeout. If at the end of the timeout has not been read the line the program continues its execution whiles keeping the previous angles values. This, procedure is important because if the Seeeduino Mega board lost the connection with 9DOF Razor IMU board the program can predicts code for example that here the motors are turned off and is activated a parachute, that save the quadcopter from crashing.
In the following sketch we can check the path followed to obtain the Euler angles in a numerical format from the 9DOF Razor IMU board.
#define TIMEOUT 100

// { roll, pitch, yaw }
float angles[3] = {0.0, 0.0, 0.0};

char read_char() {
  unsigned long starttime = millis();
  do {
    if(Serial1.available() > 0)
      return((char)Serial1.read());
  } while((millis() - starttime) < TIMEOUT);
  return NULL;
}

void get_angles() {
  for(int n=0; n<3; n++) {
    char buffer[9];
    int received = 0;
    char ch;
    do {
      if((ch = read_char()) == NULL) return;
    } while(ch != ',' && ch != '\r' && (buffer[received++] = ch));   
    buffer[received] = '\0';
    angles[n] = atof(buffer);
  }
}

void read_9dofahrs() {
  char beginstr[6] = {'!','A','N','G','\:','\0'};
  for(int i=0; i<5; i++)
    if(read_char() != beginstr[i]) return;
  get_angles();
}

void setup() {
  Serial.begin(57600);
  Serial1.begin(57600);
}

void loop() {
  read_9dofahrs();

  Serial.print(angles[0]);
  Serial.print(" | ");
  Serial.print(angles[1]);
  Serial.print(" | ");
  Serial.print(angles[2]);
  Serial.println("");
}
The result of this sketch can be seen in the following figure.

This short sketch will then be added to the main program that will control the stabilization and orientation in space of the quadcopter.

Sunday, November 21, 2010

Brushless Motors and Speed Controllers.

I am a beginner in electronics and although my skills are still basic, I am still searching documentation to see if I understand how I can properly put into operation one or more motors using the Arduino platform. In most open source quadcopter projects are almost always used the same speed controllers, however it should be possible to use any speed controller that works with a radio control (R/C).
I have been taking a look to several web sites and I have found that there were two main ways of how to communicate with speed controllers and put the motors running. One is to write a pulse width in microseconds directly to the i/o pins and the other is to use the Arduino "Servo" library or similar libraries like "SoftwareServo". In a previous post I have described how to put four motors running with the speed controllers that I have got for this project using the "Servo" library. Although, I have not investigated in depth the internals of the library I have noticed that the motor control is achieved by sending pulses to the speed controller or alternatively by sending an angle that can varies between 0º and 180º (the angle is converted internally to a pulse width in microseconds). However and for the speed controllers I am using, if I only send pulses to the i/o pins that will not put the motors in operation since the speed controllers need be initialized before using. So, in order to have more information available, I have downloaded of the speed controller specifications that I am using. After reviewing that document I have tried to develop an algorithm with the all steps to put the motors in operation. The procedure according to my adaptation of the document to initialize the speed controller is as follow (this procedure must be done before each use):
  1. Connect the Arduino board to the computer via USB to power up the board and set the pulse width value of the stop position on output pin (the stop position must be within the range 800 us to 1700 us for my speed controller). This procedure is like move the throttle stick to the desired stop position, and switch on the transmitter.
  2. Connect now the flight battery to the speed controler. The motor responds with 2 x beep.
  3. Increase the pulse width value (microseconds) in one unit on output pin until the motor responds with 3 x beep (the full-throttle position must be at least 350 us greater than the stop position). This is like move the throttle stick to the desired full-throttle position.
  4. Set again the pulse width value of the stop position on output pin. This procedure is like move the throttle stick to the desired stop position.
  5. If you now increase the pulse width value on output pin the motor will start running. This is like move the throttle stick from the stop position towards full-throttle.
I tried to implement the two methods described above but the only one that worked was the method that uses the library "Servo". The implementation of the procedure is now shown:
/*

  Motors: 4 x ROXXY 2827-34
  ___ESC: 4 x Roxxy BL-Control 818
  _Board: Seeeduino Mega v1.1
  
  ATENTION: Do not put the propellers in motors because this
            sketch is not well tested and can cause damage.
  
*/
#include <Servo.h>

// Set the pulse width value of the stop position to mid-point (1250 us).
#define STOPPOSITION          800+(1700-800)/2
// The full-throttle position must be at least 350 us greater
// than the stop position (1600 us).
#define FULLTHROTTLEPOSITION  STOPPOSITION+350
// My upper speed limit for safety.
#define MAXTHROTTLEPOSITION   FULLTHROTTLEPOSITION-100
// Create servo object to control four motors
Servo escservos[4];
// Variable to store the temporarily pulse width value.
int usvalue = STOPPOSITION;

void programpositions() {
  Serial.println("Type the character [p] to program the Stop and");
  Serial.println("Full-Throttle positions after connect the flight");
  Serial.println("battery to the ESC's.");
  Serial.println("The motor responds with 2 x beep.");
  Serial.println("");
  Serial.println("Type the character:");
  Serial.println("[+] to increase the pulse width value.");
  Serial.println("[-] to decrease the pulse width value.");
  Serial.println("[0] to set the pulse width value to stop position.");
  
  // Wait until get the input from the user.
  while(Serial.available() <= 0) {
    // Set the pulse width value of the stop position on output pins.
    for(int s=0; s<4; s++)
      escservos[s].writeMicroseconds(STOPPOSITION);
  }
  
  char ch = Serial.read();
  if(ch == 'p') {
    // Increase the pulse width value in one unit on output pins.
    // Exactly after a pulse width of the 350 microseconds from
    // the stopping position the motor responds with 3 x beep.
    for(int us=STOPPOSITION; us<=FULLTHROTTLEPOSITION; us++)
      for(int s=0; s<4; s++)
        escservos[s].writeMicroseconds(us);
    delay(5000);
  }
}

void set_speeds(int servo, int usvalue) {
  escservos[servo].writeMicroseconds(usvalue);
}

void setup() {
  Serial.begin(9600);
  
  // Attaches the ESC's on pins 2, 3, 4 and 5 to the servo object.
  for(int s=0; s<4; s++)
    escservos[s].attach(s+2, STOPPOSITION, FULLTHROTTLEPOSITION);
  
  programpositions();
}

void loop() {
  if(Serial.available()) {
    char ch = Serial.read();
    if(ch == '+') {
      // Increase the pulse width value.
      // The motor only starts running after increased up to 40 us.
      usvalue++;
      if(usvalue > MAXTHROTTLEPOSITION)
        usvalue = MAXTHROTTLEPOSITION;
    } else if(ch == '-') {
      // Decrease the pulse width value.
      usvalue--;
      if(usvalue < STOPPOSITION)
        usvalue = STOPPOSITION;
    } else if(ch == '0') {
      // Set the pulse width value to the stop position.
      usvalue = STOPPOSITION;
    }
    Serial.println(usvalue);
  }
  for(int s=0; s<4; s++)
    set_speeds(s, usvalue);
}
This implementation works very well for my speed controllers, but for other speed controllers the implementation will probably be different. The difference to the previous post is that instead using the value of the angles, I have used the pulse width value in microseconds and the delay after sending the angle has been removed. One immediate problem is that the Arduino board must always be connected before the speed controller which requires that board will check if the speed controller is switched on or off. If the speed controller is already connected and initialized and if for any reason you switched off the board and switched it on again, the motor can speed up to full speed because the speed controller was already set up, but as the board does not recognize it, it will make a new initialization. Therefore it is necessary to send a character to do or not the initialization of the speed controller. To solve this problem it is necessary a current sensor which will check whether the speed controller is switched on or off.

Wednesday, November 17, 2010

How to Upgrade 9DOF Razor IMU Test Firmware.

When I got the 9DOF - Razor IMU board I tried to upgrade the "Test Firmware" using the "Makefile" from the zip file but without success. So I sent an email to the Sparkfun tech support for them to verify what I was doing wrong. Today I finally got the answer and the best way to upgrade the firmware is upgraded manually.
The first step is to connect the 9DOF - Razor IMU board to FTDI Basic Breakout - 3.3V board following the diagram showed in Figure 1 from the post "How to upload 9DOF AHRS code". The second step is download the latest code from the git repository and execute the following commands (the commands were executed in a terminal on a machine with the Linux OS):
$ mkdir tmp
$ cd tmp
$ wget --no-check-certificate https://github.com/a1ronzo/\
SparkFun-9DOF-Razor-IMU-Test-Firmware/raw/master/9DOF-v18/9DOF-v18.zip
$ unzip 9DOF-v18.zip
$ make all
$ avrdude -p atmega328p -P /dev/ttyUSB0 -c stk500v1 -b 57600 \
-U flash:w:main.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be
         performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (9156 bytes):

Writing | ################################################## | 100% 2.99s

avrdude: 9156 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex auto detected as Intel Hex
avrdude: input file main.hex contains 9156 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 2.28s

avrdude: verifying ...
avrdude: 9156 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.
Open now the Arduino IDE and click on "Serial Monitor" icon or from the "Tools" menu select the item "Serial Monitor". Set the baud rate to 38400 and verify if the "9DOF IMU Firmware v18" menu is showed (Figure 1).
Figure 1
It's not straightforward to save the previous firmware directly from the AVR. It's easier to keep the older .hex files around if I need them.

Wednesday, November 10, 2010

How to upload 9DOF AHRS code.

Figure 1
The first step is to connect the 9DOF - Razor IMU board to FTDI Basic Breakout - 3.3V board following the diagram showed in Figure 1. Then download the latest code from the sf9domahrs Google Code repository and uncompress the zip file. Change to the directory SF9DOF_AHRS, and open the SF9DOF_AHRS.pde file in Arduino IDE (0021).
Figure 2
After opening the file will be visible seven tabs (SF9DOF_AHRS, ADC, Compass, DCM, I2C, Output, Vector and matrix) like as shown in Figure 2. Select from the "Tools" menu and then from the "Board" submenu the board Arduino Pro or Pro Mini (3.3 V, 8Mhz) w/ AtMega328 which corresponds with the 9DOF - Razor IMU board.
Figure 3
Compile the code with the Arduino IDE and upload it to the 9DOF - Razor IMU board. Open the Serial monitor, set the baud rate to 57600 and verify if the data are coming (Figure 3), and voila, it's everything that has to do with it.

Saturday, November 6, 2010

Read 9DOF Razor IMU data via Seeeduino Mega board (Arduino Mega clone).

Figure 1
Read the data from the 9DOF Razor IMU board is very simple, but first I had to solder the pin-headers on the Seeeduino Mega board since the board is not sold with the pin-headers soldered, and then I connected the Seeeduino Mega board to the 9DOF Razor IMU board according to the diagram in Figure 1. Below is shown the sketch that allows you to read the data, as can be seen is short and simple.
/*

Read 9DOF Razor IMU data via Seeeduino Mega board (Arduino Mega clone).

1. Connect the jumper wires between the two boards
   according to the following table:

9DOF Razor IMU | Seeeduino Mega
---------------|--------------------
TX0............|RX1..(pin 18).......
RX1............|TX1..(pin 19).......
3.3V...........|3V3.................
GND............|GND.................
---------------|--------------------

2. Connect the USB Cable between the PC and the Seeeduino Mega board.
3. Select the "Board" item from the "Tools" top menu and check the radio
   button Arduino Mega (ATmega1280). 
4. Upload this Sketch to the Seeeduino Mega board
5. Open Serial Monitor and set the Baud rate to 57600.
6. Send the character '0' to view the 9DOF Razor IMU Menu.

9DOF IMU Test Firmware v15
==========================
[1]Accelerometer: ADXL345
[2]Magnetometer: HMC5843
[3]Gyroscope: LPR530 and LY530
[4]Raw
[5]Self Test

 */

void setup() {
  Serial.begin(57600);
  Serial1.begin(38400);  // Baud rate fixed....
  Serial1.print(4);      // Begin with Raw data
}

void loop() {
  if(Serial.available() > 0) {
    int incomingByte = Serial.read();
    /*
       DEC - BYTE
         0 - 48
         1 - 49
         2 - 50
         3 - 51
         4 - 52
         5 - 53
    */
    if(incomingByte >= 48 && incomingByte <= 53)
        Serial1.print(incomingByte, BYTE);
  }
  
  if(Serial1.available() > 0)
    Serial.print(Serial1.read(), BYTE);
}
After making the upload of the sketch, for the Seeeduino Mega Board, I opened the serial monitor and selected the baud rate to 57600 and can immediately observe the raw data to arrive (Figure 2).
Figure 2
To view the menu with more options, send the character "0". More options available can be seen in the sketch above. If you choose the Self Test (#5 in the Menu) and you always get a "MAG: BAD" message don't worry, probably your 9DOF Razor IMU board has no problem. Try upload the sketch, but where the first menu item to send is #5 (Self Test) instead of #4 (Raw) and you will see that the result will be different.

Monday, November 1, 2010

Now I can say that the frame is finished.

Figure 1
In the figure 1 can be seen the finished frame. The sides (white square mesh) of the central box that are not fixed to show the interior. I'm not sure the final weight of the frame without the components since I do not have a scale to weigh the frame with rigor. However, I can say that is extremely lightweight. Another aspect of the design I wanted to see was the box with all the plastic parts in black. The reason that I chose the white plastic instead of black plastic material, is because the black plastic is more expensive than the white plastic.
Figure 2
In the figure 2 we can see the landing gear finalized. I opted for a rigid structure that is easy to build, but is not a good solution since there is no damping of the structure during landing. So the landing must be extremely smooth to avoid damaging the frame.
Figure 3
In the figure 3 we can see the frame on its side to see the underside and is now clearly visible the landing gear. The landing gear is held rigid by tension with the green line from the kites.
Figure 4
Finally, in the figure 4 we can see the 9DOF Razor IMU board already on the place at the base of the central box. The next step is to link all the components and start programming.