Introducing APStreamline!

Download APSync with APStreamline built in from here (BETA)!

I’m very excited to announce the release of a network adaptive video streaming solution for ArduPilot!


The APSync project currently offers a basic video streaming solution for the Raspberry Pi camera. APStreamline aims to complement this project by adding several useful features:

  • Automatic quality selection based on bandwidth and packet loss estimates

  • Selection of network interfaces to stream the video

  • Options to record the live-streamed video feed to the companion computer

  • Manual control over resolution and framerates

  • Multiple camera support using RTSP

  • Hardware-accelerated H.264 encoding for the Raspberry Pi

  • Camera settings configurable through the APWeb GUI

I’m chuffed to say that this has not only met the requirements for the GSoC project but has also covered the stretch goals I had outlined in my proposal!

Streaming video from robots is an interesting problem. There are several different use cases – you might be a marine biologist with a snazzy BlueROV equipped with several cameras or a UAV enthusiast with the itch of flying FPV. APStreamline caters to these and several other use cases.

While APStreamline works on the all network interfaces available on the Companion Computer (CC), its main value lies in the case of streaming on unreliable networks such as Wi-Fi as in most cases, we use the Companion Computer (CC) in Wi-Fi hotspot mode for streaming the video. Due to the limited range of 2.4GHz Wi-Fi, the Quality-of-Service (QoS) progressively gets worse when the robot moves further away from the receiving computer.

This project aims to fixes problem by dynamically adjusting the video quality in realtime. Over UDP we can obtain estimates of QoS using RTCP packets received from the receiver. These RTCP packets provide helpful QoS information (such as RTT and packet loss) which can be used for automatically changing the bitrate and resolution of the video delivered from the sender.

Running the Code


All the following instructions are for installing APStreamline and APWeb on the CC. A Raspberry Pi 2/3/3B+ with the latest version of Raspian or APSync is a good choice. Intel NUC’s are excellent choices as well.

Do note that the Raspberry Pi 3 and 3B+ have very low power Wi-Fi antennae which aren’t great for video streaming. Using a portable Wi-Fi router like the TPLink MR-3020 can dramatically improve range. Wi-Fi USB dongles working in hotspot mode can help as well.

Installing APStreamline

Install the gstreamer dependencies:

sudo apt install libgstreamer-plugins-base1.0* libgstreamer1.0-dev libgstrtspserver-1.0-dev gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly python3-pip 

Install meson from pip and ninja for building the code:

sudo pip3 install meson 

sudo apt install ninja-build 

Navigate to your favourite folder folder and run:

git clone -b release 

meson build 

cd build 

sudo ninja install # installs to /usr/local/bin for APWeb to spawn 

On the Raspberry Pi, use sudo modprobe bcm2835-v4l2 to load the V4L2 driver for the Raspberry Pi camera. Add bcm2835-v4l2 to /etc/modules for automatically loading this module on boot.

Installing APWeb

The APWeb server project enables setting several flight controller parameters on the fly through the use of a Companion Computer (e.g. the Raspberry Pi). We use this APWeb server for configuring the video streams as well.

Clone the forked branch with APStreamline support here:

git clone -b video_streaming 

cd APWeb 

Install libtalloc-dev and get the MAVLink submodule:

sudo apt-get install libtalloc-dev 

git submodule init 

git submodule update 

Build APWeb:

cd APWeb 


./web_server -p 80 

In case it fails to create the TCP socket, try using sudo ./web_server -p 80. This can clearly cause bad things to happen so be careful!


Video livestreams can be launched using RTSP. It is recommended to use RTSP for streaming video as it provides the advantages of supporting multiple cameras, configuring the resolution on-the-fly, and recording the livestreamed video to a file.


Start the APWeb server. This will serve the configuration page for the RTSP stream server. Connect to the web server in your favourite web browser by going to the IP address of the Companion Computer.

On navigating to the new video/ page, you will be presented with a page to start the RTSP Server:


On selecting the desired interface and starting the RTSP Server, the APWeb server will spawn the Stream Server process. The stream server will search for all the V4L2 cameras available in /dev/. It will query the capabilities of all these cameras and select hardware encoding or software encoding accordingly. The list of available cameras can be refreshed by simply stopping and starting the server.

From here, the APWeb page will display the list of available RTSP streams and their mount points:


The video quality can either be automatically set based on the available network bandwidth or set manually for more fine-grained control.

The APWeb page also presents an option to record the video stream to a file on the CC. For this the video stream must be opened on the client. This works with any of the manually set resolutions but does not work with Auto quality. This is because the dynamically changing resolution causes problems with the file recording pipeline. An exception to this is the UVC cameras which can record to a file in Auto mode as well.

The RTSP streams can be viewed using any RTSP player. VLC is a good choice. Some GCS such as QGroundControl and Mission Planner can also stream video over RTSP.

For example, this can be done by going to “Media > Open Network Stream” and pasting in the RTSP Mount Point for the camera displayed in the APWeb configuration page. However, VLC introduces two seconds of latency for the jitter reduction, making it unsuitable for critical applications. To circumvent this, RTSP streams can also be viewed at lower latency by using the gst-launch command:

gst-launch-1.0 playbin uri=<RTSP-MOUNT-POINT> latency=100

As an example RTSP Mount Point looks like: rtsp:// Refer to the APWeb page to see the mount points given for your camera.


Launch the RTSP stream server by running:

stream_server <interface>

The list of available network interfaces can be found by running ifconfig. Streams can be connected to using gst-launch.

Things to Try Out

  • Use a variety of different cameras and stream several at the same time

  • Try recording the live-streamed video to a file on the CC

  • Play with the Auto quality streaming feature on different types of network interfaces

GSoC 2018 - Batteries Included!

Much time has passed and much code has been written since my last update. Adaptive Streaming (a better name TBD) for Ardupilot is nearly complete and brings a whole slew of features useful for streaming video from cameras on robots to laptops, phones, and tablets:

  • Automatic quality selection based on bandwidth and packet loss estimates
  • Options to record the live-streamed video feed to the companion computer (experimental!)
  • Fine tuned control over resolution and framerates
  • Multiple camera support over RTSP
  • Hardware-accelerated H.264 encoding for supported cameras and GPUs
  • Camera settings configurable through the APWeb GUI


The configuration required to get everything working is minimal once the required dependencies have been installed. This is in no small part possible thanks to the GStreamer API which took care of several low level complexities of live streaming video over the air.

Streaming video from aerial robots is probably the most difficult use case of Adaptive Streaming as the WiFi link is very flaky at these high speeds and distances. I’ve optimised the project around my testing with video streaming from quadcopters so the benefits are passed on to streaming from other robots as well.


I’ve used a simplification of TCP’s congestion control algorithm for Adaptive Streaming. I had looked at other interesting approaches including estimating receiver buffer occupancy, but using this approach didn’t yield significantly better results. TCP’s congestion control algorithm avoids packet loss by mandating ACKs for each successfully delivered packet and steadily increasing sender bandwidth till it reaches a dynamically set threshold.

A crucial difference for Adaptive Streaming is that 1) we stream over UDP for lower overhead (so no automatic TCP ACKs here!) 2) H.264 live video streaming is fairly loss tolerant so it’s okay to lose some packets instead of re-transmitting them.

Video packets are streamed over dedicated RTP packets and Quality of Service (QoS) reports are sent over RTCP packets. These QoS reports give us all sorts of useful information, but we’re mostly interested in seeing the number of packets loss between RTCP transmissions.

On receiving a RTCP packet indicating any packet loss, we immediately shift to a Congested State (better name pending) which significantly reduces the rate at which the video streaming bandwidth is increased on receiving a lossless RTCP packet. The encoding H.264 encoding bitrate is limited to no higher than 1000kbps in this state.

Once we’ve received five lossless RTCP packets, we shift to a Steady State which can encode upto 6000kbps. In this state we also increase the encoding bitrate at a faster rate than we do in the Congested State. A nifty part of dynamically changing H.264 bitrates is that we can also seamlessly switch the streamed resolution according to the available bandwidth, just like YouTube does with DASH!

This algorithm is fairly simple and wasn’t too difficult to implement once I had figured out all the GStreamer plumbing for extracting packets from buffers. With more testing, I would like to add long-term bitrate adaptations for the bitrate selection algorithm.

H.264 Encoding

This is where we get into the complicated and wonderful world of video compression algorithms.

Compression algorithms are used in all kinds of media, such as JPEG for still images and MP3 for audio. H.264 is one of several compression algorithms available for video. H.264 takes advantage of the fact that a lot of the information in video between frames is redundant, so instead of saving 30 frames for 1 second of 30fps video, it saves one entire frame (known as the Key Frame or I-Frame) of video and computes and stores only the differences in frames with respect to the keyframe for the subsequent 29 frames. H.264 also applies some logic to predict future frames to further reduce the file size.

This is by no means close to a complete explanation of how H.264 works, for further reading I suggest checking out Sid Bala’s explanation on the topic.

The legendary Tom Scott also has a fun video explaining how H.264 is adversely affected by snow and confetti!

The frequency of capturing keyframes can be set by changing the encoder parameters. In the context of live video streaming over unstable links such as WiFi, this is very important as packet loss can cause keyframes to be dropped. Dropped keyframes severely impact the quality of the video until a new keyframe is received. This is because all the frames transmitted after the keyframe only store the differences with respect to the keyframe and do not actually store a full picture on their own.

Increasing the keyframe interval means we send a large, full frame less frequently, but also means we would suffer from terrible video quality for an extended period of time on losing a keyframe. On the other hand, shorter keyframe intervals can lead to a wastage of bandwidth.

I found that a keyframe interval of every 10 frames worked much better than the default interval of 60 frames without impacting bandwidth usage too significantly.

Lastly, H.264 video encoding is a very computationally expensive algorithm. Software-based implementations of H.264 such as x264enc are well supported with several configurable parameters but have prohibitively high CPU requirements, making it all but impossible to livestream H.264 encoded video from low power embedded systems. Fortunately, the Raspberry Pi’s Broadcom BCM2837 SoC has a dedicated H.264 hardware encoder pipeline for the Raspberry Pi camera which drastically reduces the CPU load in high definition H.264 encoding. Some webcams such as the Logitech C920 and higher have onboard H.264 hardware encoding thanks to special ASIC’s dedicated for this purpose.

Adaptive Streaming probes for the type of encoding supported by the webcam and whether it has the IOCTL’s required for changing the encoding parameters on-the-fly.

H.264 has been superseded by the more efficient H.265 encoding algorithm, but the CPU requirements for H.265 are even higher and it doesn’t enjoy the same hardware support as H.264 does for the time being.


The project is soon-to-be integrated with the APWeb project for configuring companion computers. Adaptive Streaming works by creating an RTSP Streaming server running as a daemon process. The APWeb process connects to this daemon service over a local socket to populate the list of cameras, RTSP mount points, and available resolutions of each camera.


The GUI is open for improvement and I would love feedback on how to make it easier to use!

Once the RTSP mount points are generated, one can livestream the video feed by entering in the RTSP URL of the camera into VLC. This works on all devices supporting VLC. However, VLC does add two seconds of latency to the livestream for reducing the jitter. I wasn’t able to find a way to configure this in VLC, so an alternative way to get a lower latency stream is by using the following gst-launch command in a terminal:

gst-launch-1.0 playbin uri=<RTSP Mount Point> latency=100

In the scope of the GSoC timeline, I’m looking to wind down the project by working on documentation, testing, and reducing the cruft from the codebase. I’m looking forward to integrating this with companion repository soon!

Title image from OscarLiang

GSoC 2018 - New Beginnings

I’m really excited to say that I’ll be working with Ardupilot for the better part of the next two months! Although this is the second time I’m making a foray into Open Source Development, the project at hand this time is quite different from what I had worked on in my first GSoC project.

Ardupilot is an open-source autopilot software for several types of semi-autonomous robotic vehicles including multicopters, fixed-wing aircraft, and even marine vehicles such as boats and submarines. As the name suggests, Ardupilot was formerly based on the Arduino platform with the APM2.x flight controllers which boasted an ATMega2560 processor. Since then, Ardupilot has moved on to officially supporting much more advanced boards with significantly better processors and more robust hardware stacks. That said, these flight controllers contain application specific embedded hardware which is unsuitable for performing intensive tasks such as real-time object detection or video processing.


CC Setup with a Flight Computer

APSync is a recent Ardupilot project which aims to ameliorate the limited processing capability of the flight controllers by augmenting them with so-called companion computers (CCs). As of writing, APSync officially supports the Raspberry Pi 3B(+) and the NVidia Jetson line of embedded systems. One of the more popular use cases for APSync is to enable out-of-the-box live video streaming from a vehicle to a laptop. This works by using the CC’s onboard WiFi chip as a WiFi hotspot to stream the video using GStreamer. However, the current implementation has some shortcomings which are:

  • Only one video output can be unicasted from the vehicle
  • The livestreamed video progressively deteriorates as the WiFi link between the laptop and the CC becomes weaker

This is where my GSoC project comes in. My project is to tackle the above issues to provide a good streaming experience from an Ardupilot vehicle. The former problem entails rewriting the video streaming code to allow for sending multiple video streams at the same time. The latter is quite a bit more interesting and it deals with several computer networks and hardware related engineering issues to solve. “Solve” is a subjective term here as there isn’t any way to significantly boost the WiFi range from the CC’s WiFi hotspot without some messy hardware modifications.

What can be done is to degrade the video quality as gracefully as possible. It’s much better to have a smooth video stream of low quality than to have a high quality video stream laden with jitter and latency. At the same time, targeting to only stream low quality video when the WiFi link and the processor of the CC allows for better quality is inefficient. To “solve” this, we would need some kind of dynamically adaptive streaming mechanism which can change the quality of the video streamed according to the strength of the WiFi connection.

My first thought was to use something along the lines of Youtube’s DASH (Dynamically Adaptive Streaming over HTTP) protocol which automatically scales the video quality according to the available bandwidth. However, DASH works in a fundamentally different way from what is required for adaptive livestreaming. DASH relies on having the same video pre-encoded in several different resolutions and bitrates. The server estimates the bandwidth of its connection to the client. On doing so, the server chooses one of the pre-encoded video chunks to send to the client. Typically, the server tries to guess which video chunk can deliver the best possible quality without buffering.

Youtube’s powerful servers have no trouble encoding a video several times, but this approach is far too intensive to be carried out on a rather anemic Raspberry Pi. Furthermore, DASH relies on QoS (short for Quality of Service which includes parameters like bitrate, jitter, packet loss, etc) reports using TCP ACK messages. This causes more issues as we need to stream the video down using RTP over UDP instead of TCP. The main draw of UDP for livestreaming is that performs better than TCP does on low bandwidth connections due to its smaller overhead. Unlike TCP which places guarantees on message delivery through ACKs, UDP is purely best effort and has no concept of ACKs at the transport layer. This means we would need some kind of ACK mechanism at the application layer to measure the QoS.

Enter RTCP. This is the official sibling protocol to RTP which among other things, reports packet loss, cumulative sequence number received, and jitter. In other words - it’s everything but the kitchen sink for QoS reports for multimedia over UDP! What’s more, GStreamer natively integrates RTCP report handling. This is the approach I’ll be using for getting estimated bandwidth reports from each receiver.

I’ll be sharing my experiences with the H.264 video encoders and hardware in my next post.

Be The Opposite

“The Opposite” (S05E21) was a watershed episode for Seinfeld. Not only did the series’ direction change hands from Tom Cherones to Andy Ackerman after it, but the plots also became more focussed on the personality flaws in the characters rather than the bizarre situations they got themselves into. “The Opposite” was probably the only episode in which these two tropes converged, making for something quite unlike any other Seinfeld episode.

But that’s not what I’m going to write about in this blog post. “The Opposite” has personal meaning for other reasons. As a short summary of the A-plot of this episode - George, a stout, balding, middle-aged man with no prospects with either a career or with the opposite sex, decides to act contrary to every instinct he’s ever had. In a span of less than a day after doing so, he ends up with a new partner, a job with the New York Yankees, and finally gets the means to move out from his much beleaguered parents’ house.

Though contrived for comical purposes, this episode holds something very profound under its veil of light-hearted comedy. The series goes to show that even when it’s painfully obvious that you’re clearly doing something wrong, it can be impossible to get out of the self-induced loop of listening to your instincts.

Jerry also drives this home with an understatedly profound remark in this episode, “If every instinct you have is wrong…then the opposite would have to be right!”.

Perhaps it’s a primal urge to follow your instincts, after all, your instincts are a product of your past experiences which have kept you alive. On the other hand, I feel a lot of it also has to do with getting into the comfort zone of being able to challenge your own perceptions. When you’ve been doing something wrong unconsciously, it becomes much harder to accept the fact that you were doing it wrong later on. Your brain accustoms itself to behaving in a certain way to a stimulus and left unchecked, this becomes a part of your personality. This is why I think shifting out of self-harmful behavior is so hard.

I’ve been a victim of falling to the trap of my own instincts ever since I joined college. Through a lot of time spent brooding and many moments of soul-searching through my daily diary entries, I was exactly aware of what I was unhappy with in life and what I had to do to fix it. Most of my problems could be traced down to a lack of self-esteem, but I was more than willing to wallow in pity than do anything about it. It was only a few months ago I decided to improve things by increasing physical activity and social exposure. There were many times I had a familiar nagging of doubt, but this too subsided as soon as I saw things can actually get better by not listening to yourself.

There is a poignant quote I’ve saved from Anne Lammot’s Bird by Bird about not listening to the radio station in your head - the radio station KFKD, or K-Fucked:

“If you are not careful, station KFKD will play in your head twenty-four hours a day, nonstop, in stereo. Out of the right speaker in your inner ear will come the endless stream of self-aggrandizement, the recitation of one’s specialness, of how much more open and gifted and brilliant and knowing and misunderstood and humble one is. Out of the left speaker will be the rap songs of self-loathing, the lists of all the things one doesn’t do well, of all the mistakes one has made today and over an entire lifetime, the doubt, the assertion that everything that one touches turns to shit, that one doesn’t do relationships well, that one is in every way a fraud, incapable of selfless love, that one has no talent or insight, and on and on and on. You might as well have heavy-metal music piped in through headphones while you’re trying to get your work done.”

Maybe the best way out lies in our mistakes, or rather, the opposite of them.


ThinkPad 13: Thoughts after 18+ months

It’s been over a year since I switched laptops and I want to share my thoughts on my current one - the Lenovo ThinkPad 13 Gen 1. Before getting this laptop, I had been using a Lenovo IdeaPad G580 which I had gotten back in 2013. While that laptop suited my needs at the time, the unwieldy 15.6” display, sub-standard 2 hrs battery life, and weight of 2.8kg just wasn’t cutting it for college. I decided to go for a smaller laptop with good battery life to replace it. I was pretty satisfied with the performance of the IdeaPad so anything as good or better than its i5-3230M was enough for me.

The first laptop which I looked at was the Asus UX305UA which ticked most of my boxes. However, some reviews had stated that its build quality was questionable so I decided to hold out for a better laptop. I later stumbled upon the Lenovo ThinkPad T460(s) which looked perfect for my needs but was just a touch out of my budget. While I was considering this, news began to surface about a 13.3” ThinkPad releasing soon, later to be known as the ThinkPad 13.

It wasn’t an easy decision between the T460s and the 13. The T460s was definitely a more charming laptop but there were just too many drawbacks for it to be a serious contender. I found several negative reviews regarding the battery life and the 1080p display lottery. The ThinkPad 13 wasn’t without issues of its own, but there wasn’t a single review that hadn’t sung praises about its keyboard, battery life, and overall value proposition. Plus it came with a USB Type-C port, dual upgradeable RAM slots, and was at least $200 cheaper than a comparatively specced T460s.

I got the silver version of the ThinkPad 13. Die-hard ThinkPad fans may condemn a non-black ThinkPad, but I think it looks great. Plus, the silver version came with the free 1080p IPS display upgrade. It also has a better choice of materials with an aluminium lid in place of the ABS plastic lid found on the black version of the ThinkPad 13.

I configured my laptop with the following specs for $720 (₹46500):

  • Intel Core i5-6300U Processor (3MB Cache, up to 3.00GHz)
  • Windows 10 Home 64 English
  • 8GB DDR4-2133 SODIMM
  • Intel HD Graphics 520
  • 3cell 42Wh
  • UltraNav (TrackPoint and ClickPad) without Fingerprint Reader
  • Software TPM Enabled
  • 720p HD Camera
  • 256 GB Solid State Drive, SATA3 OPAL2.0 - Capable
  • 45W AC Adapter - US(2pin)
  • Intel Dual Band Wireless-AC(2x2) 8260, Bluetooth Version 4.1 vPro
  • 13.3” FHD (1920 x 1080) IPS Anti-Glare, 220 nits

I don’t think the Windows 10 version is available in India presently. I believe a watered down Chromebook version is available on Amazon.

Since I was saving a fair bit of money by not buying the T460s, I maxed out the CPU with the i5-6300U though I don’t ever see myself using vPro. The other upgrades were the RAM and SSD to 8GB and 256GB respectively.

The ThinkPad 13 Gen 2 and Gen 1 share the same chassis, so most of the parts of this review regarding build quality, I/O, and keyboard apply for the Gen 2 as well.

Build Quality

Pretty decent. At 1.4kg it’s not the smallest or lightest 13.3” laptop available, but it’s small enough to not matter. Given the number of I/O ports onboard, it’s a very acceptable compromise.

You can immediately tell it isn’t made from the fancy composites of the X1 Carbon or the magnesium alloy of the T/X/P series ThinkPads. Yet the plastic frame of the laptop is good quality and can easily stand out on its own. Compared to other ThinkPads I’ve tried, it feels considerably better built than the E470 and the X1 Yoga and is on par, if not better than the T440p. The P50 is more solid, though it must be kept in mind that the P50 is a much thicker laptop than the 13. The 13’s build quality is on another level compared to the Lenovo IdeaPad G580 I had been using before this. Even after a year of heavy use, creaking on twisting the frame is non-existent and nothing feels like it’s on the verge of falling apart like it did with the IdeaPad.

The hinges are nice and tight and the lid gives a satisfying thump on closing. Speaking of which, the aluminium lid is solid and protects the display nicely. However, it does give the laptop a heterogeneous look and feel with the rest of the frame being made of plastic.

One aside here, the 13 does have unique touches not found on higher end models. For example, the “i’s” in the ThinkPad logo in both the lid and the palm-rest glow and the ThinkPad logo has a really nice brushed finish to it on the lid.

Opening the laptop for servicing and upgrading is not a good experience. The bottom base is held by 10 captive screws and is incredibly fiddly to pry open. I ended up scratching off some of the paint of the bottom cover in the two times I tried opening the base. That said, upgradability is much better than what you can find on comparable ultrabooks. Both DDR4 RAM slots, the M.2 SATA SSD (no NVMe on the Gen 1 unfortunately), the Wi-Fi card, and battery can be easily replaced.

The touchpad has its share of mechanical issues too. It is a clickpad design, similar to that found on MacBooks. Sometimes dust and debris would find its way in the gap between the base of the laptop and the touchpad causing the right button to physically stop clicking. It’s a simple problem to fix and all it needs is a swab with a piece of thick paper under the touchpad. Nevertheless, I expected a more robust design. At least this problem isn’t exclusive to the 13 as it seems to happen to the T450s as well.

Lastly, the plastic construction does have some drawbacks when it comes to scratches. A small section of the lid joining it to the hinges is plastic and is much more scratched up than the aluminium part of it. After a year, the base unit also had some paint rubbing off from the edges. I would suggest buying a carrying sleeve to avoid this from happening. The silver palmrests also have taken a slightly darker shade to the rest of the laptop.

Fortunately, all the damage is only cosmetic and the laptop has held up pretty well after being jostled around campus for more than a year.


Connectivity is a strong point for the ThinkPad 13. It’s impressive to see how many ports there are on a laptop of this size! You get 3 USB-A ports running at USB 3.0 speeds, a full size HDMI port, an SD card reader in which the card goes all the way in, a headphone jack, and a USB-C port supporting charging and 2160p/60fps video out. There’s also Lenovo’s proprietary OneLink+ docking solution though I haven’t tried this out yet.

On the subject of the USB-C port, a minor nitpick is that it’s USB 3.1 Gen1 and doesn’t support Thunderbolt. I still much prefer it to the option of having a full size Ethernet port as on the T460s. The USB-C port is so much more flexible.

I also discovered that all the USB ports support fast (faster?) charging. My phone charges as fast from the laptop’s USB port as it does from a 5V/1.5A charger.

Wireless connectivity is serviced by the Intel 8260 Wi-Fi card, the same one used on all the top-spec 2016 ThinkPads. Speed and connection quality is good and it supports 802.11ac.


You can’t really go wrong with a 1080p IPS display on a 13.3” laptop.

The LG 1080p IPS display on ThinkPad 13 comes with a matte coating. Even for an IPS display, the viewing angles are excellent. 13.3” and 1080p is a sweet spot for sharpness and UIs scale fine in both KDE Neon and Windows 10. Thanks to the matte coating, the screen brightness is perfectly sufficient 90% of the time when I use it. I’ve hardly run into any instances where I felt the need to crank the screen brightness any higher.

Colour space coverage is reportedly below average for an IPS screen and it really shows when put side by side with a MacBook Pro or a Dell Inspiron 7460. That said, for coding and web-browsing, it’s hard to ask for more.

Battery Life

The ThinkPad 13 is powered by a 42 Wh battery. It has degraded slightly from when I got the laptop - initially the battery was able to hold 46 Wh of charge but now it usually holds 40-41.5 Wh when full. I usually run several Firefox tabs open with some IDE’s like VS Code, Atom, or Android Studio on KDE Neon. The laptop is very energy efficient and power draw rarely climbs above 6.5W at 30% brightness after enabling TLP. My old laptop used to idle at 17W and when people claim that Intel has gimped their CPUs since the IvyBridge era, I think they’re disregarding the huge leaps in power efficiency.

In more than a year of owning it, I haven’t once drained the battery. I’ve even gotten through 9-5 days at a summer internship solely off battery power. I typically get around 6-8 hours of battery life depending on the usage. I can’t speak of how good or bad battery life is on Windows 10 as I’ve never used it for anything other than gaming, which brings me to my next section.


Subjectively, it’s quite snappy. A lot of the performance improvements compared to the laptop I owned before this can be chalked up to the SSD. The one used in the ThinkPad 13 I got was the LiteOn L8H-256V2G and it gives about 540MB/sec in sequential reads and 300MB/sec in sequential writes. It’s common knowledge how much faster SSDs are than HDDs, but I hadn’t expected it the difference in swapping performance to be as enormous as it is. I can hardly tell when Linux starts filling up the swap space on the SSD as the degradation in performance is minimal.

The i5-6300U is sufficient for my needs and thermals in the ThinkPad 13 are good enough that the laptop doesn’t need to throttle even under prolonged loads. The processor cools passively most of the time and the fan only kicks in under load. Even so, I’m hard pressed to hear the fan below 4000RPM. The CPU is able to overclock to 2.9 GHz on both cores but I’ve rarely seen it climb over 2.8 GHz. I’m not sure if this is due to the 15W TDP of the SoC or the laptop’s conservative policy when it comes to cooling as core temperatures never climb over 75C on Prime95.

As far as programming goes, it’s not struggled with anything I’ve thrown at it - from building large C++ codebases to running instances of IntelliJ and Android Studio (with the x86 Android emulator) together. The CPU is definitely faster than the i5-3230M in my old laptop.

Plus, for the first time, gaming isn’t a terrible experience on integrated graphics if your expectations are low enough. I can get 30fps in Skyrim Special Edition at 720p and Medium graphics presets with 2X AA. DiRT3 and Mirror’s Edge gave about 60fps at 720p with low settings. Sonic Mania works perfectly at 1080p 60fps. On the other hand, it struggled with returning a framerate greater than 30fps on Sonic Generations. Bear in mind that all this is with single channel 8GB RAM. Performance could be better with dual channel RAM.

Load times in all games are much lesser than they would be on a gaming console such as the PS4 thanks to the SSD.

Overall, as long as you don’t mind running old games at 720p with some sacrifice in visual quality, the integrated Intel HD 520 should be adequate. At least it’s good at smooth 4K video playback.


Really good! For years, I used to think that the AccuType keyboard on my Lenovo G580 was unbeatable, but that changed as soon as I laid my hands on the ThinkPad 13’s keyboard. The keys are perfectly spaced, have amazingly deep travel, and have great texture. I really like the layout too - PgUp/PgDn + Ctrl makes it very easy to switch tabs and Fn and the left Ctrl can be swapped in the BIOS. I don’t miss the lack of keyboard backlighting but I would really appreciate something like a ThinkLight found in older ThinkPad’s.

It turns out that the keyboard on the 13 is exactly the same as the one on the T460s. I learned this by ruining the stock keyboard when doing my weekly round of sterilising all my electronic devices. AliExpress didn’t have the silver 13 keyboard but the 13’s FRU manual showed that the T460s keyboard (albeit black instead of silver) could be directly dropped in. After a month of waiting to get it shipped from China, it was a simple 10 minute job to replace the keyboard. Props to Lenovo for reusing FRUs and keeping the 13 so serviceable.

I’m pretty happy with the touchpad as well. It has a smooth surface and has a very satisfying physical click to it. Gestures work well and it’s supported out of the box on Linux. The TrackPoint and click buttons have become indispensable for programming. However, I’m disappointed about how fast the TrackPoint’s coating wears off as it becomes really difficult to use the shallow TrackPoint once this happens. ThinkPads really should ship with some replacement caps.

Linux Support

I’ve been using an Ubuntu derivative distro on my laptop ever since I got it. In the first few months, I used Kubuntu 16.04 and then later on I switched to KDE Neon (which, incidentally, is based on Ubuntu 16.04). Linux support is remarkable and everything “just works” right out of the box. Older versions of the 4.x Linux kernel had some issues with the touchpad “desyncing” every 15 minutes, but this has by and large been fixed over the last few months. Thanks to the excellent Mesa drivers, 3D performance of the Intel HD 520 is very stable and actually works better than my friend’s NVidia Quadro GPU did with Nouveau drivers (not in terms of frame rate, but stability). The Trackpoint works well and all the function keys work perfectly. Also, as mentioned earlier, battery life under Linux is great. I’m curious to see if the OneLink+ works and if the USB-C can output video on Linux.

In my opinion, there’s nothing you’re missing by running Linux on the 13 instead of Windows when it comes to hardware support.


The ThinkPad 13 is a nice laptop, but it’s not for everyone. It fits my workflow perfectly with the good keyboard, display, and build quality. However, not everyone needs as many I/O ports as the 13 has and they would probably be better served by the numerous ultrabooks with better displays and bigger batteries. On the other hand, some might jump for a higher-end ThinkPad model like the T460s/T470s with better build quality and connectivity options. That said, the ThinkPad 13 does a lot of things right and fills a niche in the market for small laptops with good keyboards and several ports. A lot of compromises made in the ThinkPad 13 are reasonable and if you can live with these compromises, it definitely is worthy of consideration for your next laptop.