Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions ArduinoFreevalve/ArduinoFreevalve.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// An Arduino program for controlling valve timing on a 6.5HP Predator engine from Harbor Freight.
//
// License goes here?
//
// Wesley Kagan, 2020
// Ric Allinson, 2020

// Pins assignment.
const int HALL_MAGNET = 2;
const int EXHAUST_V = 12;
const int INTAKE_V = 13;

// Control constants.
const int DEG_PER_MAGNET = 6; // Number of degrees for per magnet.
const int ROTATION_TWO = 760/DEG_PER_MAGNET; // Number of interrupts in the full cycle.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be 720 / DEG__PER_MAGNET. However, a 60-2 wheel has 58 trigger edges over 360 degrees. Shouldn't there 58*2 -> 116 interrupts per cycle, not 120?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I totally messed up that maths. Why is it 60-2? One for the missing tooth and one for zero based array?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I made the assumption that he had made a standard 60-2 (60 teeth, 2 missing teeth) wheel. Re-watching the video it almost looks like a 60-1 wheel. Either way, it might be easier to define all of these in terms of teeth:

    static constexpr int NUM_TEETH = 60;
    static constexpr int NUM_MISSING_TEETH = 2;
    static constexpr int NUM_TRIGGER_EDGES = NUM_TEETH - NUM_MISSING_TEETH;
    static constexpr int DEG_PER_MAGNET = 360 / NUM_TEETH; // Number of degrees for per magnet.
    static constexpr int TRIGGERS_PER_CYCLE = NUM_TRIGGER_EDGES * 2;     // Number of interrupts in the full cycle.
    static constexpr int TRIGGERS_PER_ROTATION = NUM_TRIGGER_EDGES; // Number of interrupts in a half cycle
```.

This way if a change to the trigger wheel design is made you can just update the NUM_TEETH and NUM_MISSING_TEETH.  This would make the intake/exhaust maps a little more complicated.  This could be overcome by creating the maps on an arbitrary grid and then interpolating for the current calculated crank angle.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, rather than teeth I've used STEPS incase there is ever a different way to generate position data. It follows the conventions of stepper motors which implement a similar positioning index system.

I didn't use constexpr as I'm not sure it is a standard for the Arduino?

const int ROTATION_ONE = (760/DEG_PER_MAGNET)-1; // Number of interrupts in a half cycle.

// Runtime mapping variables.
bool intakeMap[ROTATION_TWO] = {}; // Intake open/close mapping is equal the total number of interrupts for two rotations.
bool exhaustMap[ROTATION_TWO] = {}; // Exhaust open/close mapping is equal the total number of interrupts for two rotations.

// ISR variables.
volatile int hallCounter = 0; // The number of magnets after the last TDC.
volatile bool secondRotation = false; // "true" if the cam is on its second rotation.
volatile bool printLog = false; // Used to stop duplicate values from printing in the loop.
volatile unsigned long timeGap = 0; // Function level time between interrupts.
volatile unsigned long lastTimeGap = 0; // Global level time between interrupts.

void setup() {
Serial.begin(115200);
pinMode(HALL_MAGNET, INPUT);
attachInterrupt(0, magnetDetect, RISING);
pinMode(INTAKE_V, OUTPUT);
pinMode(EXHAUST_V, OUTPUT);
// Load mappings here.
// intakeMap = ?
// exhaustMap = ?
}

void loop() {
// This may not print all values. Only the most recent from the last interrupt.
if(printLog){
Serial.print(lastTimeGap);
Serial.print(hallCounter);
Serial.print(secondRotation);
printLog = false;
}
}

// This function will be called about every 15.79ms at the maximum RPM of 3800.
void magnetDetect() {
// Increment the counter to keep track of the position.
hallCounter++;
// Get the time gap between this interrupt and the last.
timeGap = millis() - lastTimeGap;

// Find the missing tooth for Top Dead Center (TDC).
if (timeGap >= lastTimeGap * 3 / 2) {
// On the second rotation reset the hallCounter.
if (secondRotation) {
hallCounter = 0;
} else {
hallCounter = ROTATION_ONE; // Forcing the counter in case of drift over a rotation.
}
// Flip the secondRotation.
secondRotation = !secondRotation;
}

// Store the last time difference so we can use it in the next interrupt.
lastTimeGap = timeGap;

// If the hallCounter is greater than the mapping index reset it.
// This would only happen when the missing tooth was NOT detected.
if (hallCounter >= ROTATION_TWO) {
hallCounter = 0;
}

// Use the intake/exhaust maps to open or close the valves.
digitalWrite(INTAKE_V, intakeMap[hallCounter]);
digitalWrite(EXHAUST_V, exhaustMap[hallCounter]);

// Tells the loop() that values have changed.
printLog = true;
}
71 changes: 0 additions & 71 deletions ArduinoHallEffect_good_code.ino

This file was deleted.

13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
# Freevalve_Arduino
Codebase for the Arduino Freevalve Project- found here: www.youtube.com/c/wesleykagan
# Arduino Freevalve

Repository for the Arduino Freevalve Project at www.youtube.com/c/wesleykagan

## Overview

This code is tested with the [Harbor Freight 6.5hp 212cc OHC Horizontal Shaft Gas Engine EPA&CARB](https://www.harborfreight.com/engines-generators/gasoline-engines/65-hp-212cc-ohv-horizontal-shaft-gas-engine-epacarb-69727.html)

## Original README

Okay, so this is a super early stage of this project, but as of this post, it does work in the configuration uploaded.

If you want to do nothing else becides make the test engine run, edit the two degree functions as noted in the comments. One is intake, one is exhaust. It will require some
If you want to do nothing else besides make the test engine run, edit the two degree functions as noted in the comments. One is intake, one is exhaust. It will require some
tweaking to perfectly work. My values were around 252 degrees Open and 102 Close (next cycle) For exhaust, and then 30 degrees open and 252 Closed for intake. I will update as I get a better understanding of the abilities- there's a few odd things with this cam that I'm still working through.

CAD files can be found here: https://www.thingiverse.com/thing:4678730
Expand Down