Electric scooters are a common sight with a variety of models available in the market.
The Hexabitz Platform plays a pivotal role in customizing your E-Scooter’s control system without requiring hardware modifications.
Our team has developed a custom control system for managing an electric scooter and incorporated an IoT feature using Hexabitz Modules.
We procured the essential parts of the electric scooter, replaced the dashboard with our modules, and constructed the scooter’s iron body.
We then developed the firmware for the control system by dividing the work among the networked MCUs within the module array.
Following this, we created the software component, which includes an Android app and a web server app, to enable IoT-based control and monitoring.
Steps to implement the project :This guide provides step-by-step instructions for implementing the project, from conception to execution:
1 ) Preparing the E-Scooter Body and the Hardware Parts:Design and assemble the iron parts of the scooter body.
We designed some parts and edited some pre-made parts, then assembled them all to make the final body.
We placed all the power and control components inside an attachable deck case that we designed for this purpose, which had an attachable metal grid to install the parts on it.
We made a slot through the handlebar to install the throttle and the brake, and we also installed a mobile holder on it.
We designed the stem and the folding bars to be able to pass a cable through them from the handle bar to the deck case.
Preparing the battery:
First, we made the scooter battery. The battery must be 10S to be compatible with the BMS, and the capacity of the complete battery should be 15300 mAh to be compatible with the BMS original firmware. But we brought cells which have the 3500 mAh capacity rate, thus the complete battery for a 10S4P formation would be 14000 mAh.
We connected the cells using spot welding and the zinc strip, with the placement of the spacers on the cells. Then we connected the cells’ voltage sensing lines and connected the battery poles with the BMS using wide cables. We activated the BMS by holding the only button on the board and covered the whole battery with the protection wrap, with the distribution of the temperature sensors on the battery sides.
Finally, we made a BMS output power cable (with an XT60 connector). We also made two charging cables to connect one of them with the 3A charger, which we installed inside the deck box, and the other one to connect it with the external 5A charger.
Installing the components and doing the connections:
We first installed the motor, then the BLDC driver and the battery into the deck box grid, and made the connections between them.
We connected the three-phase lines of the motor with the driver and its hall sensor cable with the connector on the driver board.
We also connected the BMS communicating cable between it and the driver board, and made a power cable (with an XT60 connector) to connect it with the driver supply cable connector.
Discovering the hardware parts functions:
The original control system of the E-Scooter is essentially based on three devices that communicate with each other and distribute the work among them.
The dashboard takes readings from the throttle and the brake, and accordingly gives orders to the BLDC driver. It also contacts the Android app and plays the interface role between it and the hardware parts (BLDC driver, BMS) to receive orders and send back data.
The BLDC driver controls the motor, with many speed modes and brake levels. It also senses the speed by the hall sensors, motor current, voltage, and temperature, and calculates the total and single values of the riding and running times as well as the riding mileage.
The BMS works as a general BMS, providing us with much information about the cells voltages, battery current, temperature sensors readings. It counts the cycle, charge and over discharge times, and calculates the remaining capacity in the battery and its health.
These 3 parts (BMS, BLDC driver, dashboard) communicate with each other by the UART serial protocol.
Discovering the communication protocol:
The discovery of the protocol was done using the resources that we will attach below. In addition, our team performed a lot of reverse engineering operations by analyzing the messages that are sent between those three boards using the logic analyzer.
The serial bus packet format that all messages must be constructed using consists of:
1.Frame header: This is a fixed 2 bytes frame header.
2.Packet length: This represents the number of bytes in the data segment (N).
3.Source and Target ID bytes: These are the sender and the target IDs, so the target device will only catch that message through the UART network.
4.Command word: This represents the command type, such as reading, writing, etc.
5.Data index: This represents the target register address to read from or write to.
6.Data segment: This consists of (N) bytes and can represent the length of the data to be read or the write data content or anything else, it depends on the command type.
7.Checksum: These are 2 bytes for the little-endian checksum 16-bit.
Exploring the Messages Format Needed to Build the System
We will now explore the messages format that we need to build our custom control system.
The default Dashboard message should be like this:
uint8_t DashBoardMessage[14] = {0x5A,0xA5,0x05,0x21,0x20,0x65,0x00,0x04,0x27,0x23,0x02,0x00,0xF1,0xFE};
As you notice, we’ve added the 2 header bytes(0x5A, 0xA5), then we specify the number of data segment bytes(0x05), then we specify the source and target ID (0x21, 0x20), the command word for sending the updated values of the throttle and brake without asking for response from the BLDC driver should be (0x65), and the data index with that command can be any value (0x00).
The data segment for that command should consist of five bytes:
bDataLen, bThrottle, bBrake, bIsUptatingBLEFw, bIsBeeping
Where:
- bDataLen: is the number of bytes in the data segment (except this byte).
- bThrottle, bBrake: throttle and brake bytes values and can be calculated by scaling the output voltage range (0.85-2.65) volt on the byte value range for the throttle ( 0x27 - 0xC3) and for the brake is (0x23 - 0xCD).
- bIsUptatingBLEFw: this byte should be kept as it is in the default message, because it’s related to updating firmware process of the original dashboard.
- bIsBeeping: this byte also should be kept as it is in the default message, because it’s related to the beeping function in the original dashboard.
The last two bytes of the dashboard message (0xF1, 0xFE) are the little-endian checksum 16-bit, and is generated using a function in the firmware as we will see.
The default message for reading or writing registers should be like this:
uint8_t MasterControlMessage[11] = {0x5A,0xA5,0x02,0x3E,(target_ID),CMD,datInd,0x02,0x00,CHKSUM_L,CHKSUM_H}
Once again, you will notice that we added the headers, the packet length byte (0x02) which is the number of data segment, and the source ID
The target ID will be either the BLDC driver ID or the BMS ID to read the registers of one of them in every time.
The CMD byte must be (0x01) for riding and (0x02) for writing.
The datInd byte should contain the address of the register that we want to read or write.
The two data segment bytes should represent the total number of the read bytes, where the size of every single register that we deal with in our firmware is 2 bytes, thus for reading 1 register, the data segment bytes should be (0x02, 0x00), and for reading 91 registers (0xB6, 0x00) and so on.
In the result, the target device will respond by sending the values of all the registers that their addresses in that range.
Of course, it will send a message that is constructed with the same form of the protocol. You can see below the response message of the BLDC driver for the request to read 90 registers value.
0x5A·0xA5·0xB4·0x20·0x3E·0x04·0x1B
·0x00·0x00·0x00·0x00·0x00·0x08·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x5E·0x00·0x00·0x00·0x18·0x13·0xDE·0x17·0x00·0x00·0x00·0x00·0x00·0x00·0x35·0x2A·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x07·0x00·0x00·0x00·0x00·0x00·0xD4·0x26·0x03·0x00·0x75·0x0D·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0xF3·0x10·0x17·0x00·0x00·0x00·0x00·0x00·0x36·0x01·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0xA7·0x0F·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x6D·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x00·0x0F·0x00·0x20·0x00·0x14·0x00·0xAC·0xF8
You can notice that the packet length byte value is equal to the total number of the data segment in this message and equal to the total number of the requested registers to read bytes.
Also, notice that the values of these registers are listed consecutively after the data index byte (0x1B) which represents the address of the first register in the requested range. Of course, the last two bytes are the checksum bytes and we used them for checking the safety of the received messages.
As we have just learned that every 2 bytes represent the value of a register, we should know that to convert this value to readable data the order of those 2 bytes should be swapped and then multiply that value with the responsible factor depending on what it represents.
For example, from the last message, if we want to get the value of the scooter temperature, we know from the registers table that the (NB_INF_BODY_TEMP) register address is 0x3E, then to find its value in that message we find how many registers between them by subtracting the address of the desirable register from the address of the address of the first register (0x1B - 0X3E), then we multiply the result by 2 (every 2 bytes represent a register value), then add (7) because the values of the register as we’ve just seen are listed after the byte number 7, finally we convert the result to decimal.
Thus, the number of the 2 bytes of the scooter temperature are (77th = 36) and (78th = 01), and if we swap between them then convert the result to decimal we will get (310), that means the temperature value is 31.0 because according to the registers table that the temperature unit is 0.1℃.
Let’s take an example about writing this time:
0x5A·0xA5·0x02·0x3E·0x20·0x02·0x70·0x01·0x00·0x2C·0xFF
You will notice that we used the write command (0x02), and we write (1), at the (NB_CTL_LOCK) register for locking it so the BLDC driver will hold the motor if you try to move it.
3) Building the Alternative Control System with Hexabitz Platform :Planning and Assembling the Hexabitz modules array.
First, we had to decide what were the needed modules to build the hardware part of our custom control system.
Because we needed a Bluetooth module to implement the communication between the hardware and an Android app, we chose H21R2, which is based on ESP32-C3 that can work as a Wi-Fi or a BLE Module.
To control the front and the brake lights, we had to use two of H0FR7 module, which is a MOSFET switch module that can handle up to 18V/20A, work on high PWM frequency (up to 20kHz), and can measure precisely the passed current through it.
Additionally, to supply our array with a stable supply, we had to use H03R0 module, which is a compact DC-DC buck power supply module, with a 3.3V/1A DC output, and 5-40V DC input.
We’ve added the attitude estimation feature to our system, By using H0BR4 module, which is a 3-axis inertial measurement unit (IMU) combined with a 3-axis digital compass module, based on STM32G0 MCU, LSM6DS3 IMU and LSM303AGR compass.
Furthermore, for future work, we’ve added H1FR5 module, which is a compact and high-performance Global Navigation Satellite System (GNSS) receiver module, and has the ability to provide accurate positioning, navigation, and timing information.
Moreover, to build some necessary custom circuits and adding it to our Hexabitz collection, we had to add H00R4 module, which is a through-hole proto board module, with 100-mil plated hole pattern.
Also, to add mounting holes and attachment mechanisms to our Hexabitz array, we used 4 modules of T00R1, which is a triangle mounting hole module, that supports M2 and M2.5 screw sizes.
Last but not least, for future additions, we add T00R2 module which is a triangle module that has a single 2x3, 2.54 mm through-hole connector, so we have the ability to connect other Hexabitz modules to our array.
Finally, we assemble and soldered these modules together to build our Hexabitz array.
After that, we’ve designed an enclosure for this array board for protecting it and installing it at the attachable grid inside the deck.
Building the Interfacing Circuits and Cables:
Our team built interface circuits for connecting Hexabitz modules array with the other E-Scooter hardware parts, and those interface circuits are included in the through-hole proto board module (H00R4).
Firstly, for communicating with the BLDC driver, we made an interface circuit for connecting the UART of the BLDC driver with the UART of the GPS Module (H1FR5) through port number 5. It consists of two 100 ohm resistors in series with TVS in between at the two UART lines for protecting pins of the two communicating MCUs from any sudden spikes.
Secondly, replacing the dashboard button with an electronic switch, we added an interface circuit for the BLDC driver activate line where the ESP Module (H21R2) controls that line by an NPN transistor through its bottom pad of port number 5, and senses through its top pad of port number 5 the BLDC driver turn-on line.
Thirdly, for interfacing the throttle and brake sensors, we added coupling capacitors across their power lines for the stability of their power and thus the output signals of them which is connected to the port 3 of the IMU Module (H0BR4) to the top and bottom pads accordingly.
In addition, we modified the original control cable for doing the connections from these two interface circuits UART and BLDC Activate to the BLDC pins.Also, we made use of an Ethernet network cable for doing the connections from the throttle and the brake sensors to the interface circuit, and that was for isolating the sensors supply and output signals from the EMI that is generated throughout the whole scooter body especially when the motor works. Thanks to the twisted pair feature and the cable shield, we managed to transfer these analog signals safely by isolating them with the GND. Also, the front LED supply line is included in that cable.
Also, we made use an Ethernet network cable for doing the connections from the throttle and the brake sensors to the interface circuit, and that was for isolate the sensors supply and out signals from the EMI that is generated throw the whole scooter body especially when the motor works, so thanks for the twisted pair feature and the cable shield we managed to transfer these analog signals safely by isolating them with the GND, also the front led supply line included in that cable.
Finally, the modules array looks like this photo:
Building Firmware Drivers for Implementing the Protocol:
For implementing this protocol in our modules firmware, we made custom firmware drivers.
MaxG30_DashBoard driver is responsible for implementing some of the original dashboard functions, such as building the dashboard message, where it calculates the byte value of throttle and the brake by converting the analog voltage of the brake and the throttle as we’ve seen before.
MaxG30_Master control driver is for communicating with the BLDC driver as a mobile phone linked through Bluetooth, that’s mean the using of the (0x3E) id as a source id in transmitted message. Also, it is responsible for using the available orders for controlling the BLDC driver such as lock, unlock, shutdown, restart, etc, by writing on the appropriate register as we’ve seen. In addition, it is responsible for reading most of the BLDC driver and the BMS registers values, then converting them to readable data.
Building the Application Layer for Implementing Our Custom Control System Algorithm:
Thanks to the distributed system in Hexabitz Platform we distribute the tasks of our custom control system between all these connected MCUs where every firmware of these modules has an application layer for doing some tasks.
GPS Module is basically responsible for the communication with the BLDC driver, where it uses the APIs from the last two firmware drivers (that implement the protocol) to play the role of the original dashboard, where it sends an active message every 10m sec, then it repeatedly collects the data from reading the BLDC driver and the BMS by reading the registers and write to some other registers for applying some commands.
IMU Module reads the throttle and brake sensors output analog voltages through its pads, also reading the accelerometer sensor value for the X axis and Y axis, finally transmit them to the GPS module.
MOSFET Modules are responsible for controlling the operation of the front and brake lights, where the front light is controlled by the user through the Android app, and the brake lights turned on when the user pushes the brake.
ESP32 Module’s first function is the responsibility of redirecting the buffer received from GPS module to the Android app through the Bluetooth and redirecting the orders from the last to the GPS module, where that buffer contains all the collected data from the BLDC driver and BMS, and the second function is the responsibility of activating the BLDC driver by turning the NPN transistor ON, sensing the turn-on line and finally send a notification message to the GPS module about the status.
4 ) Android Application:The mobile application and web application were developed using Flutter. Connection between the mobile application and the scooter is established through Bluetooth Low Energy (BLE), leveraging the Flutter Blue Plus library. Additionally, SignalR is utilized to process real-time data received from the scooter.
The application communicates with the backend server through API calls, facilitated by the Dio library. This method is also employed for web communication.
The application is equipped with a variety of features, including the ability to switch languages and modify themes. it also presents an interactive map for location viewing, and provides comprehensive, detailed data about the scooter's condition. Additionally, it includes a configuration panel that allows users to adjust various settings, such as the scooter's maximum speed and operational mode.
The web application provides real-time tracking capabilities for a fleet of scooters, utilizing a 3-second refresh interval to ensure data accuracy. The system employs color-coding to visually signify the operational status of each scooter, such as whether they are active, locked, or low on battery.
Moreover, the application incorporates CRUD operations, enabling users to effectively manage both the scooter and user datasets. This involves the creation of new entries, reading or retrieving existing data, updating details, and the removal of entries from the system.
The application also features an analytical component, providing granular statistics on individual scooters, such as ride count within a specified timeframe and various performance indicators. It also offers aggregated data on all scooters, including the total ride count for a certain period.
The backend server is built using ASP.NET Core 6 and SQL Server for the database. The server handles the processing and storage of data, and communicates with the mobile and web applications through APIs. This server-centric architecture allows for efficient data management and ensures that all connected clients have access to the most up-to-date information.
Results:Here are some live experiments of our project. Have fun looking at them! More interesting projects will be presented in Hexabitz Channel.
References:[1]: hexabitz.com
[2]: scooterhacking.org
Comments