• Hello ES! We could use some help to get us past the finish line on building the new knowledgebase for the forum.
    Can you donate? Please see our fundraising page. Thank you!

Luna M600 Ludicrous V2 reverse engineering and firmware making

That's interesting, the https://www.ex-force.de (the aftermarket controllers for Bafang motors from the former Innotrace developers) website is down. And I just got an anonymous message on this forum asking me to figure out if they use VESC firmware lol.

Do you think the VESC guys took them down again?

Well, I guess we have one less to compete against. Too bad no one had a chance to try it.


1765005039809.png
 
Last edited:
OK guys, I browsed all the "hw_luna_m600.h" files and none of them has date 2024.06.20 in the firmware name line. It looks like marcos or Luna did not uploaded it into the Github.

But it looks like the "release_6_05" of the "bldc" archive works without issues. I was able to make it works just like the original firmware I dumped from the controller and it looks like it is the closest to the original firmware. So we are going to use it as our baseline.

It actually works even better because of the 6.05 firmware allows to calibrate the throttle though the VESC Tool application on PC with VESC Express dongle through USB (6.02 firmware turns the VESC Express dongle off during attempting to calibrate the throttle though the VESC Tool application on PC through the input wizard and does not allow to calibrate the throttle).

Here is the archive with the code we are going to use

1765151998253.png



1765152612347.png
 
Here is a good question. I found a new menu after flashing 6.05 firmware on our mostly legal controller (ADC). As I understand that menu controls the throttle values (ADC1) and readings from that pin PB0 (ADC2) which is assigned to regenerative brake. Is there any way to make it works maybe just like a throttle instead of regenerative brake through the VESC Tool application without messing with the firmware code?

1765153352535.png

1765153188939.png
 
Last edited:
In case of someone wants to fork and contribute the torque sensor code here is the link to the files with the code we need to modify


1765155737009.png
 
The VESC Tool also can read the voltage through the input wizard on the CH2 (where the Bafang M560 torque sensor pin is connected) so torque sensor circuit works OK

1765159480480.png


1765159429885.png
 
Last edited:
It looks like the mysterious circuits connected to the pins PC6, PC7 and PC8 and the temperature sensor connector are artifacts from the hall sensor connections from the Luna BBSHD Ludicrous V2 controller the M600 Luna controller is based on.

1765163784354.png

1765163924609.png

1765164474338.png


1765164557532.png
 
Last edited:
OK, before I did something irreversible with our only controller please confirm if this makes sense in order to make the Bafang M560 torque sensor works with out new M560 controller

First of all we need to disable the regenerative braking (at least disable it reading the value from the pin PB0). So we gonna hard code it always equal to 0.0 instead of reading the voltage like this?

1765166927345.png


Then we need to read that voltage from the pin PB0 (as we already figured out the rough values with VESC tool let's say the voltage on that pin is equal to 0.75V when the PAS torque is 0, and let's say it is equal to 1.4V when the PAS torque and assist level we need is maximum) and convert is through some formula. The only problem is we do not know what the units they use to define the torque value and what is the maximum value in those units. It extracts the torque values from the CAN message, but we do not know the units and the range. We need to figure out the units and the range to convert the voltage to the torque properly.

1765169765243.png
 
Last edited:
First of all we need to disable the regenerative braking
You can do that simply by setting the right working mode in the ADC App in the VESC tool.
Then you have to get the voltage value from the ADC and multiply it by 1000 to get mV instead of reading the mV from the CAN message.
There is a function to query the ADC2 voltage already.
The last thing to do is to add the code for the digital brake line.
I've linked the relevant part of the code already.
 
OK, anyone knows by chance the range of the M600 torque sensor voltage from 0 torque to maximum torque? Or maybe there is a way to tell it looking on the VESC firmware?

And how this firmware behaves in case if the obtained value of the torque is negative? Does it consider the torque is 0 if the value is negative? Or we need to code this rule additionally?
 
It looks like M600 torque sensor voltage starts from about the same voltage as the M560 toque sensor. The Luna user interface has torque calibration function and by default it is 750 (I guess this means 750 mV). So it looks like we do not need to subtract 0.75 from the voltage value because of Luna firmware does it somewhere else.

1765177005113.png

1765177248482.png
 
The last thing to do is to add the code for the digital brake line.
Hm, I looked at the options in the ADC App settings, "Current No Reverse Brake Button" sounds like a good choice, but if I look in the code there is no action in this switch case.
The standard setting in the Luna appconf is "Current No Reverse Brake ADC2" (item 8 in the list, starting with 0). But the only case that reads the torque value from the PAS app and sets a negative power for breaking is "Current Reverse ADC2 Brake Button", what is item 4 in the list. :unsure:

Edit: Ah, I didn't know this behaviour of "switch - case" that all matching cases above a "break" will execute the code before the "break",
Example:
Code:
        switch (month) {
            case 1: case 3: case 5:
            case 7: case 8: case 10:
            case 12:
                numDays = 31;
                break;
            case 4: case 6:
            case 9: case 11:
                numDays = 30;
                break;


I guess this will do the job, if you define the digital brake input to the ICU pin in hw_luna_m600.h

in line 361:
C:
        case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_BUTTON:
            if (rev_button) {
                 pwr = -1;
            }
            break;

in line 414:
C:
        case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_BUTTON:
            current_mode = true;
            if (pwr >= 0.0) {
                // if pedal assist (PAS) thread is running, use the highest current command
                if (app_pas_is_running()) {
                    pwr = utils_max_abs(pwr, app_pas_get_current_target_rel());
                }
                current_rel = pwr;
            }

            // set power to zero if brake lever is pulled
            else {
                current_rel = 0;
                current_mode_brake = true;
            }
            break;

Or define yourself the Brake Pin and Port and read it instead of the ICU pin, like I did in the Flipsky project.

1765190806084.png
 
Last edited:
There is something wrong. I applied torque and rotated the crank back and forth but motor did not react.

I tried all combinations in the line 411 of the "hw_luna_m600_core.c" file

return ADC_VOLTS(ADC_IND_EXT2)*1000;

and

return app_adc_get_voltage2()*1000;

and also without *1000 .

The ADC mode in the VESC Tool was set to Current mode (to make throttle works) and I also tried all other ADC modes and nothing makes the toque sensor+quadrature sensors work together.


I can make throttle works, and I can also make the torque sensor works through the ADC2 (basically like a second throttle) through the VESC Tool PAS menu settings adjusting the voltages, functions and reverses. But the throttle sensor in combination with quadrature sensor through the Luna firmware algorithm through that line 411 does not work.

I also tried to set the "float_brake = 0.0" in the line 252 in the "app_adc.c" file but it makes the throttle does not work at all.


Is there any way to check the quadrature signal on the pins PA5 and PA6 to make sure they receive the signal properly with the VESC Tool application? We still have an option to swap the signals but I think it should not affect because of I can simply apply torque and rotate the crank backward.

I also can swap the "Invert Pedal Direction" in the PAS menu which I guess does it without necessity of swapping the signals physically on the PCB. I tried it too and it did not make the torque sensor+quadrature sensor works.

1765259428651-png.381847


We also can match the quadrature sensor circuitry to the Bafang M560 controller quadrature sensor circuitry. Currently those circuits match the Luna M600 controller. But maybe the quadrature signal of the M600 PAS sensor is different than the M560 PAS sensor.

Here is the PAS sensor quadrature signals connection on our PCB which is matching the Luna M600 controller. I guess we can unsolder those 10K resistors connected to the +5V to match the Bafang M560

1765259859342.png



Here is the Bafang M560RS PAS sensor quadrature signals connection. It has no 10K resistors connected to the +5V. Those pins from the PAS connector are connected directly to the MCU pins through 1K resistors.

1765260105968.png

But before unsoldering the resistors it would be nice to know if there is a way to check through the VESC Tool if the STM32 obtains the quadrature signals on those pins with the current circuitry as is or not.
 

Attachments

  • 1765259428651.png
    1765259428651.png
    87.2 KB · Views: 119
Last edited:
The ADC mode in the VESC Tool was set to Current mode
you can check step by step:

App settings general: App to use = ADC and PAS
ADC control type = Current Reverse ADC2 Brake Button

comment out line 357 of the ADC app to prevent activating the break with the torque signal.

If it still doesn't work, you can send a constant value from the PAS app to the ADC app in line 118 of the PAS app, caution, the motor will start immedeatly...

Code:
float app_pas_get_current_target_rel(void) {
    return 0.5;
}

If this works, you can concentrate on the PAS app, as the ADC app works as expected, then.
 
No dice.

The line 411 in "hw_luna_m600_core.c" file of the release_6_05 is set to

return app_adc_get_voltage2() * 1000.0;

The line 358 of the "app_adc.c" file of the release_6_05 is commented out (in this file of this release this line is 358, not 357)

// pwr -= brake;

I built the firmware, Launched the VESC Tool, applied the proper motor configuration (I keep them in an .XML file)

Then I set the APP to use ADC and PAS

1765322823779.png

The ADC Control Type is set to Current Reverse ADC2 Brake Button

1765322899414.png

The result - throttle works from the beginning, the torque sensor with PAS do not spin the motor, changing settings in the ADC and PAS in the App Settings do not help.

Then I set the line 119 of the "app_pas.c" file of the release_6_05 (in this file of this release this line is 119, not 118) to

return 0.5;

After building the firmware, applying the motor configuration and applying the App Settings as above the motor does not spin if I apply torque and rotate the crank at the same time any direction. The throttle does not work when the ADC Control Type is set to Current Reverse ADC2 Brake Button. I can set to Current mode and throttle works in this case. The torque sensor does not work at any combinations of the ADC settings I tried.

I am not sure what this means. Maybe we need to try different fork or different release of the firmware.
 
We can make both the throttle and the torque sensor work together quick and dirty blending it with an equation to drive the motor power directly in the line 191 of the "app_adc.c" file and commenting out the brake from the power subtraction in the line 358 of the "app_adc" file. It works but of cause it is not safe without utilizing the quadrature signals and we lost all the PAS filters and features Luna implemented

Code:
float pwr = (ADC_VOLTS(ADC_IND_EXT) / 2) + ADC_VOLTS(ADC_IND_EXT2) - 0.35;

1765339248722.png


Code:
// pwr -= brake;


1765340462649.png
 
Last edited:
The throttle does not work when the ADC Control Type is set to Current Reverse ADC2 Brake Button
This is really strange, but difficult to debug from the distance. I guess, you have to run the firmware in debug mode from the CubeIDE with the STLinkV2 and set breakpoints to relevant parts of the code, then execute single steps to see, what the code does....
But never use a breakpoint, when the motor is runnig, or use a lab power supply, that limits the current to very small values...

1765355160063.png
 
Last edited:
Last edited:
OK. You mean normalize is to convert the voltage range from the torque sensor on the pin PB0 to the value in range between 0 and 1 ?

I am not sure about the filter, but if the minimal voltage of the torque sensor is 0.73V and maximum is 2.0V then this equation should turn the torque sensor voltage value to the value in range between 0 and 1 :

Code:
return (ADC_VOLTS(ADC_IND_EXT2) - 0.73) / 1.27;

1765395884344.png



By the way, the Luna firmware needs to see 2.2V on the PB0 pin in order to consider the brake is not engaged. But I guess we made the Luna firmware constantly considers the brake in not engaged changing the ADC mode in the VESC Tool and commenting out the line 358 in the "app_adc.c" file

1765397555389.png
 
Last edited:
then this equation should turn the torque sensor voltage value to the value in range between 0 and 1 :
There is the "map" function for that. I would pack the steps to read in, normalize, apply a deadband and filter in the function that is called by the PAS app. The code is just an example, of course, you have to declare all the needed variables in the top of the luna_m600_display.c first....
Code:
/**
 * Get torque applied to the crank arms
 *
 * @return
 * 0.0 for no torque applied, 1.0 for maximum torque applied
 */
float luna_canbus_get_PAS_torque(void){
                float normalized_torque_sensor_output = utils_map((float)ADC_VOLTS(ADC_IND_EXT2), (float)torque_offset_voltage, (float)torque_max_voltage, 0.0, 1.0);
                utils_truncate_number(&normalized_torque_sensor_output, 0.0, 1.0);
                utils_deadband(&normalized_torque_sensor_output, torque_sensor_deadband, 1.0);
                UTILS_LP_FAST(torque_sensor_output_filtered, normalized_torque_sensor_output, 0.1);
                return torque_sensor_output_filtered;
            }
 
Last edited:
It looks like there is something wrong with obtaining the quadrature signal

If I use just the torque sensor voltage to drive the "pwr" value it works. But when I multiply it on the cadence value in the line 191 of the "app_adc.c" file it keeps it always 0 and it does not work of cause. Which means the "app_pas_get_pedal_rpm()" value is always 0 for some reason no matter how fast or slow I rotate the crank arms and which direction.

1765505327932.png

The Luna firmware calculates the cadence here




1765505220046.png

I can not also make it works just in PAS mode alone. It might be an electrical issue in the quadrature signals circuits. Bafang M560RS uses new optical sensor instead if magnets sensor Bafang used before and we might need to change the circuits. The current VESC for Bafang M560 controller might work with regular Bafang M560 PAS sensor but it might need to be changed for M560RS.

Currently the signal lines are connected to 5V through 10K resistors just like on the Bafang M600. We might need to connect them to the ground or not connect to anything.

Is there any way to say at which mode and settings the pins PA6 and PA7 are configured for the STM32 MCU looking on the Luna firmware? We can measure the quadrature signal pins voltages on the Bafang PAS sensor and adjust the circuits knowing the pins configurations.

I feel like the old Bafang magnetic encoder sensors are just like mechanical switches with magnets mechanically shortens the circuit to the ground and that's why it is connected to 5V through 10K resistors to make it works. With optical sensor the output is probably different becasue of there are probably optical transistors control the outpun voltage rather than shortens the crcuit to the ground.
 
Last edited:
I also can check what is going on with the cadence "app_pas_get_pedal_rpm()" value equalizing it to the "pwr" value (and dividing it by 60 to make the result more withing the expected voltage range) and again observing it through the VESC Tool App Setup Input wizard ADC Mapping. But nope, always 0 no matter how I rotate the crank.

1765508286673.png


1765508893674.png
 
Last edited:
If I use just the torque sensor voltage to drive the "pwr" value it works. But when I multiply it on the cadence value
Why do you try to reinvent the wheel? Just change the one function, that returns the normalized torque.

There is no need to multiply the torque with the cadence on a middrive, as the cadence always has a constant factor to the motor rpm. The rpms are shortened in the formula

motor power = assist factor * riders power

If you don't follow my hints, I can't help any more.
Good luck!
 
Back
Top