Autolaturi mökille varavoimaksi Arduinon avulla

Liittynyt
10.07.2017
Viestejä
621
Järjestelmän rakenne on muuttunut moneen kertaan. Alla oleva aloituspostaus on pääosin vanhentunut. Luethan viimeiset viestit! -Tupsa 25.2.2025


Johdanto

Nyt olisi käsillä mielenkiintoinen projekti. Mökille olisi tarkoituksena tehdä 12 voltin aurinkosähkölle ”varavoimalaksi” tarpeeton Fordin autolaturi, jolla ladattaisiin tarpeen tullen akustoa. Tätä laturia pyörittäisi tavanomainen bensairtomoottori moniurahihnan välityksellä. Mekaaninen puoli työstä onnistuu, ja lisäksi lähtökohtana ovat riittävät kolvaustaidot ja P = UI, sekä kyky kopioida valmista koodia tehden siihen marginaalisia muutoksia, joten tästä projektista saanee hyvän kädet otsalle n00bin aloituskosketuksen elektroniikkarakentelun ja koodauksen ihmetyttävään maailmaan!

Viime aikoina olen kovasti googlaillut ja pohtinut tekoälyn (!) kanssa toteutusta. Nyt olen tullut siihen johtopäätöksen, että pää tulvii erilaisia vaihtoehtoja toteuttaa tätä proggista. Lähipiirissä ei ole elektroniikkarakentelun ja koodauksen taitavia, joten ajattelin, että on viisasta perustaa ketju tästä projektista. Tästä voi olla hyötyä kenelle tahansa oppimis- ja soveltamismielessä.

Varastosta löytyy Fordin 80 ampeerin autolaturi, joka toimii ainoastaan, kun sen lataussäädin saa PWM-ohjauksen. Tätä hoitaa autossa moottorinohjausyksikkö, eli PCM. Koska nyt laturi on saatava toimimaan irrallaan autosta, se onnistuisi Arduinon avulla, joka voisi tuottaa laturille sen tarvitseman signaalin. Laturi vaatii 14 voltin amplitudilla olevan 125 hertsin kanttiaallon Duty Cycle alueella 5-95 prosenttia, josta käyttökelpoinen alue akun nopeassa latauksessa on noin 50-70 prosenttia. Tällä alueella latausjännite on noin 14,0-14,5 volttia. Laturin säätimen sielunmaailmasta voi lukea lisää tästä. Kyseessä on Magneti Marelli -tyyppinen säädin.

Mitä järjestelmältä haluttaisiin?

  • Moottorinkäynnistyksen kevennys
    • Laturi tuottaa ladatessaan niin voimakkaan vastuksen, että moottori ei jaksa matalilta kierroksilta käynnistyä.
    • Moottorin käynnistyttyä laturin säätimelle menevän Duty Cyclen tulee kasvaa matalalta, esim. 5 prosentista liukuvasti, esim. 5 sekunnissa käyttäjän potentiometrillä asettamaan arvoon.
  • Käyttäjä voi säätää latausjännitettä Duty Cycle alueella 50-70 prosenttia helposti potentiometrillä.
  • Moottorin automaattinen sytytysvirran katkaisu, kun latausvirta laskee alle määritellyn rajan (esim. 5 A).
    • Käyttäjän ei tarvitse seurata vähän väliä tilannetta erikseen ja hoitaa sammuttamista manuaalisesti.
  • Säänkestävät komponentit (koteloinnillahan nämä varmasti ratkeavat, potentiometri löytynee myös, joka kestää ulkoilmaa).
  • Optionaalisena yksinkertainen näyttö, jossa näkyy senhetkinen latausvirta ampeereina (A) ja latausjännite voltteina (V). Arduinon yleisintä näyttötyyppiä, LCD:tä, katsottuani, voi olla ettei näyttö toimi alle 0 asteen lämpötilassa. Joten pitäisi miettiä, onko näyttö mahdollinen.

Mietitään, mitä ylläoleva voisi tarkoittaa. Aloitetaan perustoiminnasta. Arduino syöttää vaadittua 14 voltin amplitudin ja 125 hertsin PWM-signaalia laturin kyseen osaiseen pinniin. Käyttäjä voi säätää latausjännitettä Duty Cyclellä alueella 50-70 prosenttia, joka kääntyy laturin lataussäätimessä noin 14,0-14,5 volttiin.

Poikkeuksena on moottorin ja laitteiston käynnistysvaihe. Jotta moottori jaksaa varmasti käynnistyä, Duty Cyclen ja tätä kautta latausjännitteen tulee siirtyä moottorin käynnistyttyä liukuen esimerkiksi noin viidessä sekunnissa käyttäjän asettamaan, potentiometrin määräämään arvoon. Kysymys: millä moottorin käynnistyminen todetaan? Pelkkä aikaviive ei ehkä käy, jos käyttäjä ei nykäisekään moottoria siinä ajassa käyntiin?

Miten olisi moottorin käynnistymisen varmentaminen tulpanjohdosta? Esimerkiksi Bilteman kierroslukumittari toimi hienosti aikoinaan mopossa, kun kiersi mittarin johdon vain tulpanjohdon ympärille? Voisiko tätä ajatusta jotenkin soveltaa? Jos tulpanjohdolta tulee sykkimistä vähintään 10 sekunnin ajan, niin aloitetaan Duty Cyclen liukuva ylösajo?

Moottorin automaattinen sammutus, eli sytytysvirran katkaisu tapahtuu normaalilla releellä, johon Arduinon on annettava heräte, kun latausvirta laskee alle koodissa määritellyn kynnyksen, esimerkiksi 5 ampeeria.


Komponentit

Sitten voisi pohtia, mitä tähän projektiin tarvittaisiin. Homma olisi hyvä toteuttaa mahdollisimman vähällä koodilla ja komponenttien määrällä sekä hinta-laatusuhteeltaan parhaimmilla komponenteilla. Eli sellaisilla, jotka kestävät ainakin vuosia, mutta kuitenkin niin, että budjetti pysyisi alle 40 eurossa. Myös ulkomailta voidaan tilata komponentit. Luin myös Arduino-klooneista. Toivottavasti jo nykyään on luotettavia klooneja. Alkuperäinen kortti taitaa olla kolmisen kymppiä.

Tässä on ajatuksia mahdollisista ehdotuksista komponenteiksi. Huomaa, että voi olla väärin tai huonosti valittuja ainakin jotkut komponentit, koska en siis ole elektroniikkarakentelussa auttavaa kytkentäkaavion lukemista ja kolvaamista pidemmällä. Olisin mielissäni, jos ehdottaisit laittaa vaikka koko komponenttiluettelon laittaa uusiksi, jos nämä on huonoja valintoja!

Arduino kortti

PWM-lähtö

  • MOSFET???
Tarviiko PWM-lähtöön tämmöisen MOSFET-komponentin, kun Arduino lähtö on vain ilmeisesti 40 mA, ettei piiri kärähdä? Olisiko peräti varmuuden vuoksi jo hyvä laittaa tämmöinen komponentti, kun ei ole varmuutta, millaiset virrat laturin PWM-ohjuksessa liikkuvat?

Säänkestävä potentiometri, PWM-ohjauksen Duty Cycle säätöön
  • ???
Latausvirran mittaus

Millä latausvirta on helpompi niin kytkentöjen kuin koodin kannalta mitata, virtamuuntajalla vai shunttivastuksella? Äkkiseltään shuntit olivat virta-alueelle 0-100 A turhan hintavia. Lisäksi shuntit ilmeisesti tuottavat aimo annoksen lämpöä. Onko virtamuuntaja (current transducer) taas herkkä EMILLE, eli sähkömagneettisille häiriöille, joita luulisi esiintyvän jossain määrin käyvän moottorin ja laturin läheisyydessä? Jotenkin tässä nyt kaikesta huolimatta eniten kutittelee tuommoinen virtamuuntaja, koska siinä virtapiiriin ei tarvitse kajota.

Virtamuuntaja

Releen ohjaus

Ilmeisesti myös releelle tarvitaan erillinen ohjauskortti, kun Arduino ei pysty tuottamaan niin paljon virtaa releen ensiöpiiriin.


Moottorin käynnistymisen varmennus

  • ???
Mittaus tulpanjohdon ympäriltä TAI ensiökäämiltä, eli siitä samaisesta johdosta, joka on automaattisessa sammutuksessa. Mikä komponentti tähän tarvitaan? Ainakin tulpanjohdon jännite on kova, joten varmasti jotain suojausta vaaditaan jopa pelkän tulpanjohdon ympärille käärityn johdon ja Arduinon välillä. Kierroslukumittausta ei tarvita laisinkaan, vaan pelkkä tieto signaalin jatkuvuudesta mitattuna esim. 500 millisekunnin välein 10000 millisekunnin aikana.


Virtalähteet ja konvertterit

Arduino tarvitsee luotettavan 5 voltin tasasähkön, johon tarvitsisi jonkun tasasähkölähteen, eli virtalähteen sisääntulojännite voi olla laajalla skaalalla esim. 9-20 volttia, koska se vaihtelee väistämättä ainakin sen 12-14,5 voltin välillä.
  • Virtalähde (mikä?) Arduinolle ja virtamuuntajalle

Ilmeisesti Arduino ei suoraan pysty tuottamaan 14 voltin amplitudin PWM:ää, joten joku konvertteri ilmeisesti vaaditaan Arduinon PWM-lähtöön.
  • Operaatiovahvistin (mikä?) ja pari vastusta (mitkä?)


Vaihtoehtoiset lisäjutut: Näyttö, jossa näkyy ampeerit ja voltit

Yhteiskatodinen 7-segmenttinäyttö, tuplanäyttö, jossa näkyisi latausvirta (A) ja -jännite (V) rinnakkain

Ilmeisesti LCD-näyttö jäätyy tai menee ainakin jumiin alle nollan lämpötiloissa, niin siksi ajattelin näytöksi segmenttejä.
  • Jännitteenjakaja

Tähän liittyvä jännitteen mittaus tulisi toteuttaa ilmeisesti jännitteenjakajalla, jos ajatellaan mittausalueeksi 0-20 volttia, niin jännitettä tulisi jakaa suhteessa 3:1 neljään osaan, jolloin mittausalue sopii Arduinolle 0-5 volttia. Vastuksilla 30 ja 10 kOhm.


Yhteenveto komponenteista

Eli varsin monisyinen paketti ja melko paljon taitaa tulla komponentteja. Tässä hieman yhteenvetoa, yritän parhaani mukaan laittaa tärkeysjärjestykseen:
  1. Arduino kortti
    UNO R3 kehitysalusta Arduino yhteensopiva kopio ilman USB kaapelia | SP-Elektroniikka Oy (spelektroniikka.fi)
  2. 9-24 V DC-DC 5 V virtalähde Arduinolle, ja tarvittaville oheiskomponenteille, olisiko esim. 2 A, jotta varmasti riittää?
    ???
  3. Moottorin käynnistyksen varmennus komponentti; tulpanjohto TAI ensiökäämin johto
    ???
  4. Operaatiovahvistin (mikä?) ja pari vastusta (mitkä?)
    ???
  5. Säänkestävä potentiometri
    ???
  6. Virtamuuntaja
    HLSR 50-P/SP3 - Lem - Current Transducer, HLSR-P Series, Open Loop (farnell.com)
  7. Relekortti
    Relekortti optoerottimella yksi 5V rele 1xvaihto, liipaisu valittavissa | SP-Elektroniikka Oy (spelektroniikka.fi)
  8. Segmenttinäyttö
    8 Digit Bit Max7219 Digital Tube Display Module Board 7 Segment Digital Led Display 5v/3.3v Controller For Arduino 51/avr/stm32 - Integrated Circuits - AliExpress
  9. Jännitteenjakokytkentä, jännitteen mittaukseen
    10 ja 30 kOhmin vastukset

Sähkökytkennät

Mitä pitää huomioida komponentteja yhdistäessä? Miten maadoitukset hoidetaan niin, etteivät laitteiston eri osien häiriöt häiritse Arduinon toimintaa? Käsitykseni mukaan, laturin/akun maata ei saisi yhdistää Arduino kortin maahan, vaan Arduino kortti maadoitetaan vain sille sähköä syöttävän virtalähteen miinukseen.

Millä tavalla PWM-lähdön maadoitus pitää hoitaa? Lataussäätimen maahan täytyy olla sama kuin itse laturin maa, joten miten laturin maa vedetään Arduinoon, kun sitä ei kai suoraan saisi häiriöiden välttämiseksi vetää Arduino kortille. Ehkäpä tämä mystinen MOSFET tulee tässä apuun!


Koodi

Tekoälyn pääosin luoma ja minun joiltakin osin muokkaamana olisi koodivedos olemassa. Ainakin se menee compilesta läpi, että hujahtaa. Mutta koodissa on varmastikin työstettävää ja virheitä. Tämä selviää, kunhan ensin olisi komponentit pöydällä.

Alkutoiminnon tarkoitus olisi siis käyttää tulpanjohdon signaalia alkutoiminnon laukaisemiseksi niin, että jos tulpanjohdolta saadaan signaali 10 sekunnin ajan, käynnistetään alkutoiminto, jossa Duty Cycle nousee potentiometrin määräämään arvoon 5 sekunnissa.

Latausvirtaan perustuva moottorin sammutusreleen toiminta pitää estää alkutoiminnon yhteydessä. Moottoriahan ei voisi käynnistää, koska latausvirta on luonnollisesti nollassa, ja rele estäisi moottorin käynnistymisen. Laitoin tulpanjohdon signaalin tarkistuksen myös tähän kohtaan.

Koodista puuttuu vielä ainakin vaihtoehtoiset hifistelytoiminnot näyttö sekä volttimittaus. Volttimittaukseen pitäisi tehdä rivi, jossa neljännesjännite kerrotaan oikeaan. Eli esim. 1 voltti on oikeasti 4 volttia.

Voisimme katsoa ensin komponentit ja sähkökytkennät ja sitten voisikin alkaa testata koodia. Toki, koska Arduinon täytyy joka tapauksessa ainakin analogituloissa saada signaalina aina 0-5 volttia (näin olen ymmärtänyt), niin mahdollisesti tuolloin vielä puuttuvia antureita on helppo simuloida tuolla jännitealueella.


Loppuyhteenveto

Kaiken kaikkiaan tässä on varmaan aika paljon asiaa ja pureskeltavaa. Toivottavasti jaksoit lukea! Odotan innolla vinkkejä ja ohjeita, kuinka tämmöinen saataisiin toteutettua. Ja sitäkin, että joku sanoo, älä nyt noin tee vaan näin! :D
 
Viimeksi muokattu:
Liittynyt
08.03.2017
Viestejä
88
itellä kans paikallismoottorista ja jostai vanhasta auton laturista tehty värkki mökillä jossa on vain aurinkosähköt. sen käyttö ajoittuu lähinnä syksystä keväälle kun aurinkoa ei paljoa ole. mietin kanssa yhes kohtaa jotain automatioota sen käynistykseen jos akkujen jännite laskee alle x määrän mutta totesin sen olevan liian haastavaa. helpompi vain mennä talliin katsomaan akkujen tila jos epäilee että ne on vajaat. se hyvä puoli vanhan auton laturissa että kun laturi pyörii niin käämi tarvii vaan nopeasti herättää sen jälkeen jäännosmagnetismi jatkaa.
 
Liittynyt
31.07.2017
Viestejä
112
Rehellisesti sanottuna en lukenut koko viestiä suunniteltuine spekseineen, mutta itse lähtisin hieman erilaisesta ajatuksesta liikkeelle:
Laturiksi valitsisin "GM 1 wire" laturin, mitä löytyy esim. kaikista letukoista yms 70-luvulta asti ja on ehkä yleisimpiä yleislaturityyppejä jos harrasteautoihin / veneisiin tms ruvetaan uutta pykäämään. Muistaakseni Motonetistäkin noita löytyy, mutta Rockautossa / Ebayssa / Aliexpressissä ne eivät halvimmillaan maksa juuri mitään. "1 wire" on vähän harhaanjohtava, sillä laturiin menee kaksi johtoa: paksu ulostulokaapeli ja ohut herätevirta. Jännitteensäätimet yms on laturiin sisäänrakennettu, eikä se vaadi PWM signaaleita regulointiin.

Oletan että moottori on hieman vanhempi, missä on vielä erillinen vanhanmallinen puola ja kierreterminaalit ovat helposti näkyvissä? Kierroslukutieto saadaan puolan johdoilta, niihin kierroslukumittaritkin kytketään. Moderneimmissa CDI-sytkällisissä pienmoottoreissa kierroslukutieto saadaan joltain sytkäboksin karvalta vielä helpommin, kunhan kytkentäkaavio on saatavilla. Logiikan toteuttaisin niin yksinkertaisesti, että kierrosluvun ollessa x, arduino lähettää releelle sulkukäskyn ja rele puolestaan syöttäisi +12V laturin herätejohtoon.
Itse latausprosessia ei tuossa pystyisi enempää kontrolloimaan, koska laturi hoitaa sen sisäisesti.

Koska jännite pysyy tuossa tapauksessa melko vakiona, ei sitä voida käyttää indikaattorina akun lataustasosta. Sen sijaan virtaa voidaan, joten käyttäisin jotain virtashunttia mittaamaan laturilta akkuun menevän virran ja sen laskiessa <5A tienoille, arduino voisi katkaista moottorin puolalta virran ja lataus loppuisi moottorin sammuttua.

Itseasiassa mulla on "toteutetaan joskus eli ei ikinä" projektilistalla vähän vastaava, mutta apukäynnistysajatuksella. Jokin pieni moottorisaha tms 2t-laite, johon pulttaan kiinni vastaavan laturin ja sillä pystyisi antamaan henkeä jollekin - lähinnä omalle pakulle, mitä käytetään kerran parissa kuukaudessa - ilman tarvetta raahata painavaa lyijyakkua mikä osoittautuukin tyhjäksi.
 

dmn

Liittynyt
07.11.2016
Viestejä
1 656
Taitaa monessa vanhanaikaisessa laturissa itsessäänkin olla jo lataussäätimessä toiminta, joka kytkee latauksen päälle vasta kuin on tarpeeksi kierroksia. Moni vanhempi autoilija varmaan muistaa että luistavalla hihnalla jää laturin valo palamaan, ja hieman kun antaa kaasua niin sammuu.

Kierrosnopeuden voi varastaa laturin yhdestä laturin vaiheesta ennen tasasuuntaajaa.
 
Liittynyt
18.10.2016
Viestejä
524
no ainakin optoerotus 5v /12v puolelle niin ei käryä nuo 5v vehkeet , ja mitä lisäarvoa potikka tuo? Miksi käyttäjän pitää päästä säätämään lataus tehoa?. eikö tuon koko paskan konffais arduinolle joka valvoo akustoa ja tekee päätökset itsenäisesti. Eli jos jännite akustossa laskee arduino komentaa bensa motin tulilla ja laturin lataamaan ja taas kun akusto tai paneelit lataa sammutetaan bensamotti? itse ainakin suunittelisin systeemin niin että homma pelittää niin kauan kun bensaa riittää
 
Liittynyt
10.07.2017
Viestejä
621
Rehellisesti sanottuna en lukenut koko viestiä suunniteltuine spekseineen, mutta itse lähtisin hieman erilaisesta ajatuksesta liikkeelle:
Laturiksi valitsisin "GM 1 wire" laturin, mitä löytyy esim. kaikista letukoista yms 70-luvulta asti ja on ehkä yleisimpiä yleislaturityyppejä jos harrasteautoihin / veneisiin tms ruvetaan uutta pykäämään. Muistaakseni Motonetistäkin noita löytyy, mutta Rockautossa / Ebayssa / Aliexpressissä ne eivät halvimmillaan maksa juuri mitään. "1 wire" on vähän harhaanjohtava, sillä laturiin menee kaksi johtoa: paksu ulostulokaapeli ja ohut herätevirta. Jännitteensäätimet yms on laturiin sisäänrakennettu, eikä se vaadi PWM signaaleita regulointiin.

Oletan että moottori on hieman vanhempi, missä on vielä erillinen vanhanmallinen puola ja kierreterminaalit ovat helposti näkyvissä? Kierroslukutieto saadaan puolan johdoilta, niihin kierroslukumittaritkin kytketään. Moderneimmissa CDI-sytkällisissä pienmoottoreissa kierroslukutieto saadaan joltain sytkäboksin karvalta vielä helpommin, kunhan kytkentäkaavio on saatavilla. Logiikan toteuttaisin niin yksinkertaisesti, että kierrosluvun ollessa x, arduino lähettää releelle sulkukäskyn ja rele puolestaan syöttäisi +12V laturin herätejohtoon.
Itse latausprosessia ei tuossa pystyisi enempää kontrolloimaan, koska laturi hoitaa sen sisäisesti.

Koska jännite pysyy tuossa tapauksessa melko vakiona, ei sitä voida käyttää indikaattorina akun lataustasosta. Sen sijaan virtaa voidaan, joten käyttäisin jotain virtashunttia mittaamaan laturilta akkuun menevän virran ja sen laskiessa <5A tienoille, arduino voisi katkaista moottorin puolalta virran ja lataus loppuisi moottorin sammuttua.

Itseasiassa mulla on "toteutetaan joskus eli ei ikinä" projektilistalla vähän vastaava, mutta apukäynnistysajatuksella. Jokin pieni moottorisaha tms 2t-laite, johon pulttaan kiinni vastaavan laturin ja sillä pystyisi antamaan henkeä jollekin - lähinnä omalle pakulle, mitä käytetään kerran parissa kuukaudessa - ilman tarvetta raahata painavaa lyijyakkua mikä osoittautuukin tyhjäksi.
Moottoria ei vielä ole edes hankittu! Voi olla moderni tai ikivanha.

Itsellä kyllä kiinnostaisi myös eniten tuo 1-wire-laturi. Laturit vaan tänä päivänä maksaa aika paljon, lähes 100 euroa. Kun tarkoitus olisi pitää homman kulut mahdollisimman alhaisena. Hintana eurojen säästössä sitten toki on tämä kovempi värkkääminen. Mutta jos viitsii värkätä, lopussa toivottavasti kiitos seisoo. Jos sen laturin saisi max 40-50 eurolla, niin sittenhän tämä helpottuisi huomattavasti, kun tarvitsisi vain sen automaattisen sammutuksen.

Jännitteensäädin siis löytyy tässä Fordin laturissakin, mutta vaatii tosiaan tuon PWM-signaalin toimiakseen.

Kuinka kuumaksi tuollaiset 100 ampeerin shunttivastukset kuumenee? Näköjään näihinkin tarvii lisäkoodia ja lisäkomponentteja ihan kuin virtamuuntajiin Arduinossa... :(

no ainakin optoerotus 5v /12v puolelle niin ei käryä nuo 5v vehkeet , ja mitä lisäarvoa potikka tuo? Miksi käyttäjän pitää päästä säätämään lataus tehoa?. eikö tuon koko paskan konffais arduinolle joka valvoo akustoa ja tekee päätökset itsenäisesti. Eli jos jännite akustossa laskee arduino komentaa bensa motin tulilla ja laturin lataamaan ja taas kun akusto tai paneelit lataa sammutetaan bensamotti? itse ainakin suunittelisin systeemin niin että homma pelittää niin kauan kun bensaa riittää
No eipä se lataustehon säätö tosiaan mikään pakollinen ominaisuus olisi. PWM:n voisi laittaa koodissa vaan kiinteäksi ja kokeilla sillä, miltä vaikuttaa. Olisihan se kyllä hieno, jos joskus olisi semmoinen ohjaus, että Arduino jopa käynnistää moottorin automaattisesti pelkän sammutuksen lisäksi!
 
Liittynyt
18.10.2016
Viestejä
524
Jos hammastettu vauhtipyörä koneessa ja sähköstartti niin arduinolle voisi lukea Vauhtipyörän hampaista kierros luvun jollain auton vastaavalla anturilla jollain saisi dataa. Käykö kone
 
Liittynyt
31.07.2017
Viestejä
112
Moottoria ei vielä ole edes hankittu! Voi olla moderni tai ikivanha.

Itsellä kyllä kiinnostaisi myös eniten tuo 1-wire-laturi. Laturit vaan tänä päivänä maksaa aika paljon, lähes 100 euroa. Kun tarkoitus olisi pitää homman kulut mahdollisimman alhaisena. Hintana eurojen säästössä sitten toki on tämä kovempi värkkääminen. Mutta jos viitsii värkätä, lopussa toivottavasti kiitos seisoo. Jos sen laturin saisi max 40-50 eurolla, niin sittenhän tämä helpottuisi huomattavasti, kun tarvitsisi vain sen automaattisen sammutuksen.
Tjaa, olin oletuksessa että moottori olisi jo valmiina. Ehdottaisin että aloittaisit protoilemalla vetokäynnisteisellä versiolla: tori.fi:stä löytyy usein käyntivikaisia pari-kolme vuotta vanhoja ruohonleikkureita, mitkä saa kuntoon 10€ kaasarin rebuildisetin kanssa. Kalvot niistä menee, eikä normikuluttaja niitä ymmärrä vaihtaa. Rebuild kittejä taas saa jokaisesta pienkoneliikkeestä, myös Motonetistä. Leikkurin peltikuoriin on helppo väkertää laturin kiinnitys ja terän tilalle helppo asentaa siivapyörä. Kun paletti tuolla alkaa toimimaan, vasta sitten investoi useita satasia mihin ikinä sähkökäynnisteiseen moottoriin..

Toisaalta jos 100€ laturista kuulostaa kalliilta, olisin kyllä kiinnostunut kuulemaan minkälaista moottoria olet suunnitellut? Varsinkin jos luotettavuutta (käynnistyvyyttä) haetaan..?

Motonetissä nähtävästi on muutamaa yleismallin laturia (löytyy hakusanalla yleislaturi), mutta hinta on satasen päälle. Ebay ja ali varmaan osaa tarjota tuloksia hakusanalla "1 wire alternator gm" ja autodocistakin saa varmaan edukkaasti, mutta silloin pitää tietää jokin automalli, missä tuollaista on käytetty. Melkein kaikki amerikan GM-tuotteet 70-luvusta ysärille käytti jotain versiota tuosta. Vaikkapa 1986 G20 Chevrolet Van 5.7, väittäisin että siinä on tuollainen laturi ja osia saattaa saada vielä autodocistakin.

Kuinka kuumaksi tuollaiset 100 ampeerin shunttivastukset kuumenee? Näköjään näihinkin tarvii lisäkoodia ja lisäkomponentteja ihan kuin virtamuuntajiin Arduinossa... :(
Itseasiassa turvallisempi ja ehkä helpompikin vaihtoehto voisi olla pihtivirtamittarityylinen anturi, missä syöttöjohto vain menee loopin läpi. Suurempaa virtaa mittaavat nähtävästi vain menevät reiluun pariin kymppiin kun <50A versiot on kolikoita:
 
Liittynyt
17.01.2018
Viestejä
2 084
Kierrokset kannattaa tulpan sijaan ottaa vanhemmissa suoraan puolalta (jännitteen alennus & tasasuuntaus tarvitaan) ja uudemmissa voi saada sytkältä ulos. Tai jos akseli/hihnapyörä tms on saatavilla niin siihen sopiva ratas/magneetti ja opto/hall anturi toimii aina.

Oikein kytkettynä ei tarvitse optoja mutta ei ne kyllä haittaakaan.
Isommille ohjauksille aina fetit, jos ohjaa suoraan arduinolla niin pitää olla logic level eikä "normaali" joka vaatii isomman ohjausjännitteen. Tai sellaisen eteen pitää tehdä ohjainaste.
Tulot opton kautta tai jännitejako+transistori.

Arvaan että laturinkin pwm- ohjaus on vain alasvetoa koska se on helpompi tehdä.
 
Liittynyt
10.07.2017
Viestejä
621
@ississ, hyviä ohjeita, tutustumpa näihin. BTW laturi siis ei lataa lainkaan ilman PWM-signaalia.
 
Liittynyt
10.07.2017
Viestejä
621
No niin, eli homma on jo protovaiheessa ja speksit ovat muuttuneet alun perin suunnitellusta lähes täysin. Olisin nyt tehnyt vähän enempi testejä oskilloskoopin kanssa, olisiko ohjausboksi (vielä toistaiseksi ilman 12 voltin piirin testejä) toiminut, mutta en saa lcd:tä toimimaan. Näyttöön tulee virrat, mutta sen yläriville tulee neliöt, joka tietojeni mukaan tarkoittaa sitä, että tietoa ei liiku Arduinon ja näytön välillä. Minulla on myös toinen protoiluun tarkoitettu Uno R3 ja samanalainen I2C-väyläinen lcd-näyttö, johon ladattuna samalla koodilla sen näyttö toimii. Näytössä ei myöskään ole vikaa, koska kokeilin näyttöjä ristiin., ei myöskään kaapeleissa. Testasin näytölle menevistä pinneistä A4 ja A5 oskilloskoopilla, niin toimivassa protoilukortissa + näytössä "säkkärä" jatkui koko ajan, mutta tässä, jossa ei toimi, pulssit näkyvät vain vähän aikaa. Lisäksi näytön (tai väylän?) osoite löytyy sillä koodilla, jolla haetaan näytön osoite. 0x27. Mikä ihme vikana voi nyt olla?



Nykyiset laturiohjainprojektin speksit:
  1. Arduino Uno R3
  2. I2C LCD 16x2 näyttö
  3. Rele moottorin sammutukseen
  4. Shunttivastus + operaatiovahvistinpiiri latausvirran mittaukseen
  5. Tärinäanturi moottorin käynnissäolon tunnistukseen
  6. PWM:n "nostopiiri" (kaksi transistoria + vastuksia) 5 V:n pulssin nostamiseen akkujännitteelle
  7. Muita oheiskomponentteja, kuten virtalähde yms..

Lopuksi vielä tähän koodi, jossa on varmasti virheitä, koska se on pääosin tekoälyn luoma. Tein sittenkin kuitenkin jo jonkin verran testiä, niin ainakin ohjelma alku menee väärin, kun työsuhde alkaa heti nousta, kun virrat tulee päälle.

Eli koodin toiminta on
  1. Näytöllä näkyy koko ajan latausvirta ampeereina
  2. Mikäli tärinäanturilta saadaan signaali vähintään määrätyn ajan aikaa (esim. 6000 ms) nostetaan 125 Hz:n pulssin Duty Cycle 0 prosentista 60 prosenttiin määrätyssä ajassa (esim. 5000 ms)
  3. Pidetään Duty Cycle 60 prosentissa
  4. Mikäli latausvirta laskee alle halutun kynnyksen (esim. 5 A) annetaan sammutusreleelle heräte

Huom.! Pulssitaajuus tarkalleen 125 Hz ei tällä onnistu, mutta tietojeni mukaan pulssitaajuus ei tällaisessa sovelluksissa ole niin ajoituskriittinen. Kyseessä on vain muutaman hertsin ero.

Koodi:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Create a new LiquidCrystal_I2C display object with the correct I2C address and display size

// Define the pins
const int currentPin = A0;           //information about current
const int motorPin = 7;              //motor running pin
const int pwmPin = 9;                //PWM output pin
const int relayPin = 3;              //Relay control pin
float voltageFactor = 5.0 / 1023.0;  //Factor to convert ADC reading to voltage
float currentFactor = 80 / 4.62978;  //4.62978 volts = 80 amps, factor to convert voltage to current
const int N = 10;                    //number of readings to average
int readings[N];                     //array to store the readings

void setup() {

  Serial.begin(9600);  // Start the serial communication

  // Initialize the LCD here
  // Give the screen time to boot
  delay(3000);
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.clear();

  // Change timers on pins to change PWM freq to 122 Hz
  // Pins D9 and D10 - 122 Hz
  TCCR1A = 0b00000001;  // 8bit
  TCCR1B = 0b00000100;  // x256 phase correct

  // Make pins output/input
  pinMode(currentPin, INPUT);
  pinMode(motorPin, INPUT);
  pinMode(pwmPin, OUTPUT);
  pinMode(relayPin, OUTPUT);
}

void loop() {
  static unsigned long lastTime;
  static bool isInitialFunctionRunning;
  static bool isShutdownFunctionRunning;
  static unsigned long initialFunctionStartTime;
  static unsigned long shutdownFunctionStartTime;

  //Initial function
  // Check if the engine is running. If it has been running for at least six seconds, start the initial function.
  if (digitalRead(motorPin) == HIGH) {
    if (millis() - lastTime > 6000) {
      isInitialFunctionRunning = true;
      initialFunctionStartTime = millis();
    }
    Serial.println("Engine is running");  // Print a message when the engine is running
  } else {
    lastTime = millis();
    Serial.println("Engine is not running");  // Print a message when the engine is not running
  }

  // If the initial function is running, increase the Duty Cycle from 0 percent to 60 percent within five seconds.
  if (isInitialFunctionRunning) {
    if (millis() - initialFunctionStartTime < 5000) {
      int dutyCycle = map(millis() - initialFunctionStartTime, 0, 5000, 0, 60);
      analogWrite(pwmPin, map(dutyCycle, 0, 100, 0, 255));
      Serial.print("Duty Cycle: ");
      Serial.println(dutyCycle);  // Print the current duty cycle value
    } else {
      isInitialFunctionRunning = false;
    }
  }

  //Basic function
  // If the initial function is not running and the shutdown function is not running either, keep the Duty Cycle at 60 percent.
  else if (!isShutdownFunctionRunning) {
    analogWrite(pwmPin, map(60, 0, 100, 0, 255));
  }

  // Calculate the charging current from the average and display it on the LCD screen.

  // take N readings and store them in the array
  for (int i = 0; i < N; i++) {
    readings[i] = analogRead(currentPin);
    delay(10);  // wait for 10 milliseconds between readings
  }

  // calculate the average of the N readings
  float sum = 0;
  for (int i = 0; i < N; i++) {
    sum += readings[i];
  }
  float average = sum / N;

  float voltage = average * voltageFactor;  //  Convert ADC reading to voltage

  float current = voltage * currentFactor; // Convert voltage to current
  lcd.setCursor(0, 0);
  lcd.print("Latausvirta:");
  lcd.setCursor(0, 1);
  lcd.print((int)current);
  lcd.print(" ");
  lcd.setCursor(3, 1);
  lcd.print(" A");


  //Shutdown function
  // If the charging current drops below five amperes and the shutdown function is not running yet,
  // start the shutdown function and turn off the relay for sixty seconds.
  if (current < 5 && !isShutdownFunctionRunning) {
    isShutdownFunctionRunning = true;
    shutdownFunctionStartTime = millis();
    digitalWrite(relayPin, LOW);
    Serial.println("Shutdown function started");  // Print a message when the shutdown function starts
  }

  // If the shutdown function has been running for sixty seconds,
  // stop it and switch the relay. Then return to the initial function.
  if (isShutdownFunctionRunning && millis() - shutdownFunctionStartTime > 60000) {
    isShutdownFunctionRunning = false;
    digitalWrite(relayPin, HIGH);
    isInitialFunctionRunning = true;
    initialFunctionStartTime = millis();
    Serial.println("Shutdown function stopped");  // Print a message when the shutdown function stops
  }
}
 
Viimeksi muokattu:
Liittynyt
17.01.2018
Viestejä
2 084
Näyttöön tulee virrat, mutta sen yläriville tulee neliöt, joka tietojeni mukaan tarkoittaa sitä, että tietoa ei liiku Arduinon ja näytön välillä. Minulla on myös toinen protoiluun tarkoitettu Uno R3 ja samanalainen I2C-väyläinen lcd-näyttö, johon ladattuna samalla koodilla sen näyttö toimii. Näytössä ei myöskään ole vikaa, koska kokeilin näyttöjä ristiin., ei myöskään kaapeleissa. Testasin näytölle menevistä pinneistä A4 ja A5 oskilloskoopilla, niin toimivassa protoilukortissa + näytössä "säkkärä" jatkui koko ajan, mutta tässä, jossa ei toimi, pulssit näkyvät vain vähän aikaa. Lisäksi näytön (tai väylän?) osoite löytyy sillä koodilla, jolla haetaan näytön osoite. 0x27. Mikä ihme vikana voi nyt olla?
Ymmärsinkö nyt tästä oikein että on 2kpl Uno R3 ja 2 samanlaista näyttöä. Toisessa unossa molemmat näytöt toimii ja toisessa ei kumpikaan ?

Jos näin niin siinä jossa ei toimi voi olla eri ohjelma (varmista uudella uploadilla) tai kytkentävirhe (tarkasta kaikki johdot että on varmasti oikeissa paikoissa).
Ja molemmat unot on samaa mallia eikä toinen ole esim halpa kopio ?
Molemmissa sama käyttöjännite ja samat fuse- bitit (ehkä, jos ei ole erikseen vaihdettu). Kannattaa kuitenkin varmistaa.

Edit:
Tuosta pwm- taajuudesta vielä vähän jos vaikka haluaisit sen tarkan 125Hz.

Atmega328 dokumentaatiosta löytyy taulukko, pitää valita WGM13-WGM10 = 1010 eli "phase correct pwm, top = ICR1" jolloin taajuus määräytyy kaavalla f = clk / (2 * N * TOP)
ICR1 on 16bit rekisteri eli max = 65535. 5V Unon kello taitaa olla 16MHz eli jos valitaan f = 125, N = 1 niin TOP = 64000, pitäisi olla hyvin liki taajuuden puolesta.
Silloin:
TCCR1A = 0b00000010; // mieluummin = (1 << WGM11)
TCCR1B = 0b00010001; // mieluummin = (1 << WGM13) | (1 << CS10)
ICR1 = 64000;
OCR1A = pwm_val; // 16bit, 0 - 64000

Ja jos lähtee tälle tielle että "tekee itse" eikä kirjaston kautta niin silloin pwm% asetetaan myös suoraan OCR1A rekisteriin, arvot väliltä 0 - TOP eli tässä 0 - 64000.
Näillä asetuksilla jossa TOP > 255 ei voi käyttää analogwrite() koska se ottaa pwm- arvon vain 8bit lukuna.

Jos on laiska niin ennen omia käsiasetuksia voi kerran kutsua analogwrite(oikea_pin, 1) jolloin valmis funktio tekee ainakin osan määrityksistä, asettaa oikean pinnin lähdöksi jne. Ja heti sen perään oikea OCR1A arvo. Tämän jälkeen koodissa vain OCR1A arvon muutos niin pwm% muuttuu. Analogwrite(oikea_pin, arvo) voisi myös käyttää arvoilla 0 (= asettaa pwm pois ja lähtö alas) tai 255 (= pwm pois, lähtö ylös).
Itse tehden kannattaa kuitenkin välttää noiden valmiiden käyttöä koska ne voivat tehdä myös jotain jota ei ehkä haluaisi.
Toinen vaihtoehto on antaa valmiiden tehdä kaikki ja silloin koodissa ei mielellään saa olla noita alun TCCRxx asetuksia.

Disclaimer: vain nopeasti dokkaria vilkaisten ilman testausta eli ei ehkä toimi ihan suoraan näillä.
 
Viimeksi muokattu:
Liittynyt
10.07.2017
Viestejä
621
@ississ , tosi hyvä viesti!

Joo, eli tarkoitus olisikin käyttää kaikennäköisiä kirjastoja ynnä muita jotka sujuvoittaisivat koodin tekemistä. Eli voiko siis olla mahdollista että nuo jo tähän mennessä huomaamani ongelmat koodin toiminnassa voisivat johtua tuosta ajastin jutusta? Miten tuo ajastin kannattaisi siis säätää onko siihen olemassa jokin kirjasto tai muu sellainen, eli eikö tuota tcr... jne. kohtaa nyt sitten kannata olla tuossa kohdissa? Joka tapauksessa koodi olisi tarkoitus tehdä niin, että työsuhdetta on helppo muuttaa pelkästään koodista prosentteja muuttamalla. Eli siinä täytyy kuitenkin tehdä niin, että se työsuhdealue määritetään prosentteihin.

Näyttöongelma ratkesi sillä, että vaihdoin Uno-kortin toiseen. Ja kyllä, kyseessä eivät ole alkuperäiset kortit, vaan edullisemmat kopiot, toinen kortti meni siis elektroniikkajätteeseen ja olen jo hankkinut toisen alkuperäisen kortin, jonka aion laittaa sitten lopulliseen systeemiin.
 
Liittynyt
17.01.2018
Viestejä
2 084
On tuossa koodissa ainakin se ongelma että esim lastTime muuttuja määritellään loop- funktiossa ja sitten verrataan (millis() - lastTime) < x.
Tuossahan lastTime nollautuu joka kerran kun loop() kutsutaan eli muuttuja pitäisi määritellä loop() ulkopuolella. Lisäksi muuttujille olisi hyvä määrittää alkuarvot (paitsi jos tietää mikä on oletus ja se on ok).
Sama juttu kaikille muuttujille joiden arvo pitää säilyä loop() suoritusten välillä.

Kirjasto saattaa olla olemassa, itse käytän niitä yleensä aika vähän kun käytössä on yleensä pienempiä attiny25/atmega88/168 jolloin joutuu karsimaan koodin kokoa (monesti teen kokonaan ilman arduino framea). Eli siihen en osaa suoraan vastata.

Yleisesti on huono idea sotkea kirjaston käyttö ja säätää suoraan rekistereitä. Näin voi tehdä mutta silloin pitää tutkia mitä se kirjasto oikeasti tekee ettei mene tekemiset ns. ristiin.
Jos löytyy sopiva kirjasto joka tekee sen mitä tarvitseen niin sitten käyttää sitä. Jos kirjasto ei pysty siihen mitä pitäisi saada aikaan niin pitää joko tehdä oma versio kirjastosta johon tekee tarvittavat muutokset tai tekee kokonaan ilman kirjastoa. Yleensä jälkimmäinen on helpompi koska monissa kirjastoissa on omaan tarkoitukseen turhia toiminnallisuuksia joita ei tarvitse.

Ja tuohon yllä olevaan liittyen jos pwm 0-100% on rekisterissä numero 0-64000 niin arvohan on laskennallisesti rekisteri = (prosentti/100) * 64000 (eli sievennettynä rekisteri = prosentti * 640). Ei kovin hankala koodattava ja siitä voi sitten tehdä vaikka oman funktion jota kutsuu jos käytetään useammasta paikasta.
 
Liittynyt
10.07.2017
Viestejä
621
@ississ , eli tuohan voi olla syynä sille kun ohjelma jää looppaamaan siihen alkuun. Tarkoitus olisi päästä mahdollisimman vähällä koodaamisella joten varmaan pitäisi sitten miettiä mikä se kirjasto olisi joka pystyy tuohon pulssitaajuuden vaihtamiseen ja sitten että sen pulssitaajuuden pystyy kirjoittamaan prosentteina ajan funktiona niin että esimerkiksi kuudessa sekunnissa nollasta 60 prosenttiin.
 
Liittynyt
17.01.2018
Viestejä
2 084
Onnea kirjaston etsintään.

Joka tapauksessa logiikka pitää saada ensin toimimaan oikein.
 

dmn

Liittynyt
07.11.2016
Viestejä
1 656
@ississ , eli tuohan voi olla syynä sille kun ohjelma jää looppaamaan siihen alkuun. Tarkoitus olisi päästä mahdollisimman vähällä koodaamisella joten varmaan pitäisi sitten miettiä mikä se kirjasto olisi joka pystyy tuohon pulssitaajuuden vaihtamiseen ja sitten että sen pulssitaajuuden pystyy kirjoittamaan prosentteina ajan funktiona niin että esimerkiksi kuudessa sekunnissa nollasta 60 prosenttiin.
Eikö riitä ihan joku target_pwm ja actual_pwm muuttujat, joista actual_pwm:ää muutetaan joka loopilla pienen pykälän verran aina kohti target_pwm:ää. Tuskin on suuri synti edes tässä kohtaa käyttää floatteja, niin saa helposti ajastettua pulssin pituuden tarkasti (kunhan loop() suoritusaika pysyy joten kuten vakiona)
 
Liittynyt
17.01.2018
Viestejä
2 084
Eikö riitä ihan joku target_pwm ja actual_pwm muuttujat, joista actual_pwm:ää muutetaan joka loopilla pienen pykälän verran aina kohti target_pwm:ää. Tuskin on suuri synti edes tässä kohtaa käyttää floatteja, niin saa helposti ajastettua pulssin pituuden tarkasti (kunhan loop() suoritusaika pysyy joten kuten vakiona)
Kyllä float on ihan ok käyttää tarvittaessa, mieluummin melkein vaihtaa pois hitaat digitalRead() ja digitalWrite() riippuen tietysti tarvitaanko paljon laskentaa vai io heiluttelua...
Jos mitataan virtaa ja jännitettä niin joko float tai sitten yksiköksi mV kokonaislukuna, yleensä kuitenkin tarvew on tarkemmalle kuin 1V tai 1A.

@ississ , eli tuohan voi olla syynä sille kun ohjelma jää looppaamaan siihen alkuun. Tarkoitus olisi päästä mahdollisimman vähällä koodaamisella joten varmaan pitäisi sitten miettiä mikä se kirjasto olisi joka pystyy tuohon pulssitaajuuden vaihtamiseen ja sitten että sen pulssitaajuuden pystyy kirjoittamaan prosentteina ajan funktiona niin että esimerkiksi kuudessa sekunnissa nollasta 60 prosenttiin.
Tuossa botin koodissahan se oikeastaan on jo tehty, millis() - start kasvaa hiljalleen 0 -> 5000 joka loop() kutsulla ja se sovitetaan välille 0-60 jolla ohjataan pwm prosenttia. Sellaista kirjastoa ei varmasti olekaan joka tekisi tuon suoraan yhdellä kutsulla.
Botin koodi ei vaan kokonaisuutena toimi oikein koska botti ei ilmeisesti osaa koodata riittävästi.

Koodi:
if (millis() - initialFunctionStartTime < 5000) {
      int dutyCycle = map(millis() - initialFunctionStartTime, 0, 5000, 0, 60);
      analogWrite(pwmPin, map(dutyCycle, 0, 100, 0, 255));
      Serial.print("Duty Cycle: ");
      Serial.println(dutyCycle);  // Print the current duty cycle value
    }
Todennäköisesti myös analogWrite() tarjoama resoluutio (tai oikeammin 0-100% eli 100 askelta) riittää tällaiseen säätöön ihan mainiosti kunhan koodin oikeat virheet ensin korjataan ja se toimii kuten kuuluu. Ehkä jopa vain sillä että muuttujista tehdään globaalit lokaalin sijaan.
Sitten on vielä se juttu että tarvitseeko tuo oikeasti tasaista aloitusramppia vai voiko vaan suoraan laittaa lähtöön 60% pwm kun saa aloittaa ?
Jos kone hyytyy kuorman lisäyksestä hetkeksi mutta ei sammu tms niin ei pitäisi olla estettä. Silloin tietysti tarvitaan tarkka säätö jos latausta oikeasti säädettäisiin pwm:n avulla että saadaan tietty latausvirta mutta jos se pidetään vakiona 60% niin veikkaan ettei tarvitse ramppia ollenkaan tai riittää esim sekunnin välein 10% nosto 0->60% niin ei tule koko kuorma kerralla. Minimitarvekin voi olla jotain muuta kuin 0 tai 10 mutta se pitää kokeilla.

Tuo oma pwm- esimerkki oli ehkä vähän harhaan johtava, sen tarkoitus oli ilmaista että avr kyllä pystyy tarkkaan taajuuteen ja helposti yli 255 pykälän resoluutioonkin vaikka niin ei ole tehty arduinon peruskirjastossa jonka on kuitenkin tarkoitus toimia melkein missä vaan kortissa ja mielellään vielä samalla tavalla.
 
Liittynyt
10.07.2017
Viestejä
621
Kiitti taas vastauksista @dmn ja @ississ!

Jep, eli onko niin, että tuo koodi saattaa hyvinkin toimia, kunhan määrätyt pätkät saa oikeisiin paikkoihin? Täysin toimivaa tuossa koodissa on jo 1) näytön toiminta ja 2) virran mittaus. Virtaa ei tarvi näyttää näytöllä tarkemmin kuin 1 ampeerin tarkkuudella, mutta niinhän se tuossa koodissa taitaakin pyöristyä.

Joo, ei tässä tarkkuus ole niin justiin ja uskon vahvasti, ettei tarvita tarkalleen 125 Hz:n pulssia, toki olisihan se aina parempi. Tuo 0-60 ramp olisi juuri pehmokäynnistys. Jos olisi kerralla 60 %, eli latausjännite päälle 14 V, niin moottori ehkä saattaisi kyykätä. 80 ampeeria tekee noin 80 A x 14,4 V = 1,1 kW. Oletetaan hyötysuhteeksi 50 prosenttia, joten 2,2 kW ottaisi tehoa. Moottorin huipputeho jotain luokkaa 4 kW, joten ehkä se kuitenkin onnistuisi ilmankin tuota rampia, mutta yritetään nyt saada se sinne. Ei siitä ainakaan haitaa olisi.

 
Liittynyt
17.01.2018
Viestejä
2 084
Kiitti taas vastauksista @dmn ja @ississ!

Jep, eli onko niin, että tuo koodi saattaa hyvinkin toimia, kunhan määrätyt pätkät saa oikeisiin paikkoihin? Täysin toimivaa tuossa koodissa on jo 1) näytön toiminta ja 2) virran mittaus. Virtaa ei tarvi näyttää näytöllä tarkemmin kuin 1 ampeerin tarkkuudella, mutta niinhän se tuossa koodissa taitaakin pyöristyä.

Joo, ei tässä tarkkuus ole niin justiin ja uskon vahvasti, ettei tarvita tarkalleen 125 Hz:n pulssia, toki olisihan se aina parempi. Tuo 0-60 ramp olisi juuri pehmokäynnistys. Jos olisi kerralla 60 %, eli latausjännite päälle 14 V, niin moottori ehkä saattaisi kyykätä. 80 ampeeria tekee noin 80 A x 14,4 V = 1,1 kW. Oletetaan hyötysuhteeksi 50 prosenttia, joten 2,2 kW ottaisi tehoa. Moottorin huipputeho jotain luokkaa 4 kW, joten ehkä se kuitenkin onnistuisi ilmankin tuota rampia, mutta yritetään nyt saada se sinne. Ei siitä ainakaan haitaa olisi.
Koodi saattaa toimia kyllä. Tosin voi siellä joukossa olla vastaavia omituisuuksia kuin tuo lokaalit muuttujat... tarkkana testauksen kanssa.

Eikös se laturi ollut vain 80A ?
Laskussa pitää käyttää kuorman ottamaa virtaa, ei laturin maksimia. Eli jos kuormana on tietty kapasiteetti akkuja ja oletetaan että ne ovat suunnilleen tyhjiä niin sillä lähtövirralla pitää laskea käynnistysvirta.
Latauksessa kannattaisi kyllä olla vähän säätöä mukana eli käytettyjen akkujen mukaan max virran rajoitus, suurin osa ei tykkää ylilatauksesta.
 
Liittynyt
18.10.2016
Viestejä
524
en oo ihan tarkkaan ajatuksella tätä tavanut läpi mutta mulla käytössä Arduino/libraries/PWM/PWM_lib_example at master · atmelino/Arduino
pwm kirjasto jossa saa hertsit valita suoraan koodista , muutenkin tuskin tarttee suoraa koodia tollasessa käytössä kirjottaa kun siellä kumminkaan ei mitään kovin aikakriittistä tapahdu. eikö ton vois suoraa koodata tolla pwm libraryllä ja korottaa vaikka 1% pwm pulssia vaikka joka 100ms. ei tartte kovinkaan kummosta koodia.ps eikös arduinon analogwrite oo alueella 0-254 ei 0-100% jotenkin laittas vaikka startti koodiin ottaa millis() talteen ja vertaa jos yli 100ms on kulunut niin pwm++ ja sitten raja kun tullaan maksimiin niin poistutaan tosta if lauseesta. sitten vielä tosta moottorista oisko toi tärinä anturi parempi vaihtaa optohaarukkaan ja kiekkoon jossa reikiä niin sais rpm selville ja pwm pulssia vois laskea jos kone meinaa kyykätä? en usko että monessakaan moottorissa tutkitaan tärinää vaan pyörivän kappaleen kierroslukua. tohon kävis opto tai hall anturi jos haluaa magneetin liimata johonkin akseliin laturin hihnapyörään tms. toisaalta tota koko käynnistys rimpsua ei tarttis jos koodi odottas että max kierrosluku on saavutettu ja ampuu laturin päälle ja jos siellä on paljon kuormaa ja kierrosluku kyykkää vähennetään lataus virtaa pwmää tiputtamalla.
 
Viimeksi muokattu:
Liittynyt
17.01.2018
Viestejä
2 084
en oo ihan tarkkaan ajatuksella tätä tavanut läpi mutta mulla käytössä Arduino/libraries/PWM/PWM_lib_example at master · atmelino/Arduino
pwm kirjasto jossa saa hertsit valita suoraan koodista , muutenkin tuskin tarttee suoraa koodia tollasessa käytössä kirjottaa kun siellä kumminkaan ei mitään kovin aikakriittistä tapahdu. eikö ton vois suoraa koodata tolla pwm libraryllä ja korottaa vaikka 1% pwm pulssia vaikka joka 100ms. ei tartte kovinkaan kummosta koodia.ps eikös arduinon analogwrite oo alueella 0-254 ei 0-100% jotenkin laittas vaikka startti koodiin ottaa millis() talteen ja vertaa jos yli 100ms on kulunut niin pwm++ ja sitten raja kun tullaan maksimiin niin poistutaan tosta if lauseesta. sitten vielä tosta moottorista oisko toi tärinä anturi parempi vaihtaa optohaarukkaan ja kiekkoon jossa reikiä niin sais rpm selville ja pwm pulssia vois laskea jos kone meinaa kyykätä? en usko että monessakaan moottorissa tutkitaan tärinää vaan pyörivän kappaleen kierroslukua. tohon kävis opto tai hall anturi jos haluaa magneetin liimata johonkin akseliin laturin hihnapyörään tms. toisaalta tota koko käynnistys rimpsua ei tarttis jos koodi odottas että max kierrosluku on saavutettu ja ampuu laturin päälle ja jos siellä on paljon kuormaa ja kierrosluku kyykkää vähennetään lataus virtaa pwmää tiputtamalla.
Ilman muuta opto/magneetti ja kierrosluvun mittaus olisi parempi kuin tärinä.
Tai koneesta riippuen mittaa suoraan magneetolta tai sytkältä/puolalta.
 
Liittynyt
10.07.2017
Viestejä
621
Olette ihan oikeassa, ettei tuossa koodissa välttämättä edes PWM:ää tarvitse määritellä prosenteissa. Kun se tavoite on 60 prosenttia, niin sehän on riittävän lähelle 153 analog writenä. Ei nämä ohjaukset oli niin edes prosenttienkaan päälle.

Anturiasiaan minulla ei ole sen kummempaa ajatusta, kuin käyttää sitä tärinäanturia. Helppo rakentaa ja tulee on-off signaali. Hyvin näyttää toimivan testikokoonpanossa. Ehtona koodissa pitäisi olla että tärinää pitää jatkua x sekuntia, ja sitten nostetaan vasta sitten tuo työsuhde tavoitteeseensa. Lopullinen aika selviää vasta sitten kun koko hässäkkä on kasattu, mutta pitää yrittää ährätä tätä koodia ensin. Tätähän voi pöydällä testata helposti. Tuota virta-anturin tuloa simuloidaan potikalla ja vastaavasti tärinäanturin on-off signaali voidaan tuottaa sen omalla trimmerillä tai mieluummin kytkemällä sen tilalle normaali katkaisin.

---


EDIT1: Eli tässä nyt vähän muokattu koodi. Laitoin input pinniin pullup-vastuksen päälle, jolloin liitin siiten tuon katkaisimen. Sillä voimme nyt simuloida moottori päällä-pois. Potikka on liitetty nyt opampin, eli virtatulon tilalle, jolla voimme nyt simuloida virtatulon. Siirsin nuo kaikki määrittelyt tuonne alkuun.

Koodin toiminnasta nyt:

  • Arduinon käynnistyessä, käy 60 prosentin pwm hetken aikaa päällä, kunnes se menee nollille.
  • Jää edelleen junnamaan siihen aloitusfunktioon serial debuggingin perusteella (edit. eipä muuten kokoajaksi jääkään kts. alempaa). Sammutusfunktio ei koskaan mene päälle.
  • Kun kytken pinnitulon päälle, Duty Cycle alkaa heti nousta viidessä sekunnissa 60 prosenttiin. Kun siinä pitäisi olla se määritelty viive. Eli esim. 10 sekunnin ajan odotetaan, kunnes vasta nostetaan duty 0-60 5 sekunnissa.
  • Lisäksi huomasin oskilloskoopin ollessa tässä pöydällä samalla kytkettynä arduinoon, että yhtäkkiä pwm ajetaan alas ja se palautuu takaisin 60 prosenttiin. Katsoin debugia, niin sammutusfunktio käynnistyy. Se vaan ei käynnisty heti, kun sen pitäisi, virran laskiessa 5 ampeerin alle.
    • En onnistunut toistamaan tätä. Ei sammutusfunktio enää käynnisty. Duty Cycle vain käväisee nollissa ja palautuu taas 5 sekunnissa 60:een. Sammutusfunktion ei edes tarvitse mitenkään koskea Duty Cycleen. Riittää, että se lähettää releelle herätteen!!!
  • Toimivat osat: Virran mittaus, näyttö, pwm-signaalin taajuus.

Koodi:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Create a new LiquidCrystal_I2C display object with the correct I2C address and display size

// Define the pins
const int currentPin = A0;             //information about current
const int motorPin = 7;                //motor running pin, HIGH = motor running, TEST purpose LOW
const int pwmPin = 9;                  //PWM output pin
const int relayPin = 3;                //Relay control pin
float voltageFactor = 5.0 / 1023.0;    //Factor to convert ADC reading to voltage
float currentFactor = 80 / 4.8351848;  //4.8351848 volts = 80 amps, factor to convert voltage to current
const int N = 10;                      //number of readings to average
int readings[N];                       //array to store the readings
static unsigned long lastTime;
static bool isInitialFunctionRunning;
static bool isShutdownFunctionRunning;
static unsigned long initialFunctionStartTime;
static unsigned long shutdownFunctionStartTime;

void setup() {

  Serial.begin(9600);  // Start the serial communication

  // Initialize the LCD here
  // Give the screen time to boot
  delay(3000);
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.clear();

  // Change timers on pins to change PWM freq to 122 Hz
  // Pins D9 and D10 - 122 Hz
  TCCR1A = 0b00000001;  // 8bit
  TCCR1B = 0b00000100;  // x256 phase correct

  // Make pins output/input
  pinMode(currentPin, INPUT);
  pinMode(motorPin, INPUT_PULLUP);  //For real use, delete _PULLUP (it is for test purpose, pullup resistor)
  pinMode(pwmPin, OUTPUT);
  pinMode(relayPin, OUTPUT);
}

void loop() {


  //Initial function
  // Check if the engine is running. If it has been running for at least six seconds, start the initial function.
  if (digitalRead(motorPin) == HIGH) {
    if (millis() - lastTime > 6000) {
      isInitialFunctionRunning = true;
      initialFunctionStartTime = millis();
    }
    Serial.println("Engine is running");  // Print a message when the engine is running
  } else {
    lastTime = millis();
    Serial.println("Engine is not running");  // Print a message when the engine is not running
  }

  // If the initial function is running, increase the Duty Cycle from 0 percent to 60 percent within five seconds.
  if (isInitialFunctionRunning) {
    if (millis() - initialFunctionStartTime < 5000) {
      int dutyCycle = map(millis() - initialFunctionStartTime, 0, 5000, 0, 60);
      analogWrite(pwmPin, map(dutyCycle, 0, 100, 0, 255));
      Serial.print("Duty Cycle: ");
      Serial.println(dutyCycle);  // Print the current duty cycle value
    } else {
      isInitialFunctionRunning = false;
    }
  }

  //Basic function
  // If the initial function is not running and the shutdown function is not running either, keep the Duty Cycle at 60 percent.
  else if (!isShutdownFunctionRunning) {
    analogWrite(pwmPin, map(60, 0, 100, 0, 255));
  }

  // Calculate the charging current from the average and display it on the LCD screen.

  // take N readings and store them in the array
  for (int i = 0; i < N; i++) {
    readings[i] = analogRead(currentPin);
    delay(10);  // wait for 10 milliseconds between readings
  }

  // calculate the average of the N readings
  float sum = 0;
  for (int i = 0; i < N; i++) {
    sum += readings[i];
  }
  float average = sum / N;

  float voltage = average * voltageFactor;  //  Convert ADC reading to voltage

  float current = voltage * currentFactor;  // Convert voltage to current
  lcd.setCursor(0, 0);
  lcd.print("Latausvirta:");
  lcd.setCursor(0, 1);
  lcd.print((int)current);
  lcd.print(" ");
  lcd.setCursor(3, 1);
  lcd.print(" A");


  //Shutdown function
  // If the charging current drops below five amperes and the shutdown function is not running yet,
  // start the shutdown function and turn off the relay for sixty seconds.
  if (current < 5 && !isShutdownFunctionRunning) {
    isShutdownFunctionRunning = true;
    shutdownFunctionStartTime = millis();
    digitalWrite(relayPin, LOW);
    Serial.println("Shutdown function started");  // Print a message when the shutdown function starts
  }

  // If the shutdown function has been running for sixty seconds,
  // stop it and switch the relay. Then return to the initial function.
  if (isShutdownFunctionRunning && millis() - shutdownFunctionStartTime > 60000) {
    isShutdownFunctionRunning = false;
    digitalWrite(relayPin, HIGH);
    isInitialFunctionRunning = true;
    initialFunctionStartTime = millis();
    Serial.println("Shutdown function stopped");  // Print a message when the shutdown function stops
  }
}
 
Viimeksi muokattu:
Liittynyt
17.01.2018
Viestejä
2 084
Olette ihan oikeassa, ettei tuossa koodissa välttämättä edes PWM:ää tarvitse määritellä prosenteissa. Kun se tavoite on 60 prosenttia, niin sehän on riittävän lähelle 153 analog writenä. Ei nämä ohjaukset oli niin edes prosenttienkaan päälle.

Anturiasiaan minulla ei ole sen kummempaa ajatusta, kuin käyttää sitä tärinäanturia. Helppo rakentaa ja tulee on-off signaali. Hyvin näyttää toimivan testikokoonpanossa. Ehtona koodissa pitäisi olla että tärinää pitää jatkua x sekuntia, ja sitten nostetaan vasta sitten tuo työsuhde tavoitteeseensa. Lopullinen aika selviää vasta sitten kun koko hässäkkä on kasattu, mutta pitää yrittää ährätä tätä koodia ensin. Tätähän voi pöydällä testata helposti. Tuota virta-anturin tuloa simuloidaan potikalla ja vastaavasti tärinäanturin on-off signaali voidaan tuottaa sen omalla trimmerillä tai mieluummin kytkemällä sen tilalle normaali katkaisin.

---


EDIT1: Eli tässä nyt vähän muokattu koodi. Laitoin input pinniin pullup-vastuksen päälle, jolloin liitin siiten tuon katkaisimen. Sillä voimme nyt simuloida moottori päällä-pois. Potikka on liitetty nyt opampin, eli virtatulon tilalle, jolla voimme nyt simuloida virtatulon. Siirsin nuo kaikki määrittelyt tuonne alkuun.

Koodin toiminnasta nyt:

  • Arduinon käynnistyessä, käy 60 prosentin pwm hetken aikaa päällä, kunnes se menee nollille.
  • Jää edelleen junnamaan siihen aloitusfunktioon serial debuggingin perusteella (edit. eipä muuten kokoajaksi jääkään kts. alempaa). Sammutusfunktio ei koskaan mene päälle.
  • Kun kytken pinnitulon päälle, Duty Cycle alkaa heti nousta viidessä sekunnissa 60 prosenttiin. Kun siinä pitäisi olla se määritelty viive. Eli esim. 10 sekunnin ajan odotetaan, kunnes vasta nostetaan duty 0-60 5 sekunnissa.
  • Lisäksi huomasin oskilloskoopin ollessa tässä pöydällä samalla kytkettynä arduinoon, että yhtäkkiä pwm ajetaan alas ja se palautuu takaisin 60 prosenttiin. Katsoin debugia, niin sammutusfunktio käynnistyy. Se vaan ei käynnisty heti, kun sen pitäisi, virran laskiessa 5 ampeerin alle.
    • En onnistunut toistamaan tätä. Ei sammutusfunktio enää käynnisty. Duty Cycle vain käväisee nollissa ja palautuu taas 5 sekunnissa 60:een. Sammutusfunktion ei edes tarvitse mitenkään koskea Duty Cycleen. Riittää, että se lähettää releelle herätteen!!!
  • Toimivat osat: Virran mittaus, näyttö, pwm-signaalin taajuus.
Äkkiä katsoen tuossa voisi olla kyllä väärä logiikka.

Koodi:
if (digitalRead(motorPin) == HIGH) {
  if (millis() - lastTime > 6000) {
    isInitialFunctionRunning = true;
  }
}

....

if (isInitialFunctionRunning) {
  ...
} else if (!isShutdownFunctionRunning) {
    analogWrite(pwmPin, map(60, 0, 100, 0, 255));
}
Alun 6sek viiveen aikana isInitialFunctionRunning = false ja isShutdownFunctionRunning = false -> asetetaan pwm 60% joka ei ole oikein.

Ehkä tilakone erillisten "ollaankojustnyttekemässäjotain" muuttujien sijaan voisi olla selkeämpi. Tai sitten niitä muuttujia pitää olla enemmän, ainakin "ollaanko käynnistyksen jälkeisessä viiveessä" puuttuu.
Yhä vahvemmin vaikuttaa siltä että botti ei osannut koodata oikein ja sinänsä järkevältä näyttävän koodin virheiden etsintä on haastavaa.
 
Liittynyt
10.07.2017
Viestejä
621
Joo, saattaisi olla parempi deletoida loopista lähes kaikki ja kirjoittaa uusiksi. Jos tekisi vaan setupiin koko homman ja loopiin jäisi pelkästään virran näyttö, n. 60 prosentin duty cycle ja sammutusoperaatio. Tämä koodi toimisi jo jotenkin, mutta ei ole enää niin "hieno", kun puuttuu esim. se moottorin käynnissäolon tunnistus ja jostain syystä duty cycle voi palautua tuohon alun noin 5 prosenttiin.

Koodi:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Create a new LiquidCrystal_I2C display object with the correct I2C address and display size

// Define the pins
const int currentPin = A0;             //information about current
const int motorPin = 7;                //motor running pin, HIGH = motor running, TEST purpose LOW
const int pwmPin = 9;                  //PWM output pin
const int relayPin = 3;                //Relay control pin
float voltageFactor = 5.0 / 1023.0;    //Factor to convert ADC reading to voltage
float currentFactor = 80 / 4.8351848;  //4.8351848 volts = 80 amps, factor to convert voltage to current
const int N = 10;                      //number of readings to average
int readings[N];                       //array to store the readings
static unsigned long lastTime;
static bool isInitialFunctionRunning;
static bool isShutdownFunctionRunning;
static unsigned long initialFunctionStartTime;
static unsigned long shutdownFunctionStartTime;

void setup() {

  Serial.begin(9600);  // Start the serial communication

  // Initialize the LCD here
  // Give the screen time to boot
  delay(3000);
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.clear();

  // Change timers on pins to change PWM freq to 122 Hz
  // Pins D9 and D10 - 122 Hz
  TCCR1A = 0b00000001;  // 8bit
  TCCR1B = 0b00000100;  // x256 phase correct

  // Make pins output/input
  pinMode(currentPin, INPUT);
  pinMode(motorPin, INPUT_PULLUP);  //For real use, delete _PULLUP (it is for test purpose, pullup resistor)
  pinMode(pwmPin, OUTPUT);
  pinMode(relayPin, OUTPUT);

  // Ramp pwm up
  analogWrite(pwmPin, 13);
  delay(15000);  //let time the user to start the engine
  analogWrite(pwmPin, 50);
  delay(1000);
  analogWrite(pwmPin, 70);
  delay(1000);
  analogWrite(pwmPin, 100);
  delay(1000);
  analogWrite(pwmPin, 153);  //Duty Cycle at 60 percent
}

void loop() {

  //Basic function
  analogWrite(pwmPin, 153);  //Duty Cycle at 60 percent


  // Calculate the charging current from the average and display it on the LCD screen.
  // take N readings and store them in the array
  for (int i = 0; i < N; i++) {
    readings[i] = analogRead(currentPin);
    delay(10);  // wait for 10 milliseconds between readings
  }

  // calculate the average of the N readings
  float sum = 0;
  for (int i = 0; i < N; i++) {
    sum += readings[i];
  }
  float average = sum / N;

  float voltage = average * voltageFactor;  //  Convert ADC reading to voltage

  float current = voltage * currentFactor;  // Convert voltage to current
  lcd.setCursor(0, 0);
  lcd.print("Latausvirta:");
  lcd.setCursor(0, 1);
  lcd.print((int)current);
  lcd.print(" ");
  lcd.setCursor(3, 1);
  lcd.print(" A");

  //Shutdown function
  // If the charging current drops below five amperes
  // start the shutdown function and turn off the relay
  if (current < 5) {
    digitalWrite(relayPin, LOW);
    Serial.println("Shutdown function started");  // Print a message when the shutdown function starts
    delay(6000);                                 // Prevent loop start from the beginning
  } else {
    digitalWrite(relayPin, HIGH);
  }
}
 
Liittynyt
17.01.2018
Viestejä
2 084
Setupiin kuuluu vain se mikä pitää ajaa kerran silloin kun käynnistetään. Kaikki muu kuuluu looppiin.
Tästä tietysti poikkeuksena tapaukset joissa tekemisen jälkeen arduino/avr otetaan myös virrat pois ja aloitetaan alusta mutta jos sen on tarkoitus ns. olla koko ajan päällä ja toimia inputtien mukaan niin silloin loop().

Tuossa myös loopin alussa oleva analogWrite() on täysin turha koska loopissa arvoa ei muuteta ja sama on asetettu jo setupin lopussa.
 
Liittynyt
10.07.2017
Viestejä
621
@ississ Joo, kiitti tästä. :)

En siis osaa juurikaan koodata, lähinnä vain kopioida surkealla menestyksellä. Nyt tuo koodi joten kuten toimii. Lisäsin loppuun vielä tuon, että myös tärinäanturilta pitää tulla tieto, että rele sammutetaan. Nyt se myös toimii oikeasti, mittasin vielä yleismittarilla. Noita HIGH ja LOW -arvoja voi joutua muuttelemaan, mutta sehän on helppo juttu.

Olisi se kuitenkin parempi, että tuo käynnistys olisi riippuvainen tuosta tärinäanturista. Eli ehtona suurin piirtein vähintään 6 sekunnin ajan pin high, kunnes mennään eteenpäin. Miten se pitäisi kirjoittaa koodiin, että vasta sitten tehdään analog writenä nuo askeleet? Eli nekin pitäisi ehkä laittaa loopiin, vai olisiko kuitenkin järkevämpi, että nekin olisi setupissa?

Yritin saada tuon moottorin käynnissäolon tunnistuksen mukaan, niin en ihan onnistunut. Koodi menee nyt kyllä läpi kääntäjästä, mutta ei se toimi. TÄllä koodilla Duty Cycle on heti 60 prosenttia (setupin sisällä):


Koodi:
 //Initial function
  // if motor is running at least for six second, ramp pwm up
  if (millis() - runTime > 6000 && digitalRead(motorPin) == HIGH) {
    // Ramp pwm up
    analogWrite(pwmPin, 13);
    delay(1000);  //let time the user to start the engine
    analogWrite(pwmPin, 50);
    delay(1000);
    analogWrite(pwmPin, 70);
    delay(1000);
    analogWrite(pwmPin, 100);
    delay(1000);
    analogWrite(pwmPin, 153);  //Duty Cycle at 60 percent
    lcd.clear();
  } else {
    analogWrite(pwmPin, 153);  //Duty Cycle at 60 percent
    lcd.setCursor(0, 0);
    lcd.print("Kaynnista");
  }
}
 
Viimeksi muokattu:

Griffin

BANNATTU
BANNED
Liittynyt
16.10.2016
Viestejä
12 136
Moottorin pyöriminen:
Monissa moottoreissa on magneetossa sytytyskäämi ja matalajännitekäämi sitten erikseen. Matalajännitekäämistä saat esim diodi -> vastus (1K), ->Rinnan (Zener 4V7 +vastus 100K) rajoittamaan pulssitiedon, esim 0-4V7 alueelle..
Mittaat vain pulssien määrän, esim / sekuntti jollain laskurilla tms kikalla ja saat laskettua pyörimisnopeuden.. Jos prossu tukee keskeytyksiä, niin Pulssi aiheuttamaan keskeytyksen ja keskeytysrutiini, joka ottaa kellonajan yli, paljonko meni edellisestä keskeytyksestä ja laskee esim 10 viimeisen keskiarvon (ja jättää arvot pois, jos 2 peräkkäistä eroaa toisistaa huimasti.. Siitä arvo sitten talteen jonnekkin muistipaikkaan, josta pääohjelma voi lukea aikatiedon ja laskee sitten pyörimisnopeuden..

Auton laturit ja aurinkojärjestelmissä käytetyt akut:
Jos akut ovat kapasiteetiltään hyvin isot tai tiettyä tyyppiä, niin ne voivat ottaa erittäin suurta virtaa. Tämä puolestaan polttaa laturin, ylikuumenemisen takia. Siksi fiksuissa systeemeissä valvotaan sitä laturin lämpöä ja tiputetaan jännitettä, kunnes virta on senverran pieni, että laturi ei ylikuumene..
 
Liittynyt
10.07.2017
Viestejä
621
@Griffin , joo kiitti tästä. Tuota mietenkin aluksi, että tuo olisi ehkä ollut myös oiva keino. Mutta toisaalta halusin kajota itse moottoriin niin vähän kuin mahdollista, ja vielä se, kun moottoria ei edes ole ostettu niin tulin siihen johtopäätökseen, että paras on tunnistaa moottorin käynnissäolo akustisesti tai tärinän perusteella. Valitsin tärinäanturin, josta saa suoraan Arduinolle sopivan on-off tiedon. :)
 
Liittynyt
10.07.2017
Viestejä
621
No niin, taas on tullut vähän "edistystä". Tuo koodi alkaisi olla jo kohtuullinen, mutta jos vielä saataisiin tuo moottorin käynnissäolon tunnistus toimimaan. Alla koodi. Eli löysin tuon sensorin luku koodin netistä (laitoin sen setup-funktioon), ja tämä koko koodi kyllä menee kääntäjästä läpi. Mutta duty cycle ei nouse nyt ollenkaan. Ongelmana siis tuo kohta tuossa koodissa.

Eli toiminta pitäisi olla

  • Jos moottorin pinnistä ei tule tietoa 5 sekunnin aikaa, analogWrite 13
  • Jos moottorin pinnistä tulee tieto vähintään 5 sekunnin ajan, analogWrite 13 --> 153 kuten koodissa on

Käsitykseni mukaan, kun tämä toiminto tehdään vain kerran, en pitäisi tulla setup-funktioon. Jos tämä koodi tulisi loop-osioon, en tiedä, mitä pitäisi muuttaa, ettei tuota duty cycleä aleta ajaa ylös-alas loputtomasti.


Koodi:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Create a new LiquidCrystal_I2C display object with the correct I2C address and display size

// Define the pins
const int currentPin = A0;               //information about current
const int motorPin = 7;                  //motor running pin, HIGH = motor running, TEST purpose LOW
const int pwmPin = 9;                    //PWM output pin
const int relayPin = 3;                  //Relay control pin
float voltageFactor = 5.0 / 1023.0;      //Factor to convert ADC reading to voltage
float currentFactor = 80 / 4.8351848;    //4.8351848 volts = 80 amps, factor to convert voltage to current
const int N = 10;                        //number of readings to average
int readings[N];                         //array to store the readings
int currentSensorState;                  //motor running sensor state right now
int lastSensorState;                     //last motor running sensor state
unsigned long readTimer;                 //how long have motor running sensor input
unsigned long currentMillis = millis();  //current timer

void setup() {

  Serial.begin(9600);  // Start the serial communication

  // Initialize the LCD here
  // Give the screen time to boot
  delay(3000);
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.clear();

  // Change timers on pins to change PWM freq to 122 Hz
  // Pins D9 and D10 - 122 Hz
  TCCR1A = 0b00000001;  // 8bit
  TCCR1B = 0b00000100;  // x256 phase correct

  // Make pins output/input
  pinMode(currentPin, INPUT);
  pinMode(motorPin, INPUT_PULLUP);  //For real use, delete _PULLUP (it is for test purpose, pullup resistor)
  pinMode(pwmPin, OUTPUT);
  pinMode(relayPin, OUTPUT);

  lcd.setCursor(0, 0);
  lcd.print("K");
  lcd.print((char)0xe1);
  lcd.print("ynnist");
  lcd.print((char)0xe1);
  lcd.setCursor(0, 1);
  lcd.print("moottori");


  // Motor pin reading
  currentSensorState = digitalRead(motorPin);
  // check for change from last state
  if (lastSensorState != currentSensorState) {
    lastSensorState = currentSensorState;  // store the change
    readTimer = currentMillis;             // start the timer
  }
  // check if timing and if timing finished
  if (readTimer > 0 && currentMillis - readTimer >= 5000) {
    // reset timer
    readTimer = 0;
    // If it makes it here it has been in the new state for a second
    if (currentSensorState == LOW) {
      analogWrite(pwmPin, 13);  // do stuff for LOW state
    } else {
      analogWrite(pwmPin, 13);  // Ramp pwm up, do stuff for HIGH state if you want
      delay(1000);              //let time the user to start the engine
      analogWrite(pwmPin, 48);
      delay(1000);
      analogWrite(pwmPin, 83);
      delay(1000);
      analogWrite(pwmPin, 118);
      delay(1000);
      analogWrite(pwmPin, 153);  //Duty Cycle at 60 percent
      lcd.clear();
    }
  }
}

void loop() {

  //Basic function
  //Duty Cyle at 60 percent, setup function

  // Calculate the charging current from the average and display it on the LCD screen.
  // take N readings and store them in the array
  for (int i = 0; i < N; i++) {
    readings[i] = analogRead(currentPin);
    delay(10);  // wait for 10 milliseconds between readings
  }

  // calculate the average of the N readings
  float sum = 0;
  for (int i = 0; i < N; i++) {
    sum += readings[i];
  }
  float average = sum / N;

  float voltage = average * voltageFactor;  //  Convert ADC reading to voltage

  float current = voltage * currentFactor;  // Convert voltage to current
  lcd.setCursor(0, 0);
  lcd.print("Latausvirta:");
  lcd.setCursor(0, 1);
  lcd.print((int)current);
  lcd.print("  ");
  lcd.setCursor(3, 1);
  lcd.print(" A");
  lcd.setCursor(5, 1);
  lcd.print("        ");

  //Shutdown function
  // If the charging current drops below five amperes
  // start the shutdown function and turn off the relay
  if (current < 5 && digitalRead(motorPin) == HIGH) {
    digitalWrite(relayPin, LOW);
    Serial.println("Shutdown function started");  // Print a message when the shutdown function starts
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Ladattu");
    lcd.setCursor(0, 1);
    lcd.print("Sammuta virta");
    delay(6000);  // Prevent loop start from the beginning
  } else {
    digitalWrite(relayPin, HIGH);
  }
}
 
Viimeksi muokattu:
Liittynyt
18.10.2016
Viestejä
524
tylsyyksissä kirjotin ton kokonaan uusiks kun ei tosta ai tuotoksesta saa mitään selvää. tässä toimii startti ramppi ja sammutus , virran mittaus on suora kopio tupsan koodista ja jotain lcd rivejä joutui kommentoimaan kun mulla ei sellasta ole.
Koodi:
#include <MapFloat.h>
#include <PWM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);  // Create a new LiquidCrystal_I2C display object with the correct I2C address and display size
const int currentPin = A0;             //information about current
const int motorPin = 7;                //motor running pin, HIGH = motor running, TEST purpose LOW
const int pwmPin = 9;                  //PWM output pin
const int relayPin = 3;                //Relay control pin
const int N = 10;                      //number of readings to average
int readings[N];   
float current;                    //array to store the readings
static unsigned long lastTime;
float voltageFactor = 5.0 / 1023.0;      //Factor to convert ADC reading to voltage
float currentFactor = 80 / 4.8351848;
int motorStatus = 0; //This variable change when ever motor status change 0= stopped , 1 = startting 2=running
/*The library
 allows for a frequency range from 1Hz - 2MHz on 16 bit timers and 31Hz - 2 MHz on 8 bit timers. When
 SetPinFrequency()/SetPinFrequencySafe() is called, a bool is returned which can be tested to verify the
 frequency was actually changed.
 */
 //Here we setup pwm freq & herz
int32_t frequency = 125; //frequency (in Hz)
int pwm = 0 ;
int rampUp = 0;
void setup()
{
  //initialize all timers except for 0, to save time keeping functions
  InitTimersSafe();
  Serial.begin(9600);  // Start the serial communication

  // Initialize the LCD here
  // Give the screen time to boot
 // delay(3000);
 // lcd.begin(16, 2);
 // lcd.backlight();
 // lcd.clear();



  // Make pins output/input
  pinMode(currentPin, INPUT);
  pinMode(motorPin, INPUT_PULLUP);  //For real use, delete _PULLUP (it is for test purpose, pullup resistor)
  pinMode(pwmPin, OUTPUT);
  pinMode(relayPin, OUTPUT);
}

void motorRunning()
{
    if (digitalRead(motorPin) == HIGH && motorStatus == 0)  {
 
    if (millis() - lastTime >= 6000) {
    motorStatus = 1;
 
    Serial.println("Engine is running");  // Print a message when the engine is running
    }
  
  }
else {lastTime = millis();}
}

void pwmRampup()
{
   // pwmWrite(pwmPin, rampUp);
if (motorStatus == 1)
{

  for (int i = 0; i <= 60; i++) {
    pwmWrite(pwmPin, i);
    delay(100);
    Serial.println(i);
    motorStatus = 2;
  }
}



 }
  

void shutDown()
{
if (current < 5 && motorStatus ==2) {
    digitalWrite(relayPin, LOW);
    Serial.println("Shutdown function started");  // Print a message when the shutdown function starts
    motorStatus = 0;                           
  }

}

void readCurrent(){

  if(motorStatus ==2)
  {
  for (int i = 0; i < N; i++) {
    readings[i] = analogRead(currentPin);
    delay(10);  // wait for 10 milliseconds between readings
  }

  // calculate the average of the N readings
  float sum = 0;
  for (int i = 0; i < N; i++) {
    sum += readings[i];
  }
  float average = sum / N;

  float voltage = average * voltageFactor;  //  Convert ADC reading to voltage

  float current = voltage * currentFactor;  // Convert voltage to current
  lcd.setCursor(0, 0);
  lcd.print("Latausvirta:");
  lcd.setCursor(0, 1);
  lcd.print((int)current);
  lcd.print(" ");
  lcd.setCursor(3, 1);
  lcd.print(" A");
  }
}


void loop()
{
motorRunning();
pwmRampup(); 
shutDown();
readCurrent();
}
 
Liittynyt
18.10.2016
Viestejä
524
ps tossa koodissa on bugi viel kun sammutus tulee se alkaa starttaa uudelleen käyntiin sen voi estää ohjaamalla motorstatus = 3; ja liipasta se vaikka kytkimellä 0 ksi jos starttia halutaan
Tässä github linkki jossa tuo pwm kirjasto on PWM/examples/PWM at master · terryjmyers/PWM
Ja ylhäältä voi tuhoa mapfloat rivin niin pitäisi toimia
 
Viimeksi muokattu:
Liittynyt
10.07.2017
Viestejä
621
@Nasty76, isot pisteet koodista! En vain nyt tohdi sitä ottaa ilmaiseksi käyttöön, joten yritän vääntää tätä moottorin käynnissä olon tunnistusta tässä toimintaan.

Eikö muuten noiden PWM-kirjastojen käyttö muuta perustaajuutta, ja monet funktiot menee sitten huonoksi? Vai onko sama homma, kuin tuolla timerin muuttamisella, että määrätyllä pinneillä tehtynä ei vaikuta funktioiden toimintaan? Jos oikein ymmärrän, tuossa linkkaamassasi kirjastossa olisi joku valmis feidausominaisuus? :D

Please keep in mind that changing the PWM frequency changes the Atmega's timers and disrupts the normal operation of many functions that rely on time (delay(), millis(), Servo library).
 
Viimeksi muokattu:
Liittynyt
17.01.2018
Viestejä
2 084
@Nasty76, isot pisteet koodista! En vain nyt tohdi sitä ottaa ilmaiseksi käyttöön, joten yritän vääntää tätä moottorin käynnissä olon tunnistusta tässä toimintaan.

Eikö muuten noiden PWM-kirjastojen käyttö muuta perustaajuutta, ja monet funktiot menee sitten huonoksi? Vai onko sama homma, kuin tuolla timerin muuttamisella, että määrätyllä pinneillä tehtynä ei vaikuta funktioiden toimintaan? Jos oikein ymmärrän, tuossa linkkaamassasi kirjastossa olisi joku valmis feidausominaisuus? :D
Jos kirjasto muuttaa timer0 asetuksia niin se vaikuttaa noihin valmiisiin toiminnallisuuksiin.
=> Kannattaa välttää sellaisia kirjastoja.

ATMega328 on 3 ajastinta joista ensimmäinen (timer0) on millis() jne käytössä. Osa kirjastoista taitaa myös käyttää sitä mutta ei vaikuta muuten.
Hyvin tehty pwm- kirjasto käyttää joko timer1 tai timer2 tarpeesta ja resoluutiosta riippuen jolloin vaikutusta millis() jne toimintaan ei ole. Ja tietysti on mahdollista että useampi kirjasto haluaisi säätää samaa ajastinta, sekään ei ole hyvä idea vaan toiselle pitää löytää jokin toinen toteutus...
Niin ja jokaiselle ajastimelle on omat vakiopinnit jotka niihin voidaan kytkeä, sen mukaan pitää järjestää muihin toimintoihin valitut pinnit.

Yksi vaihtoehto on käyttää sitä mun esimerkkiä ilman kirjastoa niin ei varmasti sotke millis() yms käyttöä. Jos lähdetä tälle tielle niin koodin saa kyllä koska se on oikeastaan vaan suoraan datalehdestä napattu.
 
Liittynyt
18.10.2016
Viestejä
524
@Tupsa otaha vaan jos se toimii. teen siihen parannuksen.
mun käsittääkseni toi jättää timer0 koskemattomaksi. ja toisaalta tossa mun koodissa ei oikestaan oo mitään aika kriittistä kunhan se pwm suhde on oikein. olithan jo suurimman työn tehny ite niin ton huitasin about 15min kasaan kun odotin että pääsen lähtee terveysasemalle =). korvaa toi esimerkki koodin void shutdown() tolla alla olevalla tai lisää sinne olemassa olevaan esimerkkiin toi pwmWrite(pwmPin,0); joka kirjottaa pwm pulsit nollaan kun on sammutus ajettu
Koodi:
void shutDown()
{
if (current < 5 && motorStatus ==2) {
    digitalWrite(relayPin, LOW);
    Serial.println("Shutdown function started");  // Print a message when the shutdown function starts
    motorStatus = 0;      
    pwmWrite(pwmPin,0);                 
  }
Koodi:
#######################################
# Syntax Coloring Map PWM
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

#######################################
# Methods and Functions (KEYWORD2)
#######################################

InitTimers    KEYWORD2
InitTimersSafe    KEYWORD2
pwmWrite    KEYWORD2
pwmWriteHR    KEYWORD2
SetPinFrequency    KEYWORD2
SetPinFrequencySafe    KEYWORD2
GetPinResolution KEYWORD2

Timer0_GetFrequency    KEYWORD2
Timer0_SetFrequency    KEYWORD2
Timer0_GetPrescaler    KEYWORD2
Timer0_SetPrescaler    KEYWORD2
Timer0_GetTop    KEYWORD2
Timer0_SetTop    KEYWORD2
Timer0_Initialize    KEYWORD2
Timer0_GetResolution KEYWORD2

Timer1_GetFrequency    KEYWORD2
Timer1_SetFrequency    KEYWORD2
Timer1_GetPrescaler    KEYWORD2
Timer1_SetPrescaler    KEYWORD2
Timer1_GetTop    KEYWORD2
Timer1_SetTop    KEYWORD2
Timer1_Initialize    KEYWORD2
Timer1_GetResolution KEYWORD2

Timer2_GetFrequency    KEYWORD2
Timer2_SetFrequency    KEYWORD2
Timer2_GetPrescaler    KEYWORD2
Timer2_SetPrescaler    KEYWORD2
Timer2_GetTop    KEYWORD2
Timer2_SetTop    KEYWORD2
Timer2_Initialize    KEYWORD2
Timer2_GetResolution KEYWORD2

Timer3_GetFrequency    KEYWORD2
Timer3_SetFrequency    KEYWORD2
Timer3_GetPrescaler    KEYWORD2
Timer3_SetPrescaler    KEYWORD2
Timer3_GetTop    KEYWORD2
Timer3_SetTop    KEYWORD2
Timer3_Initialize    KEYWORD2
Timer3_GetResolution KEYWORD2

Timer4_GetFrequency    KEYWORD2
Timer4_SetFrequency    KEYWORD2
Timer4_GetPrescaler    KEYWORD2
Timer4_SetPrescaler    KEYWORD2
Timer4_GetTop    KEYWORD2
Timer4_SetTop    KEYWORD2
Timer4_Initialize    KEYWORD2
Timer4_GetResolution KEYWORD2

Timer5_GetFrequency    KEYWORD2
Timer5_SetFrequency    KEYWORD2
Timer5_GetPrescaler    KEYWORD2
Timer5_SetPrescaler    KEYWORD2
Timer5_GetTop    KEYWORD2
Timer5_SetTop    KEYWORD2
Timer5_Initialize    KEYWORD2
Timer5_GetResolution KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################

ps_1 LITERAL1
ps_8 LITERAL1
ps_64 LITERAL1
ps_256 LITERAL1
ps_1024 LITERAL1

psalt_1 LITERAL1
psalt_8 LITERAL1
psalt_32 LITERAL1
psalt_64 LITERAL1
psalt_128 LITERAL1
psalt_256 LITERAL1
psalt_1024 LITERAL1
Tossa mun käyttämäs kirjastossa voi säätää kaikkien timerien toimintaa joten ton voi laittaa käyttää vaikka timer 1 etc
 
Viimeksi muokattu:
Liittynyt
18.10.2016
Viestejä
524
jos kovin pahalta tuntuu toi mun koodi ottaa suoraan käyttöön niin copy pasteile oma koodi tolla mun idealla. itse en ainakaan keksi muuta kuin yksi muuttuja on esim motorStatus ja sille joku arvo ja sitten se otetaan if lauseeseen mukaan if(digital.Read==high && motorStatus == jotain ) niin se ajaa aina sen kohdan kun molemmat ehdot täytyy tälleen saat tehtyä tavallaan tilakoneen joka menee sen mukaan eteenpäin mitä halutaan. jos et jostain syystä halua sitä valmista pwm kirjastoa käyttää niin ota toi mun idea muuten käyttöön , itse jossain vaiheessa totesin että vähänkään isompi ohjelma on parempi tehdä void jokutoiminto() void jokutoiminto1() jne ja sitten vain kutsua noita loopissa
Koodi:
loop{
jokutoiminto();
jokutoiminto1();

}
tälleen tehden debuggaus on helppoa kun toiminto kerralaan voi ajaa ja selvii miksi joku ei toimi.
muista tehdä noi void omatoiminta() loopin yläpuolelle muuten saaTTAA kääntäjä valittaa.
mun mielestä kumminkin toi pwm kirjasto example kertoo näin
//initialize all timers except for 0, to save time keeping functions
eli se ei muuta timer0 että time säilyy muuttumattomana.
muutenkin toi sun orkinaali koodi ei voi olla aikakriittistä kun siellä on delay(xxxx) joka siis jättää koodin siihen kohtaan seis ja se arduino ei tee mitään muuta.
 
Viimeksi muokattu:
Liittynyt
17.01.2018
Viestejä
2 084
Ettei menisi pelkäksi selitykseksi ilman koodia niin tässä on myös esimerkkinä toimiva pwm käyttäen timer1 ilman kirjastoja. Saa käyttää vapaasti jos siltä tuntuu.
Muuten en lähde tekemään kilpailevaa koodia ;)

Täältä löytyy 328P datalehti
Vertaamalla arduino (uno) ja atmega328 pinnejä löytyy arduino pin 9 = OC1A (10 = OC1B) eli nämä "kuuluvat" timer1:lle.

Koodi:
#define MAX_PWM_VALUE   64000  // Max pwm arvo rekisterissä
uint8_t pwm_pin = 9;        // pwm lähtöpinni

// PWM alustus
void pwm_setup() {
    pinMode(pwm_pin, OUTPUT);   // Asetetaan lähdöksi
    digitalWrite(pwm_pin, LOW);    // Asetetaan alas
    // Datalehdestä sivu 109 ensimmäinen taulukko kertoo mitä pitää asettaa että OC1A heiluu pwm tahdissa -> rekisterin TCCR1A bitti COM1A1
    // ja toisesta taulukosta mode 10: phase correct pwm, TOP = ICR1 -> bitit WGM13 ja WGM11 pitää asettaa, ensimmäinen rekisterissä TCCR1B ja toinen TCCR1A
    TCCR1A = (1 << WGM11) | (1 << COM1A1);
    TCCR1B = (1 << WGM13);
    // sivu 105, phase correct pwm taajuus:     f = CLKIO / ( 2 * N * TOP )
    // f = 125Hz ja CLKIO on normaali 5V UNOssa 16MHz, saadaan  N * TOP = 64000  => 64000 mahtuu 16bit rekisteriin eli valitaan N = 1 jolloin TOP = 64000 (=> MAX_PWM_VALUE)
    // Jakaja N asetetaan sivu 110 taulukon mukaan (TCCR1B) rivi 2 eli CLKIO/1 (no prescaling), bitit CS12 = 0, CS11 = 0, CS10 = 1
    // Kellon (eli jakajan) asetus käynnistää ajastimen joten ei tehdä sitä vielä tässä
    ICR1 = MAX_PWM_VALUE;   // TOP eli max arvo
    OCR1A = 0;        // PWM asetusarvo
}

// PWM päälle, tätä ennen pitää asettaa arvo > 0 tai lähtö pysyy alhaalla
void pwm_start() {
    TCCR1A |= (1 << COM1A1);  // Lähdön asetus, koska pwm_stop() käytetty digitalWrite() poistaa sen
    TCCR1B |= (1 << CS10);    // Kellon asetus -> käynnistää pwm- lähdön
}

// PWM pois
void pwm_stop() {
    TCCR1B &= ~(1 << CS10);    // poistetaan kellobitti -> sammuu
    digitalWrite(pwm_pin, LOW);  // varmuuden vuoksi alas (todennäköisesti vain tämä riittäisi koska poistaa timer pwm- lähdön käytöstä
}

// PWM arvon asetus
void pwm_set(uint16_t value) {
    // Varmuuden vuoksi tarkastetaan ettei mene yli, silloin tulee väliin outoja pulsseja
    if (value > MAX_PWM_VALUE) {
        value = MAX_PWM_VALUE;
    }
    OCR1A = value;
}

// pikatesti
void setup() {
    pwm_setup();
    pwm_set(38400);  // = 60% @64000
    pwm_start();
}

void loop() {
}
Skooppi näyttää näin, aika lähellä laskettua. TOP- arvoa voisi myös ehkä säätää sopivasti muutamalla numerolla, saattaa päästä vähän lähemmäs.
1709066693796.png
 
Liittynyt
18.10.2016
Viestejä
524
@ississ tee vaan jos siltä tuntuu ja arvosttellakin saa jos toss mun koodissa on aivopieruja oon vain harraste koodari.
 
Liittynyt
10.07.2017
Viestejä
621
@ississ ja @Nasty76 kiitti taas näistä! Pitää näihin tutustua.

Delay ei tosiaan ole hyvä funktio, mutta näin ohjelmointinoobina ehkä vielä menettelee. Pitää opiskella ja yrittää tajuta tuo millis() -funktion käyttö jotenkin... :)

Eli erilliset funktiot pitää siis laittaa void loopin() yläpuolelle. Voiko niihin sitten viitata loopin sisällä normaalisti esim. tyyliin (kuvitteellinen esimerkki):

void loop()

if(X = 60) {
void erillinen funktio()

}
 
Viimeksi muokattu:
Liittynyt
18.10.2016
Viestejä
524
Totta kai toi onnistuu sekoilin ihan ite tääl. Mä siis teen niihin eri void jotain() eri jutut jotka ajetaan luupissa kuten tossa sun tapauksessa omat void jotain(), on käynnin tunnistus seuraavassa ramppi sitten oma käynnille ja sitten sammutukselle toi on helppo debugata kun ajaa esim pelkkää void rampup niin saa paremmin selvää mikä kusee koodissa jos ei toimi. Noi loopin yläpuolella olevat void jotain ei ajeta ellei loopissa kutsuta void jotain() ja kun se kutsutaan se ajaa joka kerta sen kun looppi pyörähtää ympäri. Toivottavasti auttoo hahmottaa. Toi omien void jotain käyttö ps Google varmaan kertoo jos googlaa arduino return value tms perse kun koko yön valvonut totta kai toi onnistuu viittaat siinä kun arvo yhtä suuri kuin 60 sitten se ajaa ton voidin juu. Pitää muistaa että arduino python tms koodi ajetaan ylhäältä alas nyt jos void on ajo kohdan alapuolella kääntäjä valittaa ehkä ettei löydä sitä kun se ei oo viel lukenu sitä jos tajuut mitä tarkoitan. Tosin sanoen kääntäjä tietää vain ne jutut mitä se on siihen asti lukenu. En oo varma onko se niin arduinossa kun pythonissa ainakaan ei toimi niin automaattisesti ite lisään kaiken yläpuolelle
 
Viimeksi muokattu:
Liittynyt
18.10.2016
Viestejä
524
@Tupsa sekoilin ton viestin kanssa nyt siin kai on mun aivopierun tuotos mitä koitin sanoa sun esimerkki toimii ku se on muodossa vois jotain() ; pitää olla normi arduinon rivin lopetus merkki sitten vielä toi == huono jos sitä joku muu lisää arvoa ja tuo ei just satu kohdalleen kun arvo on 60 ehto ei toteudu ja sitä ei ajeta kannattaa laittaa yhtä suuri tai isompi kuin Google kertoo oon iteki amatööri koodari niin en muista oikeen mitään ulkoa. Huom nyt kun vasta mietin tota auto teknilliseltä näkökulmalta todennäköisesti ton laturin pwm säädön tarkoitus on pitää voltit järjellisissä rajassa toi voi olla että pelkkä ramppi 60 prosenttiin saakin jännitteen vaikka esim 20 volttia tms jotain kummaa oon melko varma että lataus jännitettä pitäs seurata ja ajaa pwm pulssia jännitteen mukaan ei koodissa montaa riviä tartte ja sitten arduino osais käynnistää moottorin kun akun jännite määritetyn rajan alle. Pid säätimeks kutsutaan kai tollasta joka koittaa pitää jonkin asian kohdallaan
 
Viimeksi muokattu:
Liittynyt
10.07.2017
Viestejä
621
@Nasty76 , joo huomasin itsekin, että oli tuo esimerkki mulla väärin. Minun käsityksen mukaan tässä laturin säätimessä duty cycle asettaa latausjännitteen suoraan.
 
Liittynyt
17.01.2018
Viestejä
2 084
@ississ ja @Nasty76 kiitti taas näistä! Pitää näihin tutustua.

Delay ei tosiaan ole hyvä funktio, mutta näin ohjelmointinoobina ehkä vielä menettelee. Pitää opiskella ja yrittää tajuta tuo millis() -funktion käyttö jotenkin... :)

Eli erilliset funktiot pitää siis laittaa void loopin() yläpuolelle. Voiko niihin sitten viitata loopin sisällä normaalisti esim. tyyliin (kuvitteellinen esimerkki):

void loop()

if(X == 60) {
void(erillinen funktio)

}
Ihan tarkennuksena, funktion määrittely on muotoa

<palautustyyppi> <funktion nimi> ( <parametrit> )

Siis void jotain() on funktio joka ei palauta mitään (void), sen nimi on "jotain" eikä se ota parametreja.
Tällaista funktiota kutsutaan muualta jotain();

Toinen esimerkki: int summa ( int a, int b) on funktio nimeltä "summa" joka palauttaa kokonaisluvun ja ottaa parametrina 2 kokonailukua. Tätä kutsuttaisiin
s = summa(1, 2);


Lyhyt yksinkertaistettu selitys järjestykselle: C(++) kääntäjä lukee tiedoston alusta loppuun ja tulkkaa matkan varrella. Jos vastaan tulee jokin jota ei vielä ole määritetty niin tulee käännösvirhe.
Vaihtoehdot:
1. määritetään omat funktiot ja muuttujat aina ennen kuin niitä käytetään
2. määritetään funktio ennen ja toteutus jälkeen
Näistä 1 vaatii vähemmän kirjoittamista ja on yleensä selkeämpi.


Arduino- ympäristössä tapahtuu suunnilleen näin:

1. virrat päälle
2. arduino- juttujen alustus
3. kutsutaan setup()
4. while(true) {
tehdään arduinojuttuja()
loop()
}

Avr- prosessorin ajastimet on oikeasti toteutettu raudalla ja ajavat aidosti koodin kanssa rinnan. Tästä esimerkkinä pwm, jos ajastimen laittaa tuottamaan pwm- signaalia niin se ei vaikuta millään tavalla koodin suoritukseen koska ajastin ajaa itsenäisesti vieressä.
Poikkeuksena on jos määrittää omia keskeytysfunktioita (= interrupt) (esim ajastin voisi kutsua tällaista) niin silloin pääohjelman suoritus keskeytyy siksi ajaksi kun keskeytys suoritetaan. Näin siksi että avr:ssä on vain yksi suorittava cpu.

millis() on toteutettu timer0 keskeytyksenä niin että ajastimella on keskeytysfunktio joka suoritetaan tietyin väliajoin ja siten laskee aikaa. millis() palauttaa lasketun arvon kutsujalle. Se on siis aika millisekunteina koko sysyteemin käynnistyksestä.

Eli jos teet vaan ohjelman jossa
Koodi:
void loop() {
    Serial.prinln(millis());
}
niin tulostettu luku kasvaa koko ajan. Ja mitä enemmän koodia looppiin laittaa sen isommaksi tulostettujen lukujen ero kasvaa.

Kelloa voidaan helposti käyttää kun tarvitaan ajastuksia. Tässä esimerkissä (suoraan hatusta testaamatta) teksti tulostuu sarjaporttiin 5 sekunnin välein ja väliajalla voi suorittaa muuta koodia tuon if- blokin jälkeen (tai ennen).
Koodi:
long start = millis();
void loop() {
  if ( ( millis() - start) > 5000) {    // ( millis() - start ) on jok kutsulla aina vähän isompi, ms siitä kun start on asetettu
      Serial.println("5 sek välein");
      start = millis();   // eo yli 5sek -> asetetaan uusi alkuaika jolloin ajastus alkaa taas alusta
  }
}
Tämä tekisi loogisesti saman asian mutta odotusaikana ei voi tehdä mitään (koska delay()- funktion suoritus kestää koko 5 sek) eli ei oikeasti sovellu mihinkään muuhun kuin huonoon esimerkkiin.
Koodi:
void loop() {
  delay(5000);
  Serial.println("5 sek välein");
}
Tietyissä tilanteissa delay() on ihan ok jos pitää odotella lyhyitä aikoja, esimerkiksi vaikka muutama ms ennen kuin annetaan seuraava komento hitaalle näytölle. Mutta se ei sovellu järkevästi minkäänlaisen aikaperusteisen säädön tekemiseen.


@Nasty76 , joo huomasin itsekin, että oli tuo esimerkki mulla väärin. Minun käsityksen mukaan tässä laturin säätimessä duty cycle asettaa latausjännitteen suoraan.
Asettaa, mutta ei välttämättä pidä sitä koska reaalimaailmassa laturin jännitteeseen vaikuttaa myös kuorma sekä kierrosluku.
Esimerkkinä vaikka 3000rpm 60% antaa 14.5V ilman kuormaa. Jos kuorma ottaa esimerkkinä vaikka 40A niin todennäköisesti jännite laskee jos pwm% tai kierroksia ei kasvata.

Tässä nimenomaisessa tapuksessa jossa kuorma on tavallaan vakio niin max pwm% voi periaatteessa asettaa vakioksi niin että akkuja ei koskaan yliladata vaikka olisivat ihan tyhjiäkin. Normaalitilanteessa lataus on sitten ehkä vähän hitaampaa.
Jos haluaa vakiovirtalaturin niin pitäisi säätää pwm% mitatun virran mukaan ja lisäksi mitata myös akkujen jännite ja osata päätellä milloin ovat täynnä ettei mene ylilatauksen puolelle.
Akku on yleensä siitä mielenkiintoinen kuorma että se rajaa jännitettä aika hyvin jolloin lähteen pitää joustaa sen osalta ja latauksen loppuminen päätellään jännitteestä (ja yleensä myös virrasta). Jos geeliakkuja niin molemmat pitää rajoittaa, perinteisillä lyijyillä hieman eri.

Tähän säätosaan päästään varmaan sitten kun muuten alkaa olla homma toiminnassa.
En lukenut ihan ajatuksella kaikki ayllä olevia koodeja mutta kannattaa myös varmistaa oikea toiminta siinä tapauksessa että jotain odottamatonta tapahtuu, esimerkiksi moottori sammuu kesken kaiken.
Silloin tuohon @Nasty76 koodiin voisi lisätä varmistuksen esimerkiksi tähän tyyliin:
Koodi:
void loop()
{
 if (digitalRead(motorPin) {
  motorRunning();
  pwmRampup(); 
  shutDown();
  readCurrent();
 } else {
    nollataan lähdöt ja ollaan valmiina odottamaan uutta käynnistystä
 }
}
 
Liittynyt
10.07.2017
Viestejä
621
@ississ , no nyt tuli rautaista tietoa! Pitää tosissaan lukea tuo useampaan kertaan, että pääsee hommaan vähän enemmän kärryille. Suomenkielistä tietoa tästä on hyvin vähän. Kiitti tästä. :)

Itsellä on mielestäni toimintalogiikka kohtuu hyvin selvillä, mutta kun en käytännössä osaa koodata, niin siinä on se kompastuskivi. Ajattelin myös tuota, jos moottori vaikka sammuu kesken kaiken, vaikkapa bensa loppuu. Mutta käytännössä, virtakytkin kiinni ja tankkiin bensaa, niin ohjelma alkaa puhtaalta pöydältä. Tämmöinen mennään siitä, missä aita on matalin -ratkaisu.
 
Liittynyt
10.07.2017
Viestejä
621
@Nasty76 kiitokset vielä tuosta koodistasi. Käytin koodiasi tähän koodiini. Oikein hienosti toimii tuo anturin tuloviive. Samoin näytölle se kohta, kun odotetaan moottorin käynnistymistä. Ei välkkymistä tai värinää, joten sen osalta asia kunnossa.

En saa nyt tuota virramittausta toimimaan. En saa näytölle ollenkaan virtatietoja. Heti kun pwm on ajettu ylös, siirrytään sammutusfunktioon. Tämä myös näkyy serialmonitorista, kun laitoin debug rivin.

Eli toiminta nyt:

- heti kun motorStatus tulee tilaan 2, käynnistyy sammutusfunktio. Näyttö myös alkaa väristä, (tekstinään Käynnistä moottori..:) joka johtuu varmasti siitä, kun lcd.clear() toistuu koko ajan päällekkäisten toimintojen vuoksi. Nuo ylimääräiset merkit tulee siitä, kun näytölle yrittää tulla siis tuo käynnistä moottori-teksti sekä Sammutus... teksti, joka on tuolla sammutusfunktiossa. Eli nuo tulee nyt päällekkäin. Käynnistä-moottori teksti löytyy motorRunning() funnktiosta.

Koodi:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Create a new LiquidCrystal_I2C display object with the correct I2C address and display size

// Define the pins
const int currentPin = A0;             //information about current
const int motorPin = 7;                //motor running pin, HIGH = motor running, TEST purpose LOW
const int pwmPin = 9;                  //PWM output pin
const int relayPin = 3;                //Relay control pin
float voltageFactor = 5.0 / 1023.0;    //Factor to convert ADC reading to voltage
float currentFactor = 80 / 4.8351848;  //4.8351848 volts = 80 amps, factor to convert voltage to current
float current;                         //store current value
const int N = 10;                      //number of readings to average
int readings[N];                       //array to store the readings
int motorStatus;                       //0=stopped, 1=starting, 2=running
unsigned long lastTime;                //timer to measure engine sensor input time for starting


void setup() {

  Serial.begin(9600);  // Start the serial communication

  // Initialize the LCD here
  // Give the screen time to boot
  delay(1500);
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.clear();

  // Change timers on pins to change PWM freq to 122 Hz
  // Pins D9 and D10 - 122 Hz
  TCCR1A = 0b00000001;  // 8bit
  TCCR1B = 0b00000100;  // x256 phase correct

  // Make pins output/input
  pinMode(currentPin, INPUT);
  pinMode(motorPin, INPUT_PULLUP);  //For real use, delete _PULLUP (it is for test purpose, pullup resistor)
  pinMode(pwmPin, OUTPUT);
  pinMode(relayPin, OUTPUT);
}


void motorRunning() {  //engine running function
  if (digitalRead(motorPin) == HIGH && motorStatus == 0) {

    if (millis() - lastTime >= 6000) {
      motorStatus = 1;

      Serial.println("Engine is running");  // Print a message when the engine is running
    }

  } else {
    lastTime = millis();

    lcd.setCursor(0, 0);
    lcd.print("K");
    lcd.print((char)0xe1);
    lcd.print("ynnist");
    lcd.print((char)0xe1);
    lcd.setCursor(0, 1);
    lcd.print("moottori");
  }
}


void rampUp() {  //rampup pwm

  // Ramp pwm up
  if (motorStatus == 1) {

    analogWrite(pwmPin, 13);
    delay(1000);
    analogWrite(pwmPin, 48);
    delay(1000);
    analogWrite(pwmPin, 83);
    delay(1000);
    analogWrite(pwmPin, 118);
    delay(1000);
    analogWrite(pwmPin, 153);  //Duty Cycle at 60 percent
    motorStatus = 2;
  }
}

void readCur() {  //calculate current from shunt reading

  // Calculate the charging current from the average and display it on the LCD screen.
  // take N readings and store them in the array

  if (motorStatus == 2) {
    for (int i = 0; i < N; i++) {
      readings[i] = analogRead(currentPin);
      delay(10);  // wait for 10 milliseconds between readings
    }

    // calculate the average of the N readings
    float sum = 0;
    for (int i = 0; i < N; i++) {
      sum += readings[i];
    }
    float average = sum / N;

    float voltage = average * voltageFactor;  //  Convert ADC reading to voltage

    float current = voltage * currentFactor;  // Convert voltage to current
    lcd.setCursor(0, 0);
    lcd.print("Latausvirta:");
    lcd.setCursor(0, 1);
    lcd.print((int)current);
    lcd.print("  ");
    lcd.setCursor(3, 1);
    lcd.print(" A");
    lcd.setCursor(5, 1);
    lcd.print("        ");
  }
}


void shutDown() {  //engine shutdown, execute relay
  // If the charging current drops below five amperes
  // start the shutdown function and turn off the relay
  if (current < 5 && motorStatus == 2) {
    digitalWrite(relayPin, LOW);
    Serial.println("Shutdown function started");  // Print a message when the shutdown function starts
    lcd.setCursor(0, 0);
    lcd.print("Sammutus...");
  }
}



void loop() {

  motorRunning();
  rampUp();
  readCur();
  shutDown();
  Serial.println("Motor status: ");
  Serial.println((int) motorStatus);
}
 
Liittynyt
18.10.2016
Viestejä
524
Koodi:
if (current < 5 && motorStatus == 2) { //tässä ajetaan sammutus kun virta alle 5 ja motorStatus 2 ))
    digitalWrite(relayPin, LOW);
    Serial.println("Shutdown function started");  // Print a message when the shutdown function starts
    lcd.setCursor(0, 0);
    lcd.print("Sammutus...");
  }
koitan auttaa suo parhaan mukaan se on vähä vaikeeta atm selkä todella paha mutta sulla ongelma kun sulla ei oo tuolla engine running , tuo pwm funktio asettaa motorstatus tms =2 ja kun virta on alle 5 se sammuttaa sen kuten kuuluu. voit debuga sitä että tuolla virta jutussa määrite testin vuoksi vaikka tuon mittauksen tilasta siis jos sulla ei laturi pyöri niin
current = 5.1 ja kokeile mitä tapahtuu. toi koodi toimii just oikein kuten oot sitä muokannut
ps pahoin pelkään ettei tuo laturi kyllä lataa pelkällä pwm llä jos sielä akussa latauksen aikana kuorma vaihtelee joten se jännitteen säätö siihen pitää vielä tehdä mjutta sekin meiltä kyllä yhteis tuumin onnistuu. onneks ississ osaa suomentaa mun sanomiset suomeksi =)
pps äkkiseltään en kyllä tajuu miks toi koittaa heti perään starttata kun et shutdownissa määritä motorStatusta 0
 
Viimeksi muokattu:
Liittynyt
17.01.2018
Viestejä
2 084
Pikaluku sanoo että tilojen vaiihdoksia pitäisi olla enemmän ja sitä kautta saadaan toiminnallisuus jossa esim tuo lcd tulostus tehtäisiin vain kerran eikä jatkuvasti.
Tuossahan käy niin että jos tila jää arvoon 2 ja virta pieni niin lcd kirjoitus tehdään monta kertaa. Eli sellainen "ollaan seis eikä tehdä mitään (tai odotetaan käynnistystä)" pitäisi olla vielä sammutuksen jälkeen.
Ja lcd tulostus vain tilan vaihtuessa. Muuten menee helposti tekstit päällekkäin ja koska lcd kirjoitus on muuhun koodiin verrattuna hidasta niin vilkkumisen ehtii nähdä kun tekstit vaihtuu vuorotellen.

Melkein sanoisin että tilahärveli kannattaa tehdä loop()- funktiossa ja kutsua sitten erillisiä "tee tämä yksi juttu" funktioita tarpeen mukaan. Ja varmistaa että tulostukset ja lcd päviitetään vain tarvittaessa eikä joka kierroksella.
 
Liittynyt
10.07.2017
Viestejä
621
@Nasty76 ja @ississ , tässä taas vähän päivitetty koodi. Nyt näyttö ei värise missään vaiheessa, ainoastaan jonkin verran menee eri tilojen näytöt päällekkäin, mutta tuo ei olisi ongelma, jos se olisi ainoa. Tulostaisi vaan uuden edellisen päälle tyylillä lcd.print(" "). Virtaa ei näy edelleenkään lainkaan näytöllä, enkä osannut sille tehdä mitään. Luulen, että virta-arvo on koko ajan nolla, minkä vuoksi sammutusfunktio käynnistyy heti.

Mutta siis toimii ainakin näytön mukaan edelleen (jee en onnistunut pilaaman koodin alkua!) siihen asti, kunnes pwm on nostettu ylös. Hoksasin muuten, että tässä tapauksessa tuosta delay()-funktiosta voi olla hyötyä pwm:än nostamisen aikana, kun silloin ei huomioida virtaa. Virtahan olisi siinä moottorin käynnistyessä nollaa lähellä, jolloin muuten käynnistyisi heti sammutusfunktio. Tai näin päättelisin. Virtaa ei näy edelleenkään lainkaan näytöllä, enkä osannut sille tehdä mitään. Luulen, että virta-arvo on koko ajan nolla, minkä vuoksi sammutusfunktio käynnistyy heti.

Nyt hyppää suoraan pwm:n nostamisen jälkeen tilaan kolme, eli sammutuksen jälkeiseen tilaan. Lisäsin tilan kolme ja uuden sammutuksen jälkeisen funktion, ja näytölle tulisi teksti "Käynnistä uudelleen". Se siis kyllä tulee, mutta tosiaan hyppää heti pwm:n noston jälkeen siihen.

EDIT: Joo, jos alla olevan koodin suhteessa tämä pyyntö on oikein, current, eli virta on koko ajan nolla, joka mahdollisesti aiheuttaa sen, että siirrytään suoraan tilaan kolme eikä virtaa näy näytölläkään missään vaiheessa.

Serial.println("Current: ");
Serial.println((float)current);



Koodi:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Create a new LiquidCrystal_I2C display object with the correct I2C address and display size

// Define the pins
const int currentPin = A0;             //information about current
const int motorPin = 7;                //motor running pin, HIGH = motor running, TEST purpose LOW
const int pwmPin = 9;                  //PWM output pin
const int relayPin = 3;                //Relay control pin
float voltageFactor = 5.0 / 1023.0;    //Factor to convert ADC reading to voltage
float currentFactor = 80 / 4.8351848;  //4.8351848 volts = 80 amps, factor to convert voltage to current
float current;                         //store current value
const int N = 10;                      //number of readings to average
int readings[N];                       //array to store the readings
int motorStatus;                       //0=stopped, 1=starting, 2=running, 3=stopped but did run
unsigned long lastTime = 0;            //timer to measure engine sensor input time for starting


void setup() {

  Serial.begin(9600);  // Start the serial communication

  // Initialize the LCD here
  // Give the screen time to boot
  delay(1500);
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.clear();

  // Change timers on pins to change PWM freq to 122 Hz
  // Pins D9 and D10 - 122 Hz
  TCCR1A = 0b00000001;  // 8bit
  TCCR1B = 0b00000100;  // x256 phase correct

  // Make pins output/input
  pinMode(currentPin, INPUT);
  pinMode(motorPin, INPUT_PULLUP);  //For real use, delete _PULLUP (it is for test purpose, pullup resistor)
  pinMode(pwmPin, OUTPUT);
  pinMode(relayPin, OUTPUT);
}


void motorRunning() {  //engine running function
  if (digitalRead(motorPin) == HIGH && motorStatus == 0) {

    if (millis() - lastTime >= 6000) {

      motorStatus = 1;

    }

  } else if (motorStatus == 0) {
    lastTime = millis();

    lcd.setCursor(0, 0);
    lcd.print("K");
    lcd.print((char)0xe1);
    lcd.print("ynnist");
    lcd.print((char)0xe1);
    lcd.setCursor(0, 1);
    lcd.print("moottori");
  }
}


void rampUp() {  //rampup pwm

  // Ramp pwm up
  if (motorStatus == 1) {

    analogWrite(pwmPin, 13);
    delay(1000);
    analogWrite(pwmPin, 48);
    delay(1000);
    analogWrite(pwmPin, 83);
    delay(1000);
    analogWrite(pwmPin, 118);
    delay(1000);
    analogWrite(pwmPin, 153);  //Duty Cycle at 60 percent

    motorStatus = 2;
  }
}

void readCur() {  //calculate current from shunt reading

  // Calculate the charging current from the average and display it on the LCD screen.
  // take N readings and store them in the array

  if (motorStatus == 2) {
    for (int i = 0; i < N; i++) {
      readings[i] = analogRead(currentPin);
      delay(10);  // wait for 10 milliseconds between readings
    }

    // calculate the average of the N readings
    float sum = 0;
    for (int i = 0; i < N; i++) {
      sum += readings[i];
    }
    float average = sum / N;

    float voltage = average * voltageFactor;  //  Convert ADC reading to voltage

    float current = voltage * currentFactor;  // Convert voltage to current
    lcd.setCursor(0, 0);
    lcd.print("Latausvirta:");
    lcd.setCursor(0, 1);
    lcd.print((int)current);
    lcd.print("  ");
    lcd.setCursor(3, 1);
    lcd.print(" A");
    lcd.setCursor(5, 1);
    lcd.print("        ");
  }
}


void shutDown() {  //engine shutdown, execute relay
  // If the charging current drops below five amperes
  // start the shutdown function and turn off the relay
  if (current < 5 && motorStatus == 2) {
    digitalWrite(relayPin, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Sammutus...");

    motorStatus = 3;
  }
}

void motorDidRun() {  //engine has stopped after it was running

  if (motorStatus == 3) {
    lcd.setCursor(0, 0);
    lcd.print("K");
    lcd.print((char)0xe1);
    lcd.print("ynnist");
    lcd.print((char)0xe1);
    lcd.setCursor(0, 1);
    lcd.print("uudelleen");
 
  }
}


void loop() {

  motorRunning();
  rampUp();
  readCur();
  shutDown();
  motorDidRun();
  Serial.println("Motor status: ");
  Serial.println((int)motorStatus);
}
 
Liittynyt
17.01.2018
Viestejä
2 084
Tarjoan nyt kuitenkin hieman toisenlaisen vaihtoehdon.

- tilat nimettyinä vakioina niin saattaa olla helpompi seurata koodissa
- lisätty "sammutusviive" tila. Sen alussa asetetaan sammutusrele päälle ja viiveen jälkeen pois (tai käyntitiedon puuttuessa, kumpi sitten tuleekaan ensin)
- jos sammutetaan virran ollessa tarpeeksi pieni, sammutusviiveen ja sammutuksen jälkeen jäädään odottamaan seuraavaa käyntitietoa
- virran mittaus ja näyttö on eriytetty selkeyden vuoksi
- virta mitataan vain "ajossa"- tilassa jolloin se ei häiritse muita tiloja
- kaikki muut tulostukset sarjaporttiin tehdään vain kerran paitsi virran arvo. Vastaaviin kohtiin voi lisätä/muuttaa lcd kirjoituksen
- pwm rampille voi antaa kestoajan ja askeleiden lukumäärän josta lasketaan yhden askeleen kestoaika ja arvon lisäys.
- pwm asetusarvo (nyt 60%) on valmiiksi muuttujassa jos sitä joskus haluaisi säätää ajon aikana. Silloin pwm_set() pitää lisätä esimerkiksi heti virran mittauksen jälkeen.
- jokaisessa ajastuksessa käytetään millis() - alku. Alustuksessa kannattaa tietysti käyttää delay() ennen lcd käyttöä, samoin virran mittausten välissä.

Kannattaa huomioida ajastuksissa että esim 9600 sarjaportin kirjoitus on oikeasti todella hidas ja voi vaikuttaa ajastuksiin merkittävästi. Samoin lcd päivitys.
Eli koodi saattaa toimia eri nopeudella riippuen tulostusten määrästä.

Yritin kommentoida sen verran että toiminnasta olisi riittävän helppo saada selvää.


C++:
// Nämä pitää säätää sopiviksi
#define PWM_RAMP_TIME    6000           // pwm rampin aika, ms
#define PWM_RAMP_STEPS     50           // pwm rampin askeleiden lukumäärä
#define STARTUP_DELAY    6000           // Käynnistysviive, ms
#define SHUTDOWN_DELAY  10000           // Sammutusviive, ms
#define STOP_CURRENT        5           // Sammutuksen virtaraja, A


#define STATE_OFF           0           // tila: sammutettuna, odottaa käynnistystä
#define STATE_STARTUP_DELAY 1           // tila: latauksen käynnistysviive moottorin käynnistyksen jälkeen
#define STATE_STARTUP_RAMP  2           // tila: pwm ramppi käynnissä
#define STATE_RUNNING       3           // tila: käynnissä
#define STATE_STOPPING      4           // tila: sammutusviive käynnissä

#define MAX_PWM_VALUE   64000           // pwm max arvo (= 100%)

uint8_t state = STATE_OFF;              // tila
const uint8_t currentPin   = A0;        // virta
const uint8_t pwmPin       = 9;         // pwm ulos
const uint8_t motorPin     = 7;         // moottori käynnissä = H, sammutettu = L
const uint8_t relayPin     = 3;         // releen ohjaus
const uint8_t currentCount = 10;        // virran mittaustren lukumäärä
uint16_t pwmValue          = 0;         // pwm asetusarvo
uint16_t pwmRampStep       = 0;         // pwm rampin askel
uint16_t pwmMaxPercent     = 60;        // max pwm %
uint16_t pwmIncrement      = 0;         // pwm rampin lisäys / askel
unsigned long pwmRampTime  = 0L;        // pwm rampin aika, lasketaan
unsigned long startTime    = 0L;        // alkuaika

// Alkuperäiset, nämä pitää säätää sitten kun reaalimaailman virran mittaus on toteutettu.
// Kannattaa laskea valmiiksi alempaan curentAdjust- muuttujaan.
float voltageFactor = 5.0 / 1023.0;     // ADC value -> V
float currentFactor = 80 / 4.8351848;   // V -> A

float currentAdjust = voltageFactor * currentFactor;  // Laskennassa käytetty kerroin


// PWM alustus
void pwm_setup() {
    pinMode(pwmPin, OUTPUT);   // Asetetaan lähdöksi
    digitalWrite(pwmPin, LOW);    // Asetetaan alas
    // Datalehdestä sivu 109 ensimmäinen taulukko kertoo mitä pitää asettaa että OC1A heiluu pwm tahdissa -> rekisterin TCCR1A bitti COM1A1
    // ja toisesta taulukosta mode 10: phase correct pwm, TOP = ICR1 -> bitit WGM13 ja WGM11 pitää asettaa, ensimmäinen rekisterissä TCCR1B ja toinen TCCR1A
    TCCR1A = (1 << WGM11) | (1 << COM1A1);
    TCCR1B = (1 << WGM13);
    // sivu 105, phase correct pwm taajuus:     f = CLKIO / ( 2 * N * TOP )
    // f = 125Hz ja CLKIO on normaali 5V UNOssa 16MHz, saadaan  N * TOP = 64000  => 64000 mahtuu 16bit rekisteriin eli valitaan N = 1 jolloin TOP = 64000 (=> MAX_PWM_VALUE)
    // Jakaja N asetetaan sivu 110 taulukon mukaan (TCCR1B) rivi 2 eli CLKIO/1 (no prescaling), bitit CS12 = 0, CS11 = 0, CS10 = 1
    // Kellon (eli jakajan) asetus käynnistää ajastimen joten ei tehdä sitä vielä tässä
    ICR1 = MAX_PWM_VALUE;   // TOP eli max arvo
    OCR1A = 0;        // PWM asetusarvo
}

// PWM päälle, tätä ennen pitää asettaa arvo > 0 tai lähtö pysyy alhaalla
void pwm_start() {
    TCCR1A |= (1 << COM1A1);  // Lähdön asetus, koska pwm_stop() käytetty digitalWrite() poistaa sen
    TCCR1B |= (1 << CS10);    // Kellon asetus -> käynnistää pwm- lähdön
}

// PWM pois
void pwm_stop() {
    TCCR1B &= ~(1 << CS10);     // poistetaan kellobitti -> sammuu
    digitalWrite(pwmPin, LOW);  // varmuuden vuoksi alas (todennäköisesti vain tämä riittäisi koska poistaa timer pwm- lähdön käytöstä
}

// PWM arvon asetus
void pwm_set(uint16_t value) {
    // Varmuuden vuoksi tarkastetaan ettei mene yli, silloin tulee väliin outoja pulsseja
    if (value > MAX_PWM_VALUE) {
        value = MAX_PWM_VALUE;
    }
    OCR1A = value;
}




// Virran mittaus, 10 mittauksen keskiarvo
float readCurrent() {
    float current = 0.0;
    for (int i = 0; i < currentCount; i++) {
        current += analogRead(currentPin);
        delay(10);
    }
    return ( (current / (float)currentCount) * currentAdjust );
}





// Alustus
void setup() {
    Serial.begin(115200);

    Serial.println();
    Serial.println();
    Serial.println("setup pinnit");
    pinMode(currentPin, INPUT);
    pinMode(motorPin, INPUT_PULLUP);
    pinMode(relayPin, OUTPUT);
    digitalWrite(relayPin, LOW);

    Serial.println("setup pwm");
    pwm_setup();

    Serial.println("setup lcd");
    // delay(3000);
    // lcd.begin(16, 2);
    // lcd.backlight();
    // lcd.clear();

    state = STATE_OFF;
    Serial.println("setup valmis");
}






// loop
void loop() {

    int running = digitalRead(motorPin);  // Käynnissä- tieto
    if (running) {

        // Käynnissä- tieto ok, tila = sammutettu
        if (state == STATE_OFF) {
            // Käynnistetään aloitusviive
            digitalWrite(relayPin, LOW);
            state = STATE_STARTUP_DELAY;
            Serial.println("kaynnistysviive alkaa");
            startTime = millis();
        }


        // Käynnistysviive menossa ?
        if (state == STATE_STARTUP_DELAY) {
            // Käynnistysviive odotettu -> aloitetaan pwm ramppi
            if ((millis() - startTime) > STARTUP_DELAY) {
                state = STATE_STARTUP_RAMP;
                Serial.println("pwm ramppi alkaa");
                pwmRampStep = 1;                               // Ensimmäinen askel
                pwmRampTime = PWM_RAMP_TIME / PWM_RAMP_STEPS;  // Askeleen aika
                Serial.print("pwm step aika ");
                Serial.println(pwmRampTime);
                // pwm lisäys askeleella: (max * prosentti) / askeleet
                pwmIncrement = ((MAX_PWM_VALUE * pwmMaxPercent) / 100 ) / PWM_RAMP_STEPS;
                pwmValue = pwmIncrement;
                Serial.print("pwm asetus alku ");
                Serial.println(pwmValue);
                pwm_set(pwmValue);  // pwm asetus
                pwm_start();        // pwm päälle
                startTime = millis();
            }
        }
    
        // PWM ramppi, sekunnin välein 10% lisäys
        if (state == STATE_STARTUP_RAMP) {
            // Lasketaan odotusaika. Joka askeleella lisätään odotusaikaan yhden askeleen aika
            unsigned long pwmRampLimit = pwmRampStep * pwmRampTime;
            // Aika täynnä -> seuraava askel
            if ( ( (millis() - startTime) > pwmRampLimit ) && ( pwmRampStep <= PWM_RAMP_STEPS ) ) {
                // arvo = askeleen numero * lisäys
                pwmValue = pwmRampStep * pwmIncrement;
                //Serial.print("pwm asetus ");
                //Serial.println(pwmValue);
                pwm_set(pwmValue);
                pwmRampStep++;
                if (pwmRampStep > PWM_RAMP_STEPS) {
                    // 6 sekuntia = 6 askelta jonka jälkeen loppu
                    Serial.println("pwm ramppi valmis");

                    Serial.print("pwm rampin suoritusaika: ");
                    Serial.print(millis() - startTime);
                    Serial.println(" ms");

                    state = STATE_RUNNING;
                }
            }
        }

        // Ajossa, mitataan virtaa
        if (state == STATE_RUNNING) {
            float current = readCurrent();  // Mitataan virta

            Serial.print("Mitattu virta ");
            Serial.print(current);
            Serial.println(" A");

            // lcd.setCursor(0, 0);
            // lcd.print("Latausvirta:");
            // lcd.setCursor(0, 1);
            // lcd.print((int)current);
            // lcd.print(" ");
            // lcd.setCursor(3, 1);
            // lcd.print(" A");

            // Virta alle rajan -> sammutus alkaa
            if (current < STOP_CURRENT) {
                // Sammutetaan
                Serial.print("virta alle ");
                Serial.print(STOP_CURRENT);
                Serial.println(" -> sammutus");
                pwm_stop();
                digitalWrite(relayPin, HIGH);
                state = STATE_STOPPING;
                startTime = millis();
            }
        }

        // Sammutus
        if (state == STATE_STOPPING) {
            // Odotetaan annettu aika -> sammutettu
            if ((millis() - startTime) > SHUTDOWN_DELAY) {
                state = STATE_OFF;
                Serial.println("Sammutettu. Odotetaan kayntitietoa");
                digitalWrite(relayPin, LOW);
            }
        }

    } else {
        // Ei käyntitietoa -> palataan alkuun
        if (state != STATE_OFF) {
            Serial.println("Ei kayntitietoa. Odotetaan kayntitietoa");
            state = STATE_OFF;
            pwm_stop();
            digitalWrite(relayPin, LOW);
        }
    }


}
Esimerkkitulostus. Pwm ramppi alkaa tulosteen jälkeen trimmillä A0 jännitteen nosto. Virtojen mittauksen jälkeen poistettu käyntitieto -> tulee useaan kertaan koska kytkimenä on vain johto koekytkentälevyllä. Oikeassa kytkennässä kuuluu olla suodatus ;)
Hetken kuluttua käyntitieto asetetaan uudelleen jolloin alkaa alusta. Toisella kerralla säädetty "virta" pienmmäksi -> sammuu. Sammutuksen jälkeen uusi käynnistysviive jolloin poistettu käyntitieto
1709147215206.png
 
Toggle Sidebar

Statistiikka

Viestiketjut
239 900
Viestejä
4 188 758
Jäsenet
70 832
Uusin jäsen
alder2002

Hinta.fi

Ylös Bottom