Thursday, December 28, 2023

0000 0000 1101 1011

Mailbag #36

Well after the shocking reviews for my last two videos I've decided to do the old favourite - a mailbag!

Algorithm alone knows these are so popular, but as I'm behind on opening up my late night purchases I'd better get to it!

The only extra bit is the code I had to write for the two joystick Arduino module - I couldn't find anything online and so I cobbled together the following - which works fine.

/*
 *  Found this twin joystick module online here:
 *  https://www.aliexpress.com/item/1005001882246352.html
 *  
 *  ..but with no code I had to find out the pins for
 *  input and output, then made the code below to demonstrate
 *  the use of the module - enjoy!
 *  
 *  Exponential function provided by BARD
 *  https://bard.google.com/
 *  
 *  OneCircuit - https://www.youtube.com/@onecircuit-as
 *  Tue 26 Dec 2023 16:28:52 AEDT
 */
 
#define LjoyXaxis_pin A0
#define LjoyYaxis_pin A1
#define RjoyXaxis_pin A3
#define RjoyYaxis_pin A2
#define LSW_pin 2
#define RSW_pin 4
#define LLEDPin 9
#define RLEDPin 10

int LYLED = 0;
int RYLED = 0;
boolean LButton = 0;
boolean RButton = 0;

int exponentialMap(int S) {
  float base = 3.0;
  float normalizedS = S / 1023.0;
  float L = pow(normalizedS, base) * 255.0;
  return constrain(L, 0, 255);
}

void setup() {

  pinMode(LjoyXaxis_pin, INPUT);
  pinMode(LjoyYaxis_pin, INPUT);
  pinMode(RjoyXaxis_pin, INPUT);
  pinMode(RjoyYaxis_pin, INPUT);
  pinMode(LSW_pin, INPUT);
  pinMode(RSW_pin, INPUT);
  pinMode(LLEDPin, OUTPUT);
  pinMode(RLEDPin, OUTPUT);
  digitalWrite(LSW_pin, HIGH);
  digitalWrite(RSW_pin, HIGH);
  Serial.begin(115200);

}

void loop() {

  // Left joystick routines 
Serial.print("LX-axis:"); Serial.print(analogRead(LjoyXaxis_pin)); Serial.print(":"); LButton = 1 - digitalRead(LSW_pin); LYLED = 1023 - analogRead(LjoyYaxis_pin); Serial.print("LY-axis:"); Serial.print(LYLED); Serial.print(":"); if (LButton == 0) { // LYLED = map(LYLED, 0, 1023, 0, 255); // linear map // LYLED = pow(1.0054,LYLED); // exponential map LYLED = exponentialMap(LYLED); analogWrite(LLEDPin, LYLED); } else { analogWrite(LLEDPin, 0); } Serial.print("LSW:"); Serial.print(LButton);
  // Right joystick routines 
  Serial.print(" RX-axis:");
  Serial.print(analogRead(RjoyXaxis_pin));
  Serial.print(":");
  RButton = 1 - digitalRead(RSW_pin);
  RYLED = 1023 - analogRead(RjoyYaxis_pin);
  Serial.print("RY-axis:");
  Serial.print(RYLED);
  Serial.print(":");
  if (RButton == 0) {
    // RYLED = map(RYLED, 0, 1023, 0, 255); // linear map
    // RYLED = pow(1.0054,RYLED); // exponential map
    RYLED = exponentialMap(RYLED);
    analogWrite(RLEDPin, RYLED);
  }
  else
  {
    analogWrite(RLEDPin, 0);
  }
  Serial.print("RSW:");
  Serial.println(RButton);
  
  delay(100);
}

Thank you to BARD for the exponential mapping function - increase "float base = 3.0;" for a flatter curve.

User:
Can you suggest an Arduino function that maps 
numbers 0-1023 (S: from a joystick source)
to 0-255 (L: for an LED output), but instead of
mapping linearly it maps exponentially so that
values of S such as 300 map quite low to, for
instance, to an L value of 5, and a value of
L=600 maps to, for instance, S=25?

Bard:
Here's an Arduino function that maps
numbers 0-1023 to 0-255 exponentially,
as you described:

Arduino
int exponentialMap(int S) {
  // Adjust this base value to fine-tune the curve
  float base = 2.0;

  // Normalize S to a range of 0.0 to 1.0
  float normalizedS = S / 1023.0;

  // Apply exponential curve using pow() function
  float L = pow(normalizedS, base) * 255.0;

  // Clamp L to 0-255 range to ensure valid output
  return constrain(L, 0, 255);
}
Use code with caution. Learn more

Explanation:

Normalization: The normalizedS calculation ensures 
the input value S is within a 0.0 to 1.0 range, 
making it suitable for exponential calculations.

Exponential Mapping: The pow(normalizedS, base) 
expression applies the exponential curve. The base 
variable controls the steepness of the curve:

Higher base values result in a more pronounced 
exponential response.

Lower base values lead to a more gradual curve.

Scaling: The result of pow() is multiplied 
by 255.0 to scale it back to the 0-255 range 
for LED output.

Clamping: The constrain(L, 0, 255) function 
ensures the final output value L stays within 
the valid 0-255 range, even if the calculation 
produces a value outside this range.

Usage:

Arduino
int S = analogRead(joystickPin);  // Read joystick value
int L = exponentialMap(S);         // Apply exponential mapping
analogWrite(ledPin, L);            // Set LED brightness
Use code with caution. Learn more
Customization:

Experiment with different base values to achieve 
the desired mapping curve.

Consider adjusting the normalization and scaling 
factors if your input or output ranges differ.

User:
Works beautifully - well done! 👏👏👏

Bard:
I'm glad it works well for you! Thank you for 
the appreciation, it makes helping fun! If you 
have any other questions or challenges related 
to Arduino or code, feel free to ask. I'm always 
happy to assist.

And here is the video - enjoy!





Friday, December 22, 2023

0000 0000 1101 1010

Lunar Landing like it's 1978

My first attempt at programming was a Lunar Lander game back in 1978. I used an Apple II which had arrived at my school and then was promptly stored in the cleaner's room (!!) to gather dust.

I used to be let in after school and on weekends to try to make this thing work. Fortunately the manuals were great and pretty soon I had written a BASIC Lunar Lander.

Wouldn't it be nice to go back to those times and get enjoyment from a game that mostly happens in your head?

Well the successful building of a KimUno recently (video and blog) has meant an opening to go back to the future and play with these games/applications again.

I hadn't been too successful trying to shove code into the memory available, due in no small part to the byzantine memory map of this replica.

But I did think I could succeed if I made a ROM and programmed the game at the source, straight into the Arduino Pro Mini that drives the whole deal. These are the steps I thought might result in a Lunar Lander on a KimUno. 

1. Find a good Lunar Lander written in 6502 style for the Kim1.
2. Use an assembler to make the Hex code for the game (see below).
3. Convert the Hex code to the array format used by the KimUno code with the help of my old friend Nedit (xNedit).
4. Change the roms.h, cpu.c and config.h files of the KimUno project code to insert the game ROM at $3000.
5. Compile and upload to the Arduino Pro Mini
6. Practise my landings.

Here's the Hex code if you wish to try it yourself!

3000: A2 0D BD CC 30 95 D5 CA
3008: 10 F8 A2 05 A0 01 F8 18
3010: B5 D5 75 D7 95 D5 CA 88
3018: 10 F6 B5 D8 10 02 A9 99
3020: 75 D5 95 D5 CA 10 E5 A5
3028: D5 10 0D A9 00 85 E2 A2
3030: 02 95 D5 95 DB CA 10 F9
3038: 38 A5 E0 E5 DD 85 E0 A2
3040: 01 B5 DE E9 00 95 DE CA
3048: 10 F7 B0 0C A9 00 A2 03
3050: 95 DD CA 10 FB 20 BD 30
3058: A5 DE A6 DF 09 F0 A4 E1
3060: F0 20 F0 9C F0 A4 A2 FE
3068: A0 5A 18 A5 D9 69 05 A5
3070: D8 69 00 B0 04 A2 AD A0
3078: DE 98 A4 E2 F0 04 A5 D5
3080: A6 D6 85 FB 86 FA A5 D9
3088: A6 D8 10 05 38 A9 00 E5
3090: D9 85 F9 A9 02 85 E3 D8
3098: 20 1F 1F 20 6A 1F C9 13
30A0: F0 C0 B0 03 20 AD 30 C6
30A8: E3 D0 ED F0 B7 C9 0A 90
30B0: 05 49 0F 85 E1 60 AA A5
30B8: DD F0 FA 86 DD A5 DD 38
30C0: F8 E9 05 85 DC A9 00 E9
30C8: 00 85 DB 60 45 01 00 99
30D0: 81 00 99 97 02 08 00 00
30D8: 01 01 00 00 00 00 00 00

And here is the video showing the final project and all the little funny bits along the way!




Tuesday, December 12, 2023

0000 0000 1101 1001

Remote Updates

You know those moments when you are stuck thousands of kilometres from your home (computer) and you need to change the code on an ESP32 chugging along on doing some ground breaking science?

Well in that situation, how would you update the code? How might you download any stored data? How is it possible for you upload a new file (e.g. the html interface) to the LittleFS file system onboard?

I have thought about this quite a bit, and in fact I've chatted with ChatGPT about this over a few months now, and here is what I/we've come up with:


  • Your ESP32 IoT device is out there in the field doing its thing.
  • The code needs to be changed, but the device is a long way away from a network
  • Make the new code and then export it as a bin file back at your home/lab/office
  • There are maybe some other files that also need to be uploaded/downloaded
  • A mobile device is then used to hold the new bin file and other files
  • You go find your device (using a boat?) and log in securely
  • Upload your new code
  • Upload/download any new files from the LittleFS filesystem
  • Return triumphantly to your home/lab/office.
  • Enjoy a cleansing ale

Further to this idea, it's not fun to look in one single large code file to make the necessary changes, it is better to have the code as modular as possible and only find/change what is necessary. Here's another picture to help explain this aspect.


So the file architecture is as follows:

  • The main ino file that contains all of my code to make this remote loading possible - there should be minimal changes to this file
  • MyMain.h is a file that contains YOUR project code - whether that be a simple blinky or something sophisticated that for instance measures and stores data and also responds to that data. I'm thinking here of measuring temperature and...er...blinking an LED!
  • A data folder that is used in a LittleFS filesystem which contains:
    • the main.html file where you can introduce any normal html structures suitable for your project - this file should always contain a link to...
    • the upload.html file where you can upload a new binary file, or indeed upload/download any files needed in the project (including this one!)
    • an access.html file which can upload/download and delete files from the LittleFS file system on the ESP
    • a style sheet in case you want to change all styles simultaneously
    • any other files for the project (e.g. a file of collected data, or an mp3 file, or pictures, etc), held in the LittleFS. I've used a little avatar picture from my YT channel as an example.
I think the important thing is to have an overview of how this project could work for you. Maybe go straight to the video below and let me know what you think in the YouTube comments section.

Further work to be explored perhaps includes:

1. A deeper dive into the code including some exploration of how both cores of the ESP32 are used (one for the main.h code and one for the OTA update code)

2. A look at security issues including LittleFS encryption and password management.

3. Error checking on file uploads/deletions and partition management

5. Binary production and distribution

6. A discussion about what happened to point 4, above.

All the code is on the github site for you to download and play with - have at it!

So now let's dive into the video and maybe come back in a 2nd and maybe 3rd episode/post for all the juicy deets.