This project was for the Queen's Space Engineering (QSET) Satellite Team, a design team that is building a CubeSat for the Canadian Satellite Design Challenge (CSDC). The goal was to create a tool that the team could use to test and calibrate their permanent magnet system with Attitude Determination and Control System (ADCS).
For those who don't know, ADCS is the system that allows satellites to maintain their orientation in orbit. Due to the nature of the launch method (i.e. from the ISS), the satellite will have a tendency to rotate about its own axis while in orbit. This is a problem, as the transceiver (used for communications) won't be able to pick up radio signals from the ground station if the satellite is rotating.
So, the ADCS sub-team's solution was to implement a passive system using a permanent magnet. This magnet will eventually align itself with the north-south magnetic fields that surround the earth, holding the satellite in one orientation. This is effective especially compared to active systems (i.e. flywheels), as permanent magnets require zero power. However, this means that the physical system needs to be tested quite thoroughly, as the location of the permanent magnet can drastically change the final orientation of the CubeSat. In order to carry out the testing, I needed to create a program that will read and calibrate the magnetometers to provide accurate data about the attitude of the CubeSat.
The sub-team needed the testing system to do the following:
The first step in this project was to pick the hardware. The ADCS team lead and I decided to go with a Raspberry Pi Zero W and a MAG3110 magnetometer sensor. The Raspberry Pi was an obvious choice, as it was very affordable (around $10), has a small form factor, built-in wireless card, and a variety of GPIO pins that support SPI, I2C, UART, etc. The MAG3110 was a good choice, as it operates at the same 3.3V logic that the RPi does (no need for a voltage divider) and can be communicated with via I2C (allowing for multiple sensors to be connected if necessary).
The next step was to set up the RPi to operate headlessly (i.e. wirelessly). To do this, we connected it to the Queen's WiFi network and enabled SSH on the RPi (guide can be found here). This way, anyone with access to Queen's WiFi and an SSH client (I used PuTTY) can simply enter the IP address and start sending commands to the RPi. It should be noted that the device runs on the Raspbian OS, which is a Linux distribution. The next task was to connect the MAG3110 sensor and enable the I2C pins on the RPi. By default, the RPi has the I2C GPIO pins disabled. After the pins have been enabled, I was able to start writing a script to read the data from the sensors.
I chose to use Python for this sensor testing script, mainly because of the availability of libraries and the fact that it is native to the RPi. This made it development easier (especially over SSH), as the Pip package manager and Python compiler come pre-installed with the Raspbian OS. A link to the GitHub repository for my code can be found here.
Now, the first order of business is get to the tools/libraries Python needs to use the I2C bus. In order to do this, two libraries need to be pip installed: i2c-detect, and python-smbus. After these are installed, they can be imported into the Python script and the member functions of the libraries can be used to read and write bytes over the I2C pins.
The next order of business is to be able to talk to the MAG3110 sensor. For this, I referred to the MAG3110 datasheet. According to the datasheet, the sensor has a default I2C address of 0x0E, has control registers in 0x10 and 0x11, and has various modes for triggered or continuous sampling at 80 Hz (see section 4.2.7). For the purposes of the data logger, I used the continuous sampling mode, which meant writing 0x80 into CTRL_REG_2 using the bus.write_byte_data function in Python. Now that the MAG3110 sensor is in the correct operating mode, I can now start reading the data from the bus. According to the datasheet, data from all three axis can be read from registers 0x01 through 0x06, where 0x01 and 0x02 are the MSB and LSB of the X axis (Y and Z follow suit). In order to grab this data, the function bus.read_i2c_block_data was used, creating an array of the MSB and LSB of each axis. To get the full 16-bit magnetic field values from the MSB-LSB pair, the formula MSB*256 + LSB is used.
Now that the data has been read into Python, the script can now start calibrating the data. There are two basic types of calibration that you can do with magnetometers: hard-iron biases and soft-iron calibration. The reasoning behind the math calculations can be complicated, so I'll just refer to the GitHub article I found on it. The gist of it is basically that the testing environment will always have some other source of magnetic disturbance (whether it be the motors in the testing rig, the RPi itself, metals, etc) that we're not trying to measure. These can easily be corrected for by rotating the sensor over all of its axis, getting an average, and then subtracting it from the data to recenter it over magnetic zero. This is done in the code by getting the min and max values of each axis, averaging them, and subtracting it from the magnetic field data before writing them into a CSV file.
Speaking of CSV files, we've now reached the the point where the data is in the form that we want and calibrated for the offsets that we don't want. I was now able to move onto satisfying the last two functional requirements, which were logging the data into a file and plotting it in real time. Logging the data to a file was dead simple with Python, but the live plotting feature was a little more challenging. I came up with two options: pushing the data to a server and using Javascript to parse the JSON stream, or use an API to do all that for me. Given the purpose of the project and the time constraints, I thought the best option would be to find an API (I ended up using Plot.ly) and blackbox the whole live plotting requirement. This ended up working out well, as the web app that Plot.ly displays the data to is really easy to use; pretty much any member of the ADCS team can start up the RPi and see the immediate results of the test.
Now that the data logger system has been set up, the ADCS team can start testing their control system. I'll be making note of their feedback and interactions with the system to see if there are any improvements that can be made. Once the team is happy with the testing system, more sensors can be incorporated. In addition to the magnetometers, the team is also considering an accelerometer and a sun sensor. Both of these sensors are most likely going to be communicated with via I2C or SPI, so integrating it with the current system should (hopefully) be seamless.