12/17/2018 at 16:26 •
I like bread boards. For some reason, my father was never a fan and rather created his own rapid prototyping system which required lots of soldering wires to little shoes and pins instead of just plugging in some single strand wire into a hole. Now that I use bread boards, I really don't understand why he went that route anymore. But that's ok.
I created the first version of my remote on a bread board. This was also the first version I showed Acton in person (Thanks Peter!). To my surprise, they were very open to me reverse engineering their controller - but as it happens, the industrial design is theirs, the logic and the schematics are essentially the standard remote everybody gets when buying a skateboard using these motor controllers. At least they put their own spin on it - even though not with the best of components.
The schematics are as easy as they can get.
- Arduino Nano
- NRF24L01+ Breakout Board
- 2.5-3V to 5V DC/DC Converter Board
- 5 LEDs in different colors with their corresponding resistors
- 3 Micro Switches
- 1 Buzzer
- 1 Potentiometer for the Throttle
- 1 Power Switch
- 2 AAA batteries instead of a LiPo with additional charging circuit
That's it. It requires nothing else. I sense the real battery voltage using A5 on the Arduino by plugging it in directly. If the voltage goes too low, I cut the throttle and only allow braking - analogue to what the Acton controller also does. I liked that as the controller still works but it only let's you stop safely.
I also use AAA batteries because they can be obtained everywhere and spares can be easily kept in a pocket or a backpack. I do not follow the rechargeable battery philosophy for the remote as it lasts me forever.
I have an average power consumption of 25mA and considering the batteries have about 1000mA, I can drive for 40h(!!) before I need to swap batteries. Even if I consider 20% reserve, it's still massive!
The layout is also pretty straight forward. Although, I went with a completely custom shape that fits straight into the 3D printed part! I did this by creating the board shape in Solidworks, then exporting it as DXF, then importing it into KiCAD, and then start the layout with the DXF on the Edge.Cuts layer. This works great!
My only constraint was, I wanted to use my own PCB mill to fabricate the PCB. In order to do that, I needed to keep the trace thickness above 10mill, and the holes at around 0.8mm and 0.9mm for the different parts and vias to avoid the need to manually swap the tool all the time or accidentally cut the traces or restrings to shreds.
To machine the board, I used a China V shaped endmill with 0.2mm tip - but since the endmills came with varying quality, I used the one with the smallest possible tip shape of about 0.1mm. Not great in terms of quality but great because I could mill smaller traces.
In the end, I realized I forgot about the power switch in my enclosure design so I needed to drill two holes and file it to a rectangle to make it fit.
Connecting all the wired parts was a bit of a pain. There is not too much space in there to work with and the flying wires got caught everywhere. In the end, I went with thin magnet wire for almost everything that I secured with some hot glue where necessary.
I really like this design and was blown away by how well everything went together. Being able to create a custom shaped board like that at home was crazy cool and seeing it just slide into the 3D printed part was immesely satisfying!
12/10/2018 at 05:28 •
The code was pretty much ready at this point and required only a few touch ups here and there. The real issue now was to come up with a 3d printable CAD design that would house a custom PCB with all the parts I wanted on it in an elegant housing that wasn't completely different from what Acton had built. I liked the unusual Acton design language and wanted to keep the remote industrial looking.
I went through a large number of different design iterations until I finally settled on one that I actually liked.
The newer Bluetooth variant from a different supplier was a little too small for my hands.
It took a while to package the NRF, the Arduino, the potentiometer, the batteries and the DC/DC converter into a nice little, easy to hold and operate enclosure.
I took the design and created a PCB outline inside of Solidworks that I then exported as DXF and into KiCAD. I had never used KiCAD before, so this was a great reason to learn. I was unsatisfied with Eagle at this point so why not switch.
After the schematics where finished and the layout was routed, I fired up my PCB Mill and milled this double sided PCB. It turned out even better than I expected!
The Arduino Nano USB port is exposed at the back of the remote and can be used to upload new firmware. The battery latch is on the hand palm side of the remote so that the batts can't just fall out if you hold it in your right hand.
I managed to make my own battery contacts using an old spring that I rewound. That was surprisingly easy after I found a spring that was not stainless - because soldering to stainless steel is next to impossible.
12/10/2018 at 04:50 •
Let's take a quick look at the payload the remote is sending all the time. In fact I saw multiple payloads and I can't yet figure out what they all are for.
Everything in green is what the remote sends to the motor controller. There are two types of messages. Both contain if the drive direction is forwards or backwards but only one of them dictates how fast it should go that way. This seems incredibly redundant to me and if I was told to save energy, I would not send unnecessary messages. I have not tried NOT sending that second message but I suspect the motor controller wouldn't care... who knows.
The throttle has it's center (zero power) at 0x80, full brake at 0xFF and full throttle at 0x00. The throttle as well as the brakes run into saturation and start clipping about 10 to 20 values from min/max. The exact numbers are in my source code. There is absolutely no filtering going on from the potentiometer, through the remote into the motor controller all the way into the BLDC motor controllers. Inside the BLDC controllers the real magic happens, but I don't have access to those.
The battery message from the motor controller is also pretty random. Eight bytes are being sent back to the remote of which only one contains the information about the state of charge. The Acton remote turns this into some blink patters on the same LED. I chose to wire this straight to four individual LEDs like all other remotes for this motor controller.
12/10/2018 at 04:35 •
Now to the real meat of things: Successful pairing!
To do this right, I marked every single byte in the entire process until successful pairing according to the datasheet of the NRF24L01+. This was a surprising amount of fun as the picture that I was building in my head became clearer and clearer by the minute. I almost got euphoric feelings doing this. Obviously, I was reverse engineering someone else's product but I was also the first and I seem to get it right! That was great!
But more on the downfall, later.
I'll spare you the typed transcript but will summarize what's happening instead.
The same procedure starts as with the unsuccessful pairing attempt only this time the board sends an ACK! Yeah! However, the command had changed and was 0xC0 0xCE now. What was that all about?
Now the address changes again to 0xCE 0x31 0xE3 0xE3 0xE3 for some reason. This was specifically awkward because the 0x31 came out of nowhere - or did it? More on that further below.
With this new address we clear some IRQs and send the packet again and wait for another ACK. If it comes, the pairing process is working and the motor controller successfully processed out packet, changed it's address while the remote changed it's address as well and was now listening to and acknowledging the new packet!
Now the remote changes it's configuration and instead of a transmitter it turns into a receiver. It clears IRQs again and checks for a data packet to arrive. This is when the board needs to send data containing the new address it wishes to use. In this case 0xB6 and 0xD8: 0xB6 0xD8 0xC9 0xC9 0xC9 for transmitter and receiver.
Restart remote, and done.
But wait, where did the 0x31 come from and how does the board make this new address byte up? Is this the secret sauce to pairing these remotes?
Let's analyze this little more:
Turns out it's a calculation based on the last known address, even though that could be random as well, I believe.
0xC0 is the actual pairing command or the command that provides a byte to base the new remote address on. It makes sense to use the last used or attempted address to make sure there is little repetition when trying to pair to a new address.
Based on that byte 0xCE the remote sent out the new address can be calculated by simple subtraction: 0xFF - 0xCE = 0x31
The moment I realized this simple trick, I started walking around my room fist pumping. This was awesome!
During the pairing the new address is being calculated based on the old address. The motor controller then takes the received bytes on that new address and calculates a response which represents the new address for the remote and stores it. The remote takes these two bytes as new address and resets. Easy.
But there was another major hurdle when implementing this: Timing!
Initially, I had some wait states in my state machine to allow for some debugging and other things. I also wasn't sure how fast I may communicate with the NRF24L01+ without overrunning it's SPI port. So I ended up never reaching the second phase of the pairing process right after the remote changes the address for the second time. I never received an ACK from the motor controller! It drove me nuts until I realized it must be a timing issue.
Turns out the motor controller only waits a very small amount of time until it declares the some bytes received as trash and goes back into state 1 of the pairing process! Gnarly!
After significant optimizations on my code I fired it up and.... it worked! Hell yeah!
12/10/2018 at 03:58 •
Now that I knew I have control over the board when I reuse a known communication address for the NRF24L01+, I wanted to be able to pair to all eskateboards with this controller.
It took me several days to start this part of the exercise because I feared the pairing procedure would be pretty complicated. Turns out I was right. It's pretty involved.
First, I looked at a pairing process that failed because the board did not respond (it was powered off on purpose).
In the screenshot above you can see an excerpt of the process that eventually led to a failed pairing attempt.
The interesting bit is the 16 frequencies the remote cycles through when searching for the skateboard. Catching all those was easy but very important at the same time as can be seen later during normal operation.
- First, the power setting is changed to the lowest setting as the controller assumes pairing is only really being done with direct access to the skateboard itself.
- CRC will be activated and the power setting will be set.
- Then the address is changed to a standard address the remote and the board will both switch to during pairing.
- If this is a new cycle it would switch frequencies now.
- Otherwise it will just load and send the pairing commend 0xC0 0x5F and wait for a response.
- If the ACK from the motor controller is not received within a couple of milliseconds it will hop to the next frequency and try again.
This aborts after several cycles as far as I remember.
12/10/2018 at 00:48 •
Okey, here is where this project gets slightly out of hand.
I was not expecting to build the entire remote but what seemed impossible yesterday became inevitable. In order to do this, I first needed to identify the correct pins and then hook up my BusPirate clone (which doesn't seem to work under my Windows for some reason - I hate counterfeits!) and sniff everything that happens between the Chinese controller chip and the NRF24L01+. Apparently, a lot.
Make no mistake, this protocol is simple and completely overloaded with unused 0x00 that make no sense to me, yet. Maybe some of you have ideas?
What you see above in ongoing communication. I captured a section of what's going on and marked all the interesting bits using my tablet. There is lots of configuration, buffer flushing, sending, waiting for ack and so on going on. Really interesting to watch and learn the actual SPI commands because that makes understanding the chip a lot easier than just looking at the datasheet.
In fact, I never got to results this fast! Every datasheet should have a comprehensive example command trace attached to it. That would help so many people!
My first step was to check if I could take this exact configuration and behavior and replicate it. It took me a couple hours to establish the base firmware for my Arduino but it basically worked right out of the box. Receiving the battery status and sending throttle commands was easy when you have the address key to communicate with the board - making the board believe it's still communicating with the original remote.
It get's quite a lot more involved the moment you decide to implement the actual pairing procedure.
12/10/2018 at 00:26 •
Slightly disappointed not being able to take over the board itself, I set out to modify or even replace the god awful remote. It has so many issues, I couldn't enjoy riding the skateboard with it. Mind you, the board itself is great but the remote is, from an electrical and software standpoint, unbearable. So there was only really one option...
After opening that thing up, a rather nice PCB design was revealed that was clearly custom in nature! Extremely compact, with custom NRF layout and antenna, power supply for only two AAA batteries, full color LED and the source of all evil: The god awful 4ct 1-axis joystick!
At first I tried to use this board and only replace the potentiometer.
Great idea, but the firmware driving this remote had a lot of other issues. One of them is the idea to only send data every half second when one is not moving the throttle. They do that to save energy.
I understand that they where VERY interested in saving as much energy as possible but my testing has shown that the batteries last about 300+ miles so that's really not a concern. My testing has also shown later on that constantly sending at the highest power setting or not even connecting the entire NRF module... makes 0.5mA - 1mA difference.
Why is slow sending an issue? Because packages can get lost or damaged during the transmission, for example when driving in front of a high power communication antenna from one side of the San Francisco Bay to the other or you are driving in the WiFi polluted areas of your town. In those cases, the board feels extremely unstable and shows a lot of longitudinal jitter! This is horrible to drive and simply feels broken!
Expecting essentially zero success rate reverse engineering the actual controller chip, I decided to be more radical and build the entire thing from scratch based on an Arduino Nano clone, an NRF24L01+ module, a small boost converter a bunch of LEDs, a switch and a normal potentiometer. Here is my first bread board prototype showing a fully charged board battery. But I'm getting ahead of myself.
12/10/2018 at 00:04 •
Next up, I wanted to take over the motor controller itself.
My theory, and I wasn't able to confirm it yet, is that this controller is derived of some Infineon motor controller form some electric bike. The used controllers are in fact counterfeit Infineon 8051 controllers and are being used in lots and lots of Chinese Ebay ebike controllers. For those, a config tool exists. Unfortunately, since there is not sign of a datasheet, I couldn't get it to work.
On the contrary: The manufacturer of the board even says, these chips are programmed to the specs of the customer and cannot be reflashed with a new config after shipment. Sad, dumb, and unfortunate. I couldn't prove them wrong, yet.
However, I did a lot of research on the board to identify what's going on:
On the picture above, two chips are missing as this is the slave board. To me, it looks like these chips have been removed by hand after complete assembly to make use of the slave interface.
On the master board, these chips are present. One is the aforementioned NRF chip with antenna and everything (I ripped the external antenna plug off my accident - next to connector HALL2) and the other one is the master controller communicating with the NRF and the four motor controller ICs.
All motor controllers are connected in parallel and therefore receive exactly the same signals.
My ebike theory, btw. comes from the fact that the motor controllers consume an analogue signal for the throttle value. However, I have yet to discover WHERE this analogue value is being generated. It's not connected to the primary controller and I did not see any DACs or resistor ladders on the boards.
Unfortunately, here is where the take over story currently is. I couldn't access the firmware, I don't have a JTAG adapter at the moment, I don't know if a serial protocol is available, and so on and so forth.
What I did is prepare one of my boards with headers for later, more detailed analysis.
12/09/2018 at 23:47 •
The Acton iOS app offers the boards total millage, current velocity, battery state of charge, the drive mode (beginner, normal, pro), and the state of the exterior lighting. That's it. Can't be that hard to decipher.
So I pulled out my CC2541 sniffer and quickly realized, this is a bad idea. I just wanted the data, not the Bluetooth communication protocol with some data hidden somewhere inside of it.
So I pulled out my breadboard, plugged in two USB to serial converters and soldered of RX lines straight to RX and TX of the Bluetooth module. Et voila: Communication established!
The protocol is very simple except that I could not identify where the millage is communicated.
After about an hour of poking around and testing all options with the iOS app, I reached a limit of what I could find. For some reason, I did not see the millage anywhere. The value just didn't appear to me or I'm just blind. Any ideas?
The next step was to connect my own CC2541 to the board and mimic the iOS app. Maybe I could make my own app. Maybe I could even make this board bluetooth controlled. How cool would that be?
Unfortunately, I ran into the counterfeit issue myself and even though I was able to connect to the skateboard's bluetooth controller, I wasn't able to configure my CC2541 in a way that would allow the communication mode I needed. I hate counterfeits!
I aborted at this point.
11/14/2018 at 03:28 •
... if it's so bad it can't get any worst.
Two days after I got my skateboard, I needed to take it apart.
Looking around the electronics bay revealed a nicely packaged battery of unknown brand in the center as well as two identical motor control boards with no visible receiver module anywhere. Long story short, the motor controllers are a noname component straight out of China with adjusted settings to meet the requests of the skateboard manufacturer. Up until now, I still have no idea who manufactures and maintains these boards but they are literally everywhere even though they are being pushed off the market by newer, more capable and more configurable boards with superior remotes. No surprise.
I took a large number of pictures, specifically chips on all boards and connections going to and from each board, motor, light and antenna: Turns out, the receiver is part of the motor controller and embedded into the circuit. To make things a bit more interesting, two boards can be configured in a master / slave setup by simply removing the receiver off of one of the boards and connecting a multi-pin cable in between the boards.
My search through the selection of used ICs turned out to be almost completely useless as none of these chips have any information online AT ALL. I even asked a Chinese friend of mine to dig around for a while and even he could only reveal the datasheet of one of the ICs - but not the important ones.
One chip, though, was known to me: The NRF24L01+. A transceiver IC for 2.4Ghz ultra low power communication with up to 2mbit per second. This was good news, as the datasheet for it was very easy to find and comprehensive. Some say, it's not the easiest chip to work with from a protocol point of view, and I did realize, it has it's hiccups.
A second chip I could identify was located on an add on board on top of the motor controller. A board, none of the other Chinese skateboards has. Since it had the Acton logo on it, it must have been custom. It's the Bluetooth chip on a module CC2541 which is known to be compatible with both iOS and Android and available in large quantities - but huge warning: Most of these are counterfeit! To be bought from trusted sellers ONLY! Otherwise the module will only understand the most basic AT commands and cannot be paired with the original module. Been there, done that. I hate counterfeit parts!