Lil' Blackbox

Coding => v1.0 - v1.1 => Topic started by: Rx7man on May 19, 2015, 10:05:00 PM

Title: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 19, 2015, 10:05:00 PM
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.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 20, 2015, 12:33:06 PM
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.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 20, 2015, 02:16:52 PM
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.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 20, 2015, 05:55:14 PM
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.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 20, 2015, 06:40:02 PM
Ya if you want to make a protocol for updating ram information that'd be another way, certainly better :)
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 20, 2015, 07:00:29 PM
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 (http://forum.arduino.cc/index.php?topic=324374.new#new)
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 20, 2015, 11:04:12 PM
use memcpy to copy arrays.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 20, 2015, 11:23:16 PM
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
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 21, 2015, 09:30:37 AM

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
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 21, 2015, 11:47:52 AM
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.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 21, 2015, 12:15:07 PM
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.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 22, 2015, 11:05:50 PM
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?
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 22, 2015, 11:11:26 PM

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
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 22, 2015, 11:18:12 PM
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!
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 23, 2015, 09:38:02 AM
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.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 23, 2015, 01:14:07 PM
I'm at a loss on how to make this work in C++... I'm not good enough with pointers, and I'm getting all the same problems I had when I had a 2D array...

So I'm making a library for it, and perhaps you can give me a hand.. I am attempting to code it line-for-line the same as the VB version posted above...

So how do I declare an array in the class that I can assign a size to in the constructor.. or do I set up a pointer in the class that I create in the constructor, and then set that pointer to the array?  either way I'm not having much luck.. so here's what I have



#include "Arduino.h"
#include "Map2d.h"

  byte* Map1d; //pointer to the 1dimensional map array
  byte Rows;
  byte Columns;
 
  Map::Map(byte Columns, byte Rows){
    this->Columns = Columns;
    this->Rows = Rows;
   
    byte TheRealMap[Columns*Rows-1]; //Create the array
   
    Map1d = &TheRealMap; //this doesn't work... what do I need to do?
   
   
  }

Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 23, 2015, 06:50:13 PM
It has been eon's since I've used pointers.

If map is going to be dual array, I think you need to declare it like, byte* Map1d[][];
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 23, 2015, 08:17:43 PM
The map will appear to be a 2d array, but behind-the-scenes it's a 1D array that is converted.. I actually found it easier to do that way.

I bet it's been longer since I've used them.. I took C++ programming 101 in about 1999 and haven't used it since.

I had a whole whack of ebooks (most of the For DuMMies books) but somehow the PDF's seem to all have gotten corrupted.. grrr.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 24, 2015, 12:32:39 AM
I think I'm getting it!!! woohoo!

I will have extensive testing to do yet though, I had to change my return arrays that were 2 dimensional to unidimensional, but that's not a big thing, I do think I kept the logic the same.


I was wondering about Progmem()... How does the access time compare to RAM? is it about the same?  I should have enough memory, but if I was short, the first logical stuff to go into program memory space would be large tables right?


Here's my code so far.. not the prettiest, but it compiles, which is a good start!  I do however have a major bug...
I declare my map, and set everything in it, including the row and column labels, I double check it in setup(), and my data is there, and good.. then I run through the interpolation, and all my data is gibberish and changed up.

I thought it was something with passing the arrays, so I rewrote the part that I was doubtful of, but no change in the behavior.. I've attached it as a zip... I've dome some commenting, and left all the debugging Serial.Prints so you can see what's happening
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 24, 2015, 06:22:45 AM
progmem is ultra ultra slow compared to ram
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 24, 2015, 12:24:20 PM
Good to know.. and I'm going to assume reading from flash memory is darned slow too.


Still trying to work out that bug... will post an updated version of the program with better debugging soon.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 25, 2015, 12:03:56 PM
FOUND IT.

I declare the arrays I assign to Boostmap in Setup().... then I keep checking that my data is valid in Setup.

As soon as it exits Setup, they went out of scope and got deleted, so in Loop() they were empty arrays pointing to garbage memory.  Declared them as Static in Setup() (pretty much the same as global) and my problems went away.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 25, 2015, 03:42:31 PM
OK, so the basic tests show it's working, though there's some 'jitter' in it and I attribute it to using an integral value rather than a float,... but it will do well enough for now, and once I get more into it and see what sort of memory I still have available I may reduce the map size but increase the resolution.. logic will stay the same, just have to change a few variable types.. it will also depend on processing speed evidently as well.

I made it return a float value, I think I can afford that... it's good for testing anyhow, as the the increased resolution helps debugging...

So here it is attached, I have a pot on A0 and A1 to simulate RPM and TPS, though I remapped the RPM values to 2000-3000 so I had a bit finer control.

There's lot of debug serial prints, so you can see what it's doing, I commented it relatively well
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 25, 2015, 10:24:32 PM
More progress.. Got it to read and write to EEPROM now.. each 9x14 map takes 174 bytes using BYTE types for the map, and INT types for the row and column labels... since I think this is plenty of resolution, I will put each map on a 256 byte boundary, leaving room for additional features if I need them.. Got a while before any of this is set in stone though
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 26, 2015, 12:37:01 PM
Cool, lets clean up the loop and setup timers. I'll just post the ino

Don't need to setup the values as static in the loop, if you want to make a while loop. Also I'm really really used to X then Y for maps, any reason you did y then x ?

Lastly, incorporation of rolling RPM / Boost value, wouldn't be a bad idea. Maybe run it on a 1ms timer, so then you can average the last nth^2 ms , (2, 4, 8, 16, etc) I would average the last 8ms, and run everything on a 10ms timer for final calc.

**updated file, sorry put old one i was working on in.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 26, 2015, 12:57:56 PM
That's another way of doing it.. it comes to the same in the end though I think.. Your way Loop() never ends, so you don't need to set it as static, my way loop() does end, so keeping the variables requires them to be static. 


Did I comment the Mapping and interpolation part of it well enough for you to understand?  The "four corners" part can be a little confusing... without the enumerators it would have been impossible for me to do it!

I updated my VB version to reflect the changes, I think better in VB where the syntax is natural to me and I can concentrate on code logic.. Now that I'm a bit more familiar with C++ and it's fussiness about certain things I can hopefully code my VB to be easier to port.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: hakcenter on May 26, 2015, 01:00:41 PM
I haven't read your library yet, just making the assumption that it works, haha!

Make sure to double analogReads so you get that pin, sometimes you get the last pin, especially with another so close to last code wise.
Title: Re: Definition of a brain twister.. And a test on live tuning
Post by: Rx7man on May 26, 2015, 02:24:01 PM
I do remember that, but from something I read somewhere the problem is mainly when you read analogs from 2 different ports...   reading it once seemed to work on this, but I will definitely keep it in mind when I make a 'real' sketch that has to function correctly.

I will also be reviewing the last sketch I posted, and will try to get the arrays internal to the class.. I'm just learning about malloc() now so I can do it.