Definition of a brain twister.. And a test on live tuning

Started by Rx7man, May 19, 2015, 10:05:00 PM

Rx7man

OK, now I'm gettign my brain working hard.. switching between the Arduino C programming style and VB

Curly braces where there shouldn't be, semicolons missing, etc etc..

I'm trying to make an interface so that I can change engine parameters via a VB powered program over USB.. rather than having to re-upload the whole program to the arduino every time I change a parameter (for live tuning an engine this is pretty much essential), so I'm just trying a couple things out

So basically at this point I'm just going to work on getting the engine parameters FROM the arduino into VB over the serial port, and my data structure will be comma delimited, and look a little like this


Mode number, Address number, Value

Mode 0 will just print out a debug information.. will just print out whatever it got, this will also happen if there aren't exactly 3 substrings after parsing it out

Mode 1 will be for updating engine parameters like EGT, AFC, VGT, and all the  other 3 letter alphabet soups
Mode 2 will be for updating fixed engine parameters, like sensor pulses per revolution and other constants
Don't know what other mode types I might want, but for now this will do

So the address part of it will just be an integer that is interpreted by the program.. 0 for RPM, 1 for TPS, 2 for MAP, etc

The value part will be the raw values from the ADC's or whatever, this will reduce the load on the MCU a little bit.. I've planned on keeping everything in raw form on the arduino except for RPM.  The interpretation into "human" numbers will be done on the laptop.



Vice versa will be fairly similar.. just a little harder to do while keeping things efficient.. C isn't as nice for working with strings as VB is.
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

Rx7man

It gets really confusing when at some point you mixed up what you define as the rows and what you define as the columns of a table...

Then the Serial.println function was doing some weird stuff on me that I had to find a workaround for.. still haven't gotten to parsing the input yet.

For writing to the Arduino I'm going to go structure the command something like
Mode (read/write?), Address, Value

I'll perhaps run into problems using the address directly if I'm not really careful, but it would save a whole lot of code in the arduino doing it that way, offloading that task to the laptop.
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

hakcenter

Well if you offload to the laptop you're going to introduce a lot of delay.

Delay waiting to read, delay while parsing information, calculating then, delay sending, since then arduino will have to wait to read then parse then do whatever.

The Arduino is extremely fast, as long as you don't do any division outside of bitwise math.

If you need real-time tuning, what I would do is introduce a sd-card, and have it read on start-up, that way you can remove it anytime after its up and running. Setup a read/parse for update sd-card info, then re-do sd card information.

So you could take the card out, make your changes, put it back into the ardy, then tell it to restart.
TS2009 Deḇarim 8:2
"And you shall remember that יהוה your Elohim led you all the way these forty years in the wilderness, to humble you, prove you, to know what is in your heart, whether you guard His commands or not.

Rx7man

I think that would get old really quick when trying to fine tune, though it would certainly work.

It isn't going to have to read from or write to the laptop often, it's only for when you're updating values...

So basically it'll be getting a command like
1, 640, 255 in Mode/Address/Value style and it'll put 255 in address 640, which will only happen when you update the data on the laptop.

Once every 250millis or so it will send a bunch of data to the laptop in a similar fashion... which the laptop will decode and give you a live display about.
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

hakcenter

Ya if you want to make a protocol for updating ram information that'd be another way, certainly better :)
TS2009 Deḇarim 8:2
"And you shall remember that יהוה your Elohim led you all the way these forty years in the wilderness, to humble you, prove you, to know what is in your heart, whether you guard His commands or not.

Rx7man

Thats what I'm attempting... It's turning out to be more of a fight with pointers and arrays than anything else.. If this were VB I'd have no trouble at all, C is just so darned anally retentive!.. For such a powerful language it sure doesn't let you do a lot of stuff..

Assigning one array to another
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

hakcenter

TS2009 Deḇarim 8:2
"And you shall remember that יהוה your Elohim led you all the way these forty years in the wilderness, to humble you, prove you, to know what is in your heart, whether you guard His commands or not.

Rx7man

I don't need to copy the data, I just need to reassign it..

If I copy the data, then I have two copies of the same thing....   Does memcopy work on arrays that are difference sizes?

Like in my example, I've defined it as


byte Map[0][0];
.
.
.
void somefunction(){
byte Newmap[10][5];
//Now here I need to find a way to make Map point to Newmap
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

hakcenter


byte map_x = 4;
byte map_y = 4;
byte map[32][32];

void remap(byte new_map_x, byte new_map_y, new_map[][]) {
  // where remap is called from your protocol, and sends this function (saves ram) new_map_x, new_map_y, and the new map
  for (int i = 0 ; i < new_map_x ; i++) {
    for (int j = 0 ; j < new_map_y ; j++) {
      map[i][j] = new_map[i][j];
    }
  }
  map_x = new_map_x;
  map_y = new_map_y;
}

map will always be larger than your dynamic resize, and make sure your code knows to use the map_x / map_y so when they change sizes it all flows
TS2009 Deḇarim 8:2
"And you shall remember that יהוה your Elohim led you all the way these forty years in the wilderness, to humble you, prove you, to know what is in your heart, whether you guard His commands or not.

Rx7man

Yeah, before I do that I'll just hard-code the map size so I don't need to copy a new map.. Right now I have a 9x14 map, which is 126 members, or 252 bytes for ints... Since I don't think you'll really need any finer resolution for setting your boost, I'm going with a byte type now (originally had int type).. 256 increments for 50 lbs of boost lets you set it in .2psi steps.. PLENTY of resolution there.. it will still get interpolated between increments into an int type to make the best use of the ADC resolution.

For now I'm looking at 1 map for the boost pressure, and one map for the AFC position.. for those 2 applications the 9x14 map is perfect, but who knows what I might want to make later, and that's why I was hoping to keep it flexible.
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

Rx7man

I think I found a solution.. I'll declare the map array external to the class, it will require that I pass it as an argument to the functions, but at least that way the class can handle any size of array.
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

Rx7man

Well.. as someone on the arduino forums said, the easiest way to get around the problems with the 2 dimensional array is to make your own out of a 1 dimensional one... I really didn't want to believe that, but in the end, I had to go with it.

I haven't ported it yet to C, but I wrote it all in VB since it's so much easier to debug... I got mad at Microsoft.. I had created the project, and done a bunch of work (to the point it was basically functional) when I got a blue screen of death, and all my work was gone.. for one because windows crashed, and for two, because if you haven't explicitly saved your project after creating it, VS doesn't save it on every build.. GRRR... I mean it isn't saved *anywhere*, it does not touch hard disk space.. no temp files or anything... Then I found out there's an option (off by default) in VS2012 that will save your project upon creation.. now why the heck didn't they enable that darned thing by default!

So anyhow, I built it again, I had it mostly memorized, or could cut and paste from old work I had.. probably built it better this time around anyhow.. the class is only about 100 lines of code, and that's with generous spaces, and it works like a charm.

I've also thought of (yet another) neat feature... or rather a way to implement it.. if you want a performance mode and economy mode, you'll need 2 of each map, one for each mode, and then you could have a pot on an analog input that can select how much you want of each.. mounted wherever you want.

Meanwhile I had originally thought of contolling the AFC from an RPM and TPS signal, but I think that would be quite hard to get right, I think RPM and boost would be a better source for it.. Once the main logic is figured out it's easy enough to change the sources anyhow.

hakcenter.. do you have visual studio? what version?
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

Rx7man


Public Class Map2d
    Private Map1d() As Byte
    Public Rows As Byte
    Public Columns As Byte
    Public RowLabels() As Integer
    Public ColumnLabels() As Integer

    Public Property Map_1d As Byte()
        Get
            Return Map1d
        End Get
        Set(value As Byte())
            If UBound(value) <> UBound(Map1d) Then 'I want to be sure we don't/can't change the size of the internal map.. that's a receipe for disaster
                Throw New IndexOutOfRangeException
            Else
                Map1d = value
            End If
        End Set
    End Property

    Public Sub New(Columns As Byte, Rows As Byte)
        Me.Rows = Rows
        Me.Columns = Columns
        ReDim Map1d(Rows * Columns - 1)
        ReDim ColumnLabels(Columns - 1)
        ReDim RowLabels(Rows - 1)
    End Sub

    Default Public Property Map(Column As Byte, Row As Byte) As Integer
        Get
            Return Map1d(GetMapIndex(Column, Row))
        End Get
        Set(value As Integer)
            Map1d(GetMapIndex(Column, Row)) = value
        End Set
    End Property

    Public Function Interpolate(Xvalue As Integer, Yvalue As Integer) As Single
        Dim ColumnIndex As Byte = GetLabelIndex(ColumnLabels, Xvalue)
        Dim RowIndex As Byte = GetLabelIndex(RowLabels, Yvalue)
        Dim FourCornersValues(,) As Byte = GetFourCornersValues(ColumnIndex, RowIndex)
        Dim FourCornersLabels(,) As Integer = GetFourCournersLabels(ColumnIndex, RowIndex)
        Dim outval As Single = Remap2d(Xvalue, Yvalue, FourCornersValues, FourCornersLabels)
        Return outval
    End Function

    Private Function Remap2d(Xval As Integer, Yval As Integer, FourCornersValues(,) As Byte, FourCornersLabels(,) As Integer) As Single
        'does a 3d map interpolation to find the values between cells
        Dim a As Single = Remap(Xval, FourCornersLabels(0, 0), FourCornersLabels(0, 1), FourCornersValues(0, 0), FourCornersValues(1, 0))
        Dim b As Single = Remap(Xval, FourCornersLabels(0, 0), FourCornersLabels(0, 1), FourCornersValues(0, 1), FourCornersValues(1, 1))
        Dim c As Single = Remap(Yval, FourCornersLabels(1, 0), FourCornersLabels(1, 1), a, b)
        Return c
    End Function

    Private Function GetMapIndex(Column As Byte, Row As Byte) As Integer
        Dim index As Integer = Column + Row * Me.Columns
        Return index
    End Function

    Private Function GetLabelIndex(Labelarray() As Integer, Value As Integer) As Byte
        For i As Integer = UBound(Labelarray) - 1 To 0 Step -1
            If Value > Labelarray(i) Then Return i
        Next
        Return 0
    End Function

    Private Function GetFourCornersValues(ColumnIndex As Byte, RowIndex As Byte) As Byte(,)
        'output format is outbytes(Xlow=0 Xhigh=1, Ylow=0 Yhigh=1)
        Dim outbytes(1, 1) As Byte
        outbytes(0, 0) = Map(ColumnIndex, RowIndex)
        outbytes(1, 0) = Map(ColumnIndex + 1, RowIndex)
        outbytes(0, 1) = Map(ColumnIndex, RowIndex + 1)
        outbytes(1, 1) = Map(ColumnIndex + 1, RowIndex + 1)
     
        Return outbytes
    End Function
    Private Function GetFourCournersLabels(ColumnIndex As Byte, RowIndex As Byte) As Integer(,)
        'format is Outints(X=0 Y=1, Low=0 High=1)
        Dim Outints(1, 1) As Integer

        Outints(0, 0) = ColumnLabels(ColumnIndex)
        Outints(0, 1) = ColumnLabels(ColumnIndex + 1)
        Outints(1, 0) = RowLabels(RowIndex)
        Outints(1, 1) = RowLabels(RowIndex + 1)
        Return Outints
    End Function
   
    Public Shared Function Remap(value As Single, oldlow As Single, oldhigh As Single, newlow As Single, newhigh As Single) As Single
         Return  (value - oldlow) / (oldhigh - oldlow) * (newhigh - newlow) + newlow
    End Function

End Class
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

Rx7man

Once I get the map working properly again, I will get back to the topic at hand.. live tuning, because that will be really nice to have.. just a little complicated to do I'm sure!
'94 dually,  67/67 HE351VE, NV5600, ~600hp
'93 ECLB 47RH, new toy truck, H pump project, 1000hp goal, 300K miles
93 XCLB auto, bone stock, 350K miles
93 XCLB 5spd, bone stock, 100K miles

hakcenter

I don't have VB, haha!

No ;'s making me craaaazaaa.

When coding pressure sensors, it becomes a royal pain to make it right. Some sensors claim a 0.5v - 4.5v which only realistically gives you 4v to work with, however when you actually test it, you see it goes well outside those 'manufacturer specs' so what's a man to do ??

You're going to need to bring that upper logic down, so  the arduino can control it, (we have no method exceptions), etc.
So skip the formality of error catching, and go right into the steak and potato's since you're making the logic you shouldn't really have to error catch yourself unless things fall outside of mapping commands and what not.

Setup a sketch to use 2 ADCs with 5v pots, and start testing map interpolation. Then introduce protocol logic for size changing.
TS2009 Deḇarim 8:2
"And you shall remember that יהוה your Elohim led you all the way these forty years in the wilderness, to humble you, prove you, to know what is in your heart, whether you guard His commands or not.