AILIFE4798 / Hoverboard-Firmware-Hack-Gen2.x-MM32

A firmware to control split motherboard hoverboards with UART
MIT License
19 stars 6 forks source link

sending new config (incuding new SLAVE_ID) from ESP32 to hoverboard EEPROM.. #12

Open RoboDurden opened 7 months ago

RoboDurden commented 7 months ago

@AILIFE4798 , i have begun to implement the SerialServer2HoverConfig struct you already imported with remoteUartBus.c

                case 2: 
                {
                    SerialServer2HoverConfig* pData = (SerialServer2HoverConfig*) aReceiveBuffer;
                    if (    (pData->fBatteryVoltage > 0) && (pData->fBatteryVoltage < 60.0) )
                    {
                        BAT_FULL = pData->fBatteryVoltage;
                        BAT_EMPTY = BAT_FULL / 4.2 * 2.7;
                    }
                    if (pData->iDivemode <= SINE_SPEED)
                        DRIVEMODE = pData->iDivemode;
                    if (pData->iSlaveNew >= 0)
                        SLAVE_ID = pData->iSlaveNew;

                    EEPROM_Write((u8*)pinstorage, 2 * 64);    //if the detection failed, the pin is still saved
                    break;
                }

Maybe you want to add a slaveId-reset when the user pushes the onOff button 7 times within in the first 7 seconds to reset the slaveId to 1.. Then no Keil woud be needed to program the singe boards..

I would like this feature for the youtube tutorial to switch the different drive modes from the TestSpeed.ino. So without recompling the main binary.

Update: the 7 button pushes to reset are not really needed. User can send new slave id to all possible 64 ids and all boards connected to the uartbus will reset to the new slaveID.

AILIFE4798 commented 7 months ago

yes changing drivemode in main firmware is good but some of the settings must be locked from the main firmware like all the pins,slaveid,serial baud rate,magic number these will only be changeable in pinfinder or keil because misuse will cause connection lost to the board forever

AILIFE4798 commented 7 months ago

i will wait untill your protocol is updated and consider how much will be implemented

AILIFE4798 commented 7 months ago

ofcourse,this is easier said then done,changing some parameter including drivemode during firmware running is not possible, so after this command the chip must imidiately reboot to apply the change, or not write to running system and just apply after next normal restsrt when user do so

RoboDurden commented 7 months ago

Not so nice. It might indeed be a use case to drive in speed mode and at some point change to voltage mode. When i search your firmware for DRIVEMODE i do not find some init code that has to be run at startup. So changing DRIVEMODE at runtime might only need a speed=steer=0 or something like that ?

Update: okay a change to SINE_SPEED and speed = 0 would result in a full break :-( RemoteUartBus might set a DRIVEMODE_NEW value, and if this is >0, the main loop first slows down to 0 pwm and then replaces the new mode with DRIVEMODE.

AILIFE4798 commented 7 months ago

actually i am not sure, but i am sure change from com-speed to sine-speed will break,cuz of the pid parameter, but it can be fixed easily, im just afraid there is side effect to it

RoboDurden commented 7 months ago

Thanks, i tell you when i have my code complete and you maybe tell me which pid parameters to reset.

AILIFE4798 commented 7 months ago

after mode change call PIDrst();thenPID_Init();

AILIFE4798 commented 7 months ago

pidrst will cancel out any momentum and pidInit will change output range and p,i,d value

RoboDurden commented 7 months ago

https://youtu.be/Nx13kbKNuV0

sine -> com is okay com -> sine hangs the motor control.

AILIFE4798 commented 7 months ago

i will check why cannot go from com to sine as for the COM_SPEED it is very very hard to make it work because com at low speed really sucks you can stop the wheel with 1 finger at that speed the pid loop have to do allot for sine the torque is way more so pid loop dont have to do as much

AILIFE4798 commented 7 months ago

i already know why it doesnt work but ill have to think of the solution

AILIFE4798 commented 7 months ago

I have think of a solution now, but I will need to test if it effect the normal operation of com mode, am I allowed to update the code now, if so I'll also change other things, if not I'll tell you line by line what to replace with what

RoboDurden commented 7 months ago

This SerialServer2HoverConfig is very specific to your firmware. I may want to change to a generic struct

typedef struct {            // ´#pragma pack(1)´ needed to get correct sizeof()
   uint8_t cStart;          //  = '/';
   uint8_t  iDataType;  //  2 = unique id for this data struct
   uint8_t  iSlave;         //  contains the slave id this message is intended for
   uint8_t  iCmd;
   double fValue1;
   double fValue2;
   uint16_t checksum;
} SerialServer2HoverConfig;

Then my GD32 firmware can make use of it as well as your MM32 firmware.

Right now, every new SerialServer2HoverConfig overwrites everything BatteryEmpty, BatteryFull, DriveMode :-/

But it is nice to have a full oHoverConfig on the ESP32 ! That is always sent at startup and then the ESP32 code can be sure that the hoverboard is running on these values.

So a SerialServer2HoverConfigMM32 and a SerialServer2HoverConfigGD32 might be better.

RoboDurden commented 7 months ago

I have think of a solution now, but I will need to test if it effect the normal operation of com mode, am I allowed to update the code now, if so I'll also change other things, if not I'll tell you line by line what to replace with what

I only make changes to remoteUartBus.c so if you do not change that i happily wait for updated code on your github repo here.

AILIFE4798 commented 7 months ago

I have never edited remoteuartbus since I've adapted it Well maybe I did once or twice to change uart thing but not much This time I surely won't touch it

AILIFE4798 commented 7 months ago

i gave up on editing i will add rest of things i want to do later just add this function to bldc.c and call when changing mode

void TIMOCInit(){
    if(DRIVEMODE==COM_VOLT||DRIVEMODE==COM_SPEED){
        TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
        TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
        TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
                commutate();
    }else{
        TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM2);
        TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM2);
        TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM2);
        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);
        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);

    }
}
AILIFE4798 commented 7 months ago

if you want a dynamic config on gd32 it is required to send on every boot as gd32 does not have eeprom, so might as well do on mm32,just make it lost after power off

RoboDurden commented 7 months ago

Thank you @AILIFE4798 . I have already moved my test setup from my bed. Good night from Germany :-)

RoboDurden commented 7 months ago

No sorry, with this new function, the motor still hangs when going from COM to SINE:

                    if (pData->iDriveMode <= SINE_SPEED)
                    {
                        DRIVEMODE = pData->iDriveMode;
                        PIDrst();
                        PID_Init();
                        TIMOCInit();
                    }

P.S. i still have not found a reliable way to F8 flash. Mostly i get "No target connected." Sometimes, pulling NRST to GND with a little button switch helps, mostly i pull the st-link dongle and reinsert into the windows usb port. Currently i need about 30 tries to succeed with one flash. Maybe i shoud try the modified st-flash with working RST pin again..

AILIFE4798 commented 7 months ago

i will see if theres any other issue for me theres no problem flashing only first time nrest is needed,my firmware allow debug so mo need to use nrest i can keep flashing when firmware is still running to test changes quickly and ofcourse use debug feature which is super helpful

AILIFE4798 commented 7 months ago

sorry,one line is missing

void TIMOCInit(){
    if(DRIVEMODE==COM_VOLT||DRIVEMODE==COM_SPEED){
        TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
        TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
        TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
                commutate();
    }else{
        TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM2);
        TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM2);
        TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM2);
        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);
        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);

    }
        TIM_GenerateEvent(TIM1, TIM_EventSource_COM);
}
AILIFE4798 commented 7 months ago

see if this helps

RoboDurden commented 7 months ago

YESS ! Now i can switch to any of the 4 drive modes even while the motors are spin. Great work @AILIFE4798 :-)

I now also have both motors running. But i need the diode to receive feedback from both..

RoboDurden commented 7 months ago

I have uploaded my code changes to https://github.com/RoboDurden/Hoverboard-Firmware-Hack-Gen2.x-GD32/tree/main/Arduino%20Examples/TestSpeed and https://github.com/AILIFE4798/Hoverboard-Firmware-Hack-Gen2.x-MM32/blob/main/HoverBoardMindMotion/Src/remoteUartBus.c

and created a pull request for you to add to your main repo: https://github.com/AILIFE4798/Hoverboard-Firmware-Hack-Gen2.x-MM32/pull/13/files

AILIFE4798 commented 7 months ago

do you still want to write to eeprom,because you will send on every boot anyways

and i will remove the slave id changer code after merge because it should not exist any change that will cause lost of connection is not permitted in main

RoboDurden commented 7 months ago

no no it works to set new slave id. I do it myself already. Because main binary alwaysy has id1 when F8. Then i simply disconnect one board and send the command si 0 which set the remaining board to 0.

You can also direct every command to a specific slave: 1 bl 24 will set batterLow to 24V only for id1 So you can also send 1 si 2 with both boards connected to set id1 to id2.

And as i already wrote, You can simply make a loop from id0 to id255 and reset all boards to make them accessible again.

If i would need pinFinder to set the slave id, i would need to flash pinFinder and autodetect.ino :-( And then i would have to mark that board with a sticker to be idXY :-((

I know this feature to reprogram slave id from digital servos :-)

AILIFE4798 commented 7 months ago

I know it works, there's no reason it won't, but I think the id should be permanent,a sticker on the board is a good idea, when all of them is connected correctly and accidentally one of them is set to same id as others there no way to seperate them so no I won't allow it

AILIFE4798 commented 7 months ago

tell me a reason why you would want to change the id when it is running

RoboDurden commented 7 months ago

Good morning :-) I do not really like that discussion :-/ It seems to me that you are obsessed with your pinFinder and want to force the workflow that you have envisioned onto every other user :-(

But okay if you really want to force everyone to run pinFinder for every new board (even if they cheaply have bought a dozen of mm32 slaves..) to already know the slaveId at the time they run pinFinder, then you must also force them to enter the slaveId on every "save to eeprom [Y/N]" and NOT only optionally let them choose the non-default slaveID in the CLI.

And if they later salvage a board from some old project they have to run your beloved pinFinder again only to reset the slaveId :-(

And with a four-wheeler or 5 axis robot arm, users might not yet have decided which board to install where. When a replacement is needed for id3, users neeed to run pinFinder again before putting it in the existing hardware/software setup :-(

And the slaveId can only be overwritten with SerialServer2HoverConfig and i already said that a simple loop over all Ids can always reset the connected boards and make them accessible again.

But i already have the problem that i do not get config feedback from a board to see if my SerialServer2HoverConfig has been received. (for some reason, batterLow is not taking effect so i do not know if my message has been received.). And the problem with a slaveId conflict only truley arises with many boards on the UartBus. So it might be a good feature to also read the config stored in the board. (Only way for ESP32 to make sure a new config has been implemented) Then you might add a serial number to the eeprom which could be the uint32 unix timestamp when pinFinder saved the eeprom. Having/getting that serial number might be an alterantive way to address a slave.

But all this discussion is silly because i added the feature to immedatily make use of it. My workflow is to not care about slave id when detecting/storing the pins - that is not the focus of PIN-finder. (and again the dispute about intuitivity..) Therefore i know that every new board wil have id1 (might better be id0) After i have installed a board i reset the new board to a different id than the one pinFinder has set by default.

When i need to replace a board i can always replace it with a board from the shelf (that i can access because the default id is never used in a real enviroment) and reset it to id of the borken one.

Yes this will need a way to send SerialServer2HoverConfig data. But if a user does not have this functionality in his code, he can not change slaveID in the first place.

And with up to date hoverserial.h, everyone can add

        oHoverConfig.iSlave = 1; // default slaveId from pinFinder
        oHoverConfig.iSlaveNew = 42; 
        HoverSendData(oSerialHover,oHoverConfig);

But i suggest that we restrict the number of possible slaves to 64:

                    if (    (pData->iSlaveNew >= 0) && (pData->iSlaveNew < 64)  )
                        SLAVE_ID = pData->iSlaveNew;

Even a max of 16 should be okay because i doubt that the pullup resistors of the rx lines will allow for too many boards to receive from one esp32.

Every experienced user is free to increase BDC limit. Or use pinFinder to set higher slavIDs - which makes this dispute entirely ridiculous. Because when a user really needs to initialize more than 16 or 64 slaves, he does not want to run pinFinder for all these many boards.

You reject the idea of changing slaveIds (yet you store them in eeprom..) because BDC might brick their setup. But even then they could run pinFinder to reset the slaveId.

tell me a reason why you would want to change the id when it is running

I thought that was obvious :-(

RoboDurden commented 7 months ago

But i agree that i have the old mindset where users flash a binary for a specific board layout and serial port, and then install it in the system with led, buzzer, onOff, etc.

Your mindset is to install the empty board into the system first, the run pinFinder to initialize it and finally change the ESP32 software to real code.

I am not sure if it is a good idea to force every BDC to run the full pinFinder detection for every new identical board. Making use of https://github.com/RoboDurden/Hoverboard-Firmware-Hack-Gen2.x/blob/main/target_4%3DMM32SPIN0X/v1%3D2.8/pinFinder%20Gen2.4.1.txt would require Keil ! And then it would be more convenient to set slaveID in the main source or with SerialServer2HoverConfig :-/

AILIFE4798 commented 7 months ago

If you have 100 boards and don't want to use pinfinder to set the slaveid(and the pins), the only way is to use keil anyways,(unless you want to somehow dump firmware from 1 board which may be harder then installing keil), so you can just set the slave id there

Why digital servo use this is because they don't have the option to use pinfinder or keil to config, so now the question is what is better, set in pinfinder or main

Not a normal people you won't have more then 256 boards so every board you have can have it's own id, so there's no reason to change it, just set the correct id in your esp code For people that have a bunch of same board you will want to use mass produce mode and compile every one in keil anyways It would then be beneficial if all board come out with same id and you can change it later Now is it easier to do that or to use pinfinder but without erase so all other pin is already set and you can just change the one id? probably it's similar

The SerialServer2HoverConfig is also useful for when you want to switch drive mode dynamicly, so would be in a actual project code, so the chance of messing up the id is also not low

in conclusion, it is not useful to set slave id dynamicly, it is just used to lower the need of pinfinder which will only happen once anyways

Btw the chip have a uuid that is displayed in pinfinder, you can use to identify the board after id is changed

RoboDurden commented 7 months ago

Yes i already noticed that uuid. I was already thinking about a new issue here to propose a database of a all known boards in the main binary. Your nice main binary only has Program Size: Code=16440 RO-data=1272 RW-data=168 ZI-data=2920 It could easily store 100+ of the 25 pin bytes. And if no board is set in eeprom, the main binary would cycle the 6 possible tx pins every 6 seconds until it receives a SerialServer2HoverConfig to initialize the slaveId and also save the rx line used. Then there would only be two possible tx lines left..

But you will not like that.

I think that the average BDC will fail with your pinFinder workflow, even so you did a great job with the code. The workflow simply is too long. If you force the users to follow your workflow, i will offer the BDC-version with my fork :-/

AILIFE4798 commented 7 months ago

No board numbering, no known database, here in my firmware, that's 100% not happening I can confirm, I didn't even say oop 100% won't happen, I just say not anytime soon

Feel free to make your own fork, some feature I can implement to main, some just no good, but after all this repository will only be maintained for maximum 4 days anyways

RoboDurden commented 7 months ago

The hall pins can be different for every hardware setup because the boards no longer have yellow-blue-green phase cables :-/ Even with my slave and master having the same colors connected, your pinFinder found C15,C13,C14 for the master and C13,C14,C15 for the slave :-/ So it might indeed be neccessary to always run pinFinder when the board is installed in the final hardware ! And then of course you can set the slaveID there.

As i said, you should always prompt to change the slaveID when the BDC choose to save eeprom in pinFinder :-)

AILIFE4798 commented 7 months ago

I should add a step to change slave id when you press 1 detect all

AILIFE4798 commented 7 months ago

You can connect phase wire however you like no problem, as long as you don't change it, I personally like from left to right GBY when you are facing the connector on the board

RoboDurden commented 7 months ago

I did choose the same colors as the hall sensor.

RoboDurden commented 7 months ago

Maybe you are right and it is better to force the BDC to detect/verify the pin again and and again for every hardware setup. The hall pins might change. Some LED may be connected differently. A master may be used as a slave Ad I guess they could connect a buzzer to an led pin and then identify it as the 'b' buzzer :-)

If i would not have forgotten to set the slaveID in that process i probably would not have added that feature to SerialServer2HoverConfig.

So if you add a (10)-Set SlaveID to change the id without the CLI, that might be the best to do.

AILIFE4798 commented 7 months ago

main is updated with some fix including low battery cutoff i will deal with the slaveid in pinfinder in a moment

RoboDurden commented 7 months ago

I want to make the video tutorial in the next 3 hours. A complete walkthrough from blank master and slave to demonstratig the dynamic change of drive mode with both motors running.

AILIFE4798 commented 7 months ago

pinfinder upated with slaveid mode and backspace support in cli

RoboDurden commented 7 months ago

Thanks. But i have recorded the video already. I have mentioned that you will add the slavid to main UI :-) Now it will take a few days to compile the 40 minutes footage into a 20-30 minutes video. I was indeed able to not change the hardware for the entire walkthrough ! You flash autodetect.ino and pinFinder.bin the first board, so the second board will not respond. After pinFinder that first board, you already flash main.bin and then pinFinder.bin to the second board. Finally you flash main.bin to the second board and TestSpeed.ino to Esp32 :-)

When board is broken you flash autodetect.ino to esp32 and pinFinder to the replacement :-))

Thanks for changing your rx-tx bridging so my Autodetect.ino can work.

It might be nice if your pinFinder also supports the Arduino terminal. For many BDC this will be the only terminal. Then i would not have needed to switch to Putty. Which is a bit troublesome as i have to kill the terminals in order to free the serial port so the other terminal can connect..

Putty is a free download that is found in many places of the internet. I was never sure if the nice download site was the official place. I can understand when people do not want to download such a little software..

AILIFE4798 commented 7 months ago

I will add anti feature in pinfinder that will prohibit the boot if Arduino serial terminal is detected just in case someone didn't listen(I hope it won't interfere with the esp auto short) If you don't want to use putty you can use the online terminal I linked in the manual But you do need to use special browser like chromium based ones only

AILIFE4798 commented 7 months ago

the feature to block arduino ide serial terminal is implemented it can work normally on the online serial terminal too despite it only have 19220 baud but the difference is small enough i detect after enter is pressed to continue to be sure a terminal is connected already in order to do the detection image

RoboDurden commented 7 months ago

I was able to support the arduino terminal with my autodetect firmware. I do not remember exactly how but i simply skiped the incoming 0x13 and 0x10 and only let 0x130x13 continue as one 0x13 .. Something like that. I guess it would have been more happy if you had used your time to support this most common terminal, instead of blocking it..

AILIFE4798 commented 7 months ago

in every step line ending is used to progress to next step/go back to main menu, so it is not possible to differentiate it command line would not work at all ofcourse and the problem of copy pasting in putty would happen always on arduino terminal because it sent too fast the mm32 cannot parse it fast enough in the interrupt i dont block it because i just hate it or anything,but its just worse

RoboDurden commented 7 months ago

Did you read my solution ? You can differentiate betwee a single 13 after a line and a single ENTER click which leads to two Return 13 13 . And possible 10 can be skiped anyway. You only have to remember the last byte received and if the new rx is 13 and the old rx is 13 then skip one RETURN..

AILIFE4798 commented 7 months ago

this will be my last message,goodbye.

I-hate-2FA commented 7 months ago

@RoboDurden i have tested,in arduino ide terminal when you didnt put anything in the field and press enter,you get one \n or one \r only, never two (if you selected both then ofc you get both,but only one of each) in putty or webserial you just always get a \r when you press enter it is possible to detect a dumb terminal or inteligent terminal is connected, so theoratically you could design a seperate ui for it, that is operating in limited mode with minimal thing needed just like your autodetect but lets be real being able to use the command line and be able to press w and s to increment/decrement the pin and +/- to increment/decrement the speed is very good, who would want to use a dumb terminal anyways especially im not asking you to install linux for it or anything,its just download a software for a couple of mb for windows and linux, or if your lazy just open a page on your browser, if you are not able to do any of these then you should probably not use my firmware, vesc and odrive both require a software on pc to configure too, i just require a serial terminal, i think thats pretty decent, it can even be done on a smartphone if you are crazy (idk if you can use pyocd on a phone though,i only know you can flash stm compatiable chips)

update: smartphone can flash stm32f103 and gd32f130(correctly detected as g32f130),including unlock option byte ,but sadly cannot flash mm32

I-hate-2FA commented 7 months ago

@RoboDurden and there is still the issue in the latest autodetect and testspeed,that the LED_BUILTIN is not defined,idk why you removed it before you submitted the code,i know it is different on every board so you should always change it,but led really isnt important in this use case since there is serial communication to know the board is working, it is better to have the code compileable without modification if you think otherwise it is ok i can just add it my self every time but im sure some people will not know how to do that