added more 2019 posts

This commit is contained in:
Matthew Tran 2023-07-09 23:15:29 -07:00
parent 22f1b221c4
commit f74311598b
68 changed files with 703 additions and 1 deletions

View File

@ -143,7 +143,7 @@ Although the resolution of the encoder would end up pretty low, it was very reli
#### Closed Loop Control #### Closed Loop Control
In order to instruct the motor to go to a certain position as quickly as possible, I decided to take a page out of what I learned in MicroMouse and implement a PI loop. Considering the pretty ideal operating conditions where stopping the motor would completely stop the rollers, I didnt implement the integral completely accurately and just reset the integral when the error became 0. For tiny errors though, the integral component proved useful. Since the system was not very complex, I ended up tuning the PI loop by hand. In order to instruct the motor to go to a certain position as quickly as possible, I decided to take a page out of what I learned in Micromouse and implement a PI loop. Considering the pretty ideal operating conditions where stopping the motor would completely stop the rollers, I didnt implement the integral completely accurately and just reset the integral when the error became 0. For tiny errors though, the integral component proved useful. Since the system was not very complex, I ended up tuning the PI loop by hand.
### Making the Electronics ### Making the Electronics

View File

@ -0,0 +1,20 @@
---
title: TPS61201 - 3.3v Booster
date: 2019-06-06
categories: cool-chips
excerpt: A nifty little chip whose versatile features gave it a very warm welcome into my parts bin.
header:
teaser: /assets/img/2019/tps-board.jpg
---
<sub>Written 8-22-19</sub>
While taking apart an Amazon Dash button to see what chips I could salvage and learn about, I came across the chip that generated the 3.3v to power everything. Using info from this [website](https://mpetroff.net/2016/07/new-amazon-dash-button-teardown-jk29lp/), I was able to find that it was a [TPS61201](http://www.ti.com/lit/ds/symlink/tps61202.pdf). This was quite the fascinating chip since I was always interested in boost circuits and how to implement them into my own projects.
Checking out the datasheet, it looks like the TPS61201 and its family of chips is quite a versatile bunch. The TPS61201 specifically can supply a couple 100 milliamps, has excellent efficiency, both boost and down conversion modes, undervoltage protection and more all in one tiny package. The extra parts necessary to power it are also all quite simple and easy to route on a PCB. Even more its made by TI which has a very generous sample program. All in all, it had a very warm welcome into my parts bin.
Using my PCB laminator, I was able to turn around a test PCB rather quickly. A bit of soldering later and I was off.
{% include figure image_path="/assets/img/2019/tps-board-test.jpg" %}
I also explored a bunch of boards from eBay that could generate 3.3v from a lower or higher voltage, but none could quite compare to the TPS61201. Of course, there are definitely better options for different use cases, but this is a great general purpose chip for my projects.

View File

@ -0,0 +1,61 @@
---
title: Arc Lighter v1
date: 2019-06-21
categories: projects
excerpt: What better way to light things on fire than with electricity?
header:
teaser: /assets/img/2019/arc-v1.jpg
gallery:
- image_path: /assets/img/2019/arc-v1-cad.jpg
- image_path: /assets/img/2019/arc-v1-electronics.jpg
- image_path: /assets/img/2019/arc-v1-assembled-no-electrode.jpg
---
<sub>Written 8-21-19</sub>
Thinking back to my younger years, it appears that I always had a fascination with high voltage. Because of the incredibly high voltages they could generate, things like stun guns, plasma globes, and Tesla coils were absolutely awe-inspiring. Finding out about arc lighters was equally cool because they could generate around 10kV in the palm of your hand. Of course, that meant I had to figure out how to build one. Either from not wanting to wind my own transformer or always having other stuff to do, I never really got around to it.
## Reverse Engineering an Existing Design
Coming back for the summer after my first year at Berkeley I randomly decided, “Hey! Lets take a look at that arc lighter again.” I had bought an electric flyswatter from Harbor Freight not too long ago so I decided to take a look at it. Taking a look at the circuit (after discharging the capacitor of course), I saw that the high voltage side capacitor was rated at 600v, so I assumed the output voltage was less than that. Hooking up my trusty Craftsman multimeter that had served me for almost a decade, I heard a pop and saw that my multimeter had broken. After a brief grieving period, I wisely decided not to hook up my expensive Fluke 117 but instead a cheap multimeter I got for free at school. That one broke too. I had a pretty powerful circuit on my hands, so I decided to reverse engineer it.
{% include figure image_path="/assets/img/2019/lighterv1-sketches.jpg" %}
After analyzing the circuit and redrawing it, it became pretty clear how it worked. When the circuit is turned on, current flows through the feedback coil and through the base of the BJT transistor, turning on the primary coil. The magnetic field generated by the primary induces a reverse voltage in the feedback coil, turning off the BJT and thus the primary. The primary coils magnetic field collapses, and the induced voltage in the feedback coil drops. The BJT turns on again, and the cycle continues. This cycle of on and off in the primary coil generates the AC signal necessary to induce a higher voltage in the secondary.
## Building My Own Circuit
Doing some research, it seems like most people use some variation of this circuit for their arc lighters. To get the turns ratio necessary to produce a good arc, they usually took an existing one and rewound the primary with fewer turns.
Thats when I ran into my first problem. Arcs formed between the secondarys coil windings when the voltage was high enough, effectively destroying the transformer. I did attempt repairs by soldering wires to the super thin magnet wire, but this fix proved only temporary. I tried using a CFL inverter transformer instead, which could handle higher voltages. It worked, but I still broke two of them before finalizing a working design.
Another issue I ran into was heat. If the arc was on longer than a couple seconds, the transistor would get too hot. Using MOSFETs produced satisfactory arcs but far more heat than BJTs. I searched for an improved circuit and found [GreatScotts](https://youtu.be/lk_1lzMiUVc) which worked really well. The waveform at the primary was now a sine wave instead of the jagged one of the old circuit. I could even keep an arc going for about a minute before the MOSFETs got too hot.
## Putting It All Together
With the circuit finalized, I was ready to put everything into a nice case.
{% include gallery %}
I initially intended to make this lighter a USB charger too because of the 18650 Li-ion battery I was using, but for some reason, the high current draw from the lighter causes the [HT4928S](http://www.hotchip.com.cn/Uploads/goods/2017-11-03/59fc3d69cabf0.pdf) to heat up and release the magic smoke. So for future reference, dont use it for anything thats powered directly off the battery.
After a bunch of sanding and gluing in some magnets, I had a pretty cool lighter on my hands. Its easily taken apart for debugging/maintenance, has an elegant on switch, and a lid with a nice tactile feel. The one thing I still needed to finalize was the electrode material.
### Picking an Electrode
The issue with using an arc is that its basically plasma which is quite hot. The tips of the electrodes tend to oxidize over time, making it more difficult to start an arc. They also heat up the electrodes entirely over time which is why I used a fiberglass insert and silicone tubing around the wires.
{% include figure image_path="/assets/img/2019/arc-v1-pogo.jpg" %}
At first I tried using these Pogo pins I got off eBay because they were probably oxidation resistant. They worked for awhile, but the nice orange arc they created was a telltale sign they wouldnt last.
{% include figure image_path="/assets/img/2019/arc-v1-copper.jpg" %}
Next I tried using copper electrodes because GreatScott used them in his arc lighter. It worked really well for quite awhile but they oxidized and failed to create a reliable arc. It seems that whatever circuit I cooked up was more powerful than I thought. (The largest electrode spacing I could reliably use was around 6-7mm which is about 20kV.)
{% include figure image_path="/assets/img/2019/arc-v1-final-elec.jpg" %}
The last thing I tried were these tin plated copper wires I got from an arc lighter kit I bought for reference. Looking at commercial arc lighter teardowns, I noticed that they used the same wires but also used a ceramic casing around them. I dont have the ability to acquire or machine ceramic yet so I stuck to just using the wire. Thankfully, its still working to this day.
{% include figure image_path="/assets/img/2019/arc-v1.jpg" %}

View File

@ -0,0 +1,28 @@
---
title: 3D-Printed Peristaltic Pump
date: 2019-06-24
categories: projects
excerpt: It's the perfect way to transport and rejuvenate etchant while being really easy to manufacture.
header:
teaser: /assets/img/2019/pump-assembled.jpg
---
<sub>Written 8-21-19</sub>
Of the things that show up while I browse Thingiverse for something cool to print, peristaltic pumps keep coming up. Its a pretty interesting concept, squeezing a tube to pump a liquid. One of its best features is that liquids only ever come into contact with the tubing so its really good for corrosive liquids. Seeing as I needed a pump to help me transport my super corrosive PCB etchant and also to bubble air through it to rejuvenate it, this was perfect.
My design philosophy focuses on aesthetics and functionality but, especially when it comes to prototypes, ease of manufacture matters too. I like to not cut screws down if I can because I either have to use my Dremel or rethread the ends. I also like to use up the existing parts I have at home because otherwise theyll just sit there collecting dust. That meant that I couldnt use any of the designs online, so I modeled my own.
{% include figure image_path="/assets/img/2019/pump-model.jpg" %}
As expected, the print and assembly process was straightforward. I was quite surprised with how well the pump worked, especially with how little torque it took to drive it. I used a stepper motor because I wasnt sure what kind of torque the pump needed. Well, based on the design I was pretty sure it was low, but I wasnt sure how low.
{% include figure image_path="/assets/img/2019/pump-assembled.jpg" %}
One of the things I needed to do was filter my etchant because I accidentally left a board in too long, like forgot about it and went to sleep long, and everything came off. Ever since then there have been quite a few toner particles in the etchant, but after a couple minutes pumping the etchant through an aquarium filter, it was perfectly clean.
{% include figure image_path="/assets/img/2019/pump-cleaned-etchant.jpg" %}
Heres a video of the pump in action.
{% include video id="aL9Voegy8xI" provider="youtube" %}

View File

@ -0,0 +1,26 @@
---
title: Arc Lighter v2
date: 2019-06-27
categories: projects
excerpt: Turned a leftover arc lighter kit into an even smaller version of my first one.
header:
teaser: /assets/img/2019/arc-v2.jpg
gallery:
- image_path: /assets/img/2019/arc-v2-cad.jpg
- image_path: /assets/img/2019/arc-v2-half-assembled.jpg
---
<sub>Written 8-22-19</sub>
After finishing the first lighter, I was still left with the kit I got on Amazon. I decided to make a much tinier arc lighter, preferably one on par with the size of a Zippo. First, I started by shrinking the circuitry as much as I could, while also adding a heatsink. I also replaced the base resistor with a smaller one to increase the voltage output and get the arc to around 3mm.
{% include figure image_path="/assets/img/2019/arc-v2-electronics.jpg" %}
With the circuitry done, I started designing the lighter. I didnt have a Zippo on hand at the time, so I worked off of dimensions I found online. I tried to make everything as sleek as possible, complete with a flush switch and magnetic lid.
{% include gallery %}
After some sanding I was done. Except for having a smaller arc and more heat output, its better in every way than v1. Its even got USB charging.
{% include figure image_path="/assets/img/2019/arc-v2.jpg" %}

View File

@ -0,0 +1,87 @@
---
title: MCS-12085 - Mouse Sensor
date: 2019-07-04
categories: cool-chips
excerpt: A pretty cool sensor salvaged from a really old mouse.
header:
teaser: /assets/img/2019/mcs12085-bottom.jpg
gallery:
- image_path: /assets/img/2019/mcs12085-top.jpg
- image_path: /assets/img/2019/mcs12085-bottom.jpg
---
<sub>Written 8-19-19</sub>
During one of my random thoughts, I had the idea of taking apart a mouse and reverse engineering its sensor for use with an Arduino. Rummaging through my dads old electronics, I found a PS2 mouse that I was pretty sure we would never use. First I used a PS2 library to communicate with the mouse and make sure it was still working. After that I took it apart to take a look at its sensor.
As it turns out, this mouse (I think it was a Dell) used a MCS-12085. Its so old that I couldnt find any major electronics distributors selling it. Surprisingly though, there are a bunch of articles online about this sensor. I proceeded to desolder this sensor and its associated components to put together my own board.
{% include gallery %}
While there were libraries available, the communication method shown in [datasheet](http://www.rmrsystems.co.uk/download/MCS12085.pdf) looked pretty simple so I decided it was the perfect exercise to do. I looked at code from this [library](https://github.com/jgrahamc/mcs12085) for inspiration.
{% highlight C %}
#define CLK_PIN 11
#define DAT_PIN 12
void setup() {
Serial.begin(115200);
mcs12085_init();
}
int x, y = 0;
void loop() {
x += mcs12085_dx();
y += mcs12085_dy();
Serial.print(x);
Serial.print(" ");
Serial.println(y);
delay(5);
}
void mcs12085_init() {
pinMode(CLK_PIN, OUTPUT);
pinMode(DAT_PIN, OUTPUT);
digitalWrite(CLK_PIN, HIGH);
digitalWrite(DAT_PIN, LOW);
delay(100); //Power Supply Rise Time
}
int8_t mcs12085_dx() {
return mcs12085_read_register(0x03);
}
int8_t mcs12085_dy() {
return mcs12085_read_register(0x02);
}
uint8_t mcs12085_read_register(uint8_t reg) {
mcs12085_write_byte(reg);
delayMicroseconds(100);
return mcs12085_read_byte();
}
uint8_t mcs12085_read_byte() {
pinMode(DAT_PIN, INPUT);
uint8_t result = 0;
for (int i = 0; i < 8; i++) {
digitalWrite(CLK_PIN, LOW);
digitalWrite(CLK_PIN, HIGH);
result = result << 1 | digitalRead(DAT_PIN);
}
pinMode(DAT_PIN, OUTPUT);
return result;
}
void mcs12085_write_byte(uint8_t val) {
for (int i = 0; i < 8; i++) {
digitalWrite(CLK_PIN, LOW);
digitalWrite(DAT_PIN, val & 1 << 7); //get msb
val = val << 1;
digitalWrite(CLK_PIN, HIGH);
}
}
{% endhighlight %}
The sensor actually worked really well. Ill probably use it for some kind of robot in the future but for now its nice to add another sensor to my repertoire.

View File

@ -0,0 +1,197 @@
---
title: Wireless Accelerometer
date: 2019-07-06
categories: projects
excerpt: Curiosity as to the identity of a mystery accelerometer taught me about logic analyzers, the ATtiny817, and low level communication with the nRF24l01+.
header:
teaser: /assets/img/2019/attiny817-accelboard-quarter.jpg
gallery:
- image_path: /assets/img/2019/I2C-Capture.jpg
- image_path: /assets/img/2019/I2C-Capture2.jpg
gallery2:
- image_path: /assets/img/2019/mc3413-breadboard-side-view.jpg
- image_path: /assets/img/2019/mc3413-breadboard-top-view.jpg
gallery3:
- image_path: /assets/img/2019/attiny817-accelboard-kicad-pcb.jpg
- image_path: /assets/img/2019/attiny817-accelboard-pcb.jpg
---
<sub>Written 8-19-19</sub>
While taking apart and analyzing the circuit board of a Wii Nunchuk I got off eBay, I tried to figure out what chips they used. The main microcontroller was a glop-top so no luck there. There was also an I2C EEPROM chip which I did end up desoldering and figuring out how to use. However there was one chip that I just couldnt figure out the part number of. The markings on it didnt bring up any useful information, but I assumed it was an accelerometer because the Nunchuk has one.
{% include figure image_path="/assets/img/2019/nunchuk-accelerometer.jpg" %}
## Figuring Out The Mystery Chip
Based on the pinout of the EEPROM and following the traces, I deduced that the mystery chip communicated over I2C and was on the same bus as the EEPROM. After connecting an Arduino to the thankfully exposed I2C test points, I ran some [I2C scanner code](https://playground.arduino.cc/Main/I2cScanner/) to figure out the addresses of the devices on the bus. There were two devices, 0x50 matched the EEPROM, so the other, 0x4C, was the accelerometer.
In hindsight, literally Googling “0x4C accelerometer” would have resulted in finding the datasheet that likely matched the chip. I somehow didnt think of that at the time because the Nunchuk was so cheap. Well, I did end up learning a lot in the process, so it was a blessing in disguise.
I started looking into I2C sniffers to analyze all the traffic on the I2C bus. I had a bunch of STM32 Blue Pill boards lying around, so I looked to see if someone had written code for it. To my pleasant surprise, someone [had](https://github.com/kongr45gpen/i2c-sniffer). I loaded the project into STM32CubeIDE and tried it out. First, I tried analyzing the communication between an Arduino and Wii Nunchuk and it worked perfectly. I could see all the addresses, data, start conditions, Acks, etc.
However, when I tried analyzing the I2C bus that housed the accelerometer, I got a bunch of gibberish. As it turns out, the I2C communication for a Nunchuk runs at 100KHz, but the accelerometer and EEPROM bus runs at 400KHz. Since I didnt have the money for an expensive logic analyzer, I looked around the internet for an I2C analyzer that could analyze a 400KHz bus but to no avail. Using the I2C scanner code from earlier as a test signal, the fastest bus I could read was about 150KHz.
### Making a 400KHz I2C Analyzer
Knowing a bit or two about optimizing and speeding up code, I took a look at the code for the STM32 sniffer. I first tried overclocking the chip from 72MHz to 128MHz by setting the PLL multiplier to 16. To my surprise, this worked flawlessly and I was able to scan buses up to 250KHz. I wondered if I could overclock it even further. I made a new project in STM32CubeIDE to test this out. The maximum PLL setting was 16, which limited me to 128MHz with an 8MHz crystal oscillator, so I replaced the oscillator with a 16MHz one. I immediately ran into stability issues. Dialing the settings back, I was able to overclock the STM32F103C8T6 to 144MHz, a 100% increase!
Still, I was only able to read buses of up to maybe 300KHz. The next step was optimizing the code. I heard that the HAL library used to control the GPIO adds a lot of overhead, so I looked into that first. It turns out every HAL GPIO access call does a bunch of checks which werent necessary in my use case. After a bit of tinkering, I was able to replace all the HAL calls in the code with register calls. I basically just replaced one function, as shown below:
{% highlight C %}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
uint8_t datum;
if (GPIO_Pin == GPIO_PIN_8) {
// Clock triggered; bit received
if (GPIOB->IDR & GPIO_PIN_9) {
datum = 1;
} else {
datum = 0;
}
} else if (GPIOB->IDR & GPIO_PIN_8) { // SDA pin necessarily
// START or STOP condition
// A for START, B for STOP
if (GPIOB->IDR & GPIO_PIN_9) {
datum = 'B';
} else {
datum = 'A';
}
} else {
// Nothing interesting here...
return;
}
buffer[bufferPos] = datum; // Store the received bit in the buffer
bufferPos++;
if (bufferPos >= I2C_BUFFER_SIZE) {
bufferPos = 0;
}
//if (bufferPos == bufferStart) printf("ERROR! I2C buffer too small!\r\n"); // Buffer overflow! //never really happens
}
{% endhighlight %}
After that, I was able to read up to around 350KHz I2C buses reliably. The next thing I was going to try was clock stretching, but I found that the decent reliability at 400KHz was good enough for my goal of reverse engineering what commands to send.
{% include gallery %}
### Revealing Its Identity
With the commands captured I was finally able to hook up the mystery chip to my Arduino and directly access the raw data off of it. I correctly assumed that it gave out readings in order X, Y, Z, but the data was jumbled at first. Turns out this chip sends out the LSB byte first then MSB byte. A simple bit shift later and everything was working.
I began to wonder what the chip actually was so I Googled “0x4C accelerometer” and I found some people talking about a MC3451 so I checked that out. Looking through the datasheet, everything seemed to match up perfectly with regards to register locations. The manufacturer, mCube, doesnt have that many different offerings so I looked at the datasheet of each and found that the model that best matched my mystery chip was the [MC3413](https://mcubemems.com/wp-content/uploads/2014/10/MC3413-Preliminary-Datasheet-APS-048-0029v1.7.pdf). The initialization commands all matched up to reasonable settings on the chip. Still, trying to read the PCODE register returned an incorrect value, so its likely my mystery chip isnt exactly an MC3413 but perhaps a knockoff or reject or something.
## Figuring Out the ATtiny817
Initially I was going to use a standard Atmega328P-AU for the microcontroller but I found that it was too big and overkill for my use case. My eyes turned to the ATtiny817 that I had sitting around for over a year. On paper it had every feature I needed so I took out my ATtiny817 Xplained Mini board and fired up Atmel Studio 7. At first I looked through the datasheet and learned how to write directly to the registers controlling I2C and SPI, but I found out that using Atmel START was far easier. The code doesnt use any unnecessary checks or abstractions, so speed-wise there wouldnt be much difference.
### Hooking Up The USART
Well technically Im using UART because its asynchronous. Atmel START provides USART_0_write() and USART_0_read() for UART communications, but I wanted to get that printf() functionality. Doing some research online, I found that I just needed to add a few lines of code to usart_basic.c. I also wanted to get scanf() working, so using some good old educational guessing I got that working too.
{% highlight C %}
//Add these lines below #if defined(__GNUC__)
int USART_0_printCHAR(char character, FILE *stream) {
USART_0_write(character);
return 0;
}
int USART_0_receiveCHAR(FILE *stream) {
return USART_0_read();
}
FILE USART_0_stream = FDEV_SETUP_STREAM(USART_0_printCHAR, USART_0_receiveCHAR, _FDEV_SETUP_RW);
//Add these lines below #if defined(__GNUC__) in USART_0_init()
stdout = &USART_0_stream;
stdin = &USART_0_stream;
{% endhighlight %}
### Integrating I2C
The next step was hooking up the MC3413 to the ATtiny817. I wanted to make sure I could use the MC3413 with a board of my own design, so I desoldered it using my reflow oven and soldered a bunch of tiny wires to the pins.
{% include gallery id="gallery2" %}
Despite how fragile the wiring looks, it actually works for testing.
Atmel START also provides the i2c_master.h and i2c_simple_master.h libraries for using the I2C interface. It defaults to interrupt mode when you add the module, so make sure you enable interrupts in the SREG register. I was coming from the Wire library for Arduino, so the i2c_simple_master.h library provided a smooth transition.
I2C generally uses the concept of addresses and registers when communicating. Writing to a register involves sending the device address (with a write bit), the desired register, and finally any data to write. Heres the code I used to initialize the MC3413:
{% highlight C %}
I2C_0_write1ByteRegister(accel_addr, 0x08, 0x0A);
I2C_0_write1ByteRegister(accel_addr, 0x20, 0x35);
I2C_0_write1ByteRegister(accel_addr, 0x07, 0x01);
{% endhighlight %}
Reading from registers is similar. First youd send the device address (with a write bit) and then the desired register. Then youd send the device address again (with a read bit this time) and then read in as much data as you need. Heres the code I used to read the accelerometer data from the MC3413:
{% highlight C %}
I2C_0_readDataBlock(accel_addr, 0x0D, dat, 6);
{% endhighlight %}
### Synthesizing SPI and nRF24
Like with I2C, Atmel START provides a really nice spi\_basic.h library. I chose to use polling mode instead of interrupt mode because I was still a beginner and didnt need the added functionality of interrupt mode. It also provided an easy transition from the Arduino SPI library. Heres the 4 methods to be aware of:
{% highlight C %}
uint8_t SPI_0_exchange_byte(uint8_t data);
void SPI_0_exchange_block(void *block, uint8_t size);
void SPI_0_write_block(void *block, uint8_t size);
void SPI_0_read_block(void *block, uint8_t size);
{% endhighlight %}
Theyre pretty self explanatory. SPI is generally much simpler than I2C in how to use it. Theres a chip select (CS) pin for each slave. To communicate, just pull the CS pin low and then start sending/receiving data.
Finding a good nRF24 library for Atmel Studio 7 yielded no results, so I decided to figure out how to port TMRh20s RF24 library. Looking through the source code, it appears very well written. It uses the Arduino SPI library instead of low level register manipulation so swapping out any SPI calls with spi\_basic.h equivalents would do the job. I ended up only porting over the functionality that I needed, mainly interrupt support and radio settings. My code can be found [here](https://gist.github.com/dragonlock2/0b9706dc3f48a7c6ba9d6c096f0a29ec).
### Initializing External Interrupts
One really nice thing about the ATtiny817 is it has interrupt capability on all pins, and supports all interrupt types instead of just pin change like on the Atmega328P. After using Atmel START to setup the pin, I implemented the ISR routine. Every pin belongs to a certain register, so the corresponding interrupt vector gets triggered when the pins interrupt triggers.
{% highlight C %}
ISR(PORTB_PORT_vect) {
PORTB.INTFLAGS |= 1 << 0; //clear interrupt flag
uint8_t tx, fail, rx;
RF24_whatHappened(&tx, &fail, &rx);
if (tx) { //on success
PORTA.OUTSET = 1 << 6; //turn off red
PORTA.OUTCLR = 1 << 7; //turn on green
} else {
PORTA.OUTCLR = 1 << 6; //turn on red
PORTA.OUTSET = 1 << 7; //turn off green
}
}
{% endhighlight %}
## Putting It All Together
With pretty much every component tested and working, it was time to make the PCB. I threw all the components into KiCad, where I did have to make my own schematic symbol for the MC3413. The VLGA-12 footprint it used was available though.
{% include figure image_path="/assets/img/2019/attiny817-accelboard-schematic.jpg" %}
As usual the PCB manufacture was pretty easy, but soldering the MC3413 proved quite the pain with my lack of solder paste and the VLGA-12 package. After several reflows and lifted traces, I did get it pinned down. I did accidentally pull up the TX trace so couldnt use UART. That did allow me to experiment with the UPDI debugging interface, so it worked out.
{% include gallery id="gallery3" %}
After putting the board together, I attached a LiPo I salvaged from my old Pebble Steel along with a TP4056 charger board and threw it all into a little 3D printed case. After some meticulous sanding to get all sides smooth and level, I was done.
{% include figure image_path="/assets/img/2019/attiny817-accelboard-quarter.jpg" %}
## Demonstration
One of the things I could never quite figure out, in part due to my relative inexperience at the time and also because I was always encumbered by wires when testing, was how to distinguish between swings and clashes. I literally couldnt find any code at the time to help me out except for one person who used the Z accelerometer measurement with some thresholds which was still mostly wrong.
With some basic knowledge of physics and accelerometers, it became pretty clear that a swing provided a low acceleration and a clash a high acceleration. Thus I just needed to combine the X, Y, and Z measurements into a measurement of the gravity vector and just look at that.
{% include video id="7bsAQNb6qpI" provider="youtube" %}
As the theory would predict, theres a pretty clear difference between swings and clashes. I basically facepalmed myself multiple times after this realization because of how much work I put into trying to figure out this simple fact a couple years ago.
{% include figure image_path="/assets/img/2019/attiny817-accelboard-free-fall.jpg" %}
Of course, no accelerometer demonstration would be complete without showing the weightlessness experienced in free fall.

View File

@ -0,0 +1,18 @@
---
title: ATtiny817 - Feature Packed Tiny MCU
date: 2019-07-07
categories: cool-chips
excerpt: Atmel's relatively new lineup of chips is quite promising.
header:
teaser: /assets/img/2019/attiny817-xplained-mini.jpg
---
<sub>Written 8-19-19</sub>
Over a year ago Arrow was giving away free ATtiny817 Xplained Mini boards. Intrigued, I got one along with a few separate ATtiny817s. I didnt have much experience moving beyond Arduino at the time, so it was the perfect opportunity to get started using Atmel Studio 7. Reading through the datasheet, which as usual with Atmel was very well written, I was able to get some lights flashing and changed the clock speed. I had to get back to working on Mission Possible for SciOly so I set it aside for the time being.
Fast forward a year later and I decided to take another look at the ATtiny817. With more experience around my belt, I finally understood what an amazingly cool chip it was. The acquisition of Atmel by Microchip had allowed a bunch of features from PIC chips to be added to AVR chips. Even more, these new chips use the UPDI, a single pin programming interface. It was a very welcome update from the 4-pin ISP programming of older Atmel chips in terms of making PCB design easier.
Overall, the ATtiny817 provides a perfect balance of features and size for a lot of the uses cases I foresee for my projects. It has 8KB of flash, 512B of RAM, I2C, SPI, USART, 3 Timers, 8 bit DAC, 10 bit ADC, and an internal RC oscillator among other features. Of course, for every project I do Ill need to analyze what chip provides the best fit, but the ATtiny817 does get a warm welcome into my parts bin.
{% include figure image_path="/assets/img/2019/attiny817-xplained-mini.jpg" %}

View File

@ -0,0 +1,22 @@
---
title: LMC6482 - Rail to Rail OpAmp
date: 2019-07-08
categories: cool-chips
excerpt: An excellent opamp for prototyping.
header:
teaser: /assets/img/2019/lmc6482.jpg
gallery:
- image_path: /assets/img/2019/piezo-amplifier.jpg
- image_path: /assets/img/2019/clamp-overview.jpg
---
<sub>Written 8-19-19</sub>
When I was just getting started using opamps late last year, I decided to buy a bunch of the most popular one, LM358. Little did I know about all the various specifications that I had to consider when picking the right opamp. At the time I was trying to amplify the signal for a sine wave encoder I was working on, but I hit a wall when the maximum voltage I could get out of the LM358 was around 3.7v with a 5v power input. It was then that I found out that I had to use a rail to rail opamp. Soon after though I was entering my senior year of high school, complete with a stressful college application season and engineering for upcoming SciOly 2018 competitions and team tryouts, so I set my tinkering aside for the time being.
Enter EE16B lab section during my 2nd semester at UC Berkeley. We used opamps pretty extensively in that class for various purposes but one of the things I noticed was that we used an [LMC6482](http://www.ti.com/product/LMC6482), which was a rail to rail opamp. We were also forced to order a free sample of them which was pretty awesome. So I spent plenty of time with this cool chip. For me the most important feature is its rail to rail output, but a lot of other specifications, from CMRR to input current are also excellent.
{% include gallery %}
It is a little expensive though compared to an LM358, but TIs sample program is pretty generous to students.

View File

@ -0,0 +1,74 @@
---
title: Wireless Arduino Nunchuk
date: 2019-07-13
categories: projects
excerpt: Compact, Ergonomic, Functional - behold my Wireless Arduino Nunchuk
header:
teaser: /assets/img/2019/nunchuk-overall.jpg
gallery:
- image_path: /assets/img/2019/aaa-battery-holder.jpg
- image_path: /assets/img/2019/nunchuk-battery.jpg
gallery2:
- image_path: /assets/img/2019/nunchuk-pcb-after-etch.jpg
- image_path: /assets/img/2019/nunchuk-pcb-tin-plated.jpg
- image_path: /assets/img/2019/nunchuk-pcb-kapton.jpg
gallery3:
- image_path: /assets/img/2019/nunchuk-assembly-1.jpg
- image_path: /assets/img/2019/nunchuk-assembly-2.jpg
- image_path: /assets/img/2019/nunchuk-assembly-3.jpg
---
<sub>Written 8-19-19</sub>
One of the things that Ive been meaning to build for awhile is an easily programmable and elegant remote to power random wireless projects I come up with. During our RoboSub electrical team meetings I found out that our PM Mark had used a Wii Nunchuk as a remote for his electric skateboard. I thought that was a really awesome idea, so I kept it on the stack of stuff to build the next summer.
My design philosophy is pretty much the embodiment of “form follows function.” No one is going to use a product that doesnt work. However, people also like to use products that have a nice aesthetic. The two arent mutually exclusive. Usability is also very important because if a product is hard to use, fewer people will use it. Thats why I chose a Wii Nunchuk as the outer shell for my remote. It packs excellent ergonomics, ease of use, and multiple control inputs all into a compact and beautiful package.
## Build
At first I wanted to 3D print a Nunchuk and then fit everything inside but my CAD skills arent yet advanced enough to make organic looking designs so I ended up buying a cheap Nunchuk off Ebay. Upon taking it apart I immediately began to wonder how I was going to fit a battery inside it. I didnt have any LiPo batteries small enough so I picked a NiMH AAA as a good compromise of size and capacity as well as being swappable. Then I started removing internal structures to make room for the AAA and cut a hole large enough to fit. Using some springs from the Amazon Dash Button and a 3D printed part, I fitted the Nunchuk with a battery holder, leaving ample room for rest of the electronics.
{% include gallery %}
The next step was picking out the features of the remote. I chose to keep the joystick and buttons, but added an MPU6050 and RGB LED. Since I still have a couple left and its the most widely supported Arduino microcontroller, I stuck with the Atmega328P-AU. I threw everything into KiCad, where the only part I had to design a schematic symbol and footprint for was the generic joystick.
{% include figure image_path="/assets/img/2019/nunchuk-schematic.png" %}
With my trusty caliper in hand and a couple 3D printed tests, I was able to create a board outline that would fit perfectly into the Nunchuk and maximized available area for placing components.
{% include figure image_path="/assets/img/2019/nunchuk-kicad-pcb.jpg" %}
Making the PCB was relatively straightforward, except for the drilling because I didnt have the right size bits. FR4 does sand nicely, so getting it exactly to size was a breeze.
{% include gallery id="gallery2" %}
I even tried making a solder mask using Kapton tape and an X-Acto knife. It worked really well, but is too tedious for me to give a recommendation. The UV cure solder mask Im working on now is far easier and more effective.
{% include figure image_path="/assets/img/2019/nunchuk-pcb-half-assembled.jpg" %}
I had to jerry-rig my soldering job because I didnt have solder paste, but after several reflows, lots of flux, and some of the finest trace repairs Ive ever done, the board was working.
{% include gallery id="gallery3" %}
All the electronics ended up fitting really nicely. I had to add a piece to improve the rigidity of the casing but other than that, the rest of the assembly was clean. I really liked how I routed the RGB LED to the front top and made a custom port at the bottom for programming and serial debugging. There was also quite a bit of room underneath the PCB to fit the nRF24 board.
## Programming
Since I didnt have a specific project I wanted to control with this remote, I stuck to creating a template that would make integrating it into any project relatively easy. You can find it [here](https://gist.github.com/dragonlock2/6c691bc0acdd57ce0ce8567d596a251c). The Teensy I used as a receiver has a little quirk because it uses ARM instead of AVR architecture.
Using a Teensy with the FreqCount library, I first calibrated the internal RC oscillator, setting the OSCCAL register.
Sending the battery voltage in a uint8_t (range is 0-255, which is good enough for a 1.5v AAA) instead of as a float proved a little tricky, but I got it working. analogRead() returns an int which when multiplied by 330 overflows so I had to cast it as a long.
The code for the joystick was a little trickier than expected to get clean because it centers at a point not exactly in the middle of its range so I had to use two different map calls.
The last part was calibrating the MPU6050 and getting it working with the InvenSense Teapot Demo. I used a program I found online to get the gyroscope and accelerometer offsets, using some tape rolls to hold the remote in the proper orientation. I then set the fine gain on the accelerometer so that the measured gravity vector was constant in all orientations.
Since I was heading to Maui soon, I didnt have much time to do much other than create a really basic demonstration of using the remote as a mouse. I pretty much just used the raw gyroscope values to determine movement and the accelerometer to determine orientation to simulate lifting the mouse.
{% include video id="xuXBSWcld10" provider="youtube" %}
Overall, as a prototype Id say this was a success. Im not sure what the market is for these things but itd be pretty cool to bring this into production. The case needs rework and Id probably want to modify the internals to incorporate the nRF24 into the main board and use a 9-axis IMU and add USB programming/debugging but otherwise its pretty solid.

View File

@ -0,0 +1,61 @@
---
title: Tinkering with TensorFlow (and OpenCV)
date: 2019-07-27
categories: projects
excerpt: Some free time and a project idea provided the perfect opportunity to get my feet wet with TensorFlow and OpenCV.
header:
teaser: /assets/img/2019/tf-imgs.jpg
---
<sub>Written 8-19-19</sub>
One project Ive really wanted to do for a long time is a robot that identifies lightsabers and shoots at them using Nerf darts or something. Star Wars was a huge part of my childhood and recreating those iconic blaster deflection scenes would be so cool. I keep getting distracted by other cool things I want to do so hopefully Ill get around to it next summer or so.
During my family trip to Maui this summer, I had a bunch of free time on my hands whenever we werent hiking, eating, or going to the beach. I thought about how I could be productive and settled on figuring out the vision system for my future robot.
A few weeks previously, I experimented with OpenCV on my Raspberry Pi 2 and tried using filters and other functions to draw a box around any identified lightsabers. It worked rather well, but it was prone to several inaccuracies that I couldnt quite adjust out. It also didnt work for flashlight sabers (like SaberForge), whose brightness decrease significantly by the end of the blade.
{% include video id="Uj7dXJSIqWI" provider="youtube" %}
My code also only worked for one lightsaber and didnt identify any colors, so I decided that it was the perfect time to dive into using machine learning and object detectors to do what I wanted. I learned about using object detectors with OpenCVs DNN module so I looked up how to train my own model. I decided on using TensorFlow because its really popular and theres a lot of tutorials out there on it.
### Training a Model
If you want step by step instructions on how to train your own object detector using TensorFlow, check out some of the links below, especially the Medium articles. I will just be outlining the basic steps I took and fixes for some hiccups along the way.
The first part is choosing a model. Since Im going to end up deploying my model on relatively weak hardware (probably a Jetson Nano when I eventually buy one) and lightsabers are pretty easy to describe and supposedly detect, I chose to use SSDLite MobileNet v2.
The next step is creating a dataset, which takes up a surprising amount of time. I spent quite awhile pouring through Google Images, picking out images of varying color, background, orientation, brightness. Since I wanted the model to work with flashlight lightsabers and not just LED blade ones, I made sure to also include a bunch of cosplay pictures.
{% include figure image_path="/assets/img/2019/tf-imgs.jpg" %}
After getting a bunch of images (all PNGs and JPEGs), I had to manually annotate each one. I used [LabelImg](https://github.com/tzutalin/labelImg) because it seemed to be the most popular and was quite easy to use. I put all of the generated XML files into a separate folder.
TensorFlow requires data to be in the TFRecord file format. Theres scripts that automatically convert the files from LabelImg to TFRecord, but I had issues with it and ended up writing my own script based off of the example on the Github. You can find it [here](https://gist.github.com/dragonlock2/f2486feb42fa211708a53ec85e45a74b).
Finally, I got onto doing the actual training. A lot of tutorials say to use train.py but the new way is using model_main.py. The [Github](https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/running_locally.md) provides pretty clear directions on this. I then used TensorBoard to monitor everything.
{% include figure image_path="/assets/img/2019/tensorboard-light.jpg" %}
Since I was in Maui and didnt have access to my GTX 970 powered desktop at home, I had to do all the training on my Macbook Pro. After 3 days of my Macbook running at basically 100% load, the training finally got to a point where I was happy with the accuracy. One thing to keep in mind is not to leave the training going on too long because you might end up overfitting.
Next is exporting the model as a .pb file for OpenCV. OpenCV also requires a .pbtxt to import which can be generated using tf_text_graph_ssd.py on the OpenCV repository. I ran into an AssertionError when running it, which I found a fix for [here](https://github.com/opencv/opencv/issues/11560). Turns out the nodes need to be sorted.
After all that, I was finally able to import my model into OpenCV and run it.
{% include video id="xziQ5t213Mg" provider="youtube" %}
The results are actually pretty good. My training data could have been improved to include multiple lightsabers hitting each other, but it did a great job nevertheless. One thing to note is that the video is slowed down because my Macbook isnt quite fast enough to run the detector at the playback speed. Still, Id call this a success.
Using TensorFlow to train and deploy models is pretty cool, but it doesnt really teach you anything about how machine learning and object detectors actually work. Im familiar with the basics, but Im definitely going to take machine learning classes later because I really want to gain a fundamental understanding of how it works.
#### Sources:
- <https://medium.com/@WuStangDan/step-by-step-tensorflow-object-detection-api-tutorial-part-1-selecting-a-model-a02b6aabe39e>
- <https://towardsdatascience.com/creating-your-own-object-detector-ad69dda69c85>
- <https://towardsdatascience.com/how-to-train-your-own-object-detector-with-tensorflows-object-detector-api-bec72ecfe1d9>
- <https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/installation.md>
- <https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/running_locally.md>
- <https://jeanvitor.com/tensorflow-object-detecion-opencv/>
- <https://github.com/opencv/opencv/issues/11560>
- <https://www.pyimagesearch.com/2017/09/18/real-time-object-detection-with-deep-learning-and-opencv/>

View File

@ -0,0 +1,94 @@
---
title: DIY DC Current Clamp
date: 2019-08-09
categories: projects school
excerpt: In a relatively straightforward build, I learned how DC current clamp meters work and ended up with a surprisingly functional device.
header:
teaser: /assets/img/2019/clamp-overview.jpg
gallery:
- image_path: /assets/img/2019/current-measurement-setup.jpg
- image_path: /assets/img/2019/current-measurement-data.jpg
---
<sub>Written 8-18-19</sub>
While competing at RoboSub this year (our 1st year competing!), one of the things we realized was that we likely seriously overestimated the current demands of our sub. At competition we realized that, even after a whole day, we barely depleted one of our 4 batteries. Thus, we decided that one of the things we needed to do next year was determine power draw with actual current measurements. Total current draw will probably still be in the 10s of amps, and since we definitely dont want to deal with using current shunts in the tight electronics enclosure of our sub, I wondered about using those current clamps that Ive heard about.
As it turns out, DC current clamp meters are widely available on Amazon. As usual, I began to wonder how they worked since DC current doesnt generate a changing magnetic field. A quick Google search later and I found out that these meters cleverly use a Hall effect sensor to measure the strength of the magnetic field. Thus, I decided to put together a little prototype.
{% include figure image_path="/assets/img/2019/currentclamp-drawing.jpg" %}
The basic composition of a DC current clamp is a ferrite toroid, cut in half to fit a wire through, and a linear Hall effect sensor. The toroid “captures” the magnetic field from the wire and directs it straight into the sensor. Its a pretty neat way of noninvasive current measurement.
## Build
Before doing any CAD or finalizing any design, I needed to make sure the theory actually worked. I took the largest ferrite toroid I had and chopped it in half with a hacksaw. I soldered some wires onto a 49E linear Hall effect sensor and hooked it up to an Arduino outputting the analog readings to the serial monitor graph. One hand holding all the parts around the battery wire of my RC car, other hand on the remote, and eyes on the screen, I was delighted to see the readings change as I revved the RC car. (I also realized how much noise a brushless motor puts into the system, something well consider more in-depth next year for the sub.)
Next, I modeled a basic clamp in Fusion 360. I still had to determine the amplifier requirements and whether to use an example circuit I found online or one of my own design. I printed out my design and proceeded with prototyping the circuit.
{% include figure image_path="/assets/img/2019/clamp-proto.jpg" %}
To improve usability and reliability, I ended up designing my own circuit based off of one I found [online](http://www.electronoobs.com/eng_circuitos_tut12_1.php). I made the gain adjustable as well as the reference voltage on the non-inverting input of the opamp. I added resistors around the potentiometer to make finely adjusting it easier. Since making PCBs is pretty easy now, I threw the circuit into KiCad.
{% include figure image_path="/assets/img/2019/clamp-kicad.jpg" %}
I did my best to design the circuit to reduce noise because we are making pretty fine measurements.
{% include figure image_path="/assets/img/2019/clamp-pcb-soldermask.jpg" %}
I also tried doing a DIY soldermask for the second time and it actually worked pretty well.
{% include figure image_path="/assets/img/2019/clamp-cad.jpg" %}
I updated the clamp design with the observations I made while using the prototype and also made room for the circuit board.
{% include figure image_path="/assets/img/2019/clamp-overview.jpg" %}
## Calibration & Code
First things first, I adjusted the potentiometers so that the range of the meter was around 100A. I jacked up the gain to accentuate small voltage differences to make it easier to adjust the reference voltage on the non-inverting input of the opamp. After setting the reference voltage so that the output is roughly around 2.5v with no wire clamped, I used my battery charger to provide a 5A reference current to help adjust the gain.
Next thing to do was to gather a bunch of data points. I didnt have any accurate current sources so I jerry-rigged a setup with a current shunt, some lithium batteries, and a power resistor. I made sure to be as safe as possible, but I still wouldnt recommend doing what I did for safety reasons.
{% include gallery %}
After all that was done, I wrote a simple Arduino program to put everything together.
{% highlight C++ %}
#define BUFFER_SIZE 512
#define READ_PIN A0
#define CENTER 503.2 //reading at 0A
#define SLOPE 0.1625 // in Amps/Reading
/*
* To Perform Reading:
* 1. Probs wanna rough calibrate against known current
* 2. Angle changes CENTER for some reason, so hold at angle u wanna measure
* and update CENTER
* 3. Do the reading.
*/
void setup() {
Serial.begin(115200);
}
void loop() {
float r = getReading();
Serial.print("Raw: ");
Serial.print(r);
Serial.print("\t Current(A): ");
Serial.println((r - CENTER) * SLOPE);
delay(1);
}
float getReading() {
long tot = 0;
for (int i = 0; i < BUFFER_SIZE; i++) {
tot += analogRead(READ_PIN);
}
return 1.0 * tot / BUFFER_SIZE;
}
{% endhighlight %}
At the end of the day, I ended up with a decently accurate (±0.5A) device. It definitely wont replace one I can buy off Amazon but for a total cost of around $1, itll do the job just fine for now. And it was an awesome learning experience.

View File

@ -0,0 +1,14 @@
---
title: Hello World!
date: 2019-08-16
categories: other
excerpt: Hello there! Obligatory first post.
header:
teaser: /assets/img/2019/maui-valley-me.jpg
---
{% include figure image_path="/assets/img/2019/maui-valley-me.jpg" %}
Hi! Im Matthew Tran and Ive been a maker for as long as I can remember. Im currently an EECS major at UC Berkeley, pursuing my passion for all things electrical engineering and computer science. After years of tinkering and building things, Ive finally decided to start a blog to document most of what Ive done and perhaps be a stepping off point to inspire and help others. Im endlessly fascinated by what I do and would love to share that with everyone.
Every post before this one will be my attempt at retracing all the knowledge Ive gained (and fun Ive had :P) over the past couple years. It feels a bit weird to write things from the perspective of my younger self, so Ill write about everything with the perspective of hindsight. For dates, Im using rough approximations instead of todays date because itll be pretty cool to scroll back and say, “Hey! I did that way back then!”

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
assets/img/2019/arc-v1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
assets/img/2019/arc-v2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
assets/img/2019/lmc6482.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
assets/img/2019/tf-imgs.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB